Skip to main content

idakit_sys/
hexrays.rs

1//! Hex-Rays ctree-emit vtbl PODs ([`EmitVtbl`]) and the ctree-walk entry points
2//! (`idakit_hexrays_init`, `idakit_cfunc_walk_ctree`).
3
4use std::ffi::{c_char, c_int, c_void};
5
6use crate::Address;
7
8/// Absent optional child / sentinel, matching `IDAKIT_NONE` in the facade.
9pub const IDAKIT_NONE: u32 = 0xFFFF_FFFF;
10
11/// One `switch` case, as passed to [`EmitVtbl::s_switch`].
12#[repr(C)]
13#[derive(Clone, Copy, Debug)]
14pub struct CaseDesc {
15    pub values: *const u64,
16    pub nvalues: usize,
17    pub body: u32,
18}
19
20/// One fragment of a scattered (`ALOC_DIST`) local's location, as the facade passes it inside
21/// [`LvarLoc::pieces`]. `atype` is the fragment's own `ALOC_*` (a register or stack slot).
22#[repr(C)]
23#[derive(Clone, Copy, Debug)]
24pub struct LocPiece {
25    pub atype: u32,
26    pub reg: u32,
27    pub sval: i64,
28    pub off: u32,
29    pub size: u32,
30}
31
32/// A local variable's location, decoded from IDA's `argloc_t` and passed to
33/// [`EmitVtbl::l_lvar`]. `atype` is the `ALOC_*` discriminant; only the fields it selects are
34/// meaningful: `reg1` (REG1 / REG2 low / RREL reg), `reg2` (REG2 high), `sval` (STACK offset /
35/// STATIC ea / RREL displacement). `pieces`/`npieces` describe a scattered location and are
36/// empty otherwise.
37#[repr(C)]
38#[derive(Clone, Copy, Debug)]
39pub struct LvarLoc {
40    pub atype: u32,
41    pub reg1: u32,
42    pub reg2: u32,
43    pub sval: i64,
44    pub pieces: *const LocPiece,
45    pub npieces: u32,
46}
47
48/// The callbacks the facade invokes while streaming a ctree walk. The consumer (idakit)
49/// builds owned nodes inside each callback and returns the handle the parent will
50/// reference; children are emitted before parents. `#[repr(C)]` and field order mirror
51/// `idakit_emit_vtbl_t` exactly, since the facade indexes by offset.
52///
53/// Every `*const c_char`/byte-slice pointer passed to a callback (names, string literals,
54/// member and enum-constant names, comments, value arrays) borrows a C++ stack temporary
55/// owned by the walk. It is valid for that single callback invocation only and dangles once
56/// the callback returns, so a callback must copy any data it needs to outlive the call.
57#[repr(C)]
58pub struct EmitVtbl {
59    pub e_num: unsafe extern "C" fn(*mut c_void, Address, u64, u32) -> u32,
60    pub e_fnum: unsafe extern "C" fn(*mut c_void, Address, f64, u32) -> u32,
61    pub e_obj:
62        unsafe extern "C" fn(*mut c_void, Address, Address, *const c_char, usize, u32) -> u32,
63    pub e_var: unsafe extern "C" fn(*mut c_void, Address, u32, u32) -> u32,
64    pub e_str: unsafe extern "C" fn(*mut c_void, Address, *const c_char, usize, u32) -> u32,
65    pub e_helper: unsafe extern "C" fn(*mut c_void, Address, *const c_char, usize, u32) -> u32,
66    pub e_call: unsafe extern "C" fn(*mut c_void, Address, u32, *const u32, usize, u32) -> u32,
67    pub e_memref: unsafe extern "C" fn(*mut c_void, Address, u32, u32, u32) -> u32,
68    pub e_memptr: unsafe extern "C" fn(*mut c_void, Address, u32, u32, u32) -> u32,
69    pub e_deref: unsafe extern "C" fn(*mut c_void, Address, u32, u32, u32) -> u32,
70    pub e_op: unsafe extern "C" fn(*mut c_void, Address, u32, u32, u32, u32, u32) -> u32,
71
72    pub s_block: unsafe extern "C" fn(*mut c_void, Address, *const u32, usize) -> u32,
73    pub s_expr: unsafe extern "C" fn(*mut c_void, Address, u32) -> u32,
74    pub s_if: unsafe extern "C" fn(*mut c_void, Address, u32, u32, u32) -> u32,
75    pub s_for: unsafe extern "C" fn(*mut c_void, Address, u32, u32, u32, u32) -> u32,
76    pub s_while: unsafe extern "C" fn(*mut c_void, Address, u32, u32) -> u32,
77    pub s_do: unsafe extern "C" fn(*mut c_void, Address, u32, u32) -> u32,
78    pub s_switch: unsafe extern "C" fn(*mut c_void, Address, u32, *const CaseDesc, usize) -> u32,
79    pub s_break: unsafe extern "C" fn(*mut c_void, Address) -> u32,
80    pub s_continue: unsafe extern "C" fn(*mut c_void, Address) -> u32,
81    pub s_return: unsafe extern "C" fn(*mut c_void, Address, u32) -> u32,
82    pub s_goto: unsafe extern "C" fn(*mut c_void, Address, i32) -> u32,
83    pub s_asm: unsafe extern "C" fn(*mut c_void, Address, *const u64, usize) -> u32,
84    pub s_try: unsafe extern "C" fn(*mut c_void, Address, u32, *const u32, usize) -> u32,
85    pub s_throw: unsafe extern "C" fn(*mut c_void, Address, u32) -> u32,
86    pub s_empty: unsafe extern "C" fn(*mut c_void, Address) -> u32,
87
88    pub l_lvar: unsafe extern "C" fn(
89        *mut c_void,
90        *const c_char,
91        usize,
92        u32,
93        u32,
94        u32,
95        *const c_char,
96        usize,
97        *const LvarLoc,
98    ),
99}
100
101// hex-rays decompiler
102unsafe extern "C" {
103    pub fn idakit_hexrays_init() -> c_int;
104    /// Walk `cfunc`'s ctree, driving `vtbl` (with `ctx`) per node and `visitor` (an opaque
105    /// [`TypeWalkVisitor`](crate::TypeWalkVisitor)) per node type, writing the root statement handle
106    /// to `*root`. Returns 0 on success, non-zero if any pointer argument is null.
107    pub fn idakit_cfunc_walk_ctree(
108        cfunc: *mut c_void,
109        vtbl: *const EmitVtbl,
110        ctx: *mut c_void,
111        visitor: *mut c_void,
112        root: *mut u32,
113    ) -> c_int;
114}