[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.
This commit is contained in:
Quantum 2021-01-26 15:13:10 -05:00 committed by Geoffrey McRae
parent 1808adc2de
commit 7e15ec5e66
2 changed files with 139 additions and 2 deletions

View File

@ -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()

View File

@ -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 <stdio.h>
#include <inttypes.h>
#include <windows.h>
#include <dbghelp.h>
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;
}
}
#else
bool installCrashHandler(const char * exe)
{
return true;
}
#endif