From 7e15ec5e66e6a16c2d0fcdf9c8d528369d8ccd49 Mon Sep 17 00:00:00 2001 From: Quantum Date: Tue, 26 Jan 2021 15:13:10 -0500 Subject: [PATCH] [common] windows: implement crash handler for stack traces This commit uses the DbgHelp library which is shipped with Windows to generate stack traces with function names and line number information. It takes advantage of the pdb file generated by cv2pdb that is now installed with looking-glass-host.exe. --- common/src/platform/windows/CMakeLists.txt | 4 + common/src/platform/windows/crash.c | 137 ++++++++++++++++++++- 2 files changed, 139 insertions(+), 2 deletions(-) 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