| name | disassembly |
| description | Inspect code structure through ghidrasql tables for functions, instructions, blocks, CFG, loops, switches, dominators, and tail calls. |
| allowed-tools | ["Bash","Read","Glob","Grep"] |
Disassembly
Trigger Intents
Use this skill when the user asks about:
- instructions, operands, raw code layout
- function boundaries and sizes
- blocks and CFG edges
- loops, switch tables, dominators, tail calls, function chunks
- control flow without needing pseudocode first
Route to:
decompiler when higher-level reconstruction is needed
xrefs for cross-function tracing
analysis for ranking and triage
Performance Contract
| Surface | Predicate | Pushdown? | Note |
|---|
funcs | any | Indexed by addr | Cheap |
blocks | WHERE func_addr = X | Yes | Per-function CFG build |
cfg_edges | WHERE func_addr = X | Yes | Per-function CFG build |
instructions | exact WHERE addr = X or WHERE func_addr = X | Yes | Exact address and containing-function predicates issue bounded source reads. An address range or mnemonic predicate still scans the full instruction surface. |
instruction_operands | exact WHERE addr = X or WHERE func_addr = X | Yes | One-instruction or one-function bounded source read. |
loops, switch_tables, dominators, post_dominators, tail_calls, function_chunks | WHERE func_addr = X | Per-table | Most are per-function — verify via PRAGMA table_xinfo |
For function-scoped questions, filter instructions directly by func_addr, or use the disasm_blocks and disasm_calls views (which also resolve callee names from funcs/names).
Do This First
Pick the function and inspect its shape:
SELECT name, printf('0x%X', addr) AS addr, size
FROM funcs
ORDER BY size DESC
LIMIT 10;
Per-function block layout (cheap, pushed):
SELECT printf('0x%X', start_addr) AS start, printf('0x%X', end_addr) AS end, in_degree, out_degree
FROM blocks
WHERE func_addr = 0x401000
ORDER BY start_addr;
Per-function call sites (cheap, pushed via the view):
SELECT printf('0x%X', addr) AS site, callee_name, printf('0x%X', callee_addr) AS callee
FROM disasm_calls
WHERE func_addr = 0x401000
ORDER BY addr;
Instruction spot-check by tight range (post-filter scan — keep the range narrow):
SELECT printf('0x%X', addr) AS addr, mnemonic, operands
FROM instructions
WHERE addr BETWEEN 0x401020 AND 0x401060
ORDER BY addr;
For a function-scoped instruction slice, filter by func_addr (indexed, pushed down):
SELECT printf('0x%X', addr) AS addr, mnemonic, operands
FROM instructions
WHERE func_addr = 0x401000
ORDER BY addr;
Decoded per-operand rows come from instruction_operands (getDefaultOperand Representation / getOperandType / getOperandRefType). Filter by addr (one
instruction) or func_addr (whole function) — both push down:
SELECT operand_index, text, type_name, ref_type
FROM instruction_operands
WHERE addr = 0x401000
ORDER BY operand_index;
Critical Rules
instructions exposes an indexed func_addr column (containing-function start) — scope a function's instructions with WHERE func_addr = X or use exact addr = X; both push down. A range is useful for result filtering but still reads the full instruction surface.
blocks and cfg_edges also take func_addr and push it down — use them for control-flow questions.
- For "what does this function call?" prefer
disasm_calls over scanning instructions for CALL opcodes — disasm_calls resolves callee names from funcs/names.
- Hand off to
decompiler once instruction-level evidence is enough.
CFG and Loop Surfaces
SELECT printf('0x%X', from_addr) AS src,
printf('0x%X', to_addr) AS dst,
edge_type
FROM cfg_edges
WHERE func_addr = 0x401000
ORDER BY from_addr, to_addr;
SELECT DISTINCT edge_type FROM cfg_edges WHERE func_addr = 0x401000;
SELECT printf('0x%X', header_addr) AS header, loop_kind, depth, block_count
FROM loops
WHERE func_addr = 0x401000;
SELECT printf('0x%X', instr_addr) AS site,
printf('0x%X', table_addr) AS jump_table,
min_case, max_case, case_count,
printf('0x%X', default_addr) AS default_target
FROM switch_tables
WHERE func_addr = 0x401000;
Dominator Surfaces
SELECT printf('0x%X', node_addr) AS node,
printf('0x%X', idom_addr) AS idom,
depth, is_entry
FROM dominators
WHERE func_addr = 0x401000
ORDER BY depth, node_addr;
SELECT printf('0x%X', node_addr) AS node,
printf('0x%X', ipdom_addr) AS ipdom,
depth, is_exit
FROM post_dominators
WHERE func_addr = 0x401000;
Tail Calls and Function Chunks
SELECT printf('0x%X', call_site) AS site,
printf('0x%X', dst_addr) AS dst,
printf('0x%X', dst_func_addr) AS dst_func,
tail_kind
FROM tail_calls
WHERE src_func_addr = 0x401000;
SELECT chunk_id,
printf('0x%X', start_addr) AS start,
printf('0x%X', end_addr) AS end,
chunk_kind, is_primary
FROM function_chunks
WHERE func_addr = 0x401000
ORDER BY start_addr;
Useful Views
| View | What it adds |
|---|
disasm_calls | Every call site with attributed callee (func_addr, addr, callee_addr, callee_name, kind) — prefer over instructions scans |
disasm_blocks | Block layout with computed size |
disasm_v_leaf_funcs | Functions that make no calls (mnemonic-derived; complementary to ctree_v_leaf_funcs) |
disasm_v_call_chains | Recursive call-chain projection from disasm_calls |
cfg_edges_detailed | cfg_edges enriched with attributes |
loop_summary | One row per loop with kind/depth/block_count |
switch_summary | One row per switch with case range |
dominator_tree, post_dominator_tree | Hierarchical dominator projections |
function_chunks_detailed | Chunks with computed metadata |
function_frame_layout, stack_var_layout, register_var_summary | Frame/stack/register layouts |
Failure and Recovery
- Query takes very long. You probably scanned
instructions with only a range or mnemonic predicate. Switch to WHERE func_addr = X, exact addr = X, disasm_blocks, or disasm_calls.
edge_type value is unfamiliar. It comes verbatim from libghidra's RefType taxonomy (CONDITIONAL_JUMP, FALL_THROUGH, CALL, UNCONDITIONAL_JUMP, COMPUTED_JUMP, INDIRECTION, etc.). Run SELECT DISTINCT edge_type FROM cfg_edges WHERE func_addr = X to enumerate what's present.
switch_tables is empty. Either the function has no switch, or the decompiler didn't recover one. Cross-check via decomp_tokens for case keywords.