diff --git a/common/src/platform/windows/CMakeLists.txt b/common/src/platform/windows/CMakeLists.txt index 26e5a3b8..685c407a 100644 --- a/common/src/platform/windows/CMakeLists.txt +++ b/common/src/platform/windows/CMakeLists.txt @@ -20,3 +20,7 @@ target_link_libraries(lg_common_platform_code lg_common setupapi ) + +if (ENABLE_BACKTRACE) + target_link_libraries(lg_common_platform_code dbghelp) +endif() diff --git a/common/src/platform/windows/crash.c b/common/src/platform/windows/crash.c index 9c6d5985..cc93084f 100644 --- a/common/src/platform/windows/crash.c +++ b/common/src/platform/windows/crash.c @@ -18,9 +18,142 @@ Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common/crash.h" +#include "common/debug.h" +#include "common/version.h" + +#ifdef ENABLE_BACKTRACE + +#include +#include +#include +#include + +static const char * exception_name(DWORD code) +{ + switch (code) + { + case EXCEPTION_ACCESS_VIOLATION: + return "ACCESS_VIOLATION"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "ARRAY_BOUNDS_EXCEEDED"; + case EXCEPTION_BREAKPOINT: + return "BREAKPOINT"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "DATATYPE_MISALIGNMENT"; + case EXCEPTION_FLT_DENORMAL_OPERAND: + return "FLT_DENORMAL_OPERAND"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "FLT_DIVIDE_BY_ZERO"; + case EXCEPTION_FLT_INEXACT_RESULT: + return "FLT_INEXACT_RESULT"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "FLT_INVALID_OPERATION"; + case EXCEPTION_FLT_OVERFLOW: + return "FLT_OVERFLOW"; + case EXCEPTION_FLT_STACK_CHECK: + return "FLT_STACK_CHECK"; + case EXCEPTION_FLT_UNDERFLOW: + return "FLT_UNDERFLOW"; + case EXCEPTION_ILLEGAL_INSTRUCTION: + return "ILLEGAL_INSTRUCTION"; + case EXCEPTION_IN_PAGE_ERROR: + return "IN_PAGE_ERROR"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "INT_DIVIDE_BY_ZERO"; + case EXCEPTION_INT_OVERFLOW: + return "INT_OVERFLOW"; + case EXCEPTION_INVALID_DISPOSITION: + return "INVALID_DISPOSITION"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "NONCONTINUABLE_EXCEPTION"; + case EXCEPTION_PRIV_INSTRUCTION: + return "PRIV_INSTRUCTION"; + case EXCEPTION_SINGLE_STEP: + return "SINGLE_STEP"; + case EXCEPTION_STACK_OVERFLOW: + return "STACK_OVERFLOW"; + default: + return "unknown"; + } +} + +static LONG CALLBACK exception_filter(EXCEPTION_POINTERS * exc) +{ + PEXCEPTION_RECORD excInfo = exc->ExceptionRecord; + CONTEXT context; + memcpy(&context, exc->ContextRecord, sizeof context); + + DEBUG_ERROR("==== FATAL CRASH (%s) ====", BUILD_VERSION); + DEBUG_ERROR("exception 0x%08lx (%s), address is %p", excInfo->ExceptionCode, + exception_name(excInfo->ExceptionCode), excInfo->ExceptionAddress); + + if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) + { + DEBUG_ERROR("Failed to SymInitialize: 0x%08lx, could not generate stack trace", GetLastError()); + goto fail; + } + SymSetOptions(SYMOPT_LOAD_LINES); + + STACKFRAME64 frame = { 0 }; + frame.AddrPC.Offset = context.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; + frame.AddrStack.Mode = AddrModeFlat; + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + for (int i = 1; StackWalk64(IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, &frame, &context, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL); ++i) + { + DWORD64 moduleBase = SymGetModuleBase64(hProcess, frame.AddrPC.Offset); + char moduleName[MAX_PATH]; + + if (moduleBase && GetModuleFileNameA((HMODULE) moduleBase, moduleName, MAX_PATH)) + { + DWORD64 disp; + + char symbolBuf[sizeof(SYMBOL_INFO) + 255]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO) symbolBuf; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = 256; + + if (SymFromAddr(hProcess, frame.AddrPC.Offset, &disp, symbol)) + { + IMAGEHLP_LINE line = { sizeof(IMAGEHLP_LINE), 0 }; + DWORD lineDisp; + + if (SymGetLineFromAddr64(hProcess, frame.AddrPC.Offset, &lineDisp, &line)) + DEBUG_ERROR("[trace]: %2d: %s:%s+0x%" PRIx64 " (%s:%ld+0x%lx)", i, moduleName, symbol->Name, disp, + line.FileName, line.LineNumber, lineDisp); + else + DEBUG_ERROR("[trace]: %2d: %s:%s+0x%" PRIx64, i, moduleName, symbol->Name, disp); + } + else + DEBUG_ERROR("[trace]: %2d: %s+0x%08" PRIx64, i, moduleName, frame.AddrPC.Offset - moduleBase); + } + else + DEBUG_ERROR("[trace]: %2d: 0x%016" PRIx64, i, frame.AddrPC.Offset); + } + + SymCleanup(hProcess); + +fail: + fflush(stderr); + return EXCEPTION_CONTINUE_SEARCH; +} bool installCrashHandler(const char * exe) { - //TODO + SetUnhandledExceptionFilter(exception_filter); return true; -} \ No newline at end of file +} + +#else +bool installCrashHandler(const char * exe) +{ + return true; +} +#endif