plugins/idasql/skills/annotations/SKILL.md
Edit IDA databases. Use when asked to add comments, rename symbols, apply types, create bookmarks, or clean up decompiled code for review.
npx skillsauth add allthingsida/idasql-skills annotationsInstall 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.
This skill is your guide for editing IDA databases through idasql. Use it whenever you need to annotate, rename, retype, comment, or otherwise modify decompiled output, disassembly, or type information. Every edit operation follows the Mandatory Mutation Loop (see connect Global Agent Contracts).
Use this skill when user asks to:
Route to:
decompiler for analysis before editingtypes when declarations or struct models need constructionre-source for recursive narrative/source recovery passes-- 1) Confirm target row/function before editing
SELECT * FROM funcs WHERE address = 0x401000;
-- 2) Inspect current comment state
SELECT ea, line, comment
FROM pseudocode
WHERE func_addr = 0x401000
LIMIT 30;
-- 3) Inspect existing disassembly comments
SELECT * FROM comments WHERE address BETWEEN 0x401000 AND 0x401100;
Interpretation guidance:
func_addr + ea, idx, slot) over fuzzy name matches.annotations -> decompiler when semantic meaning is unclear.annotations -> types when edits imply missing declarations.annotations -> re-source when function-level notes must become recursive campaign notes.Treat annotate this function as a full-function workflow, not a single comment operation.
Default behavior:
funcs.rpt_commentdecompile(addr, 1) and verify the resultUse narrower intents only when the user asks narrowly:
add a comment -> comment onlyfunc-summary / function summary -> summary onlyannotate this function -> full cleanup plus summaryWhy the summary is mandatory:
True IDA function comments live on funcs, not on pseudocode and not on the address-level comments table.
Use:
funcs.comment for the regular function commentfuncs.rpt_comment for the repeatable function commentDefault function-summary behavior:
add function comment as UPDATE funcs SET rpt_comment = ...funcs.comment only when the user explicitly asks for a non-repeatable function commentpseudocode block comment only when the user explicitly asks for a decompiler note/summary rather than a true function commentCanonical SQL pattern:
SELECT address, name, comment, rpt_comment
FROM funcs
WHERE address = 0x401000;
UPDATE funcs
SET rpt_comment = 'One-paragraph summary of what the function does, inputs/outputs, and key behavior.'
WHERE address = 0x401000;
The pseudocode table is the editing surface for decompiler comments. Use decompile(addr) to view; use the table to edit. For full table schema, see decompiler skill.
Important separation:
pseudocode.comment edits Hex-Rays decompiler comments only.pseudocode writes never call set_func_cmt().funcs.comment / funcs.rpt_comment for true function comments.Writable columns: comment, comment_placement. Placements: semi (after ;), block1 (own line above), block2, curly1, curly2, colon, case, else, do.
Anchor guidance:
ea maps to multiple pseudocode rows ({, statement, }), resolve a unique non-brace anchor first.line_num only to inspect candidate rows. Comment writes persist by ea + comment_placement; shared-ea rows need extra care, so do not assume every displayed shared-ea row is independently writable.Inspect anchors before writing:
SELECT line_num, ea, line, comment
FROM pseudocode
WHERE func_addr = 0x401000
ORDER BY line_num;
-- The example UPDATEs below assume 0x401020 is an already resolved writable
-- non-brace anchor from the inspection query above; do not substitute func_addr.
-- Edit: Add inline comment to decompiled code
UPDATE pseudocode SET comment_placement = 'semi',
comment = 'buffer overflow here'
WHERE func_addr = 0x401000 AND ea = 0x401020;
-- Edit: Add block comment (own line above statement)
UPDATE pseudocode SET comment_placement = 'block1', comment = 'vulnerable call'
WHERE func_addr = 0x401000 AND ea = 0x401020;
-- Edit: Delete comments at a resolved unique anchor
-- Warning: comment = NULL currently clears all placements at that ea.
UPDATE pseudocode SET comment = NULL
WHERE func_addr = 0x401000 AND ea = 0x401020;
-- Read edited pseudocode with comments
SELECT ea, line, comment FROM pseudocode WHERE func_addr = 0x401000;
If the database contains stale decompiler comments that no longer attach to current pseudocode, use the orphan comment surfaces instead of trying to clear them through pseudocode.
Read-first pattern:
SELECT func_addr, func_name, orphan_count
FROM pseudocode_v_orphan_comment_groups
ORDER BY orphan_count DESC
LIMIT 20;
SELECT ea, comment_placement, orphan_comment
FROM pseudocode_orphan_comments
WHERE func_addr = 0x401000
ORDER BY ea, comment_placement;
Delete-only mutation pattern:
UPDATE pseudocode_orphan_comments
SET orphan_comment = NULL
WHERE func_addr = 0x401000
AND ea = 0x401020
AND comment_placement = 'semi';
Notes:
pseudocode_orphan_comments is delete-only.WHERE func_addr = ... on both surfaces for the fast path.Use function summary and func-summary as equivalent intent.
Trigger contract:
function summary or func-summary, add or update exactly one repeatable function comment on funcs.rpt_comment.add function comment (singular) without line-specific targets, treat it as a repeatable function comment update.pseudocode.comment with a resolved writable anchor instead.Default behavior:
funcs.rpt_comment.funcs.comment only when the user explicitly asks for a non-repeatable function comment.Length guidance:
Canonical SQL pattern:
SELECT address, name, comment, rpt_comment
FROM funcs
WHERE address = 0x401000;
UPDATE funcs
SET rpt_comment = 'One-paragraph summary of what the function does, inputs/outputs, and key behavior.'
WHERE address = 0x401000;
Prompt examples:
function summary 0x401000func-summary DriverEntryfunc-summary this functionRead disassembly-level comments from the comments table:
SELECT COALESCE(NULLIF(comment, ''), NULLIF(rpt_comment, '')) AS comment
FROM comments
WHERE address = 0x401000
LIMIT 1;
Upsert semantics: for the names and comments tables, INSERT at an address that already has a value replaces the existing entry (IDA allows only one name and one comment-slot per EA). UPDATE is equivalent for the in-place case. For names, IDA's SN_CHECK flag also auto-disambiguates global name conflicts (e.g. foo may become foo_0 if the name is already used at a different EA) — read back the row after writing to see what was actually stored.
The comments table supports INSERT, UPDATE, and DELETE:
| Table | INSERT | UPDATE columns | DELETE |
|-------|--------|---------------|--------|
| comments | Yes | comment, rpt_comment | Yes |
INSERT INTO comments(address, comment) VALUES (0x401000, 'regular comment');
INSERT INTO comments(address, rpt_comment) VALUES (0x401000, 'repeatable comment');
UPDATE comments SET comment = 'updated comment' WHERE address = 0x401000;
DELETE FROM comments WHERE address = 0x401000;
Notes:
comments edits address comments via set_cmt().funcs.comment / funcs.rpt_comment edit true function comments via set_func_cmt().The bookmarks table supports full CRUD for editing marked positions:
| Column | Type | Description |
|--------|------|-------------|
| slot | INT | Bookmark slot index |
| address | INT | Bookmarked address |
| description | TEXT | Bookmark description |
-- List all bookmarks
SELECT printf('0x%X', address) as addr, description FROM bookmarks;
-- Edit: Add bookmark
INSERT INTO bookmarks (address, description) VALUES (0x401000, 'interesting branch');
-- Edit: Update bookmark description
UPDATE bookmarks SET description = 'confirmed branch' WHERE slot = 0;
-- Edit: Delete bookmark
DELETE FROM bookmarks WHERE slot = 0;
For canonical schema and owner mapping, see ../connect/references/schema-catalog.md (bookmarks).
The ctree_lvars table is the editing surface for decompiler local variables. Writable columns: name, type, comment. For full table schema, see decompiler skill.
Local-variable edit guidance:
idx, then update by func_addr + idx.UPDATE ctree_lvars SET name = ..., type = ..., or comment = ... for local edits.func_addr + name, choose one idx, then update by idx.-- Inspect current locals before renaming
SELECT idx, name, type, comment
FROM ctree_lvars
WHERE func_addr = 0x401000
ORDER BY idx;
-- Edit: Rename a local variable by index (canonical, deterministic)
UPDATE ctree_lvars SET name = 'buffer_size' WHERE func_addr = 0x401000 AND idx = 2;
-- Edit: Rename by current name after selecting one deterministic idx
UPDATE ctree_lvars SET name = 'buffer_size'
WHERE func_addr = 0x401000
AND idx = (
SELECT idx FROM ctree_lvars
WHERE func_addr = 0x401000 AND name = 'v2'
ORDER BY idx LIMIT 1
);
-- Edit: Set local-variable comment by index
UPDATE ctree_lvars SET comment = 'points to decrypted buffer' WHERE func_addr = 0x401000 AND idx = 2;
-- Edit: Change variable type
UPDATE ctree_lvars SET type = 'char *'
WHERE func_addr = 0x401000 AND idx = 2;
Read the current labels first, then rename the exact label you observed. Prefer label_num identity over guessing from line text.
-- Inspect labels before renaming
SELECT label_num, name, printf('0x%X', item_ea) AS item_ea
FROM ctree_labels
WHERE func_addr = 0x401000
ORDER BY label_num;
-- Rename deterministically by label number
UPDATE ctree_labels SET name = 'fail' WHERE func_addr = 0x401000 AND label_num = 12;
-- Equivalent UPDATE path
UPDATE ctree_labels
SET name = 'fail'
WHERE func_addr = 0x401000 AND label_num = 12;
For type creation, member CRUD, enum values, parse_decls(), applied_types, and name writes via names/funcs, see types skill.
Quick apply patterns used in annotation workflows:
-- Apply type to a function
UPDATE funcs SET prototype = 'void __fastcall exec_command(command_t *cmd);'
WHERE address = 0x140001BD0;
-- Apply/replace the type at any mapped address
INSERT INTO applied_types(address, decl)
VALUES (0x140001BD0, 'void __fastcall exec_command(command_t *cmd);');
The instructions table operand*_format_spec columns allow editing operand display:
-- Edit: Apply enum representation to operand 1
UPDATE instructions
SET operand1_format_spec = 'enum:MY_ENUM'
WHERE address = 0x401020;
-- Edit: Apply struct-offset representation
UPDATE instructions
SET operand0_format_spec = 'stroff:MY_STRUCT,delta=0'
WHERE address = 0x401030;
-- Edit: Clear representation back to plain
UPDATE instructions
SET operand1_format_spec = 'clear'
WHERE address = 0x401020;
For union selection helpers (set_union_selection*, get_union_selection*), see decompiler skill.
Recommended: Retype the variable to an enum type — IDA's decompiler will then automatically render all constants using enum names:
-- 1. Define the enum type (skip if it already exists)
SELECT parse_decls('typedef enum { DLL_PROCESS_DETACH=0, DLL_PROCESS_ATTACH=1 } fdw_reason_t;');
-- 2. Retype the parameter/variable
UPDATE ctree_lvars SET type = 'fdw_reason_t'
WHERE func_addr = 0x180001050 AND idx = 1;
-- 3. Verify
SELECT decompile(0x180001050, 1);
For per-operand numform control (set_numform*, get_numform*), see decompiler skill.
Follow the read -> edit -> refresh -> verify cycle defined in
connectGlobal Agent Contracts.
When editing many functions or annotations, keep these costs in mind:
decompile(addr, 1) triggers a full re-decompilation (~50-200ms per function). When editing multiple items in the same function, batch all edits before the refresh:
-- Good: structural typing first, then refresh, then naming cleanup
UPDATE ctree_lvars SET type = 'MY_CTX *' WHERE func_addr = 0x401000 AND idx = 0;
SELECT decompile(0x401000, 1);
UPDATE ctree_lvars SET name = 'ctx' WHERE func_addr = 0x401000 AND idx = 0;
UPDATE ctree_lvars SET name = 'size' WHERE func_addr = 0x401000 AND idx = 1;
SELECT decompile(0x401000, 1); -- final refresh after cleanup
pseudocode comment writes are lightweight — they persist to IDA's user comments store without triggering re-decompilation. You can write comments to many functions without calling decompile(addr, 1) between each.ctree_lvars type changes invalidate the decompiler cache — after changing a variable type, refresh before you trust idx/name-based cleanup. The decompiler may split locals or re-render expressions.save_database() can be costly on large databases. Batch all writes and save once at the end of an annotation campaign, not after each edit.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
Query IDA disassembly. Use when asked about functions, segments, instructions, blocks, operands, control flow, or raw code structure.
development
Decompile and analyze IDA functions. Use when asked for pseudocode, ctree AST analysis, local variables, labels, or decompiler-driven cleanup.