Memory Slice (.msl) support: io/bin/debug plugins + dgm + reverse-exec#26128
Memory Slice (.msl) support: io/bin/debug plugins + dgm + reverse-exec#26128ricardojrdez wants to merge 4 commits into
Conversation
Support opening, mapping and emulating Memory Slice process dumps produced by memslicer (https://github.com/MemorySlice/memslicer): - io.msl: exposes the captured virtual address space (msl://), honoring the three-state page map; decodes lz4-compressed regions in memory (zstd is not decodable by radare2 and warns clearly). Acts as a debug IO so a slice can be opened in debug mode without spawning a process. - bin.msl: parses a slice as a CORE object (arch/bits/OS, entry0 = captured PC, one section/map per contiguous run of captured pages). - debug.msl: emulated debug backend. On attach it sets the arch from the slice header, initializes ESIL, seeds the full register file from the Current thread's Thread Context (0x0011), and clears cfg.debug so ds/dso/dc/dr/dm dispatch to ESIL. Step with ds/dso, run to a breakpoint with dc. Usage: `r2 dump.msl` (analysis) or `r2 -D msl -d msl://dump.msl` (emulated debugging). See doc/msl.md. MVP scope: uncompressed or lz4, unencrypted slices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
"ds" already dispatches to the ESIL stepper (aes) when cfg.debug is false, but "dc" always went through r_debug_continue (arena swap + trace + recoil), which assumes a live ptrace process and corrupts state on an emulated target such as a Memory Slice or the esil backend. Mirror the ds behaviour: when cfg.debug is unset, continue via aec. Stops at a breakpoint, an invalid instruction or a memory fault. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a producer for the Memory Slice format: while debugging, `dgm [file]` serializes the current session — file header, Process Identity, a Thread Context with the current registers, and one Memory Region per debug map with a three-state page map — into an .msl readable by the io/bin/debug "msl" plugins and by memslicer. The integrity chain uses SHA-256 (HashAlgo 0x01) since radare2 has no BLAKE3. Maps are read in 1 MiB chunks (not page-by-page); unreadable maps are skipped and, unless `dgma` is used, maps larger than 512 MiB (e.g. the macOS dyld shared cache) are skipped so the dump stays fast and small. Also implement map_get for the msl debug backend so the captured regions show up as debug maps (and so dgm can read them when re-dumping an emulated slice). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Enable ESIL step-back recording in the msl debug backend (esil.maxbacksteps, applied after aei) so `dsb` / `aesb` step execution backwards through an emulated slice, reverting both the program counter and register/memory state. Time-travel debugging of a static snapshot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
i think that adds too much complexity for such an niche feature and i think it will be better to ship it in radare2-extras or as an external repository until lthe code is mature enough to consider it to ship it directly in core. Can you please make this pr against the radare2-extras repo instead? we can have an r2pm pkg later to install all those plugins in 1 command. if you want to ship that in an r2 build we can add a 'r2plugin' directory to expose the plugin for make and meson. but for now i think its better to maintain this project outside the core and maybe update the readme referencing the plugin for visibility reasons. |
|
i can do this moving into radare2-extras for you if you want |
|
Thanks @trufae, makes sense; done. I moved the whole thing into radare2-extras as a self-contained msl/ bundle (io/bin/debug plugins + a core plugin for the dgm/dgma producer), buildable standalone via pkg-config and r2pm-friendly: The only piece I kept for core is a generic one unrelated to the format: routing dc to ESIL when cfg.debug is unset, so it works on any emulated backend (mirrors how ds already dispatches to aes). Sent as its own small PR, see #26144 I'll close this one in favor of those. Happy to add an r2pm recipe and reference it from the README whenever you think it's ready :). Thanks for the pointer! |
Summary
Adds support for Memory Slice (
.msl) process memory dumps — the formatproduced by memslicer — so a static
snapshot can be analyzed and emulated/stepped in radare2, plus a producer to
write a slice from a live debug session. Three commits (plugins, a small core
fix, the dump command).
Commits
io,bin,debug: add Memory Slice (.msl) plugins.
io.msl— exposes the captured virtual address space (msl://), honoringthe three-state page map; decodes lz4 regions in memory (zstd isn't
decodable by r2 — warns clearly). Doubles as a debug IO so a slice can be
opened in debug mode without spawning a process.
bin.msl— parses a slice as CORE (arch/bits/OS,entry0= captured PC,one section/map per contiguous run of captured pages).
debug.msl— emulated backend: sets arch from the header, seeds the fullregister file from the Thread Context, and routes
ds/dso/dc/dr/dmto ESIL.
r2 dump.msl(analysis) orr2 -D msl -d msl://dump.msl(debug).See
doc/msl.md.core/debug: route
dcto ESIL whencfg.debugis unset.dsalready dispatches toaesfor emulated targets;dcalways wentthrough
r_debug_continue(arena swap + trace + recoil), which assumes alive ptrace process and corrupts state on an emulated target (msl / esil).
Mirror the
dsbehaviour: continue viaaec. General fix, also helps thestock
esilbackend.debug:
dgmwrites a Memory Slice of the debuggee.Producer side:
dgm [file]serializes the live session (header, ProcessIdentity, Thread Context with the current registers, one Memory Region per
map). Reads maps in 1 MiB chunks, skips unreadable maps, and by default skips
very large maps (e.g. the macOS dyld shared cache) —
dgmafor everything.Integrity chain uses SHA-256 (HashAlgo 0x01) since r2 has no BLAKE3.
debug: reverse execution (
dsb/aesb).Enable ESIL step-back recording so execution can be stepped backwards
through an emulated slice, reverting PC and register/memory state
(time-travel debugging of a static snapshot).
Notes