In a stripped program, an unconditional jump to code below a function's entry that the function hasn't reached otherwise is a tail call to a function of its own (such as frame_dummy jumping to register_tm_clones), instead of pulling that code into the caller.
ARM32 and Thumb loads and stores keep their memory operands, so pseudo-C shows r0 = *(uint32_t*)(r1 + 4); instead of r0 = 0;; write-back and shifted or subtracted index forms are shown as written. Fixes#277.
ARM and Thumb branches, BL/BLX calls and CBZ/CBNZ point at the targets llvm-objdump reports, so Thumb calls no longer land four bytes early. Fixes#250.
ELF files whose section headers were removed (common in NAS and router firmware) now show their functions, imports and exports. The dynamic symbol table is found through PT_DYNAMIC (DT_SYMTAB/DT_STRTAB, counted from DT_HASH, then DT_GNU_HASH, then an estimate with a warning), shared with the Flutter reader. The prologue scan walks executable segments when there are no sections.
Fixes#223
An A32 LDRD/STRD with Rt=15 (e.g. 0xc0c7fef3) made the decoder library panic on the nonexistent r16; such a word now decodes as no instruction, before the library sees it.
The PLT, prologue and pointer scans in disasm/program.rs use checked steps, so code near u64::MAX no longer wraps to 0 and walks the whole address space. Adds open roadmap lines for an A32 STRD/LDRD decoder panic and unchecked header offsets in dart.rs.
A native, pure-Rust app that shows anyone how a piece of software works, with
evidence-backed answers, then helps them rebuild it. It ships a desktop app, a
CLI and an MCP server, all driven by one engine.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>