summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/os/windows/crashlog_win.cpp131
1 files changed, 129 insertions, 2 deletions
diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp
index 11791528b..cdadb27da 100644
--- a/src/os/windows/crashlog_win.cpp
+++ b/src/os/windows/crashlog_win.cpp
@@ -29,6 +29,16 @@
#include <windows.h>
#include <signal.h>
+static const uint MAX_SYMBOL_LEN = 512;
+static const uint MAX_FRAMES = 64;
+
+/* printf format specification for 32/64-bit addresses. */
+#ifdef _M_AMD64
+#define PRINTF_PTR "0x%016IX"
+#else
+#define PRINTF_PTR "0x%08X"
+#endif
+
/**
* Windows implementation for the crash logger.
*/
@@ -44,6 +54,9 @@ class CrashLogWindows : public CrashLog {
public:
#if defined(_MSC_VER)
/* virtual */ int WriteCrashDump(char *filename, const char *filename_last) const;
+ char *AppendDecodedStacktrace(char *buffer, const char *last) const;
+#else
+ char *AppendDecodedStacktrace(char *buffer, const char *last) const { return buffer; }
#endif /* _MSC_VER */
/** Buffer for the generated crash log */
@@ -314,6 +327,119 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod)
#if defined(_MSC_VER)
#include <dbghelp.h>
+char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) const
+{
+#define M(x) x "\0"
+ static const char dbg_import[] =
+ M("dbghelp.dll")
+ M("SymInitialize")
+ M("SymSetOptions")
+ M("SymCleanup")
+ M("StackWalk64")
+ M("SymFunctionTableAccess64")
+ M("SymGetModuleBase64")
+ M("SymGetModuleInfo64")
+ M("SymGetSymFromAddr64")
+ M("SymGetLineFromAddr64")
+ M("")
+ ;
+#undef M
+
+ struct ProcPtrs {
+ BOOL (WINAPI * pSymInitialize)(HANDLE, PCSTR, BOOL);
+ BOOL (WINAPI * pSymSetOptions)(DWORD);
+ BOOL (WINAPI * pSymCleanup)(HANDLE);
+ BOOL (WINAPI * pStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
+ PVOID (WINAPI * pSymFunctionTableAccess64)(HANDLE, DWORD64);
+ DWORD64 (WINAPI * pSymGetModuleBase64)(HANDLE, DWORD64);
+ BOOL (WINAPI * pSymGetModuleInfo64)(HANDLE, DWORD64, PIMAGEHLP_MODULE64);
+ BOOL (WINAPI * pSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
+ BOOL (WINAPI * pSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
+ } proc;
+
+ buffer += seprintf(buffer, last, "\nDecoded stack trace:\n");
+
+ /* Try to load the functions from the DLL, if that fails because of a too old dbghelp.dll, just skip it. */
+ if (LoadLibraryList((Function*)&proc, dbg_import)) {
+ /* Initialize symbol handler. */
+ HANDLE hCur = GetCurrentProcess();
+ proc.pSymInitialize(hCur, NULL, TRUE);
+ /* Load symbols only when needed, fail silently on errors, demangle symbol names. */
+ proc.pSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_UNDNAME);
+
+ /* Initialize starting stack frame from context record. */
+ STACKFRAME64 frame;
+ memset(&frame, 0, sizeof(frame));
+#ifdef _M_AMD64
+ frame.AddrPC.Offset = ep->ContextRecord->Rip;
+ frame.AddrFrame.Offset = ep->ContextRecord->Rbp;
+ frame.AddrStack.Offset = ep->ContextRecord->Rsp;
+#else
+ frame.AddrPC.Offset = ep->ContextRecord->Eip;
+ frame.AddrFrame.Offset = ep->ContextRecord->Ebp;
+ frame.AddrStack.Offset = ep->ContextRecord->Esp;
+#endif
+ frame.AddrPC.Mode = AddrModeFlat;
+ frame.AddrFrame.Mode = AddrModeFlat;
+ frame.AddrStack.Mode = AddrModeFlat;
+
+ /* Copy context record as StackWalk64 may modify it. */
+ CONTEXT ctx;
+ memcpy(&ctx, ep->ContextRecord, sizeof(ctx));
+
+ /* Allocate space for symbol info. */
+ IMAGEHLP_SYMBOL64 *sym_info = (IMAGEHLP_SYMBOL64*)alloca(sizeof(IMAGEHLP_SYMBOL64) + MAX_SYMBOL_LEN - 1);
+ sym_info->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+ sym_info->MaxNameLength = MAX_SYMBOL_LEN;
+
+ /* Walk stack at most MAX_FRAMES deep in case the stack is corrupt. */
+ for (uint num = 0; num < MAX_FRAMES; num++) {
+ if (!proc.pStackWalk64(
+#ifdef _M_AMD64
+ IMAGE_FILE_MACHINE_AMD64,
+#else
+ IMAGE_FILE_MACHINE_I386,
+#endif
+ hCur, GetCurrentThread(), &frame, &ctx, NULL, proc.pSymFunctionTableAccess64, proc.pSymGetModuleBase64, NULL)) break;
+
+ if (frame.AddrPC.Offset == frame.AddrReturn.Offset) {
+ buffer += seprintf(buffer, last, " <infinite loop>\n");
+ break;
+ }
+
+ /* Get module name. */
+ const char *mod_name = "???";
+
+ IMAGEHLP_MODULE64 module;
+ module.SizeOfStruct = sizeof(module);
+ if (proc.pSymGetModuleInfo64(hCur, frame.AddrPC.Offset, &module)) {
+ mod_name = module.ModuleName;
+ }
+
+ /* Print module and instruction pointer. */
+ buffer += seprintf(buffer, last, "[%02d] %-20s " PRINTF_PTR, num, mod_name, frame.AddrPC.Offset);
+
+ /* Get symbol name and line info if possible. */
+ DWORD64 offset;
+ if (proc.pSymGetSymFromAddr64(hCur, frame.AddrPC.Offset, &offset, sym_info)) {
+ buffer += seprintf(buffer, last, " %s + %I64u", sym_info->Name, offset);
+
+ DWORD line_offs;
+ IMAGEHLP_LINE64 line;
+ line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+ if (proc.pSymGetLineFromAddr64(hCur, frame.AddrPC.Offset, &line_offs, &line)) {
+ buffer += seprintf(buffer, last, " (%s:%d)", line.FileName, line.LineNumber);
+ }
+ }
+ buffer += seprintf(buffer, last, "\n");
+ }
+
+ proc.pSymCleanup(hCur);
+ }
+
+ return buffer + seprintf(buffer, last, "\n*** End of additional info ***\n");
+}
+
/* virtual */ int CrashLogWindows::WriteCrashDump(char *filename, const char *filename_last) const
{
int ret = 0;
@@ -391,9 +517,10 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
CrashLogWindows *log = new CrashLogWindows(ep);
CrashLogWindows::current = log;
- log->FillCrashLog(log->crashlog, lastof(log->crashlog));
- log->WriteCrashLog(log->crashlog, log->crashlog_filename, lastof(log->crashlog_filename));
+ char *buf = log->FillCrashLog(log->crashlog, lastof(log->crashlog));
log->WriteCrashDump(log->crashdump_filename, lastof(log->crashdump_filename));
+ log->AppendDecodedStacktrace(buf, lastof(log->crashlog));
+ log->WriteCrashLog(log->crashlog, log->crashlog_filename, lastof(log->crashlog_filename));
log->WriteScreenshot(log->screenshot_filename, lastof(log->screenshot_filename));
/* Close any possible log files */