#include "pch.h" #if _DEBUG && _WIN64 #include "unhandled_exception_handler.h" #include #pragma comment(lib, "DbgHelp.lib") #include #include #include static IMAGEHLP_SYMBOL64* p_symbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + MAX_PATH * sizeof(WCHAR)); static IMAGEHLP_LINE64 line; static bool processing_exception = false; static WCHAR module_path[MAX_PATH]; static LPTOP_LEVEL_EXCEPTION_FILTER default_top_level_exception_handler = NULL; static const WCHAR* exception_description(const DWORD& code) { switch (code) { case EXCEPTION_ACCESS_VIOLATION: return L"EXCEPTION_ACCESS_VIOLATION"; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; case EXCEPTION_BREAKPOINT: return L"EXCEPTION_BREAKPOINT"; case EXCEPTION_DATATYPE_MISALIGNMENT: return L"EXCEPTION_DATATYPE_MISALIGNMENT"; case EXCEPTION_FLT_DENORMAL_OPERAND: return L"EXCEPTION_FLT_DENORMAL_OPERAND"; case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"EXCEPTION_FLT_DIVIDE_BY_ZERO"; case EXCEPTION_FLT_INEXACT_RESULT: return L"EXCEPTION_FLT_INEXACT_RESULT"; case EXCEPTION_FLT_INVALID_OPERATION: return L"EXCEPTION_FLT_INVALID_OPERATION"; case EXCEPTION_FLT_OVERFLOW: return L"EXCEPTION_FLT_OVERFLOW"; case EXCEPTION_FLT_STACK_CHECK: return L"EXCEPTION_FLT_STACK_CHECK"; case EXCEPTION_FLT_UNDERFLOW: return L"EXCEPTION_FLT_UNDERFLOW"; case EXCEPTION_ILLEGAL_INSTRUCTION: return L"EXCEPTION_ILLEGAL_INSTRUCTION"; case EXCEPTION_IN_PAGE_ERROR: return L"EXCEPTION_IN_PAGE_ERROR"; case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"EXCEPTION_INT_DIVIDE_BY_ZERO"; case EXCEPTION_INT_OVERFLOW: return L"EXCEPTION_INT_OVERFLOW"; case EXCEPTION_INVALID_DISPOSITION: return L"EXCEPTION_INVALID_DISPOSITION"; case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"EXCEPTION_NONCONTINUABLE_EXCEPTION"; case EXCEPTION_PRIV_INSTRUCTION: return L"EXCEPTION_PRIV_INSTRUCTION"; case EXCEPTION_SINGLE_STEP: return L"EXCEPTION_SINGLE_STEP"; case EXCEPTION_STACK_OVERFLOW: return L"EXCEPTION_STACK_OVERFLOW"; default: return L"UNKNOWN EXCEPTION"; } } void init_symbols() { SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); auto process = GetCurrentProcess(); SymInitialize(process, NULL, TRUE); } void log_stack_trace(std::wstring& generalErrorDescription) { memset(p_symbol, '\0', sizeof(*p_symbol) + MAX_PATH); memset(&module_path[0], '\0', sizeof(module_path)); line.LineNumber = 0; CONTEXT context; RtlCaptureContext(&context); auto process = GetCurrentProcess(); auto thread = GetCurrentThread(); STACKFRAME64 stack; memset(&stack, 0, sizeof(STACKFRAME64)); stack.AddrPC.Offset = context.Rip; stack.AddrPC.Mode = AddrModeFlat; stack.AddrStack.Offset = context.Rsp; stack.AddrStack.Mode = AddrModeFlat; stack.AddrFrame.Offset = context.Rbp; stack.AddrFrame.Mode = AddrModeFlat; std::wstringstream ss; ss << generalErrorDescription << std::endl; for (ULONG frame = 0;; frame++) { auto result = StackWalk64(IMAGE_FILE_MACHINE_AMD64, process, thread, &stack, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); p_symbol->MaxNameLength = MAX_PATH; p_symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); DWORD64 dw64Displacement; SymGetSymFromAddr64(process, stack.AddrPC.Offset, &dw64Displacement, p_symbol); DWORD dwDisplacement; SymGetLineFromAddr64(process, stack.AddrPC.Offset, &dwDisplacement, &line); auto module_base = SymGetModuleBase64(process, stack.AddrPC.Offset); if (module_base) { GetModuleFileName((HINSTANCE)module_base, module_path, MAX_PATH); } ss << module_path << "!" << p_symbol->Name << "(" << line.FileName << ":" << line.LineNumber << ")\n"; if (!result) { break; } } auto errorString = ss.str(); MessageBoxW(NULL, errorString.c_str(), L"Unhandled Error", MB_OK | MB_ICONERROR); } LONG WINAPI unhandled_exceptiont_handler(PEXCEPTION_POINTERS info) { if (!processing_exception) { processing_exception = true; try { init_symbols(); std::wstring ex_description = L"Exception code not available"; if (info != NULL && info->ExceptionRecord != NULL && info->ExceptionRecord->ExceptionCode != NULL) { ex_description = exception_description(info->ExceptionRecord->ExceptionCode); } log_stack_trace(ex_description); } catch (...) {} if (default_top_level_exception_handler != NULL && info != NULL) { default_top_level_exception_handler(info); } processing_exception = false; } return EXCEPTION_CONTINUE_SEARCH; } extern "C" void AbortHandler(int signal_number) { init_symbols(); std::wstring ex_description = L"SIGABRT was raised."; log_stack_trace(ex_description); } void init_global_error_handlers() { default_top_level_exception_handler = SetUnhandledExceptionFilter(unhandled_exceptiont_handler); signal(SIGABRT, &AbortHandler); } #endif