From 1517a63974d9e5385afb699375a0e44d5c734b5f Mon Sep 17 00:00:00 2001 From: MechaCat02 Date: Sun, 7 Jun 2026 11:12:18 +0200 Subject: [PATCH] [Audit] round 12: ExCreateThread + XThread::Execute probes Two cvar-gated AUDIT-HLC probes for thread-spawn lineage attribution: 1. ExCreateThread_entry shim logs (start_address, start_context, xapi, flags, kernel lr, guest_lr). guest_lr is recovered via the same one-frame-up PPC back-chain walk used by the NtWaitForSingleObjectEx probe (lr saved at [back2 - 8]). 2. XThread::Execute emits (tid, start_address, start_context, xapi) at the very top so each running thread can be matched back to its creating ExCreateThread entry by (start_address, start_context). Gated on the existing cvars::audit_handle_lifecycle; no new cvar. Pulled in xenia/kernel/kernel_flags.h from xthread.cc to expose the cvar declaration there. Used by audit-059 round 12 to enumerate the 23 thread spawns in canary's 35 s boot, attribute each to its guest_lr caller, and cross- reference against ours' 10 spawns to identify the 7 missing spawner functions (including sub_824F7800 which spawns the 4 silph PKEVENT workers at entry=0x82506528/58/88/B8 via guest_lr=0x824F7B24). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 24 +++++++++++++++++++ src/xenia/kernel/xthread.cc | 8 +++++++ 2 files changed, 32 insertions(+) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 3f99be340..c8b540dc5 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -197,6 +197,30 @@ dword_result_t ExCreateThread_entry(lpdword_t handle_ptr, dword_t stack_size, lpvoid_t start_address, lpvoid_t start_context, dword_t creation_flags) { + if (cvars::audit_handle_lifecycle) { + auto* ctx = cpu::ThreadState::Get()->context(); + uint32_t lr = static_cast(ctx->lr); + // Walk one PPC stack frame up from the shim's frame to recover the GUEST + // caller's LR (lr_enter is just the kernel-internal shim's return + // address; we want the function that called *it*). Same convention as + // the NtWaitForSingleObjectEx probe above. + uint32_t guest_lr = 0; + uint32_t sp = static_cast(ctx->r[1]); + uint32_t back1 = xe::load_and_swap(ctx->TranslateVirtual(sp)); + if (back1) { + uint32_t back2 = + xe::load_and_swap(ctx->TranslateVirtual(back1)); + if (back2) { + guest_lr = + xe::load_and_swap(ctx->TranslateVirtual(back2 - 8)); + } + } + XELOGKERNEL( + "AUDIT-HLC ExCreateThread entry={:08X} start_ctx={:08X} xapi={:08X} " + "flags={:08X} lr={:08X} guest_lr={:08X}", + uint32_t(start_address), uint32_t(start_context), + uint32_t(xapi_thread_startup), uint32_t(creation_flags), lr, guest_lr); + } return ExCreateThread(handle_ptr, stack_size, thread_id_ptr, xapi_thread_startup, start_address, start_context, creation_flags); diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index 33610bfb3..e2c4ecedc 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -21,6 +21,7 @@ #include "xenia/base/threading.h" #include "xenia/cpu/processor.h" #include "xenia/emulator.h" +#include "xenia/kernel/kernel_flags.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h" @@ -544,6 +545,13 @@ X_STATUS XThread::Terminate(int exit_code) { void XThread::Execute() { XELOGKERNEL("XThread::Execute thid {} (handle={:08X}, '{}', native={:08X})", thread_id_, handle(), thread_name_, thread_->system_id()); + if (cvars::audit_handle_lifecycle) { + XELOGKERNEL( + "AUDIT-HLC XThread::Execute tid={} start_address={:08X} " + "start_context={:08X} xapi={:08X}", + thread_id_, creation_params_.start_address, + creation_params_.start_context, creation_params_.xapi_thread_startup); + } // Let the kernel know we are starting. kernel_state()->OnThreadExecute(this);