[Audit] JIT-prolog: optional audit_jit_prolog_mem_dump chain (3 levels)
Round-14 of AUDIT-2BF (singleton-dump). Pairs with xenia-rs' --audit-mem-read-hex to emit one comparable XELOGKERNEL line resolving the bctrl target at sub_822F1AA8+0x90 (PC 0x822F1B4C): [0x828E1F08] -> singleton instance ptr [singleton+0] -> vtable [vtable+0] -> vtable[0] (= first virtual method, bctrl tgt) [vtable+24] -> vtable[24] (= slot 6, silph chain target) Two complementary hooks: 1. src/xenia/cpu/backend/x64/x64_emitter.cc: extend AuditLogJitPrologArgs. New cvar `audit_jit_prolog_mem_dump` (uint32). When non-zero and an `audit_jit_prolog_pc` fire happens, the host side dereferences the VA 3 levels deep and emits one AUDIT-MEM-READ line in the same format ours emits. Defensive per-level null + VA-range checks. 2. src/xenia/kernel/kernel_state.cc: one-shot dump in EmulateCPInterruptDPC of the same chain (hard-coded to 0x828E1F08). Useful when audit_jit_prolog_pc isn't set; fires the first time the CP interrupt path runs (after the singleton ctor has had time to populate). Read-only. Both gates default-off; no impact when cvars unset. ~65 LOC total across the two files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,15 @@ DEFINE_uint32(audit_jit_prolog_pc, 0,
|
||||
"bytes at host(r3). Zero (default) disables the probe. Audit-059 "
|
||||
"round 7+ JIT-prolog probe — generic PC-configurable variant.",
|
||||
"Auditing");
|
||||
DEFINE_uint32(audit_jit_prolog_mem_dump, 0,
|
||||
"Audit-059 round 14 — paired memory-dump VA. When non-zero "
|
||||
"AND audit_jit_prolog_pc fires, dereference the guest VA 3 "
|
||||
"levels deep and emit one XELOGKERNEL line: addr -> val "
|
||||
"(singleton instance), val -> vtable, vtable -> vtable[0] / "
|
||||
"vtable[24]. Reads the singleton at [0x828E1F08], its vtable, "
|
||||
"and its vtable[0] (first virtual method = bctrl target at "
|
||||
"sub_822F1AA8+0x90). Zero (default) disables.",
|
||||
"Auditing");
|
||||
DEFINE_bool(ignore_undefined_externs, true,
|
||||
"Don't exit when an undefined extern is called.", "CPU");
|
||||
DEFINE_bool(emit_source_annotations, false,
|
||||
@@ -503,6 +512,28 @@ uint64_t AuditLogJitPrologArgs(void* raw_context, uint64_t /*unused*/) {
|
||||
XELOGKERNEL("AUDIT-HLC JitProlog pc={:08X} r3 out of VA range, skipping dump",
|
||||
pc);
|
||||
}
|
||||
|
||||
// Audit-059 round 14 — paired 3-level dereference. When
|
||||
// `audit_jit_prolog_mem_dump` is set, read the singleton at that VA,
|
||||
// its vtable, vtable[0] (first virtual method = bctrl target), and
|
||||
// vtable[24] (slot 6 = silph chain method per round 9).
|
||||
uint32_t mem_addr = static_cast<uint32_t>(cvars::audit_jit_prolog_mem_dump);
|
||||
if (mem_addr != 0u && mem_addr >= 0x10000 && mem_addr < 0xE0000000) {
|
||||
auto load_be32 = [&](uint32_t va) -> uint32_t {
|
||||
if (va < 0x10000 || va >= 0xE0000000) return 0u;
|
||||
uint8_t* h = ctx->TranslateVirtual(va);
|
||||
if (!h) return 0u;
|
||||
return xe::load_and_swap<uint32_t>(h);
|
||||
};
|
||||
uint32_t val = load_be32(mem_addr);
|
||||
uint32_t vtable = val != 0u ? load_be32(val) : 0u;
|
||||
uint32_t m0 = vtable != 0u ? load_be32(vtable) : 0u;
|
||||
uint32_t m6 = vtable != 0u ? load_be32(vtable + 24u) : 0u;
|
||||
XELOGKERNEL(
|
||||
"AUDIT-MEM-READ addr={:08X} val={:08X} vtable={:08X} vtable[0]={:08X} "
|
||||
"vtable[24]={:08X} pc={:08X} tid={:08X}",
|
||||
mem_addr, val, vtable, m0, m6, pc, tid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user