From 289c2f3a3efa5f76b2fcba65a1329cf88af30c33 Mon Sep 17 00:00:00 2001 From: MechaCat02 Date: Sat, 6 Jun 2026 18:42:15 +0200 Subject: [PATCH] [Audit] handle-lifecycle: one-shot silph::WorkerCtx hexdump on first KeSetEvent Adds a 41-LOC cvar-gated probe (audit_handle_lifecycle) that emits a one-shot 0x300-byte hexdump of the silph::WorkerCtx context the first time KeSetEvent fires into the silph UI PKEVENT cluster (0xBCE25200..0xBCE25300 in current builds). Recovers ctx_base by anchoring on the canonical layout (events at ctx+0x54/+0x64/+0x74/+0x84 with 16-byte stride; ctx_base = ev_addr - (ev_addr - 0xBCE251C0)). Also emits an explicit per-slot summary of the 8 candidate KEVENT headers at +0x54..+0xC4 for sanity. Produces 48 DUMP rows + 8 slot rows in canary.log on the first triggering KeSetEvent. Guarded by std::atomic_bool so subsequent fires are silent. Used by iterate 2.BF context-replication in ours: we need the live [ctx+0] vtable pointer and the 4 quiet/4 active KEVENT slot config to synthesize a matching WorkerCtx and spawn the four sub_82506xxx entries. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 93a07272a..460978fe2 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -8,6 +8,7 @@ */ #include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h" +#include #include "xenia/base/atomic.h" #include "xenia/base/clock.h" #include "xenia/base/platform.h" @@ -23,6 +24,9 @@ namespace xe { namespace kernel { namespace xboxkrnl { +// AUDIT-HLC: one-shot guard for silph::WorkerCtx context dump (round5). +static std::atomic g_audit_silph_ctx_dumped{false}; + // r13 + 0x100: pointer to thread local state // Thread local state: // 0x058: kernel time @@ -552,6 +556,43 @@ dword_result_t KeSetEvent_entry(pointer_t event_ptr, uint32_t lr = static_cast(cpu::ThreadState::Get()->context()->lr); XELOGKERNEL("AUDIT-HLC KeSetEvent guest_ptr={:08X} lr={:08X}", uint32_t(event_ptr.guest_address()), lr); + // AUDIT-HLC round5: one-shot hexdump of the silph::WorkerCtx context when + // KeSetEvent first fires into the silph UI PKEVENT cluster + // (0xBCE25214/24/34/44 in current builds; widened a bit for allocator + // drift). Used by iterate 2.BF context-replication. + uint32_t ev_addr = uint32_t(event_ptr.guest_address()); + if (ev_addr >= 0xBCE25200 && ev_addr < 0xBCE25300) { + if (!g_audit_silph_ctx_dumped.exchange(true)) { + // Events live at ctx+0x54, +0x64, +0x74, +0x84 (16-byte stride). + // Compute ctx_base assuming the canonical layout (lowest event at + // ctx+0x54 → ctx_base = 0xBCE251C0 when ev_addr == 0xBCE25214). + uint32_t event_offset_in_ctx = ev_addr - 0xBCE251C0; + uint32_t ctx_base = ev_addr - event_offset_in_ctx; + auto* ctx = cpu::ThreadState::Get()->context(); + uint8_t* host = ctx->TranslateVirtual(ctx_base); + XELOGKERNEL( + "AUDIT-HLC silph_ctx_dump ctx_base={:08X} (event {:08X} at +{:02X})", + ctx_base, ev_addr, event_offset_in_ctx); + for (uint32_t off = 0; off < 0x300; off += 16) { + uint32_t d0 = xe::load_and_swap(host + off + 0); + uint32_t d1 = xe::load_and_swap(host + off + 4); + uint32_t d2 = xe::load_and_swap(host + off + 8); + uint32_t d3 = xe::load_and_swap(host + off + 12); + XELOGKERNEL("AUDIT-HLC DUMP {:08X}: {:08X} {:08X} {:08X} {:08X}", + ctx_base + off, d0, d1, d2, d3); + } + XELOGKERNEL("AUDIT-HLC silph_ctx event-slots:"); + for (uint32_t i = 0; i < 8; ++i) { + uint32_t ev_off = 0x54 + i * 0x10; + uint32_t hdr = xe::load_and_swap(host + ev_off + 0); + uint32_t state = xe::load_and_swap(host + ev_off + 4); + XELOGKERNEL( + "AUDIT-HLC slot[{}] off=+{:02X} addr={:08X} hdr={:08X} " + "state={:08X}", + i, ev_off, ctx_base + ev_off, hdr, state); + } + } + } } return xeKeSetEvent(event_ptr, increment, wait); }