Rust workspace that turns a core dump of a stripped, optimized C/C++ binary into a typed heap object graph: objects, sizes, allocator state, references, and probable struct layouts, all without debug info. - glibc ptmalloc carving (main + thread arenas, tcache/fastbin freed state, mmap allocations), ELF core + memory-list minidump parsing - pointer scan, layout clustering, vtable/string/vector detection, confidence + evidence on every node - ASCII/JSON/Graphviz/HTML output, synthetic fixtures with ground truth, and real-dump validation harness (aarch64 glibc 2.39) in scripts/ - web deployment reference stack in deploy/ MIT OR Apache-2.0 |
||
|---|---|---|
| crates | ||
| deploy | ||
| fixtures | ||
| scripts | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| deployment.md | ||
| README.md | ||
naksheap
Reconstruct the heap from a core dump. Point it at a crash dump of a stripped, optimized C++ binary and it recovers the live heap objects, their sizes and states, the pointers between them, and probable struct layouts, all without debug info and without a debugger.
Why
A stripped -O2 binary crashes. The stack is garbage, gdb has no symbols, and nobody can tell you what the heap held at the moment of death. That is usually where the evidence lives.
The tools you already have stop at the wrong layer. Volatility works on the operating system, pwndbg needs a live process, Valgrind needs to re-run the program, and ASan needs the source rebuilt. None of them read a dead core dump and answer the real question: which objects were alive, and who pointed at what.
naksheap reads the allocator metadata that is already in the dump. It walks glibc's chunk headers, decodes the tcache and fastbin free lists, finds large mmap-served allocations, discovers main and thread arenas, and builds a reference graph of everything it recovers. Every object gets a label with a confidence score and the evidence behind it, not a bare guess.
What it does
The pipeline is one command, end to end.
flowchart LR
A[core dump] --> B[find arenas and heap regions]
B --> C[carve objects: address, size, allocated or freed]
C --> D[scan for pointers between objects, registers, stack]
D --> E[group identical layouts, detect vtables, strings, vectors]
E --> F[object graph: ASCII, JSON, Graphviz, HTML report]
Quick start
cargo build --release
./target/release/naksheap self-test # smoke test on a synthetic fixture
./target/release/naksheap graph dump.core # analyze a real core dump
./target/release/naksheap graph dump.core --html --out report
Open report/report.html in a browser to browse the object graph. Or use --json for the machine-readable version.
Generate a demo fixture if you do not have a core handy:
cargo run -p naksheap-testkit --example gen_fixture -- /tmp/fixtures
./target/release/naksheap graph /tmp/fixtures/toy-server.core
CLI
| Command | What it prints |
|---|---|
info |
file format, process, pointer width, memory map |
maps |
the memory map, one range per line |
heap |
carved objects: address, size, state, arena |
graph |
the object graph. Default is an ASCII tree; add --json, --dot, or --html to export |
self-test |
run the whole pipeline on a synthetic fixture |
graph accepts --max-depth, and --out writes files into a directory instead of stdout. Piping to head is fine; a truncated core prints a warning instead of failing silently.
Output
The graph lists objects and their relationships. This is real output from a real crash core, with the source object noted:
0xf742c8000b70
└── likely std::vector [conf 0.80, n=2] [root]
├── +0x00 pointer begin -> 0xf742c8000c90
├── +0x08 pointer end -> 0xf742c8000ca8
├── +0x10 pointer capacity -> 0xf742c8000cb0
└── 0xf742c8000c90
└── opaque buffer [conf 0.45, n=1]
├── +0x00 pointer -> 0xf742c8000b90
└── 0xf742c8000b90
└── vtable object [conf 0.95, n=4]
├── +0x00 vtable -> 0xbab435e1fbb0 in test
Each node carries its label, a confidence between 0 and 1, and evidence lines in the JSON export. Reachability from the registers and stack is computed, so objects with no live references are listed separately as unreachable.
Supported inputs
| Input | Status |
|---|---|
| ELF core dumps, x86-64 | primary; validated on synthetic fixtures, real-core runs pending |
| ELF core dumps, aarch64 | works, validated against real cores |
| Windows minidumps | memory list only, 64-bit, no threads or registers |
| 32-bit, macOS cores, /proc/kcore, QEMU snapshots | not supported |
The allocator parser targets glibc ptmalloc on 64-bit. jemalloc and tcmalloc heaps are not parsed.
Validation
The pipeline is tested on two layers.
Synthetic fixtures with a ground-truth manifest cover the carve, scan, inference, and export stages, and regenerate byte-for-byte.
Real core dumps come from scripts/real-dump-test.sh. It runs real C++ programs in a Linux container, crashes them, and snapshots them with gcore. It then checks that every address the program printed appears in the recovered graph at the same address. The checked-in results are aarch64 Ubuntu 24.04 with glibc 2.39. That testing is what exposed the glibc quirks the tool handles: tcache and fastbin frees do not clear the chunk PREV_INUSE bit, so freed chunks are found by cross-referencing the free lists, and large mmap allocations are recovered from their own chunk headers.
Limitations
| Limitation | Detail |
|---|---|
| Inference is heuristic | Type labels are hypotheses with confidence and evidence, never certainty. Addresses, sizes, and allocator state are the reliable part. |
| Zombie memory | Freed chunks stay physically present until reused. They are flagged as freed, not silently dropped. |
| Large bin lists | Unsorted, small, and large bins are not walked yet. Fastbin and tcache free lists are. |
| No live debugging | This reads a static snapshot. It cannot groom a live heap or predict the next allocation. |
Privacy
Analysis is fully offline. The only network request in the whole stack is the optional cytoscape.js download in the HTML report, made by the browser, not by the tool. Dumps can contain credentials and keys, so the reference web deployment is self-hosted and documented in deployment.md.
License
MIT OR Apache-2.0