Made crash reporting work with 32- and 64-bit windows executables.
This commit is contained in:
parent
f3d56b37df
commit
5a35bb6195
@ -20,7 +20,7 @@
|
|||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if defined(WIN32) && !defined(DEBUG) && !defined(__MINGW32__) && !defined(_WIN64)
|
#if defined(WIN32) && !defined(DEBUG) && !defined(__MINGW32__)
|
||||||
// --------------------- Windows version -----------------
|
// --------------------- Windows version -----------------
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <DbgHelp.h>
|
#include <DbgHelp.h>
|
||||||
@ -76,11 +76,19 @@
|
|||||||
_In_ DWORD maxStringLength,
|
_In_ DWORD maxStringLength,
|
||||||
_In_ DWORD flags
|
_In_ DWORD flags
|
||||||
);
|
);
|
||||||
|
typedef BOOL (__stdcall *tSymFromAddr) (
|
||||||
|
_In_ HANDLE hProcess,
|
||||||
|
_In_ DWORD64 Address,
|
||||||
|
_Out_opt_ PDWORD64 Displacement,
|
||||||
|
_Inout_ PSYMBOL_INFO Symbol
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
namespace CrashReporting
|
namespace CrashReporting
|
||||||
{
|
{
|
||||||
void getCallStackWithContext(std::string& callstack, PCONTEXT pContext);
|
void getCallStackWithContext(std::string& callstack, PCONTEXT pContext);
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
void winCrashHandler(PCONTEXT pContext=NULL)
|
void winCrashHandler(PCONTEXT pContext=NULL)
|
||||||
{
|
{
|
||||||
std::string callstack;
|
std::string callstack;
|
||||||
@ -95,35 +103,43 @@
|
|||||||
"\n"
|
"\n"
|
||||||
"Call stack:\n";
|
"Call stack:\n";
|
||||||
msg += callstack;
|
msg += callstack;
|
||||||
|
Log::error("StackTrace", "%s", msg.c_str());
|
||||||
MessageBoxA(NULL, msg.c_str(), "SuperTuxKart crashed :/", MB_OK);
|
MessageBoxA(NULL, msg.c_str(), "SuperTuxKart crashed :/", MB_OK);
|
||||||
}
|
} // winCrashHandler
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
LONG WINAPI sehHandler(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
|
LONG WINAPI sehHandler(_In_ struct _EXCEPTION_POINTERS *ExceptionInfo)
|
||||||
{
|
{
|
||||||
winCrashHandler(ExceptionInfo->ContextRecord);
|
winCrashHandler(ExceptionInfo->ContextRecord);
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
}
|
} // sehHandler
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
void pureCallHandler()
|
void pureCallHandler()
|
||||||
{
|
{
|
||||||
winCrashHandler();
|
winCrashHandler();
|
||||||
}
|
} // pureCallHandler
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
int newHandler( size_t )
|
int newHandler( size_t )
|
||||||
{
|
{
|
||||||
winCrashHandler();
|
winCrashHandler();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} // newHandler
|
||||||
|
|
||||||
void invalidParameterHandler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
|
// --------------------------------------------------------------------
|
||||||
|
void invalidParameterHandler(const wchar_t *, const wchar_t *,
|
||||||
|
const wchar_t *, unsigned int, uintptr_t)
|
||||||
{
|
{
|
||||||
winCrashHandler();
|
winCrashHandler();
|
||||||
}
|
} // invalidParameterHandler
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
void signalHandler(int code)
|
void signalHandler(int code)
|
||||||
{
|
{
|
||||||
winCrashHandler();
|
winCrashHandler();
|
||||||
}
|
} // signalHandler
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
void installHandlers()
|
void installHandlers()
|
||||||
{
|
{
|
||||||
@ -144,39 +160,42 @@
|
|||||||
|
|
||||||
// ----- Per-thread handlers -----
|
// ----- Per-thread handlers -----
|
||||||
// TODO
|
// TODO
|
||||||
}
|
} // installHandlers
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
|
||||||
void getCallStackWithContext(std::string& callstack, PCONTEXT pContext)
|
void getCallStackWithContext(std::string& callstack, PCONTEXT pContext)
|
||||||
{
|
{
|
||||||
HINSTANCE hImageHlpDll = LoadLibraryA("imagehlp.dll");
|
HINSTANCE hDbgHelpDll = LoadLibraryA("DbgHelp.dll");
|
||||||
if(!hImageHlpDll)
|
if (!hDbgHelpDll)
|
||||||
{
|
{
|
||||||
Log::warn("CrashReporting", "Failed to load DLL imagehlp.dll");
|
Log::warn("CrashReporting", "Failed to load DLL dbghelp.dll");
|
||||||
callstack = "Crash reporting failed to load DLL imagehlp.dll";
|
callstack = "Crash reporting failed to load DLL dbghelp.dll";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the DLL functions
|
// Retrieve the DLL functions
|
||||||
#define GET_FUNC_PTR(FuncName) \
|
#define GET_FUNC_PTR(FuncName) \
|
||||||
t##FuncName _##FuncName = (t##FuncName)GetProcAddress(hImageHlpDll, #FuncName); \
|
t##FuncName _##FuncName = (t##FuncName)GetProcAddress(hDbgHelpDll, #FuncName); \
|
||||||
if(!_##FuncName) { \
|
if(!_##FuncName) { \
|
||||||
Log::warn("CrashReporting", "Failed to import symbol " #FuncName " from imagehlp.dll"); \
|
Log::warn("CrashReporting", "Failed to import symbol " #FuncName " from hDbgHelpDll"); \
|
||||||
FreeLibrary(hImageHlpDll); \
|
FreeLibrary(hDbgHelpDll); \
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_FUNC_PTR(SymCleanup )
|
GET_FUNC_PTR(SymCleanup)
|
||||||
GET_FUNC_PTR(SymFunctionTableAccess64 )
|
GET_FUNC_PTR(SymFunctionTableAccess64)
|
||||||
GET_FUNC_PTR(SymGetLineFromAddr64 )
|
GET_FUNC_PTR(SymGetLineFromAddr64)
|
||||||
GET_FUNC_PTR(SymGetModuleBase64 )
|
GET_FUNC_PTR(SymGetModuleBase64)
|
||||||
GET_FUNC_PTR(SymGetSymFromAddr64 )
|
GET_FUNC_PTR(SymGetSymFromAddr64)
|
||||||
GET_FUNC_PTR(SymInitialize )
|
GET_FUNC_PTR(SymInitialize)
|
||||||
GET_FUNC_PTR(SymSetOptions )
|
GET_FUNC_PTR(SymSetOptions)
|
||||||
GET_FUNC_PTR(StackWalk64 )
|
GET_FUNC_PTR(UnDecorateSymbolName)
|
||||||
GET_FUNC_PTR(UnDecorateSymbolName )
|
GET_FUNC_PTR(SymFromAddr);
|
||||||
|
GET_FUNC_PTR(StackWalk64);
|
||||||
|
|
||||||
#undef GET_FUNC_PTR
|
#undef GET_FUNC_PTR
|
||||||
|
|
||||||
|
|
||||||
const HANDLE hProcess = GetCurrentProcess();
|
const HANDLE hProcess = GetCurrentProcess();
|
||||||
const HANDLE hThread = GetCurrentThread();
|
const HANDLE hThread = GetCurrentThread();
|
||||||
|
|
||||||
@ -188,7 +207,7 @@
|
|||||||
if(!filepath)
|
if(!filepath)
|
||||||
{
|
{
|
||||||
Log::warn("CrashReporting", "GetModuleFileNameA failed");
|
Log::warn("CrashReporting", "GetModuleFileNameA failed");
|
||||||
FreeLibrary(hImageHlpDll);
|
FreeLibrary(hDbgHelpDll);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +228,7 @@
|
|||||||
if (!bOk)
|
if (!bOk)
|
||||||
{
|
{
|
||||||
Log::warn("CrashReporting", "SymInitialize() failed");
|
Log::warn("CrashReporting", "SymInitialize() failed");
|
||||||
FreeLibrary(hImageHlpDll);
|
FreeLibrary(hDbgHelpDll);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,24 +239,25 @@
|
|||||||
|
|
||||||
// Get the stack trace
|
// Get the stack trace
|
||||||
{
|
{
|
||||||
// Initialize the IMAGEHLP_SYMBOL64 structure
|
|
||||||
const size_t MaxNameLength = 256;
|
|
||||||
IMAGEHLP_SYMBOL64* sym = (IMAGEHLP_SYMBOL64*)_malloca(sizeof(IMAGEHLP_SYMBOL64) + MaxNameLength);
|
|
||||||
sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
|
||||||
sym->MaxNameLength = MaxNameLength;
|
|
||||||
|
|
||||||
// Initialize the STACKFRAME structure so that it
|
// Initialize the STACKFRAME structure so that it
|
||||||
// corresponds to the current function call
|
// corresponds to the current function call
|
||||||
STACKFRAME64 stackframe;
|
STACKFRAME64 stackframe;
|
||||||
memset(&stackframe, 0, sizeof(stackframe));
|
memset(&stackframe, 0, sizeof(stackframe));
|
||||||
stackframe.AddrPC.Offset = pContext->Eip;
|
|
||||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||||
stackframe.AddrStack.Offset = pContext->Esp;
|
|
||||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||||
stackframe.AddrFrame.Offset = pContext->Ebp;
|
|
||||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||||
|
#ifdef _WIN64
|
||||||
|
stackframe.AddrPC.Offset = pContext->Rip;
|
||||||
|
stackframe.AddrStack.Offset = pContext->Rsp;
|
||||||
|
stackframe.AddrFrame.Offset = pContext->Rsp;
|
||||||
|
const DWORD machine_type = IMAGE_FILE_MACHINE_AMD64;
|
||||||
|
#else
|
||||||
|
stackframe.AddrPC.Offset = pContext->Eip;
|
||||||
|
stackframe.AddrStack.Offset = pContext->Esp;
|
||||||
|
stackframe.AddrFrame.Offset = pContext->Ebp;
|
||||||
|
const DWORD machine_type = IMAGE_FILE_MACHINE_I386;
|
||||||
|
#endif
|
||||||
|
|
||||||
const DWORD machine_type = IMAGE_FILE_MACHINE_I386;
|
|
||||||
|
|
||||||
// Walk the stack
|
// Walk the stack
|
||||||
const int max_nb_calls = 32;
|
const int max_nb_calls = 32;
|
||||||
@ -256,10 +276,12 @@
|
|||||||
{
|
{
|
||||||
// Decode the symbol and add it to the call stack
|
// Decode the symbol and add it to the call stack
|
||||||
DWORD64 sym_displacement;
|
DWORD64 sym_displacement;
|
||||||
if(_SymGetSymFromAddr64( hProcess,
|
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||||
stackframe.AddrPC.Offset,
|
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||||
&sym_displacement,
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||||
sym))
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
|
if(_SymFromAddr(hProcess, stackframe.AddrPC.Offset,
|
||||||
|
&sym_displacement, symbol) )
|
||||||
{
|
{
|
||||||
IMAGEHLP_LINE64 line64;
|
IMAGEHLP_LINE64 line64;
|
||||||
DWORD dwDisplacement = (DWORD)sym_displacement;
|
DWORD dwDisplacement = (DWORD)sym_displacement;
|
||||||
@ -278,7 +300,7 @@
|
|||||||
}
|
}
|
||||||
callstack += filename;
|
callstack += filename;
|
||||||
callstack += ":";
|
callstack += ":";
|
||||||
callstack += sym->Name;
|
callstack += symbol->Name;
|
||||||
|
|
||||||
char str[128];
|
char str[128];
|
||||||
_itoa(line64.LineNumber, str, 10);
|
_itoa(line64.LineNumber, str, 10);
|
||||||
@ -288,7 +310,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
callstack += "\n ";
|
callstack += "\n ";
|
||||||
callstack += sym->Name;
|
callstack += symbol->Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -299,27 +321,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLibrary(hImageHlpDll);
|
FreeLibrary(hDbgHelpDll);
|
||||||
}
|
} // // getCallStackWithContext
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------
|
||||||
void getCallStack(std::string& callstack)
|
void getCallStack(std::string& callstack)
|
||||||
{
|
{
|
||||||
// Get the current CONTEXT
|
CONTEXT context;
|
||||||
// NB: this code is ONLY VALID FOR X86 (32 bit)!
|
memset(&context, 0, sizeof(CONTEXT));
|
||||||
CONTEXT ctx;
|
context.ContextFlags = CONTEXT_FULL;
|
||||||
memset(&ctx, '\0', sizeof(ctx));
|
RtlCaptureContext(&context);
|
||||||
ctx.ContextFlags = CONTEXT_FULL;
|
getCallStackWithContext(callstack, &context);
|
||||||
__asm call x
|
} // getCallStack
|
||||||
__asm x: pop eax // get eip (can't directly use mov)
|
|
||||||
__asm mov ctx.Eip, eax
|
|
||||||
__asm mov ctx.Ebp, ebp
|
|
||||||
__asm mov ctx.Esp, esp
|
|
||||||
|
|
||||||
getCallStackWithContext(callstack, &ctx);
|
|
||||||
}
|
|
||||||
} // end namespace CrashReporting
|
} // end namespace CrashReporting
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
#elif ENABLE_LIBBFD
|
#elif ENABLE_LIBBFD
|
||||||
// --------------------- Unix version -----------------------
|
// --------------------- Unix version -----------------------
|
||||||
/* Derived from addr2line.c from binutils
|
/* Derived from addr2line.c from binutils
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
namespace CrashReporting
|
namespace CrashReporting
|
||||||
{
|
{
|
||||||
void installHandlers();
|
void installHandlers();
|
||||||
void getCallStack(std::string& callstack);
|
void getCallStack(std::string& callstack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user