Standalone tooling and learnings from studying old compilers and executables for matching-decompilation work. Everything here is self-contained: plain Python 3 (no dependencies) plus two Ghidra scripts.
mwcc-compiler-notes.md is the write-up: how the GameCube-era CodeWarrior
PowerPC compiler's optimization pipeline and register allocator behave, with
confidence levels, references to the underlying algorithms, and the memory
addresses/struct layouts needed to observe allocator state live.
-
pe_inspect.py— dependency-free PE32 parser and CLI: section map, string/byte search, reads at virtual addresses, pointer xref scan.python3 tools/pe_inspect.py target.exe info python3 tools/pe_inspect.py target.exe find-string "some diagnostic" python3 tools/pe_inspect.py target.exe xrefs 0x00562060 -
coff_inspect.py— i386 COFF object/library parser, plus a fingerprinting trick that has punched well above its weight: extract relocation-free function bodies from period library objects and search a target executable's.textfor exact matches. A 12+ byte relocation-free body is close to a toolchain fingerprint — one exact hit can tie an unknown executable to the compiler family and era that built it.python3 tools/coff_inspect.py functions some_object.obj python3 tools/coff_inspect.py match-pe --pe target.exe path/to/period_libs/
-
architecture.py— report format/bits/endianness/machine for PE and ELF files. Handy for quick "what did this compiler actually emit" checks. -
verify_artifact.py— verify an analysis input against a pinned JSON config (size, MD5/SHA-1/SHA-256, PE timestamp) before trusting any result. Cheap insurance against silently analyzing the wrong build of "the same" binary; run it at the front of every pipeline. -
ghidra_headless.py— reproducible headless Ghidra: imports a binary into a self-contained project directory (Ghidra's per-user state included, via-Duser.home) and runs export scripts against it. LocatesanalyzeHeadlessfrom$GHIDRA_ANALYZE_HEADLESS,$PATH, or Homebrew.python3 tools/ghidra_headless.py --project-dir build/ghidra import target.exe python3 tools/ghidra_headless.py --project-dir build/ghidra run \ --binary-name target.exe --script-dir ghidra_scripts \ RankLeafFunctions.java out/leaves.md 0x00400000 0x00500000 50
ExportFunctions.java— for a list of addresses, export each containing function as Markdown: size, callers, callees, referenced strings, full disassembly with bytes, and decompiled C. Great for diffing analysis snapshots or feeding a focused function set to review.RankLeafFunctions.java— find small leaf functions (no calls, 3–30 instructions) in an address range, sorted by size, with decompilation. Leaf functions are the best starting points for decompilation and the best probes for identifying an unknown compiler, since they expose pure code-generator behavior with minimal frontend ambiguity.
Version-pinned to the compiler identified by hash in
mwcc-compiler-notes.md; the tools refuse snapshots from anything else.
allocator_snapshot.py— reads the compiler's in-memory PCode blocks and interference graph into validated JSON (mwcc-allocator-snapshot-v1,mwcc-coloring-snapshot-v1); also a CLI validator for existing snapshots.gdb_allocator_snapshot.py— GDB commands built on the reader:mwcc-snapshot PATH(pre-coloring PCode),mwcc-coloring-snapshot PATH(interference graph + simplify order at color selection), andmwcc-auto-capture DIR(indexed snapshots for every function compiled, with before/after pairs around each GPR coloring attempt).compare_coloring_snapshots.py— diff two coloring snapshots by virtual register: graph-field changes, color changes, simplify-order moves.Dockerfile.debugger— minimal image (gdb-multiarch, qemu-user, python3) for driving the compiler underqemu-i386 -g PORTand attaching GDB to the QEMU stub, so captures work even where hostptraceis unavailable.
Capture pattern: run the compiler under Wibo inside a hardened container
(--network none --read-only --cap-drop ALL --security-opt no-new-privileges, inputs mounted read-only, tmpfs scratch) via
qemu-i386 -g 1234, then gdb-multiarch -batch with a script that does
target remote :1234, sources gdb_allocator_snapshot.py, runs
mwcc-auto-capture /capture, and continues. Capture indices follow emitted
function order and correlate with powerpc-eabi-nm -n on the output object.
- Pin your inputs. Record size, hashes, and PE timestamp of every analyzed binary; verify before every run. Version confusion produces confidently wrong conclusions.
- Treat downloaded binaries as untrusted data. Parse them; don't run
them. If dynamic behavior is essential, use a disposable sandbox with no
network, a read-only root, dropped capabilities,
no-new-privileges, and resource limits — and record the input hash and exact invocation with every result. - Label evidence. Every recovered fact carries a tier: confirmed (established from this exact binary), inferred (strong semantic conclusion), or hypothesis (borrowed from a neighboring version or external reference). Neighboring versions suggest what to test; they never override the target.
- Corroborate struct offsets. Require at least two independent consumer functions (or one consumer plus an allocation site) before naming a field. A disassembler's inferred types are not evidence by themselves.
- Write predictions down first. A source experiment only counts as model-backed if the expected outcome was recorded before compiling. Rejected predictions stay in the record — they constrain the model and stop the next person from repeating the sweep.
0 comments
log in to comment.