| name | types |
| description | IDA type system. Use when asked to create, modify, or apply structs, unions, enums, typedefs, or parse C declarations. |
| allowed-tools | ["Bash","Read","Glob","Grep"] |
This skill is the authoritative reference for IDA's type system as exposed through idasql. For annotation workflows that use types, see annotations. For decompiler-specific type interactions (ctree, lvars, union selection, numform), see decompiler.
Trigger Intents
Use this skill when user asks to:
- create/edit structs, unions, enums, typedefs
- inspect function prototype argument types
- resolve hidden pointer/typedef behavior
- apply or refine recovered data models
Route to:
decompiler for expression-level type context
annotations for applying and documenting type decisions
re-source for recursive structure-recovery workflows
Do This First (Warm-Start Sequence)
SELECT ordinal, name, kind, size
FROM types
ORDER BY ordinal
LIMIT 30;
SELECT name, size
FROM types
WHERE is_struct = 1
ORDER BY size DESC
LIMIT 20;
SELECT type_name, arg_index, arg_name, arg_type
FROM types_func_args
WHERE arg_index >= 0
LIMIT 40;
Interpretation guidance:
- Start with inventory and prioritize large/high-fanout types.
- Use
types_func_args resolved fields for typedef-aware reasoning.
Failure and Recovery
- Type insert/update failed:
- Validate declaration syntax and target ordinal/name existence.
- Conflicting/incomplete type picture:
- Correlate with
decompiler (ctree_lvars, call args) before committing changes.
- Unexpected disassembly rendering:
- Re-check operand format settings and applied declarations.
- Use the real surface names — common mistakes:
- Members live in
types_members (not struct_members); enum constants in
types_enum_values (not enum_members).
- There is no
print_type() / exec_python() SQL function — render a type with
SELECT definition FROM types WHERE ...; run Python via the idapython skill.
- IDA 9 has no
ida_struct; structs/unions are edited through types /
types_members (see "Fixed layout, gaps & recovery").
- To find references to a field, use
struct_member_xrefs, not a
LIKE '%field%' scan of instructions.disasm / instruction_operands.text.
Handoff Patterns
types -> decompiler to validate semantic effect in pseudocode.
types -> annotations for naming/comments on newly typed fields.
types -> re-source for multi-function struct refinement.
Type Tables
local_types
Local type declarations as stored in the database.
Use this for quick inventory/filtering of local types; use types* tables for deeper editing workflows.
| Column | Type | Description |
|---|
ordinal | INT | Type ordinal (local type ID) |
name | TEXT | Type name |
type | TEXT | Declared type text |
is_struct | INT | 1=struct |
is_enum | INT | 1=enum |
is_typedef | INT | 1=typedef |
SELECT ordinal, name, type FROM local_types ORDER BY ordinal LIMIT 50;
For canonical schema and owner mapping, see ../connect/references/schema-catalog.md (local_types).
types
All local type definitions. Supports INSERT (create struct/union/enum), UPDATE, DELETE, and local type folder organization through folder_path.
| Column | Type | Description |
|---|
ordinal | INT | Type ordinal (unique identifier) |
name | TEXT | Type name |
folder_path | TEXT | RW local type folder relative to Local Types root; NULL/'' means root |
full_path | TEXT | RO full dirtree path, including the type name |
size | INT | Size in bytes |
kind | TEXT | struct/union/enum/typedef/func |
is_struct | INT | 1=struct |
is_union | INT | 1=union |
is_enum | INT | 1=enum |
SELECT ordinal, name, size FROM types WHERE is_struct = 1 ORDER BY size DESC;
SELECT ordinal, name FROM types WHERE is_enum = 1;
SELECT * FROM types WHERE name LIKE '%CONTEXT%';
SELECT ordinal, name, folder_path
FROM types
WHERE folder_path LIKE 'idasql/types/%'
ORDER BY folder_path, name;
Performance. types WHERE ordinal = ? and types WHERE name = ? are direct
lookups (resolve and render a single type). types WHERE name LIKE 'prefix%' is
optimized too — it scans names cheaply and only renders the matches. Prefer these
over name LIKE '%substr%', which has no shortcut and renders every type
(slow on large IDBs); the same applies to an unfiltered SELECT * FROM types. If
a broad query is cut off by the query timeout, it returns cleanly and the next
query still works — narrow it with an exact name/ordinal or a 'prefix%' filter.
Organizing Local Types
Use types.folder_path for type recovery buckets and dirtree_folders for empty folder lifecycle. This is useful when recovered layouts move from draft to verified states.
INSERT INTO dirtree_folders(tree, path)
VALUES ('local_types', 'idasql/types/recovered');
UPDATE types
SET folder_path = 'idasql/types/recovered'
WHERE name IN ('MY_HEADER', 'COMMAND_RECORD');
UPDATE types
SET folder_path = 'idasql/types/verified'
WHERE name = 'MY_HEADER';
UPDATE types SET folder_path = NULL WHERE name = 'MY_HEADER';
For raw browsing across all IDA dirtrees, use dirtree_entries; for normal type organization, prefer types.folder_path. Folder writes use relative / paths. IDASQL rejects ./.., duplicate separators, backslashes, non-empty folder deletes, and folder renames whose destination already exists.
local_type_bookmarks
Local-type (Local Types view) bookmarks, backed by the bookmarks_t store and
folder-aware via the DIRTREE_LTYPES_BOOKMARKS dirtree. Full CRUD:
| Column | Type | RW | Description |
|---|
slot | INT | R | Bookmark slot in the store |
ordinal | INT | R | Local type ordinal |
type_name | TEXT | R | Type name resolved from the ordinal |
description | TEXT | RW | Bookmark description |
inode | INT | R | Dirtree inode (-1 if not linked into the dirtree) |
folder_path | TEXT | RW | Folder path; NULL/'' means root |
full_path | TEXT | R | Full dirtree path |
INSERT INTO local_type_bookmarks(ordinal, description)
SELECT ordinal, 'review this struct' FROM types WHERE name = 'MY_STRUCT';
UPDATE local_type_bookmarks SET description = 'done'
WHERE ordinal = (SELECT ordinal FROM types WHERE name = 'MY_STRUCT');
SELECT slot, ordinal, type_name, description FROM local_type_bookmarks;
DELETE FROM local_type_bookmarks
WHERE ordinal = (SELECT ordinal FROM types WHERE name = 'MY_STRUCT');
Note: a freshly INSERTed bookmark is created in the bookmarks_t store but is
not auto-linked into the dirtree (so folder_path is NULL until linked), and
folder moves currently require an already-linked bookmark. Reliably mapping a
store slot back to its dirtree inode (to auto-link on INSERT) is a known
limitation.
Creating Types
INSERT INTO types (name, kind) VALUES ('MY_HEADER', 'struct');
INSERT INTO types (name, kind) VALUES ('PARAM_UNION', 'union');
INSERT INTO types (name, kind) VALUES ('CMD_TYPE', 'enum');
SELECT ordinal, name, kind FROM types WHERE name = 'MY_HEADER';
Deleting Types
DELETE FROM types WHERE name = 'MY_HEADER';
DELETE FROM types WHERE ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER');
Refining Existing Types Safely
When a type already exists, prefer targeted types_members edits over
re-importing a whole declaration. Member rename/retype/comment/delete operations
use IDA's UDM APIs against the existing local type ordinal, so dependent
prototypes and member type references keep pointing at the same type ID.
SELECT ordinal, name, kind FROM types WHERE name = 'MY_HEADER';
UPDATE types_members
SET member_name = 'payload_len'
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'len';
UPDATE types_members
SET member_type = 'unsigned __int16'
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'payload_len';
UPDATE types_members
SET offset = 16
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'payload_len';
INSERT INTO types_members (type_ordinal, member_index, member_name, member_type, offset, comment)
SELECT ordinal, 2, 'flags', 'unsigned short', 8, 'inserted in place' FROM types WHERE name = 'MY_HEADER';
Notes:
- Key writes by
type_ordinal plus member_name or member_index; read back
the row after a write.
member_type accepts member type text such as int, void *, char[64],
and named local types. Invalid type text fails instead of silently falling
back to int.
offset / offset_bits currently support byte-aligned struct moves. Union
member offsets remain zero.
- Use
parse_decls() to seed new related declarations or perform an intentional
whole-definition redeclaration; for fine refinements of an existing recovered
type, table edits are safer.
- For compound types, read
member_type_ordinal before and after editing the
referenced type. It should keep pointing at the same local type ordinal.
SELECT h.member_name, h.member_type_ordinal, t.ordinal AS target_ordinal
FROM types_members AS h
JOIN types AS t ON t.name = 'MY_HEADER'
WHERE h.type_name = 'MY_PACKET'
AND h.member_name = 'header';
types_members
Structure and union members. Supports INSERT, UPDATE, and DELETE.
| Column | Type | Description |
|---|
type_ordinal | INT | Parent type ordinal |
type_name | TEXT | Parent type name |
member_index | INT | Member index within the parent type |
member_name | TEXT | Member name |
offset | INT | Byte offset |
offset_bits | INT | Bit offset |
size | INT | Member size |
size_bits | INT | Member size in bits |
member_type | TEXT | Type string (e.g., int, void *, char[256]) |
comment | TEXT | Member comment |
mt_is_ptr | INT | 1=pointer |
mt_is_array | INT | 1=array |
mt_is_struct | INT | 1=embedded struct |
member_type_ordinal | INT | Referenced local type ordinal, or -1 |
SELECT member_name, member_type, offset, size
FROM types_members WHERE type_name = 'MY_HEADER'
ORDER BY offset;
INSERT INTO types_members (type_ordinal, member_name, member_type)
SELECT ordinal, 'magic', 'unsigned int' FROM types WHERE name = 'MY_HEADER';
INSERT INTO types_members (type_ordinal, member_name, member_type)
SELECT ordinal, 'data_ptr', 'void *' FROM types WHERE name = 'MY_HEADER';
INSERT INTO types_members (type_ordinal, member_name, member_type, offset)
SELECT ordinal, 'reserved', 'char[16]', 16 FROM types WHERE name = 'MY_HEADER';
UPDATE types_members SET member_name = 'signature'
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'magic';
UPDATE types_members SET member_type = 'DWORD'
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'signature';
UPDATE types_members SET offset = 32
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'data_ptr';
DELETE FROM types_members
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'MY_HEADER') AND member_name = 'reserved';
Fixed layout, gaps & recovery
A struct has two layout modes. Auto-layout (default): IDA recomputes member
offsets — repacking can shift fields and change the size. Fixed-layout
(types.is_fixed = 1): every offset is frozen, the size can be pinned, and empty
space is exposed as gaps. Use fixed layout to refine a recovered struct in place
without disturbing the bytes you've already mapped — this replaces the old
parse_decls() full-rebuild workaround for ordinary edits.
| Surface | Meaning |
|---|
types.is_fixed (writable) | 1 freezes member offsets; 0 returns to auto-layout — IDA repacks/compacts only on the fixed→auto transition (may shrink), so 0 on an already-auto struct is a no-op |
types.size (writable) | pin a fixed struct's total size (errors on an auto struct) |
types_members.is_gap | 1 if the member is an IDA gap placeholder (free space) |
type_gaps | one row per free byte range in a struct: gap_offset, gap_size (requires a type_ordinal/type_name filter) |
DELETE leaves the slot as a gap (the following members' offsets and the struct
size are preserved — non-collapsing, like IDA's Undefine) on any struct, auto
or fixed — it never shifts the members after it. INSERT at an offset inside a gap
absorbs it without moving neighbors. An INSERT whose explicit offset overlaps an
existing (non-gap) member is rejected ("offset range overlaps an existing
member") — it never overwrites a real field; target a free type_gaps range, or omit
offset to append. To deliberately compact and shrink a struct (drop the gaps and
repack), set is_fixed = 1 then is_fixed = 0: IDA only repacks on the fixed→auto
transition, so a plain is_fixed = 0 on an already-auto struct is a no-op.
UPDATE types SET is_fixed = 1 WHERE name = 'VARBIND_VARIABLE';
SELECT gap_offset, gap_size FROM type_gaps WHERE type_name = 'VARBIND_VARIABLE';
SELECT member_name, "offset" FROM types_members
WHERE type_name = 'VARBIND_VARIABLE' AND is_gap = 1;
INSERT INTO types_members (type_ordinal, member_name, member_type, "offset")
SELECT ordinal, 'handler_cookie', 'int', 28 FROM types WHERE name = 'VARBIND_VARIABLE';
DELETE FROM types_members
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'VARBIND_VARIABLE')
AND member_name = 'scratch';
UPDATE types SET size = 68 WHERE name = 'VARBIND_VARIABLE';
UPDATE types SET is_fixed = 0 WHERE name = 'VARBIND_VARIABLE';
Recovery (prefer this over parse_decls() for refinements). If a fixed struct
got into a bad state from earlier edits: set is_fixed = 1, pin size, inspect
type_gaps/is_gap to find free space, then add/move/delete members
incrementally. Reserve parse_decls() full replacement for building a type from
scratch or a wholesale redefinition — not for ordinary member refinements.
types_enum_values
Enum constant values. Supports INSERT, UPDATE, and DELETE.
| Column | Type | Description |
|---|
type_ordinal | INT | Enum type ordinal |
type_name | TEXT | Enum name |
value_name | TEXT | Constant name |
value | INT | Constant value |
SELECT value_name, value FROM types_enum_values
WHERE type_name = 'CMD_TYPE'
ORDER BY value;
INSERT INTO types_enum_values (type_ordinal, value_name, value)
SELECT ordinal, 'CMD_INIT', 0 FROM types WHERE name = 'CMD_TYPE';
INSERT INTO types_enum_values (type_ordinal, value_name, value)
SELECT ordinal, 'CMD_READ', 1 FROM types WHERE name = 'CMD_TYPE';
UPDATE types_enum_values SET value_name = 'CMD_OPEN'
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'CMD_TYPE') AND value_name = 'CMD_INIT';
UPDATE types_enum_values SET value = 11, comment = 'opens a stream'
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'CMD_TYPE') AND value_name = 'CMD_OPEN';
DELETE FROM types_enum_values
WHERE type_ordinal = (SELECT ordinal FROM types WHERE name = 'CMD_TYPE') AND value_name = 'CMD_READ';
Enum value edits update the existing enum type ordinal. Prefer this path over
redeclaring the enum when the enum is already used by structs, prototypes,
operand representations, or decompiler numforms.
Bitfield (bitmask) enums
A bitmask enum has flag members that combine with OR; a matching operand value
renders as A or B (disassembly) / A | B (pseudocode) instead of a number. Mark
the enum with the writable types.is_bitmask column and set its byte width with the
writable types.size column. Members are added the normal way (flat flags — each
value is its own mask).
INSERT INTO types(name, kind) VALUES ('FILE_FLAGS', 'enum');
UPDATE types SET is_bitmask = 1, size = 4 WHERE name = 'FILE_FLAGS';
INSERT INTO types_enum_values(type_ordinal, value_name, value)
SELECT ordinal, 'FF_READ', 1 FROM types WHERE name='FILE_FLAGS';
UPDATE instructions SET operand1_format_spec = 'enum:FILE_FLAGS' WHERE addr = 0x401050;
is_bitmask applies to enums only; size must be 1/2/4/8. The flag + width persist
across later value edits. Decompiler propagation is operand-dependent (a cmp/test
or call-argument immediate is the reliable case). Omitting value when inserting a
bitmask member auto-assigns the next free single-bit mask (1, 2, 4, …) —
0 is not a valid mask, so a value-less insert never yields it. The auto-mask is
bounded by the enum width: a 1-byte bitmask only has 0x01..0x80, so once every
in-width bit is used a value-less insert fails ("no free single-bit mask remains
within the enum width") — widen types.size or pass an explicit value.
types_func_args
Function prototype arguments with deep type classification.
| Column | Type | Description |
|---|
type_ordinal | INT | Function type ordinal |
type_name | TEXT | Function type name |
arg_index | INT | Argument index (-1 = return type, 0+ = args) |
arg_name | TEXT | Argument name |
arg_type | TEXT | Argument type string |
calling_conv | TEXT | Calling convention (on return row only) |
Surface-Level Type Classification
Literal type as written — what you see in the declaration:
| Column | Description |
|---|
is_ptr | 1 if pointer type |
is_int | 1 if exactly int |
is_integral | 1 if int-like (int, long, short, char, bool) |
is_float | 1 if float/double |
is_void | 1 if void |
is_struct | 1 if struct/union |
is_array | 1 if array |
ptr_depth | Pointer depth (int** = 2) |
base_type | Type with pointers stripped |
Resolved Type Classification
After typedef resolution — what the type actually is:
| Column | Description |
|---|
is_ptr_resolved | 1 if resolved type is pointer |
is_int_resolved | 1 if resolved type is exactly int |
is_integral_resolved | 1 if resolved type is int-like |
is_float_resolved | 1 if resolved type is float/double |
is_void_resolved | 1 if resolved type is void |
ptr_depth_resolved | Pointer depth after resolution |
base_type_resolved | Resolved type with pointers stripped |
This dual classification is critical for typedef-aware queries. For example, HANDLE appears as non-pointer at surface level but resolves to void *.
SELECT DISTINCT type_name, arg_type, base_type_resolved
FROM types_func_args
WHERE is_ptr = 0 AND is_ptr_resolved = 1;
SELECT type_name, arg_name, arg_type FROM types_func_args
WHERE arg_index >= 0 AND is_struct = 1;
For more types_func_args query patterns (string parameters, pointer counts, return type filters), see references/type-patterns.md.
Type Views
Convenience views for filtering types:
| View | Description |
|---|
types_v_structs | SELECT * FROM types WHERE is_struct = 1 |
types_v_unions | SELECT * FROM types WHERE is_union = 1 |
types_v_enums | SELECT * FROM types WHERE is_enum = 1 |
types_v_typedefs | SELECT * FROM types WHERE is_typedef = 1 |
types_v_funcs | SELECT * FROM types WHERE is_func = 1 |
types_v_inheritance | Struct/class inheritance relationships (baseclasses from types_members) |
types_v_inheritance view
Shows struct/class inheritance relationships extracted from baseclass members.
| Column | Type | Description |
|---|
derived_ordinal | INT | Ordinal of the derived type |
derived_name | TEXT | Name of the derived type |
base_type_name | TEXT | Name of the base type |
base_ordinal | INT | Ordinal of the base type |
base_offset | INT | Byte offset of the base within the derived type |
SELECT * FROM types_v_inheritance WHERE derived_name = 'MyClass';
WITH RECURSIVE ancestors(name, depth) AS (
SELECT base_type_name, 1 FROM types_v_inheritance WHERE derived_name = 'MyClass'
UNION ALL
SELECT i.base_type_name, a.depth + 1
FROM types_v_inheritance i JOIN ancestors a ON i.derived_name = a.name
WHERE a.depth < 10
)
SELECT * FROM ancestors;
Importing C Declarations (parse_decls)
parse_decls(text) imports C declarations into the local type library. It is
best for seeding related types, typedefs, enums, and whole declarations. For
small refinements to an existing recovered type, prefer types_members updates
so the local type ordinal stays stable and existing references do not need to be
rebuilt.
SELECT parse_decls('
struct MY_HEADER {
unsigned int magic;
unsigned int version;
unsigned int size;
void *data;
};
');
SELECT parse_decls('
#pragma pack(push, 1)
typedef enum operations_e { op_empty=0, op_open=11, op_read=22 } operations_e;
typedef union command_payload_u { void *ptr; unsigned __int64 qword; } command_payload_u;
typedef struct command_t {
operations_e cmd_id;
command_payload_u payload;
unsigned __int64 ret;
} command_t;
#pragma pack(pop)
');
SELECT name, kind, size FROM types WHERE name IN ('command_t', 'operations_e');
For a full multi-struct parse_decls example with nested unions, see references/type-patterns.md.
Applying Types to Functions and Variables
Function Prototypes
UPDATE funcs SET prototype = 'void __fastcall exec_command(command_t *cmd);'
WHERE addr = 0x140001BD0;
INSERT INTO applied_types(addr, decl)
VALUES (0x140001BD0, 'void __fastcall exec_command(command_t *cmd);');
SELECT decl, ordinal, type_name
FROM applied_types
WHERE addr = 0x140001BD0;
UPDATE applied_types
SET decl = 'void __fastcall exec_command(command_t *cmd);'
WHERE addr = 'exec_command';
DELETE FROM applied_types WHERE addr = 0x140001BD0;
SELECT decompile(0x140001BD0, 1);
applied_types point lookup is intentionally write-friendly: WHERE addr = X
returns one mapped row even when no declaration is applied yet, with decl,
ordinal, and type_name as NULL. Range scans return only addresses that
currently have applied type information.
Local Variables
UPDATE ctree_lvars SET type = 'MY_STRUCT *'
WHERE func_addr = 0x401000 AND idx = 0;
SELECT decompile(0x401000, 1);
SELECT idx, name, type FROM ctree_lvars
WHERE func_addr = 0x401000 AND idx = 0;
Call Sites
Use call-site typing for indirect calls when function prototypes and local-variable types still leave a specific call under-typed.
SELECT call_addr, target_op, target_var_name, arg_count
FROM ctree_v_indirect_calls
WHERE func_addr = 0x140001BD0
ORDER BY call_addr;
UPDATE disasm_calls
SET callee_type = 'int __fastcall emit_message(const char *name, const char *target, int flag, const char *tag);'
WHERE addr = 0x140001C3E;
SELECT callee_type FROM disasm_calls WHERE addr = 0x140001C3E;
SELECT call_arg_addrs(0x140001C3E);
SELECT decompile(0x140001BD0, 1);
Typing Surfaces Matrix
| Surface | Scope | Semantic vs render-only | Typical use |
|---|
UPDATE funcs SET prototype = ... / applied_types | Function/global address | Semantic | Give a function or global the right declared type |
UPDATE ctree_lvars SET type = ... | One decompiled local/arg | Semantic | Clean up local pointer/struct inference |
UPDATE disasm_calls SET callee_type = ... WHERE addr = ... | One call site | Semantic | Fix an indirect call when the callee prototype must be explicit |
instructions.operand*_format_spec | One disassembly operand | Render-only | Show enums/struct offsets in listing output |
set_union_selection* | One decompiler expression | Render-only | Choose a union arm for nicer pseudocode |
set_numform* | One decompiler expression operand | Render-only | Change numeric rendering without changing base type |
Names
INSERT INTO names(addr, name) VALUES (0x402000, 'g_config');
UPDATE names SET name = 'g_config' WHERE addr = 0x402000;
Note: INSERT and UPDATE against names both call IDA's set_name(addr, name, SN_CHECK). IDA permits only one name per address, so INSERT at an already-named EA replaces. SN_CHECK also auto-disambiguates if the new name string conflicts globally (foo → foo_0); read back the row to see what was actually stored.
Struct Offset Representation in Disassembly
The instructions table operand*_format_spec column applies struct offset display to disassembly operands:
UPDATE instructions SET operand0_format_spec = 'stroff:MY_STRUCT,delta=0'
WHERE addr = 0x401030;
UPDATE instructions SET operand0_format_spec = 'stroff:OUTER_T/INNER_T'
WHERE addr = 0x401030;
UPDATE instructions SET operand1_format_spec = 'sizeof:MY_STRUCT'
WHERE addr = 0x4015EB;
UPDATE instructions SET operand1_format_spec = 'enum:MY_ENUM'
WHERE addr = 0x401020;
Number/offset/forced/char display forms (hex/dec/oct/bin, char,
offset[:base], forced:<text>, plus ,signed/,bnot modifiers) are also
applied through operand*_format_spec — see the disassembly skill for the
full vocabulary.
Enum/Union Rendering in Decompiled Code
For numform helpers (set_numform*) and union selection helpers (set_union_selection*), see decompiler skill.
disasm_calls.callee_type belongs on the semantic side of the fence: it affects call analysis, unlike render-only enum/union formatting helpers.
Performance Rules
| Table | Architecture | Key Constraint | Notes |
|---|
types | Cached | ordinal (optional) | Full cache rebuilt on demand; usually fast (<1000 types) |
types_members | Cached | type_ordinal | O(1) lookup with constraint; without it iterates all types |
types_enum_values | Cached | type_ordinal | O(1) lookup with constraint |
types_func_args | Cached | type_ordinal | O(1) lookup with constraint |
Key rules:
type_ordinal constraint pushdown gives O(1) access to a single type's members, enum values, or func args.
- Without constraint, these tables iterate all local types. This is usually fast (most binaries have <1000 local types), but prefer filtered queries when you know the target.
- Type views (
types_v_structs, etc.) are pre-filtered — use them for categorical queries.
parse_decls() is the fastest way to seed multiple types at once (single call vs multiple INSERTs).
See Also
xrefs — struct_member_xrefs finds references TO a struct/union member
(filter by type_name/type_ordinal/member_id); the right tool after you
resolve a type/member here, instead of disasm-text scans.
annotations — apply type via funcs.prototype / applied_types; combine with renames and comments.
decompiler — ctree consumes applied types; union selection, numform, mutation loop.
re-source — structure recovery methodology from offset casts.
Additional Resources