From b85ac715ebf1c14760a873d9396a0bf157d9ebe0 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Thu, 8 Sep 2022 19:05:09 -0400 Subject: [PATCH] Backport crash handler (#1401) * backport crash handler * backport crash handler * Fix windows. --- libultraship/libultraship/CrashHandler.cpp | 352 ++++++++++++++++++ libultraship/libultraship/CrashHandler.h | 44 +++ .../libultraship/libultraship.vcxproj | 2 + .../libultraship/libultraship.vcxproj.filters | 9 + soh/src/code/main.c | 8 + 5 files changed, 415 insertions(+) create mode 100644 libultraship/libultraship/CrashHandler.cpp create mode 100644 libultraship/libultraship/CrashHandler.h diff --git a/libultraship/libultraship/CrashHandler.cpp b/libultraship/libultraship/CrashHandler.cpp new file mode 100644 index 000000000..a01a82e67 --- /dev/null +++ b/libultraship/libultraship/CrashHandler.cpp @@ -0,0 +1,352 @@ +#include "spdlog/spdlog.h" +#include "Utils/StringHelper.h" +#include "CrashHandler.h" +#include "Window.h" + +#if defined(__linux__) +#include +#include +#include // for __cxa_demangle +#include // for dladdr +#include +#include + + + +static void PrintRegisters(ucontext_t* ctx) { + char regbuffer[1024]; + SPDLOG_CRITICAL("Registers:"); +#if defined(__x86_64__) + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RAX]); + SPDLOG_CRITICAL("RAX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDI]); + SPDLOG_CRITICAL("RDI: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSI]); + SPDLOG_CRITICAL("RSI: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RDX]); + SPDLOG_CRITICAL("RDX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RCX]); + SPDLOG_CRITICAL("RCX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R8]); + SPDLOG_CRITICAL("R8 : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R9]); + SPDLOG_CRITICAL("R9 : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R10]); + SPDLOG_CRITICAL("R10: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R11]); + SPDLOG_CRITICAL("R11: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RSP]); + SPDLOG_CRITICAL("RSP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBX]); + SPDLOG_CRITICAL("RBX: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RBP]); + SPDLOG_CRITICAL("RBP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R12]); + SPDLOG_CRITICAL("R12: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R13]); + SPDLOG_CRITICAL("R13: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R14]); + SPDLOG_CRITICAL("R14: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_R15]); + SPDLOG_CRITICAL("R15: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_RIP]); + SPDLOG_CRITICAL("RIP: {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer), "0x%016llX", ctx->uc_mcontext.gregs[REG_EFL]); + SPDLOG_CRITICAL("EFLAGS: {} ", regbuffer); +#else + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDI]); + SPDLOG_CRITICAL("EDI : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESI]); + SPDLOG_CRITICAL("ESI : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBP]); + SPDLOG_CRITICAL("EBP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ESP]); + SPDLOG_CRITICAL("ESP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EBX]); + SPDLOG_CRITICAL("EBX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EDX]); + SPDLOG_CRITICAL("EDX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_ECX]); + SPDLOG_CRITICAL("ECX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EAX]); + SPDLOG_CRITICAL("EAX : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EIP]); + SPDLOG_CRITICAL("EIP : {} ", regbuffer); + snprintf(regbuffer, std::size(regbuffer),"0x%08lX", ctx->uc_mcontext.gregs[REG_EFL]); + SPDLOG_CRITICAL("EFL : {} ", regbuffer); +#endif +} + +static void ErrorHandler(int sig, siginfo_t* sigInfo, void* data) { + std::array arr; + ucontext_t* ctx = static_cast(data); + constexpr size_t nMaxFrames = arr.size(); + size_t size = backtrace(arr.data(), nMaxFrames); + char** symbols = backtrace_symbols(arr.data(), nMaxFrames); + + SPDLOG_CRITICAL("(Signal: {})", sig); + + switch (sig) { + case SIGILL: + SPDLOG_CRITICAL("ILLEGAL INSTRUCTION"); + break; + case SIGABRT: + SPDLOG_CRITICAL("ABORT"); + break; + case SIGFPE: + SPDLOG_CRITICAL("ERRONEUS ARITHEMETIC OPERATION"); + break; + case SIGSEGV: + SPDLOG_CRITICAL("INVALID ACCESS TO STORAGE"); + break; + } + + PrintRegisters(ctx); + + SPDLOG_CRITICAL("Traceback:"); + for (size_t i = 1; i < size; i++) { + Dl_info info; + int gotAddress = dladdr(arr[i], &info); + std::string functionName(symbols[i]); + + if (gotAddress != 0 && info.dli_sname != nullptr) { + FILE* pipe; + int32_t status; + char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); + const char* nameFound = info.dli_sname; + + if (status == 0) { + nameFound = demangled; + } + #if 0 + char command[256]; + char addrLine[128]; + snprintf(command, sizeof(command), "addr2line -e soh.elf %s + 0x%lX", nameFound, (uintptr_t)arr[i] - (uintptr_t)info.dli_saddr); + pipe = popen(command, "r"); + fgets(addrLine, 128, pipe); + #endif + + functionName = StringHelper::Sprintf("%s (+0x%X)", nameFound, + (char*)arr[i] - (char*)info.dli_saddr); + free(demangled); + } + + SPDLOG_CRITICAL("{} {}", i, functionName.c_str()); + } + + free(symbols); + //DeinitOTR(); + exit(1); +} + +static void ShutdownHandler(int sig, siginfo_t* sigInfo, void* data) { + //DeinitOTR(); + exit(1); +} + +extern "C" void SetupHandlerLinux() { + struct sigaction action; + struct sigaction shutdownAction; + + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = ErrorHandler; + + sigaction(SIGILL, &action, nullptr); + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); + + shutdownAction.sa_flags = SA_SIGINFO; + shutdownAction.sa_sigaction = ShutdownHandler; + sigaction(SIGINT, &shutdownAction, nullptr); + sigaction(SIGTERM, &shutdownAction, nullptr); + sigaction(SIGQUIT, &shutdownAction, nullptr); + sigaction(SIGKILL, &shutdownAction, nullptr); +} +#elif _WIN32 + +#if defined(_WIN32) && !defined(_WIN64) +#define WINDOWS_32_BIT +#endif + +static void PrintRegisters(CONTEXT* ctx) { + SPDLOG_CRITICAL("Register dump"); + char regBuff[50]; +#if defined(_M_AMD64) + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rax); + SPDLOG_CRITICAL("RAX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rcx); + SPDLOG_CRITICAL("RCX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rdx); + SPDLOG_CRITICAL("RDX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rbx); + SPDLOG_CRITICAL("RBX: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rsp); + SPDLOG_CRITICAL("RSP: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rbp); + SPDLOG_CRITICAL("RBP: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rsi); + SPDLOG_CRITICAL("RSI: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rdi); + SPDLOG_CRITICAL("RDI: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R9); + SPDLOG_CRITICAL("R9: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R10); + SPDLOG_CRITICAL("R10: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R11); + SPDLOG_CRITICAL("R11: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R12); + SPDLOG_CRITICAL("R12: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R13); + SPDLOG_CRITICAL("R13: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R14); + SPDLOG_CRITICAL("R14: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->R15); + SPDLOG_CRITICAL("R15: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%016llX", ctx->Rip); + SPDLOG_CRITICAL("RIP: {}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->EFlags); + SPDLOG_CRITICAL("EFLAGS: {}", regBuff); +#elif WINDOWS_32_BIT + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Edi); + SPDLOG_CRITICAL("EDI: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Esi); + SPDLOG_CRITICAL("ESI: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Ebx); + SPDLOG_CRITICAL("EBX: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Ecx); + SPDLOG_CRITICAL("ECX: 0x{}", ctx->Ecx); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Eax); + SPDLOG_CRITICAL("EAX: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Ebp); + SPDLOG_CRITICAL("EBP: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Esp); + SPDLOG_CRITICAL("ESP: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->EFlags); + SPDLOG_CRITICAL("EFLAGS: 0x{}", regBuff); + + snprintf(regBuff, std::size(regBuff), "0x%08lX", ctx->Eip); + SPDLOG_CRITICAL("EIP: 0x{}", regBuff); +#endif +} + +static void printStack(CONTEXT* ctx) { + BOOL result; + HANDLE process; + HANDLE thread; + HMODULE hModule; + ULONG frame; + DWORD64 displacement; + DWORD disp; + +#if defined(_M_AMD64) + STACKFRAME64 stack; + memset(&stack, 0, sizeof(STACKFRAME64)); +#elif WINDOWS_32_BIT + STACKFRAME stack; + memset(&stack, 0, sizeof(STACKFRAME)); + stack.AddrPC.Offset = (*ctx).Eip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrStack.Offset = (*ctx).Esp; + stack.AddrStack.Mode = AddrModeFlat; + stack.AddrFrame.Offset = (*ctx).Ebp; + stack.AddrFrame.Mode = AddrModeFlat; +#endif + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME + sizeof(TCHAR)]; + char module[512]; + + PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; + + CONTEXT ctx2; + memcpy(&ctx2, ctx, sizeof(CONTEXT)); + + PrintRegisters(&ctx2); + + process = GetCurrentProcess(); + thread = GetCurrentThread(); + SymInitialize(process, nullptr, true); + + + constexpr DWORD machineType = +#if defined(_M_AMD64) + IMAGE_FILE_MACHINE_AMD64; +#elif WINDOWS_32_BIT + IMAGE_FILE_MACHINE_I386; +#endif + + displacement = 0; + for (frame = 0;; frame++) { + result = StackWalk(machineType, process, thread, &stack, &ctx2, nullptr, SymFunctionTableAccess, + SymGetModuleBase, nullptr); + if (!result) { + break; + } + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + SymFromAddr(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol); +#if defined(_M_AMD64) + IMAGEHLP_LINE64 line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); +#elif WINDOWS_32_BIT + IMAGEHLP_LINE line; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE); +#endif + if (SymGetLineFromAddr(process, stack.AddrPC.Offset, &disp, &line)) { + SPDLOG_CRITICAL("{} in {}: line: {}: ", symbol->Name, line.FileName, line.LineNumber); + } + else { + char addrString[25]; + snprintf(addrString, std::size(addrString), "0x%016llX", symbol->Address); + SPDLOG_CRITICAL("at {}, addr 0x{}", symbol->Name, addrString); + hModule = nullptr; + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR)(stack.AddrPC.Offset), &hModule); + + if (hModule != nullptr) { + GetModuleFileNameA(hModule, module, sizeof(module)); + } + SPDLOG_CRITICAL("In {}", module); + } + } + Ship::GlobalCtx2::GetInstance()->GetLogger()->flush(); + spdlog::shutdown(); +} + +extern "C" LONG seh_filter(struct _EXCEPTION_POINTERS* ex) { + char exceptionString[20]; + + snprintf(exceptionString, std::size(exceptionString), "0x%x", ex->ExceptionRecord->ExceptionCode); + + SPDLOG_CRITICAL("EXCEPTION {} occurred", exceptionString); + printStack(ex->ContextRecord); + MessageBox(nullptr, L"SoH Has crashed. Please upload the logs to the support channel in discord.", L"Crash", MB_OK | MB_ICONERROR); + + return EXCEPTION_EXECUTE_HANDLER; +} + + +#endif diff --git a/libultraship/libultraship/CrashHandler.h b/libultraship/libultraship/CrashHandler.h new file mode 100644 index 000000000..53d9783f7 --- /dev/null +++ b/libultraship/libultraship/CrashHandler.h @@ -0,0 +1,44 @@ +#ifndef CRASH_HANDLER_H +#define CRASH_HANDLER_H + +#ifdef __linux__ + +#ifdef __cplusplus +extern "C" { +#endif + +void SetupHandlerLinux(void); + +#ifdef __cplusplus +} +#endif + +#elif _WIN32 // __linux__ ^^^^ _WIN32 vvvvv +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOGDI +#define NOGDI +#endif + +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +LONG seh_filter(struct _EXCEPTION_POINTERS* ex); + +#ifdef __cplusplus +} +#endif + +#pragma comment(lib, "Dbghelp.lib") +#endif + +#endif // CRASH_HANDLER_H diff --git a/libultraship/libultraship/libultraship.vcxproj b/libultraship/libultraship/libultraship.vcxproj index 27e868afa..1c7b92468 100644 --- a/libultraship/libultraship/libultraship.vcxproj +++ b/libultraship/libultraship/libultraship.vcxproj @@ -257,6 +257,7 @@ + @@ -344,6 +345,7 @@ + diff --git a/libultraship/libultraship/libultraship.vcxproj.filters b/libultraship/libultraship/libultraship.vcxproj.filters index ec1c6f870..b3fa4d185 100644 --- a/libultraship/libultraship/libultraship.vcxproj.filters +++ b/libultraship/libultraship/libultraship.vcxproj.filters @@ -100,6 +100,9 @@ {010dc29b-d1f6-4793-a4e7-4156aa4fcdd6} + + {2bfc7e1d-8d0f-44c8-bb1e-af3e9de30da1} + @@ -366,6 +369,9 @@ Source Files\Lib\Mercury + + Source Files\CrashHandler + @@ -683,5 +689,8 @@ Source Files\Lib\Mercury + + Source Files\CrashHandler + \ No newline at end of file diff --git a/soh/src/code/main.c b/soh/src/code/main.c index 372e3947c..cfab85c65 100644 --- a/soh/src/code/main.c +++ b/soh/src/code/main.c @@ -3,6 +3,8 @@ #include #include "soh/OTRGlobals.h" +#include "../libultraship/CrashHandler.h" + s32 gScreenWidth = SCREEN_WIDTH; s32 gScreenHeight = SCREEN_HEIGHT; @@ -38,6 +40,12 @@ void Main_LogSystemHeap(void) { void main(int argc, char** argv) { +#ifdef __linux__ + SetupHandlerLinux(); +#elif _WIN32 + SetUnhandledExceptionFilter(seh_filter); +#endif + GameConsole_Init(); InitOTR(); BootCommands_Init();