mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-05-01 02:56:27 +00:00
162 lines
5.0 KiB
C
162 lines
5.0 KiB
C
/**
|
|
* Looking Glass
|
|
* Copyright © 2017-2021 The Looking Glass Authors
|
|
* https://looking-glass.io
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "common/crash.h"
|
|
#include "common/debug.h"
|
|
#include "common/version.h"
|
|
#include "common/windebug.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_WINERROR("Failed to SymInitialize, 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)
|
|
{
|
|
SetUnhandledExceptionFilter(exception_filter);
|
|
return true;
|
|
}
|
|
|
|
#else
|
|
bool installCrashHandler(const char * exe)
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|