plugins/idasql/skills/disassembly/SKILL.md
Query IDA disassembly. Use when asked about functions, segments, instructions, blocks, operands, control flow, or raw code structure.
npx skillsauth add allthingsida/idasql-skills disassemblyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when user asks for:
Route to:
decompiler for AST/pseudocode semanticsxrefs for relationship-heavy caller/callee workflowsdebugger for patching/breakpoint actions-- 1) Orientation
SELECT * FROM welcome;
-- 2) Segment map
SELECT name, printf('0x%X', start_ea) AS start_ea, printf('0x%X', end_ea) AS end_ea, perm
FROM segments
ORDER BY start_ea;
-- 3) Largest functions (triage anchors)
SELECT name, printf('0x%X', address) AS addr, size
FROM funcs
ORDER BY size DESC
LIMIT 20;
Interpretation guidance:
func_addr constraints early when querying instruction-heavy surfaces.instructions/heads:
WHERE func_addr = X or tight EA ranges.names updates later.disasm_calls and then escalate to decompiler.disassembly -> xrefs for relation expansion.disassembly -> decompiler for semantic interpretation.disassembly -> debugger for patch/breakpoint execution.All detected functions in the binary with prototype information.
| Column | Type | Description |
|--------|------|-------------|
| address | INT | Function start address |
| name | TEXT | Function name |
| size | INT | Function size in bytes |
| end_ea | INT | Function end address |
| flags | INT | Function flags |
Prototype columns (populated when type info available):
| Column | Type | Description |
|--------|------|-------------|
| return_type | TEXT | Return type string (e.g., "int", "void *") |
| return_is_ptr | INT | 1 if return type is pointer |
| return_is_int | INT | 1 if return type is exactly int |
| return_is_integral | INT | 1 if return type is int-like (int, long, DWORD, BOOL) |
| return_is_void | INT | 1 if return type is void |
| arg_count | INT | Number of function arguments |
| calling_conv | TEXT | Calling convention (cdecl, stdcall, fastcall, etc.) |
-- 10 largest functions
SELECT name, size FROM funcs ORDER BY size DESC LIMIT 10;
-- Functions starting with "sub_" (auto-named, not analyzed)
SELECT name, printf('0x%X', address) as addr FROM funcs WHERE name LIKE 'sub_%';
-- Functions returning integers with 3+ arguments
SELECT name, return_type, arg_count FROM funcs
WHERE return_is_integral = 1 AND arg_count >= 3;
Write operations:
-- Create a function
INSERT INTO funcs (address) VALUES (0x401000);
-- Rename a function
UPDATE funcs SET name = 'my_func' WHERE address = 0x401000;
-- Delete a function
DELETE FROM funcs WHERE address = 0x401000;
Memory segments. Supports INSERT, UPDATE (name, class, perm), and DELETE.
| Column | Type | RW | Description |
|--------|------|----|-------------|
| start_ea | INT | R | Segment start |
| end_ea | INT | R | Segment end |
| name | TEXT | RW | Segment name (.text, .data, etc.) |
| class | TEXT | RW | Segment class (CODE, DATA) |
| perm | INT | RW | Permissions (R=4, W=2, X=1) |
-- Find executable segments
SELECT name, printf('0x%X', start_ea) as start FROM segments WHERE perm & 1 = 1;
-- Rename a segment
UPDATE segments SET name = '.mytext' WHERE start_ea = 0x401000;
All named locations (functions, labels, data). Supports INSERT, UPDATE, and DELETE.
| Column | Type | RW | Description |
|--------|------|----|-------------|
| address | INT | R | Address |
| name | TEXT | RW | Name |
-- Create/set a name
INSERT INTO names (address, name) VALUES (0x401000, 'my_symbol');
-- Rename
UPDATE names SET name = 'my_symbol_renamed' WHERE address = 0x401000;
Entry points (exports, program entry, tls callbacks, etc.).
| Column | Type | Description |
|--------|------|-------------|
| ordinal | INT | Export ordinal |
| address | INT | Entry address |
| name | TEXT | Entry name |
instructions is the disassembly table. For scalar disassembly text at a specific EA, use disasm_at(ea[, context]).
Use disasm_func() or disasm_range() when you explicitly need a function/range listing.
Decoded instructions support DELETE (converts instruction to unexplored bytes) and operand representation updates via operand*_format_spec.
WHERE func_addr = X is the fast path (function-item iterator). Without it, the table scans all code heads.
| Column | Type | Description |
|--------|------|-------------|
| address | INT | Instruction address |
| func_addr | INT | Containing function |
| itype | INT | Instruction type (architecture-specific) |
| mnemonic | TEXT | Instruction mnemonic |
| size | INT | Instruction size |
| operand0..operand7 | TEXT | Operand text (0..7) |
| disasm | TEXT | Full disassembly line |
| operand0_class..operand7_class | TEXT | Operand class: reg, imm, displ, mem, ... |
| operand0_repr_kind..operand7_repr_kind | TEXT | Current representation: plain, enum, stroff |
| operand0_repr_type_name..operand7_repr_type_name | TEXT | Enum name or stroff path |
| operand0_format_spec..operand7_format_spec | TEXT (RW) | Apply/clear representation for a specific operand |
-- Instruction profile of a function (FAST)
SELECT mnemonic, COUNT(*) as count
FROM instructions WHERE func_addr = 0x401330
GROUP BY mnemonic ORDER BY count DESC;
-- Find all call instructions in a function
SELECT address, disasm FROM instructions
WHERE func_addr = 0x401000 AND mnemonic = 'call';
-- Apply enum representation to operand 1
UPDATE instructions
SET operand1_format_spec = 'enum:MY_ENUM'
WHERE address = 0x401020;
-- Clear representation back to plain
UPDATE instructions
SET operand1_format_spec = 'clear'
WHERE address = 0x401020;
One row per decoded non-void operand. Use this table for operand type/value details and for joinable replacements of old operand/decode helper functions.
| Column | Type | Description |
|--------|------|-------------|
| address | INT | Instruction address |
| func_addr | INT | Containing function |
| opnum | INT | Operand index |
| text | TEXT | Operand text |
| type_code | INT | IDA operand type code |
| type_name | TEXT | Operand type name (reg, imm, near, ...) |
| dtype | INT | Operand dtype |
| reg | INT | Register number when applicable |
| addr | INT | Referenced address/displacement when applicable |
| raw_value | INT | Raw operand value |
| value | INT | Best-effort scalar operand value |
SELECT opnum, text, type_name, value
FROM instruction_operands
WHERE address = 0x401000
ORDER BY opnum;
SELECT i.address, i.itype, i.mnemonic, o.opnum, o.text, o.type_name, o.value
FROM instructions i
LEFT JOIN instruction_operands o
ON o.address = i.address AND o.func_addr = 0x401000
WHERE i.func_addr = 0x401000
ORDER BY i.address, o.opnum;
Performance: WHERE address = X decodes one instruction; WHERE func_addr = X uses O(function_size) iteration. Without one of these constraints, it scans the entire database.
All call instructions with resolved targets and optional call-site prototype overrides.
| Column | Type | Description |
|--------|------|-------------|
| func_addr | INT | Function containing the call |
| ea | INT | Call instruction address |
| callee_addr | INT | Target address (0 if unknown) |
| callee_name | TEXT | Target name |
| callee_type | TEXT | RW nullable call-site prototype; UPDATE applies/replaces, NULL or empty clears |
-- Functions that call malloc
SELECT DISTINCT (SELECT name FROM funcs WHERE func_addr >= address AND func_addr < end_ea LIMIT 1) as caller
FROM disasm_calls WHERE callee_name LIKE '%malloc%';
-- Apply/replace a call-site prototype, then clear it
UPDATE disasm_calls
SET callee_type = 'int (__fastcall *)(const char *path)'
WHERE ea = 0x401234;
UPDATE disasm_calls SET callee_type = NULL WHERE ea = 0x401234;
Basic blocks within functions. Use func_ea constraint for performance.
| Column | Type | Description |
|--------|------|-------------|
| func_ea | INT | Containing function |
| start_ea | INT | Block start |
| end_ea | INT | Block end |
| size | INT | Block size |
-- Blocks in a specific function (FAST - uses constraint pushdown)
SELECT * FROM blocks WHERE func_ea = 0x401000;
-- Functions with most basic blocks
SELECT (SELECT name FROM funcs WHERE func_ea >= address AND func_ea < end_ea LIMIT 1) as name, COUNT(*) as blocks
FROM blocks GROUP BY func_ea ORDER BY blocks DESC LIMIT 10;
Control flow graph edges between basic blocks. Always use WHERE func_ea = X (filter_eq pushdown, O(blocks in function)).
| Column | Type | Description |
|--------|------|-------------|
| func_ea | INT | Containing function |
| from_block | INT | Source block address |
| to_block | INT | Target block address |
| edge_type | TEXT | normal (single-successor or fallback label), true/false (generic first/second arms for a two-way branch; labels follow successor order, not taken/fallthrough semantics) |
-- Get CFG structure
SELECT * FROM cfg_edges WHERE func_ea = 0x401000;
-- Find branch points (conditional blocks)
SELECT from_block, COUNT(*) as succ_count
FROM cfg_edges WHERE func_ea = 0x401000
GROUP BY from_block HAVING succ_count > 1;
-- Find merge points (blocks with multiple predecessors)
SELECT to_block, COUNT(*) as pred_count
FROM cfg_edges WHERE func_ea = 0x401000
GROUP BY to_block HAVING pred_count > 1;
-- Function complexity ranking: combine CFG, loops, and call metrics
SELECT f.name, f.size,
(SELECT COUNT(*)
FROM (
SELECT ce.from_block
FROM cfg_edges ce
WHERE ce.func_ea = f.address
GROUP BY ce.from_block
HAVING COUNT(*) > 1
) branch_blocks) as branch_sites,
(SELECT COUNT(*) FROM disasm_loops dl WHERE dl.func_addr = f.address) as loops,
(SELECT COUNT(*) FROM disasm_calls dc WHERE dc.func_addr = f.address) as calls_made
FROM funcs f
WHERE f.size > 32
ORDER BY branch_sites DESC
LIMIT 20;
Cached table with one row per function chunk. Aggregate by func_addr when you
need function-level span or density metrics.
| Column | Type | Description |
|--------|------|-------------|
| func_addr | INT | Function address |
| chunk_start | INT | Chunk start address |
| chunk_end | INT | Chunk end address |
| block_count | INT | Number of blocks in chunk |
| total_size | INT | Total size of chunk |
SELECT * FROM function_chunks WHERE func_addr = 0x401000;
| Function | Description |
|----------|-------------|
| disasm_at(addr) | Canonical listing line for containing head (works for code/data) |
| disasm_at(addr, n) | Canonical listing line with +/- n neighboring heads |
| disasm(addr) | Single disassembly line at address |
| disasm(addr, n) | Next N instructions from address (count-based) |
| disasm_range(start, end) | All disassembly lines in address range [start, end) |
| disasm_func(addr) | Full disassembly of function containing address |
| make_code(addr) | Create instruction at address (returns 1/0) |
| make_code_range(start, end) | Create instructions in range, returns created count |
-- Canonical single-EA disassembly (safe for code or data)
SELECT disasm_at(0x401000);
-- Canonical context window (+/- 2 heads)
SELECT disasm_at(0x401000, 2);
-- Full function disassembly (resolves boundaries via get_func)
SELECT disasm_func(address) FROM funcs WHERE name = '_main';
-- Disassemble a specific address range
SELECT disasm_range(0x401000, 0x401100);
-- Sliding window: next 5 instructions from an address
SELECT disasm(0x401000, 5);
Use table lookups for address and containing-function metadata. Resolve symbol names to integer EAs before using these patterns.
| Pattern | Description |
|---------|-------------|
| SELECT name FROM names WHERE address = :ea LIMIT 1 | Name at address |
| SELECT name FROM funcs WHERE :ea >= address AND :ea < end_ea LIMIT 1 | Function containing address |
| SELECT address FROM funcs WHERE :ea >= address AND :ea < end_ea LIMIT 1 | Start of containing function |
| SELECT end_ea FROM funcs WHERE :ea >= address AND :ea < end_ea LIMIT 1 | End of containing function |
Function count and index lookup are table-driven:
SELECT COUNT(*) AS function_count FROM funcs;
SELECT address FROM funcs WHERE rowid = 0;
Use heads ordering for defined-item navigation and SQLite formatting functions for display strings. Address equality/range filters are optimized; ORDER BY address or ORDER BY address DESC is consumed for next/previous-item lookups.
SELECT address
FROM heads
WHERE address > 0x401000
ORDER BY address
LIMIT 1;
SELECT address
FROM heads
WHERE address < 0x401000
ORDER BY address DESC
LIMIT 1;
SELECT printf('0x%llx', address) AS address_hex
FROM heads
LIMIT 10;
Segment lookup is table-driven:
SELECT name
FROM segments
WHERE 0x401000 >= start_ea
AND 0x401000 < end_ea
LIMIT 1;
Use heads for item classification, size, and raw flags:
SELECT address, size, type, flags, disasm
FROM heads
WHERE address = 0x401000;
Use instructions and instruction_operands for decoded instruction facts:
SELECT address, itype, mnemonic
FROM instructions
WHERE func_addr = 0x401000
LIMIT 10;
SELECT opnum, text, type_code, type_name, value
FROM instruction_operands
WHERE address = 0x401000
ORDER BY opnum;
SELECT i.address, i.itype, i.mnemonic, i.size, o.opnum, o.text, o.type_name, o.value
FROM instructions i
LEFT JOIN instruction_operands o
ON o.address = i.address AND o.address = 0x401000
WHERE i.address = 0x401000
ORDER BY o.opnum;
| Function | Description |
|----------|-------------|
| gen_listing(path) | Generate full-database listing output (LST) |
| Function | Description |
|----------|-------------|
| gen_cfg_dot(addr) | Generate CFG as DOT graph string |
| gen_cfg_dot_file(addr, path) | Write CFG DOT to file |
| gen_schema_dot() | Generate database schema as DOT |
-- Get CFG for a function as DOT format
SELECT gen_cfg_dot(0x401000);
| Table | Architecture | Key Constraint | Notes |
|-------|-------------|----------------|-------|
| funcs | Index-Based | none needed | O(1) per row via getn_func(i) -- always fast |
| instructions | Iterator | func_addr | Function-item iterator (fast) vs full code-head scan (slow) |
| blocks | Iterator | func_ea | Constraint pushdown: iterates blocks of one function |
| cfg_edges | Iterator | func_ea | filter_eq pushdown: O(blocks in function) |
| disasm_calls | Generator | func_addr, ea for writes | Lazy streaming, respects LIMIT; callee_type is writable |
| heads | Generator | address =, address range | Consumes ORDER BY address for next/previous navigation; broad scans can still be large |
| instruction_operands | Iterator | address, func_addr | Address lookup decodes one instruction; function lookup iterates one function |
| segments | Index-Based | none needed | Small table, always fast |
| names | Iterator | none needed | Iterates IDA's name list |
Key rules:
funcs is always fast -- no constraint needed.instructions without func_addr scans every code head -- use func_addr for per-function queries.blocks without func_ea iterates all functions' flowcharts -- always constrain.heads is often large. Use address = X for item facts and address range plus ORDER BY address [DESC] LIMIT 1 for navigation.Cost model:
funcs (full scan) -> O(number of functions), typically ~1000s, fast
instructions WHERE func_addr -> O(function_size / avg_insn_size)
instructions (no constraint) -> O(total_code_heads), potentially 100K+
blocks WHERE func_ea -> O(block_count_in_func), fast
cfg_edges WHERE func_ea -> O(block_count_in_func), fast
disasm_calls WHERE func_addr -> O(instructions_in_func), streaming
disasm_calls UPDATE callee_type WHERE ea -> O(1) call-site lookup
heads WHERE address -> O(1) IDA head check
heads next/prev LIMIT 1 -> O(distance to next/previous defined head)
instruction_operands address -> O(operands in one instruction)
instruction_operands func -> O(operands in one function)
tools
IDA type system. Use when asked to create, modify, or apply structs, unions, enums, typedefs, or parse C declarations.
databases
Complete idasql SQL function reference catalog. Use when looking up function signatures, parameters, or usage examples.
development
Decompile and analyze IDA functions. Use when asked for pseudocode, ctree AST analysis, local variables, labels, or decompiler-driven cleanup.
development
IDA debugger operations. Use when asked to set breakpoints, patch bytes, add conditions, or manage a patch inventory.