From bcd9663349f1e2404976188d9997878ea036bc93 Mon Sep 17 00:00:00 2001 From: luci4 <142809264+l00sy4@users.noreply.github.com> Date: Mon, 13 Apr 2026 13:47:44 +0100 Subject: [PATCH] Thread.cpp: Added stack trace and register logging to exception filter (#18564) --- Utilities/Thread.cpp | 33 ++++++++++++++++++++++++++++++- Utilities/stack_trace.cpp | 41 ++++++++++++++++++++++++++++----------- Utilities/stack_trace.h | 10 ++++++++++ rpcs3/Emu/CMakeLists.txt | 2 +- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index b22c1aeb52..4ec70b58bb 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -25,6 +25,7 @@ #include #include +#include "stack_trace.h" #include "util/dyn_lib.hpp" DYNAMIC_IMPORT_RENAME("Kernel32.dll", SetThreadDescriptionImport, "SetThreadDescription", HRESULT(HANDLE hThread, PCWSTR lpThreadDescription)); @@ -1981,9 +1982,39 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept } fmt::append(msg, "RPCS3 image base: %p.\n", GetModuleHandle(NULL)); + +#if defined(ARCH_X64) + fmt::append(msg, "RAX: %016llX RBX: %016llX\n", pExp->ContextRecord->Rax, pExp->ContextRecord->Rbx); + fmt::append(msg, "RCX: %016llX RDX: %016llX\n", pExp->ContextRecord->Rcx, pExp->ContextRecord->Rdx); + fmt::append(msg, "RSI: %016llX RDI: %016llX\n", pExp->ContextRecord->Rsi, pExp->ContextRecord->Rdi); + fmt::append(msg, "RBP: %016llX RSP: %016llX\n", pExp->ContextRecord->Rbp, pExp->ContextRecord->Rsp); + fmt::append(msg, "R8: %016llX R9: %016llX\n", pExp->ContextRecord->R8, pExp->ContextRecord->R9); + fmt::append(msg, "R10: %016llX R11: %016llX\n", pExp->ContextRecord->R10, pExp->ContextRecord->R11); + fmt::append(msg, "R12: %016llX R13: %016llX\n", pExp->ContextRecord->R12, pExp->ContextRecord->R13); + fmt::append(msg, "R14: %016llX R15: %016llX\n", pExp->ContextRecord->R14, pExp->ContextRecord->R15); + fmt::append(msg, "RFLAGS: %08X\n", pExp->ContextRecord->EFlags); +#elif defined(ARCH_ARM64) + for (int i = 0; i < 29; i += 2) + { + if (i + 1 < 29) + fmt::append(msg, "X%-2d: %016llX X%-2d: %016llX\n", i, pExp->ContextRecord->X[i], i + 1, pExp->ContextRecord->X[i + 1]); + else + fmt::append(msg, "X%-2d: %016llX\n", i, pExp->ContextRecord->X[i]); + } + fmt::append(msg, "SP: %016llX FP: %016llX LR: %016llX\n", pExp->ContextRecord->Sp, pExp->ContextRecord->Fp, pExp->ContextRecord->Lr); + fmt::append(msg, "CPSR: %08X\n", pExp->ContextRecord->Cpsr); +#endif - // TODO: print registers and the callstack + const auto stack_trace = utils::get_backtrace(64, pExp->ContextRecord); + const auto stack_symbols = utils::get_backtrace_symbols(stack_trace); + msg += "Stack Trace:\n"; + + for (const auto& symbol : stack_symbols) + { + fmt::append(msg, "%s\n", symbol); + } + sys_log.fatal("\n%s", msg); logs::listener::sync_all(); diff --git a/Utilities/stack_trace.cpp b/Utilities/stack_trace.cpp index f44751fcda..049e0f1805 100644 --- a/Utilities/stack_trace.cpp +++ b/Utilities/stack_trace.cpp @@ -30,42 +30,61 @@ namespace utils return out.data(); } - std::vector get_backtrace(int max_depth) + std::vector get_backtrace(int max_depth, PCONTEXT ctx) { + static struct sym_initer_t + { + sym_initer_t() noexcept + { + SymInitialize(GetCurrentProcess(), NULL, TRUE); + } + ~sym_initer_t() noexcept + { + SymCleanup(GetCurrentProcess()); + } + } s_initer{}; + std::vector result = {}; const auto hProcess = ::GetCurrentProcess(); const auto hThread = ::GetCurrentThread(); CONTEXT context{}; - RtlCaptureContext(&context); + if (ctx) + context = *ctx; + else + RtlCaptureContext(&context); STACKFRAME64 stack = {}; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Mode = AddrModeFlat; #if defined(ARCH_X64) + const DWORD machineType = IMAGE_FILE_MACHINE_AMD64; stack.AddrPC.Offset = context.Rip; stack.AddrStack.Offset = context.Rsp; stack.AddrFrame.Offset = context.Rbp; #elif defined(ARCH_ARM64) + const DWORD machineType = IMAGE_FILE_MACHINE_ARM64; stack.AddrPC.Offset = context.Pc; stack.AddrStack.Offset = context.Sp; stack.AddrFrame.Offset = context.Fp; +#else +#error "Unsupported architecture" #endif while (max_depth--) { if (!StackWalk64( - IMAGE_FILE_MACHINE_AMD64, - hProcess, - hThread, - &stack, - &context, - NULL, - SymFunctionTableAccess64, - SymGetModuleBase64, - NULL)) + machineType, + hProcess, + hThread, + &stack, + &context, + NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, + NULL)) { break; } diff --git a/Utilities/stack_trace.h b/Utilities/stack_trace.h index f57175611f..d0cec0cf4c 100644 --- a/Utilities/stack_trace.h +++ b/Utilities/stack_trace.h @@ -2,6 +2,11 @@ #include #include +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + namespace utils { namespace stack_trace @@ -30,7 +35,12 @@ namespace utils }; } +#ifdef _WIN32 + std::vector get_backtrace(int max_depth = 255, PCONTEXT ctx = nullptr); +#else std::vector get_backtrace(int max_depth = 255); +#endif + std::vector get_backtrace_symbols(const std::vector& stack); FORCE_INLINE void print_trace(stack_trace::Logger auto& logger, int max_depth = 255) diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index c20b72f694..8591399ce8 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -161,7 +161,7 @@ if(WIN32) Audio/XAudio2/xaudio2_enumerator.cpp ) target_compile_definitions(rpcs3_emu PRIVATE UNICODE _UNICODE _WIN32_WINNT=0x0A00) - target_link_libraries(rpcs3_emu PRIVATE pdh bcrypt) + target_link_libraries(rpcs3_emu PRIVATE pdh bcrypt dbghelp) endif() # Cell