Skip to main content

Crate callgraph_verify

Crate callgraph_verify 

Source
Expand description

Pure-byte call-graph + fact verifier for the Rust rebuild.

When a rebuild function is tagged origin: 0xADDR, it claims to be a 1:1 port of the function at that VA in the target binary. This crate establishes ground truth by disassembling the actual bytes (no Ghidra, no decompiled C) and lets a port declare what it should structurally match:

  • direct CALL targets (the call graph)
  • struct field offsets ([reg+0xNN] accesses)
  • global / static VAs ([0x00bXXXXX] data refs)
  • vtable / immediate VAs (MOV [esi],0x00a7e38c)
  • virtual-call slots (CALL [reg+0x84])
  • IAT import targets (CALL [0x00a28xxx])

Use the verify_callgraph! macro to turn declarations into #[test]s.

Re-exports§

pub use disasm::analyze;
pub use disasm::analyze_opt;
pub use disasm::reg_params;
pub use disasm::resolve_thunk;
pub use disasm::tail_referenced;
pub use disasm::ArgKind;
pub use disasm::CallGraph;
pub use disasm::CallSite;
pub use pe::FixupStatus;
pub use pe::Pe;
pub use skel::cfg_fingerprint;
pub use skel::CfgFingerprint;

Modules§

disasm
Recursive-descent function disassembly over real PE bytes (iced-x86).
pe
Minimal, dependency-free PE32 reader — just enough to map a virtual address (VA) to file bytes. We deliberately hand-parse the headers instead of pulling in goblin/object: the contract is “pure byte”, and the only thing the disassembler needs is va -> &[machine code bytes].
skel
Byte-derived reference skeleton emitter: turns a function’s machine code into a Rust-flavored structural outline — labeled basic blocks, ordered calls with their recovered arguments, struct-field accesses (rd/wr), globals (g/s), and the branch / loop / switch structure. It is NOT compilable Rust; it is a faithful hint for porting, generated from the same byte-truth the gates verify against. Use it next to the naked asm and the Ghidra C: the asm is ground truth, Ghidra C gives high-level naming, and this gives the byte-accurate call order + arguments + offsets + control flow in the porter’s target idiom.

Macros§

verify_callgraph
Declare expected facts for origin: functions and generate one #[test] per function, checked against the real binary.

Structs§

CorpusDiff
Result of diffing a Rust function’s resolved body calls against the binary.
Diff
Back-compat thin diff over direct calls only (used by the CLI / build gate).
Spec
One declared expectation for a function, checked against the binary’s facts.

Functions§

diff_body_calls
Diff the calls a Rust body makes (already resolved to ported addresses) against the binary’s real call set at own_addrs. corpus is the set of all ported origin addresses (only calls within it are diffable). Mirrors the logic of tools/analysis/verify_callgraph.py, but on bytes instead of Ghidra .asm.
diff_body_calls_ext
Like diff_body_calls, plus indirect_targets: addresses the binary reaches through a register/memory indirect call at own_addrs (a stack-slot callback, a registered handler, an IAT thunk, …). They widen the ACCEPTANCE set only: a body that spells one as a direct call is faithful, and they never become a MISSING requirement (the binary issues no direct CALL to them).
diff_calls
has_direct_branch_target
Does ANY instruction in .text statically target target via a relative branch (CALL/JMP/Jcc rel32)? Used by the macro to warn on vtable-only dispatch.