decompiler
Decompile functions with ghidrasql and work with pseudocode, locals, parameters, and ctree pattern views safely.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Decompile functions with ghidrasql and work with pseudocode, locals, parameters, and ctree pattern views safely.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Analyze binaries with ghidrasql using safe, high-signal query patterns.
Apply persistent ghidrasql annotations such as names, comments, signatures, and local-variable edits.
Connect to ghidrasql sources, verify live access, and route to the right analysis skill.
Query strings, bytes, data items, memory blocks, and relocations through ghidrasql.
Manage breakpoints and patch bytes through ghidrasql — the breakpoints table and bytes single-byte UPDATE.
Inspect code structure through ghidrasql tables for functions, instructions, blocks, CFG, loops, switches, dominators, and tail calls.
| name | decompiler |
| description | Decompile functions with ghidrasql and work with pseudocode, locals, parameters, and ctree pattern views safely. |
| allowed-tools | ["Bash","Read","Glob","Grep"] |
Use this skill when the user asks for:
pcode_ops, pcode_varnodes, ir_ops, ir_operands)Route to:
annotations for persistent editstypes for declaration import or type recoveryxrefs for caller / callee expansion from a decompiled targetDecompiler-backed tables MUST be function-scoped. Use func_addr for decompiler-backed tables. pseudocode and decomp_lvars also support exact func_name = ... when you need name-based lookup.
| Table | Predicate | Without it |
|---|---|---|
pseudocode | WHERE func_addr = X or exact WHERE func_name = 'name' | Decompiles every function in the program |
decomp_lvars | WHERE func_addr = X or exact WHERE func_name = 'name' | Same — full-program decompile |
decomp_tokens | WHERE func_addr = X | Same |
decomp_comments | WHERE func_addr = X | Same |
pcode_ops, pcode_varnodes, ir_ops, ir_operands | WHERE func_addr = X | Extracts P-code for every function |
Per-function decompile typically takes ~500 ms. Without the filter, the cost scales with the function count — minutes per query for thousands of functions.
The ctree* views also compose over per-function surfaces and are best filtered the same way.
For genuine low-level IR, use pcode_ops/pcode_varnodes or their canonical
ir_ops/ir_operands projections; discover the high and raw rungs through
ir_maturities.
Direct full-text:
SELECT text FROM pseudocode WHERE func_addr = 0x401000;
Structured rows:
SELECT text FROM pseudocode WHERE func_addr = 0x401000;
SELECT local_id, name, type, storage FROM decomp_lvars WHERE func_addr = 0x401000;
SELECT func_addr, local_id, name, type, storage FROM decomp_lvars WHERE func_name = 'main';
SELECT text, kind, var_name, var_type FROM decomp_tokens WHERE func_addr = 0x401000;
SELECT ordinal, param_name, param_type FROM function_params WHERE func_addr = 0x401000;
pseudocode is the full-function decompiler table. With a libghidra live source, table materialisation can be reused across one-shot /query calls while the native freshness token is unchanged. Writes through ghidrasql and external Ghidra/libghidra edits change Ghidra's modification number, while program switches change program_id, so the next query invalidates before reading. Custom sources without freshness tracking still invalidate on every one-shot query.
The cache_invalidate dance mostly matters inside a batched script (-f script.sql, multi-statement REPL input) or when you want to force one surface to rebuild:
-- inside a -f script:
SELECT rename_local(0x401000, 'arg0', 'configHandle');
SELECT cache_invalidate('pseudocode'); -- needed because the cache was built earlier in this batch
SELECT cache_invalidate('decomp_lvars');
SELECT text FROM pseudocode WHERE func_addr = 0x401000;
cache_invalidate('<table>') is cheaper than refresh_database() when only one surface is stale. Use refresh_database() when you want to force a full source refresh regardless of revision.
Do not run two ghidrasql clients hitting decompiler tables on the same host in parallel. Overlapping requests against pseudocode/decomp_lvars/decomp_comments can deadlock the host on a fair ReentrantReadWriteLock. Symptoms: queries stop returning, threads in getComments / decompileFunction are parked. Workaround: serialise decompiler-backed work, or kill java.exe and restart if already stuck.
Read pseudocode:
SELECT text FROM pseudocode WHERE func_addr = 0x401000;
Inspect locals (local_id is arg0, arg1, ..., var_<N>, local_<N> etc., storage looks like Stack[0x4]:4 or a register name):
SELECT local_id, name, type, storage
FROM decomp_lvars
WHERE func_addr = 0x401000;
SELECT func_addr, local_id, name, type, storage
FROM decomp_lvars
WHERE func_name = 'main';
Inspect tokens (structured decompiler output with semantic info):
SELECT text, kind, var_name, var_type
FROM decomp_tokens
WHERE func_addr = 0x401000;
Token kinds: keyword, variable, type, function, parameter, global, const, comment, default, error, special. Filter to variable references only:
SELECT text, kind, var_name, var_type, var_storage
FROM decomp_tokens
WHERE func_addr = 0x401000 AND kind = 'variable';
Inspect parameters:
SELECT ordinal, param_name, param_type
FROM function_params
WHERE func_addr = 0x401000
ORDER BY ordinal;
ghidrasql exposes 16 ctree* views. They are not Ghidra's real PcodeAST. They are a SQL composition over call_edges, loops, blocks, funcs, instructions, and decomp_lvars that simulates an AST-shape catalog (cot_call, cit_for, cit_while, cit_do, cit_if, cit_return). They are useful for pattern queries ("calls inside loops", "leaf functions", "call chains") but not for syntactically exact AST traversal — for that, use decomp_tokens (which IS from the real decompiler).
| View | Composes over | Useful for |
|---|---|---|
ctree | call_edges + loops + blocks (out_degree > 1) + funcs | Master catalog used by the rest |
ctree_call_args | call_edges with attributed callee | Per-call argument inspection |
ctree_v_calls | ctree filtered to cot_call | Every call in a function with callee resolution |
ctree_v_loops | ctree filtered to cit_for/cit_while/cit_do | Loop list per function |
ctree_v_ifs | ctree filtered to cit_if | Branch points per function |
ctree_v_signed_ops | instructions filtered by mnemonic (imul/idiv/sar/sal/sub/add) | Arithmetic-of-interest hits |
ctree_v_comparisons | instructions filtered to cmp/test | Comparison hits |
ctree_v_assignments | instructions filtered to mov/lea | Assignment hits |
ctree_v_derefs | instructions where operand contains [ | Pointer-dereference hits |
ctree_v_calls_in_loops | ctree_v_calls JOIN loops on EA range | "What gets called inside a loop body?" |
ctree_v_calls_in_ifs | ctree_v_calls JOIN if_nodes | "What gets called from a conditional branch?" |
ctree_v_leaf_funcs | funcs LEFT JOIN ctree_v_calls (no callees) | Bottom-up annotation entry points |
ctree_v_call_chains | RECURSIVE over ctree_v_calls | Reachability with cycle guard |
ctree_v_returns | funcs (synthetic return at end_addr) | Return-point markers |
ctree_lvars | decomp_lvars with derived stable index | Stable per-function variable index for cross-references |
Worked examples:
-- Every call site inside a loop in this function
SELECT printf('0x%X', addr) AS site, callee_name, loop_op, printf('0x%X', loop_id) AS loop_header
FROM ctree_v_calls_in_loops
WHERE func_addr = 0x401000;
-- Leaf functions (good seed set for bottom-up annotation)
SELECT printf('0x%X', addr) AS addr, name
FROM ctree_v_leaf_funcs
ORDER BY name
LIMIT 50;
-- Call chains rooted at a function (cycle-guarded recursion)
SELECT printf('0x%X', current_func) AS current, depth, path
FROM ctree_v_call_chains
WHERE root_func = 0x401000 AND depth <= 5
ORDER BY depth;
WHERE func_addr = X, or exact WHERE func_name = 'name' for pseudocode/decomp_lvars. Without it you triggered a full-program decompile.decomp_lvars again and use the exact local_id from the result (don't synthesise arg0, query for it).pseudocode still looks stale. Check program_revision() and cache_stats(). Libghidra live sources refresh after Ghidra's native modification number or the program identity changes; inside a batch or when forcing a rebuild: SELECT cache_invalidate('pseudocode'); then SELECT text FROM pseudocode WHERE func_addr = 0xX;.java.exe, delete *.lock / *.lock~, restart the host, run sequentially.