diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 495ebca24..93a07272a 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -549,8 +549,9 @@ uint32_t xeKeSetEvent(X_KEVENT* event_ptr, uint32_t increment, uint32_t wait) { dword_result_t KeSetEvent_entry(pointer_t event_ptr, dword_t increment, dword_t wait) { if (cvars::audit_handle_lifecycle) { - XELOGKERNEL("AUDIT-HLC KeSetEvent guest_ptr={:08X}", - uint32_t(event_ptr.guest_address())); + 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); } return xeKeSetEvent(event_ptr, increment, wait); } @@ -610,9 +611,12 @@ dword_result_t NtCreateEvent_entry( *handle_ptr = ev->handle(); } if (cvars::audit_handle_lifecycle) { - XELOGKERNEL("AUDIT-HLC NtCreateEvent handle={:08X} type={} initial_state={}", - handle_ptr ? uint32_t(*handle_ptr) : 0u, - uint32_t(event_type), uint32_t(initial_state)); + uint32_t lr = static_cast(cpu::ThreadState::Get()->context()->lr); + XELOGKERNEL( + "AUDIT-HLC NtCreateEvent handle={:08X} type={} initial_state={} " + "lr={:08X}", + handle_ptr ? uint32_t(*handle_ptr) : 0u, uint32_t(event_type), + uint32_t(initial_state), lr); } return X_STATUS_SUCCESS; } @@ -640,7 +644,9 @@ uint32_t xeNtSetEvent(uint32_t handle, xe::be* previous_state_ptr) { dword_result_t NtSetEvent_entry(dword_t handle, lpdword_t previous_state_ptr) { if (cvars::audit_handle_lifecycle) { - XELOGKERNEL("AUDIT-HLC NtSetEvent handle={:08X}", uint32_t(handle)); + uint32_t lr = static_cast(cpu::ThreadState::Get()->context()->lr); + XELOGKERNEL("AUDIT-HLC NtSetEvent handle={:08X} lr={:08X}", + uint32_t(handle), lr); } return xeNtSetEvent(handle, previous_state_ptr); } @@ -1016,17 +1022,41 @@ dword_result_t NtWaitForSingleObjectEx_entry(dword_t object_handle, dword_t wait_mode, dword_t alertable, lpqword_t timeout_ptr) { + uint32_t lr_enter = 0; + uint32_t guest_lr = 0; if (cvars::audit_handle_lifecycle) { - XELOGKERNEL("AUDIT-HLC NtWaitForSingleObjectEx handle={:08X} alertable={}", - uint32_t(object_handle), uint32_t(alertable)); + auto* ctx = cpu::ThreadState::Get()->context(); + lr_enter = static_cast(ctx->lr); + // Walk one PPC stack frame up from the wait wrapper's frame to recover + // the GUEST caller's LR (lr_enter is just the kernel-internal wait + // wrapper's return address; we want the function that called *it*). + // Xbox 360 PPC convention: prologue stores caller's LR at [old_sp - 8] + // *before* bumping r1 to the new frame, so from any frame, the LR saved + // by that frame's prologue lives at (back_chain - 8). See xenia-rs + // walk_guest_back_chain in crates/xenia-kernel/src/state.rs. + 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 NtWaitForSingleObjectEx handle={:08X} alertable={} " + "lr={:08X} guest_lr={:08X}", + uint32_t(object_handle), uint32_t(alertable), lr_enter, guest_lr); } uint64_t timeout = timeout_ptr ? static_cast(*timeout_ptr) : 0u; uint32_t result = NtWaitForSingleObjectEx(object_handle, wait_mode, alertable, timeout_ptr ? &timeout : nullptr); if (cvars::audit_handle_lifecycle) { XELOGKERNEL( - "AUDIT-HLC NtWaitForSingleObjectEx_done handle={:08X} result={:08X}", - uint32_t(object_handle), result); + "AUDIT-HLC NtWaitForSingleObjectEx_done handle={:08X} result={:08X} " + "lr={:08X} guest_lr={:08X}", + uint32_t(object_handle), result, lr_enter, guest_lr); } return result; }