From idasql
Decompiles and analyzes IDA Pro functions with Hex-Rays for pseudocode, ctree AST, local variables, labels, and decompiler-driven cleanup in reverse engineering.
npx claudepluginhub allthingsida/idasql-skills --plugin idasqlThis skill is limited to using the following tools:
---
Edits IDA databases via idasql: add comments to pseudocode/disassembly, rename symbols/locals, apply types/enums/structs, create bookmarks, clean decompiled code for review.
Decompiles binary functions to C-like pseudocode using VulHunt tools. Analyze function logic, control flow, or prepare for code pattern matching.
Performs depth-first reverse engineering on Ghidra binaries, answering questions like function behavior, crypto usage, or C2 addresses via iterative analysis and database improvements.
Share bugs, ideas, or general feedback.
Use this skill when user asks for:
Route to:
annotations for persistent comments/renames after interpretationtypes for struct/enum/type construction and applicationdisassembly when decompiler is unavailable or insufficient-- 1) Capability/profile probe
SELECT * FROM pragma_table_list WHERE name IN ('pseudocode', 'ctree', 'ctree_lvars');
-- 2) Pick one concrete function target
SELECT name, printf('0x%X', address) AS addr, size
FROM funcs
ORDER BY size DESC
LIMIT 10;
-- 3) View decompiled text via primary read surface
SELECT decompile(0x401000);
Interpretation guidance:
decompile(addr) is primary display surface.pseudocode/ctree* are structured query/edit surfaces.Always constrain decompiler tables by function:
WHERE func_addr = 0x...
Without this, decompiler tables may decompile every function and become extremely slow.
disassembly + xrefs workflows.func_addr exists and refresh decompile cache (decompile(addr, 1) where supported).decompiler -> types for local type seeding and richer declarations.decompiler -> annotations for persistent narrative and naming.decompiler -> disassembly for opcode-level validation.CRITICAL: Always filter by func_addr. Without constraint, these tables will decompile EVERY function - extremely slow!
The pseudocode table is a structured line-by-line pseudocode with writable comments. Use decompile(addr) to view pseudocode; use this table only for surgical edits (comments) or structured queries.
| Column | Type | Writable | Description |
|---|---|---|---|
func_addr | INT | No | Function address |
line_num | INT | No | Line number |
line | TEXT | No | Pseudocode text |
ea | INT | No | Corresponding assembly address (from COLOR_ADDR anchor) |
comment | TEXT | Yes | Decompiler comment at this ea |
comment_placement | TEXT | Yes | Comment placement: semi (inline, default), block1 (above line) |
Filter behavior:
WHERE func_addr = X: best performance; iterates pseudocode for one function only.WHERE ea = X: decompiles only the containing function and returns matching lines for that EA.WHERE line_num = N: scans functions and returns rows at that line index; use only when you need cross-function line alignment.Comment placements: semi (after ;), block1 (own line above), block2, curly1, curly2, colon, case, else, do
-- VIEWING: Use decompile() function, NOT the pseudocode table
SELECT decompile(0x401000);
-- COMMENTING: Use pseudocode table to add/edit/delete comments
UPDATE pseudocode SET comment_placement = 'semi',
comment = 'buffer overflow here'
WHERE func_addr = 0x401000 AND ea = 0x401020;
-- Add block comment (appears on own line above the statement)
UPDATE pseudocode SET comment_placement = 'block1', comment = 'vulnerable call'
WHERE func_addr = 0x401000 AND ea = 0x401020;
-- Delete comments at a resolved unique anchor
UPDATE pseudocode SET comment = NULL
WHERE func_addr = 0x401000 AND ea = 0x401020;
True function comments are not part of pseudocode:
UPDATE funcs SET comment = ... WHERE address = ... for the regular function commentUPDATE funcs SET rpt_comment = ... WHERE address = ... for the repeatable function commentPersisted Hex-Rays comments that no longer attach to the current decompiled output of a live function. Use it to inspect or delete stale comments.
| Column | Type | Writable | Description |
|---|---|---|---|
func_addr | INT | No | Function address |
func_name | TEXT | No | Current function name for triage |
ea | INT | No | Stored orphan comment EA |
comment_placement | TEXT | No | Stored treeloc_t.itp placement |
orphan_comment | TEXT | Delete-only | Stored orphan comment text |
Rules:
UPDATE ... SET orphan_comment = NULL or '' deletes that orphan comment.Grouped, read-only orphan triage surface. One row per function with orphan comments.
Columns: func_addr, func_name, orphan_count, orphan_comments_json
Use this recipe before writing heading-style decompiler notes.
Rules:
ea == func_addr.ea = 0 and is not the right write target.ea can map to multiple rows ({, statement, }); prefer a unique non-brace anchor.funcs.comment / funcs.rpt_comment instead of pseudocode.-- Resolve the first attachable non-brace row near function start
SELECT line_num, ea, line
FROM pseudocode
WHERE func_addr = 0x401000
AND ea != 0
AND TRIM(line) NOT IN ('{', '}')
AND ea IN (
SELECT ea
FROM pseudocode
WHERE func_addr = 0x401000 AND ea != 0
GROUP BY ea
HAVING COUNT(*) = 1
)
ORDER BY line_num
LIMIT 1;
-- Write a heading-style summary using the resolved ea
UPDATE pseudocode
SET comment_placement = 'block1',
comment = 'One-paragraph summary of the function.'
WHERE func_addr = 0x401000
AND ea = (
SELECT ea
FROM pseudocode
WHERE func_addr = 0x401000
AND ea != 0
AND TRIM(line) NOT IN ('{', '}')
AND ea IN (
SELECT ea
FROM pseudocode
WHERE func_addr = 0x401000 AND ea != 0
GROUP BY ea
HAVING COUNT(*) = 1
)
ORDER BY line_num
LIMIT 1
);
Full Abstract Syntax Tree of decompiled code.
| Column | Type | Description |
|---|---|---|
func_addr | INT | Function address |
item_id | INT | Unique node ID |
is_expr | INT | 1=expression, 0=statement |
op_name | TEXT | Node type (cot_call, cit_if, etc.) |
ea | INT | Address in binary |
parent_id | INT | Parent node ID |
depth | INT | Tree depth |
x_id, y_id, z_id | INT | Child node IDs |
var_idx | INT | Local variable index |
var_name | TEXT | Variable name |
obj_ea | INT | Target address |
obj_name | TEXT | Symbol name |
num_value | INT | Numeric literal |
label_num | INT | Label number when node defines a label |
goto_label_num | INT | Target label number for cit_goto nodes |
str_value | TEXT | String literal |
Local variables from decompilation.
| Column | Type | Description |
|---|---|---|
func_addr | INT | Function address |
idx | INT | Variable index |
name | TEXT | Variable name |
type | TEXT | Type string |
comment | TEXT | Local-variable comment shown next to declaration |
size | INT | Size in bytes |
is_arg | INT | 1=function argument |
is_stk_var | INT | 1=stack variable |
stkoff | INT | Stack offset |
Mutation guidance:
idx-based updates for deterministic writes.comment updates map to Hex-Rays local-variable comments (lv.cmt) and appear in decompile(...) output.Decompiler control-flow labels. Supports UPDATE (name) and mirrors label facilities on cfunc_t.
| Column | Type | RW | Description |
|---|---|---|---|
func_addr | INT | R | Function address |
label_num | INT | R | Label number (LABEL_<n>) |
name | TEXT | RW | Current label name |
item_id | INT | R | Backing ctree item id for this label |
item_ea | INT | R | Address of label-bearing ctree item |
is_user_defined | INT | R | 1 if name differs from default LABEL_<n> |
Flattened call arguments for easy querying.
| Column | Type | Description |
|---|---|---|
func_addr | INT | Function address |
call_item_id | INT | Call node ID |
call_ea | INT | Call-site EA |
call_obj_name | TEXT | Callee object name |
call_helper_name | TEXT | Callee helper name |
arg_idx | INT | Argument index (0-based) |
arg_item_id | INT | Argument expression item ID |
arg_op | TEXT | Argument type |
arg_var_name | TEXT | Variable name if applicable |
arg_num_value | INT | Numeric value |
arg_str_value | TEXT | String value |
Pre-built views for common patterns (always filter by func_addr):
| View | Purpose |
|---|---|
ctree_v_calls | Function calls with callee info |
ctree_v_indirect_calls | Indirect/dynamic call sites for call-site typing |
pseudocode_v_orphan_comment_groups | Grouped orphan comment triage |
ctree_v_loops | for/while/do loops |
ctree_v_ifs | if statements |
ctree_v_comparisons | Comparisons with operands |
ctree_v_assignments | Assignments with operands |
ctree_v_derefs | Pointer dereferences |
ctree_v_returns | Return statements with value details |
ctree_v_calls_in_loops | Calls inside loops (recursive) |
ctree_v_calls_in_ifs | Calls inside if branches (recursive) |
ctree_v_leaf_funcs | Functions with no outgoing calls |
ctree_v_call_chains | Call chain paths up to depth 10 |
For types, types_members, types_enum_values, types_func_args schemas, type views, and type CRUD examples, see types skill.
When to use decompile() vs pseudocode table:
SELECT decompile(addr). Returns full function as one text block with per-line prefixes.[lv:N]) so rename operations can target rename_lvar(func_addr, N, new_name) safely.SELECT decompile(addr, 1) to force re-decompilation.pseudocode table.| Function | Description |
|---|---|
decompile(addr) | PREFERRED -- Full pseudocode with line prefixes |
decompile(addr, 1) | Same output but forces re-decompilation |
apply_callee_type(call_ea, decl) | Apply a prototype to one call site |
callee_type_at(call_ea) | Read explicit call-site prototype when present |
call_arg_addrs(call_ea) | Read persisted argument-loader addresses as JSON |
list_lvars(addr) | List local variables as JSON |
rename_lvar(func_addr, lvar_idx, new_name) | Rename a local variable by index |
rename_lvar_by_name(func_addr, old_name, new_name) | Rename a local variable by existing name |
rename_label(func_addr, label_num, new_name) | Rename a decompiler label by label number |
set_lvar_comment(func_addr, lvar_idx, text) | Set local-variable comment by index |
set_union_selection(func_addr, ea, path) | Set/clear union selection path at EA |
set_union_selection_item(func_addr, item_id, path) | Set/clear union selection path by ctree.item_id |
set_union_selection_ea_arg(func_addr, ea, arg_idx, path[, callee]) | PREFERRED call-arg targeting helper |
call_arg_item(func_addr, ea, arg_idx[, callee]) | Resolve call-arg coordinate to explicit arg_item_id |
ctree_item_at(func_addr, ea[, op_name[, nth]]) | Resolve generic expression coordinate to explicit ctree.item_id |
set_union_selection_ea_expr(func_addr, ea, path[, op_name[, nth]]) | Set/clear union selection via generic expression coordinate |
get_union_selection(func_addr, ea) | Read union selection path JSON at EA |
get_union_selection_item(func_addr, item_id) | Read union selection path JSON by ctree.item_id |
get_union_selection_ea_arg(func_addr, ea, arg_idx[, callee]) | Read union selection JSON via call-arg coordinate |
get_union_selection_ea_expr(func_addr, ea[, op_name[, nth]]) | Read union selection JSON via generic expression coordinate |
set_numform(func_addr, ea, opnum, spec) | Set/clear numform directly by EA + operand index |
get_numform(func_addr, ea, opnum) | Read numform JSON directly by EA + operand index |
set_numform_item(func_addr, item_id, opnum, spec) | Set/clear numform by explicit ctree item id |
get_numform_item(func_addr, item_id, opnum) | Read numform JSON by explicit ctree item id |
set_numform_ea_arg(func_addr, ea, arg_idx, opnum, spec[, callee]) | Set/clear numform via call-arg coordinate |
get_numform_ea_arg(func_addr, ea, arg_idx, opnum[, callee]) | Read numform JSON via call-arg coordinate |
set_numform_ea_expr(func_addr, ea, opnum, spec[, op_name[, nth]]) | Set/clear numform via generic expression coordinate |
get_numform_ea_expr(func_addr, ea, opnum[, op_name[, nth]]) | Read numform JSON via generic expression coordinate |
Targeting guidance:
*_ea_arg helpers for repeated callees and call-site arguments.ctree_item_at(..., op_name, nth) plus *_ea_expr helpers for non-call expressions and assignment-side struct/union population stores.For set_name(), type_at(), set_type(), parse_decls() reference, see types skill.
Preferred SQL write surface for function metadata:
UPDATE funcs SET name = '...', prototype = '...', comment = '...', rpt_comment = '...' WHERE address = ...prototype maps to type_at/set_type behavior and invalidates decompiler cache.comment / rpt_comment map to get_func_cmt() / set_func_cmt().| Table | Architecture | Key Constraint | Notes |
|---|---|---|---|
pseudocode | Cached | func_addr | Lazy per-function cache, freed after query |
pseudocode_orphan_comments | Cached | func_addr | Query-scoped orphan rows; writable delete-only |
pseudocode_v_orphan_comment_groups | Cached | func_addr | Query-scoped grouped orphan triage; start broad with LIMIT |
ctree | Generator | func_addr | Lazy streaming, never materializes full result, respects LIMIT |
ctree_lvars | Cached | func_addr | Lazy per-function cache, freed after query |
ctree_call_args | Generator | func_addr | Lazy streaming, respects LIMIT |
Critical rules:
func_addr constraint. Without it, every function is decompiled.ctree, ctree_call_args) stream rows lazily and stop at LIMIT.ctree_v_calls, ctree_v_indirect_calls, ctree_v_loops, etc.) inherit the func_addr constraint -- always filter.decompile(addr) is internally cached. decompile(addr, 1) forces a full re-decompilation -- only use when you need to see effects of a mutation.Cost model:
decompile(addr) -> ~50-200ms first call, ~0ms cached
decompile(addr, 1) -> ~50-200ms always (forces re-decompile)
ctree WHERE func_addr=X -> one decompilation + streaming rows
ctree (no constraint) -> N decompilations where N = func_qty()