types
Import, inspect, and apply Ghidra types through ghidrasql — structs, unions, enums, typedefs, and function signatures.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Import, inspect, and apply Ghidra types through ghidrasql — structs, unions, enums, typedefs, and function signatures.
用 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.
Decompile functions with ghidrasql and work with pseudocode, locals, parameters, and ctree pattern views safely.
| name | types |
| description | Import, inspect, and apply Ghidra types through ghidrasql — structs, unions, enums, typedefs, and function signatures. |
| allowed-tools | ["Bash","Read","Glob","Grep"] |
Use this skill when the user asks to:
Route to:
annotations for the broader rename/comment workflow that wraps a type applydecompiler to verify the effect in pseudocodere-source for iterative cross-function struct recovery| Table | UPDATE columns | INSERT (required positional) | DELETE |
|---|---|---|---|
types | name | name, kind (size, declaration optional) | yes |
type_members | member_name, member_type, comment | parent_type_id, member_name, member_type | yes |
type_enums | name | name (width default 4, is_signed default 0) | yes |
type_enum_members | name, value, comment | type_id, name, value | yes |
type_unions | name | name (size, declaration optional) | yes |
type_aliases | name, target_type | name, target_type | yes |
signatures | name (function rows only), prototype | – | – |
function_params | param_name, param_type | – | – |
Important: UPDATE on kind, size, declaration, width, is_signed, target_type.declaration, etc. is not implemented — those columns are read-only post-INSERT. To change a struct's layout or kind, delete and re-create (or use parse_decls()).
INSERT-only views: apply_type_data, apply_type_param, apply_type_local — see references/type-workflows.md.
Inspect the existing type surface:
SELECT name, kind, size
FROM types
ORDER BY name
LIMIT 50;
Discover the real kind values on this binary (don't hard-code — values come from Ghidra):
SELECT DISTINCT kind FROM types;
For new declarations, parse_decls():
SELECT parse_decls('typedef struct { int flags; char tag[8]; } Session;');
Returns the count of newly created types (0 if everything already existed) or -1 on parse error. Standard C only — no preprocessor, no #include. Verify by re-reading types.
type_family(decl) returns exactly one of these 10 strings:
aggregate | enum | alias | function | pointer | boolean
floating | integral | void | unknown
SELECT name, type_family(declaration) AS fam
FROM types
WHERE name LIKE '%Context%';
Two helpers built on the same logic:
type_is_pointer(decl) returns 0/1.type_strip_cv(decl) removes const/volatile/restrict/mutable, preserves * and &.Apply a function signature (writes through funcs.prototype):
UPDATE funcs
SET prototype = 'int processCommand(Command *cmd, Result *out)'
WHERE addr = 0x401200;
If __cdecl (or any explicit calling-convention prefix) causes a vague set_function_signature error, drop it and retry. Calling-convention parsing in Ghidra can reject otherwise-valid prototypes.
Inspect struct members. The type_members table column is parent_type_name (and parent_type_id); the types_members view exposes a friendlier resolved alias type_name plus extra metadata (mt_is_struct, ...):
-- Direct table
SELECT parent_type_name, member_name, member_type, offset, size, comment
FROM type_members
WHERE parent_type_name = 'Session'
ORDER BY offset;
-- View with resolved type_name + extra metadata
SELECT type_name, member_name, member_type, offset
FROM types_members
WHERE type_name = 'Session'
ORDER BY offset;
Add a member. INSERT requires parent_type_id (not parent_type_name) — look it up from types first. The C++ insertable handler reads parent_type_id (column 0), member_name (column 2), member_type (column 3), size (column 5). Other columns including offset are ignored on INSERT — Ghidra computes offset from existing layout:
INSERT INTO type_members (parent_type_id, member_name, member_type, size)
SELECT type_id, 'last_seen', 'uint32_t', 4
FROM types WHERE name = 'Session';
member_type must name a type Ghidra can already resolve — a base type
(uint32_t, char, …), a pointer/array of one, or a type you created earlier.
A bare typedef name that isn't in the archive yet (e.g. time_t before any
<time.h> parse) is rejected; parse_decls() a declaration for it first, or use
a base type as above. For non-trivial layouts, use parse_decls() instead — it goes through Ghidra's CParser which handles offsets and alignment.
Update a member's name, type, or comment (offset and size are read-only post-INSERT):
UPDATE type_members
SET member_type = 'uint32_t',
comment = 'flags bitfield'
WHERE parent_type_name = 'Session' AND member_name = 'flags';
Create an enum and add values:
INSERT INTO type_enums (name, width, is_signed) VALUES ('CmdType', 4, 0);
INSERT INTO type_enum_members (type_id, name, value)
SELECT type_id, 'CMD_INIT', 0 FROM type_enums WHERE name = 'CmdType';
INSERT INTO type_enum_members (type_id, name, value)
SELECT type_id, 'CMD_RUN', 1 FROM type_enums WHERE name = 'CmdType';
SELECT value_name, value, comment
FROM types_enum_values
WHERE type_name = 'CmdType'
ORDER BY value;
Explore signatures (read-mostly — only name, function rows only, and prototype are writable):
SELECT name, prototype, return_type, calling_convention, is_variadic
FROM signatures
WHERE name LIKE '%parse%';
Three views with INSTEAD OF INSERT triggers for compositional type application:
-- Apply a global data type at an address
INSERT INTO apply_type_data (addr, type_name) VALUES (0x404000, 'IMAGE_DOS_HEADER');
-- Apply a parameter type by ordinal
INSERT INTO apply_type_param (func_addr, ordinal, type_name) VALUES (0x401200, 0, 'Command *');
-- Apply a local-variable type by local_id (calls set_local_type underneath)
INSERT INTO apply_type_local (func_addr, local_id, type_name) VALUES (0x401200, 'arg2', 'Result *');
UPDATE/DELETE on these views is not implemented — they are write-paths only.
#include, no #define, no comments-as-pragmas.uint8_t, uint16_t, uint32_t, int8_t, size_t, ptrdiff_t. (Older builds mis-mapped uint8_t/uint16_t/uint32_t; current builds resolve them correctly.)-1 on error. Partial failures are silent — verify by re-reading types after the call.parse_decls() for an already-imported declaration returns 0, not an error. It is idempotent for the no-op case.-- Bulk import with verification:
SELECT parse_decls('
typedef enum { CMD_INIT=0, CMD_RUN=1, CMD_STOP=2 } CmdType;
typedef struct {
CmdType type;
int flags;
char tag[8];
} Command;
');
SELECT name, kind FROM types WHERE name IN ('Command', 'CmdType');
parse_decls() — preprocessor directives are not supported.pseudocode after type changes that affect decompilation. In one-shot mode, the next query already sees the updated decompilation; inside a batched script, drop the cache first: SELECT cache_invalidate('pseudocode'); SELECT text FROM pseudocode WHERE func_addr = 0xX;.signatures writes only name and prototype — UPDATE signatures SET name = ... works for function rows only (it renames the owning function, same as writing funcs.name); other columns (calling_convention, return_type, ...) are read-only.parse_decls() returned 0 but the type didn't appear. Either the declaration was already imported, or the parser silently rejected it. Re-read types; if absent, simplify the declaration (drop forward declarations, qualifiers) and retry.apply_type_param INSERT raises 'apply_type_param requires func_addr, ordinal, and type_name'. All three must be non-NULL; type_name must be non-empty.UPDATE decomp_lvars SET type = 'wchar_t[128]' works. The writable-type resolver handles array (T[N], multi-dimensional T[N][M]), pointer, and array-of-pointer (void *[4]) declarators. The apply_type_local view / set_local_type() SQL function remain available for scripted, all-or-nothing application.Can't parse name: *fn. Ghidra's CParser tokenises <type> *fn(...) as a name *fn instead of a return-type pointer. Workaround: write the asterisk on the type, not the name — char* fn(...), void** fn(...). Same trap on parameter lists; prefer T* name over T *name when authoring prototypes.char *, int) and verify each apply in pseudocode.