From ghidrasql
Applies persistent Ghidra SQL annotations: rename functions/symbols/locals, add comments, adjust function signatures, tag functions, and apply types. Useful for Ghidra reverse-engineering cleanup sessions.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ghidrasql:annotationsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill when the user asks to:
Use this skill when the user asks to:
apply_type_* viewsRoute to:
decompiler to inspect locals and pseudocode before editingtypes when a mutation depends on declarations or type importsre-source when the campaign expands beyond a single functionfunc_addr, local_id, ordinal, address).SELECT save_database(); once at the end.curl -X POST http://127.0.0.1:8081/shutdown (managed mode applies the launch-time --shutdown save policy; proxy mode leaves the upstream host running).There is no SQL shutdown(...) function.
save_database() returning 1 is not always proof the change persisted — in some configurations the save is silently dropped on reopen. For critical edits, save → shut the host down → reconnect with --readonly --no-analyze → re-query the affected rows and compare against the post-write values. See the connect skill's mutation-loop section for the full recipe.pseudocode/decomp_lvars/decomp_comments on the same host can deadlock on a fair ReentrantReadWriteLock. Serialise decompiler-backed work — do not run two parallel annotation pipelines against one host.| Table | UPDATE columns | INSERT | DELETE |
|---|---|---|---|
funcs | name, signature | – | – |
names | name | yes | yes |
comments | comment, repeatable, source | yes | yes |
data_items | name, data_type | yes | yes |
bookmarks | type, category, comment | yes | yes |
decomp_lvars | name, type | – | – |
decomp_comments | comment, source | yes | yes |
function_params | param_name, param_type | – | – |
function_tags | comment | yes | yes |
function_tag_mappings | – | yes | yes |
signatures | prototype only (not name) | – | – |
breakpoints | enabled, type, size, condition, group | yes | yes |
memory_bytes | value (single-byte patch) | – | – |
Type tables (types, type_members, type_enums, type_enum_members, type_unions, type_aliases) support INSERT and DELETE; UPDATE is mostly limited to name (full per-table matrix in the types skill).
INSERT-only views: apply_type_data, apply_type_param, apply_type_local — INSTEAD OF INSERT triggers that wrap the underlying type write.
Function rename and signature:
UPDATE funcs
SET name = 'parseConfig',
signature = 'bool parseConfig(const char *path, Config *out)'
WHERE address = 0x4011F0;
Parameter rename or type:
UPDATE function_params
SET param_name = 'path',
param_type = 'const char *'
WHERE func_addr = 0x4011F0 AND ordinal = 0;
Decompiler local rename or type — prefer the SQL helpers (direct RPC, no re-decompilation between statements):
SELECT rename_local(0x4011F0, '<local_id>', 'configFile');
SELECT set_local_type(0x4011F0, '<local_id>', 'FILE *');
Alternative via UPDATE (works for the name; type rewrites can fail on array locals — see Gotchas):
UPDATE decomp_lvars
SET name = 'configFile'
WHERE func_addr = 0x4011F0 AND local_id = '<local_id>';
Apply a type via the dedicated view (compositional — works even when the agent only knows the type name):
INSERT INTO apply_type_data (address, type_name) VALUES (0x404000, 'IMAGE_DOS_HEADER');
INSERT INTO apply_type_param (func_addr, ordinal, type_name) VALUES (0x4011F0, 0, 'const char *');
INSERT INTO apply_type_local (func_addr, local_id, type_name) VALUES (0x4011F0, 'arg2', 'FILE *');
Comment insertion (the source column controls the comment kind: 'plate', 'pre', 'post', 'eol', 'repeatable'):
INSERT INTO comments (address, comment, source)
VALUES (0x4011F0, 'Reads and parses the configuration file.', 'plate');
Decompiler-attached comments (anchored at decompiler tokens, not raw addresses):
INSERT INTO decomp_comments (func_addr, address, comment, source)
VALUES (0x4011F0, 0x4012A0, 'fail path: invalid magic', 'pre');
Bookmark (defaults to type='Analysis' if not specified):
INSERT INTO bookmarks (address, type, category, comment)
VALUES (0x4011F0, 'Note', 'review', 'check overflow handling');
Function tags (catalog first, then map):
INSERT INTO function_tags (name, comment) VALUES ('reviewed', 'manually reviewed');
INSERT INTO function_tag_mappings (func_addr, tag_name) VALUES (0x4011F0, 'reviewed');
Tag deletion cascades through both tables: DELETE FROM function_tags WHERE name = 'reviewed'; removes every mapping.
signatures is read-mostly. Only prototype is writable. To rename the function itself, UPDATE funcs SET name = .... To change the calling convention, write a full prototype string into either funcs.signature or signatures.prototype.__cdecl in a prototype string can fail with a vague diagnostic. If set_function_signature at 0xN errors without a parse detail, drop the calling-convention prefix and retry — the signature without __cdecl typically applies cleanly.UPDATE decomp_lvars SET name = ... may fail with "unable to resolve writable data type 'wchar_t[128]'". The UPDATE path re-applies the current type during the rename, and Ghidra refuses arrays in some contexts. Fall back to:
SELECT rename_local(0x4011F0, '<local_id>', 'configFile');
which goes through a direct RPC and ignores the type.uint8_t/uint16_t/uint32_t/unsigned/unsigned int) are mis-mapped in older builds of parse_decls(). Current builds resolve them correctly; if you hit a width mismatch, suspect an outdated build.program_id, so the next query refreshes automatically. Inside a -f script or multi-statement REPL input, drop just the table you wrote to before reading it again when you need to force a rebuild:
SELECT cache_invalidate('decomp_lvars');
Cheaper than refresh_database() when only one surface is stale.<type> *fn(...) as a name *fn rather than a return type. Use <type>* fn(...) form when authoring prototypes — char* foo, void** bar, int* baz. Same trap applies to multi-statement parameter lists. Verify the apply landed by re-reading funcs.signature or function_params.apply_type_local (or a direct UPDATE on decomp_lvars) at one site can change unrelated variables. Mitigation: keep the recovered type on prototypes/parameters, back the local out to a neutral type (char *, int) at the questionable site, and verify each step in pseudocode before continuing.SELECT text FROM pseudocode WHERE func_addr = 0x4011F0;
SELECT local_id, name, type FROM decomp_lvars WHERE func_addr = 0x4011F0;
SELECT ordinal, param_name, param_type FROM function_params WHERE func_addr = 0x4011F0;
SELECT save_database();
pseudocode, verify you used the canonical local_id / ordinal / address. If you're inside a batched script and the row is correct in decomp_lvars but pseudocode looks stale, SELECT cache_invalidate('pseudocode'); SELECT decompile(0xX);.save_database() once at the end.npx claudepluginhub 0xeb/ghidrasql-skills --plugin ghidrasqlEdits IDA databases via idasql: add comments to pseudocode/disassembly, rename symbols/locals, apply types/enums/structs, create bookmarks, clean decompiled code for review.
Lists Ghidra SQL functions for decompilation, type analysis, search, and persistence. Helps choose the right helper for reverse-engineering tasks.
Analyzes binaries using IDA Pro's Domain API: program structure, functions, disassembly, cross-references, and strings. Provides Pythonic API usage, database opening, and configuration options for headless analysis.