add --dump-section=BASE:LEN:PATH for end-of-run guest memory snapshot

Drives byte-level memory diffs against canary's Memory::Save dump.
Hot-path zero-cost when absent; lockstep digest unaffected
(instructions=100000003 deterministic across reruns).
This commit is contained in:
MechaCat02
2026-05-07 21:40:45 +02:00
parent de5a15ecfb
commit 08d41cf2fc
2 changed files with 88 additions and 0 deletions

View File

@@ -237,6 +237,11 @@ pub struct KernelState {
/// dump is performed by `dump_thread_diagnostic`, never during
/// the hot interpreter loop, so lockstep determinism is unaffected.
pub dump_addrs: Vec<u32>,
/// Diagnostic. Optional contiguous memory range to dump verbatim to a
/// file at end-of-run: `(base, length, path)`. Populated from
/// `--dump-section=BASE:LEN:PATH`. Bulk read via `GuestMemory::read_bulk`;
/// host pages that were never committed read as zero (mmap-reserved).
pub dump_section: Option<(u32, u32, std::path::PathBuf)>,
}
impl KernelState {
@@ -296,6 +301,7 @@ impl KernelState {
pc_probe_consumers: HashMap::new(),
branch_probe_pcs: std::collections::HashSet::new(),
dump_addrs: Vec::new(),
dump_section: None,
};
crate::exports::register_exports(&mut state);
crate::xam::register_exports(&mut state);
@@ -1412,6 +1418,23 @@ mod tests {
assert!(state.ctor_probe_pcs.contains(&0x8217_C850));
}
#[test]
fn dump_section_field_round_trip_via_read_bulk() {
use xenia_memory::page_table::MemoryProtect;
let mem = GuestMemory::new().expect("memory init");
mem.alloc(0x4000_0000, 0x1000, MemoryProtect::READ | MemoryProtect::WRITE)
.expect("page");
let probe = [0xDEu8, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78];
mem.write_bulk(0x4000_0040, &probe);
let mut state = KernelState::new();
let tmp = std::env::temp_dir().join("xenia_dump_section_round_trip.bin");
state.dump_section = Some((0x4000_0040, 8, tmp.clone()));
let (base, len, ref _path) = state.dump_section.as_ref().expect("set").clone();
let mut out = vec![0u8; len as usize];
mem.read_bulk(base, &mut out);
assert_eq!(out, probe);
}
#[test]
fn read_ascii_cstring_handles_termination_and_garbage() {
use xenia_memory::page_table::MemoryProtect;