[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) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-06 18:42:15 +02:00
parent 3c7aa73512
commit 35f58b147f

View File

@@ -8,6 +8,7 @@
*/
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
#include <atomic>
#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<bool> g_audit_silph_ctx_dumped{false};
// r13 + 0x100: pointer to thread local state
// Thread local state:
// 0x058: kernel time
@@ -587,6 +591,43 @@ dword_result_t KeSetEvent_entry(pointer_t<X_KEVENT> event_ptr,
uint32_t lr = static_cast<uint32_t>(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<uint32_t>(host + off + 0);
uint32_t d1 = xe::load_and_swap<uint32_t>(host + off + 4);
uint32_t d2 = xe::load_and_swap<uint32_t>(host + off + 8);
uint32_t d3 = xe::load_and_swap<uint32_t>(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<uint32_t>(host + ev_off + 0);
uint32_t state = xe::load_and_swap<uint32_t>(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);
}