Skip to content

Instantly share code, notes, and snippets.

@dicej
Created June 30, 2014 15:03
Show Gist options
  • Save dicej/7c11c8f27b3a34ffc3ad to your computer and use it in GitHub Desktop.
Save dicej/7c11c8f27b3a34ffc3ad to your computer and use it in GitHub Desktop.
attempt to use CaptureStackBackTrace for lightweight crash reporting
diff --git a/src/system/windows/signal.cpp b/src/system/windows/signal.cpp
index 23d57b9..0114474 100644
--- a/src/system/windows/signal.cpp
+++ b/src/system/windows/signal.cpp
@@ -90,6 +90,24 @@ struct MINIDUMP_EXCEPTION_INFORMATION {
LPEXCEPTION_POINTERS exception;
BOOL exceptionInCurrentAddressSpace;
};
+
+struct SYMBOL_INFO {
+ ULONG SizeOfStruct;
+ ULONG TypeIndex;
+ ULONG64 Reserved[2];
+ ULONG Index;
+ ULONG Size;
+ ULONG64 ModBase;
+ ULONG Flags;
+ ULONG64 Value;
+ ULONG64 Address;
+ ULONG Register;
+ ULONG Scope;
+ ULONG Tag;
+ ULONG NameLen;
+ ULONG MaxNameLen;
+ TCHAR Name[1];
+};
#pragma pack(pop)
struct MINIDUMP_USER_STREAM_INFORMATION;
@@ -111,6 +129,20 @@ typedef BOOL (*MiniDumpWriteDumpType)(HANDLE processHandle,
const MINIDUMP_CALLBACK_INFORMATION
* callback);
+typedef BOOL WINAPI (*SymInitializeType)(HANDLE hProcess,
+ PCTSTR UserSearchPath,
+ BOOL fInvadeProcess);
+
+typedef BOOL WINAPI (*SymFromAddrType)(HANDLE hProcess,
+ DWORD64 Address,
+ PDWORD64 Displacement,
+ SYMBOL_INFO* Symbol);
+
+extern "C"
+NTSYSAPI WORD NTAPI RtlCaptureStackBackTrace(DWORD FramesToSkip,
+ DWORD FramesToCapture,
+ PVOID* BackTrace,
+ PDWORD BackTraceHash);
#endif
void dump(LPEXCEPTION_POINTERS e, const char* directory)
@@ -155,6 +187,100 @@ void dump(LPEXCEPTION_POINTERS e, const char* directory)
}
}
+void logException(LPEXCEPTION_POINTERS e, const char* directory)
+{
+ char name[MAX_PATH];
+ _timeb tb;
+ FTIME(&tb);
+ vm::snprintf(name,
+ MAX_PATH,
+ "%s\\exceptions.txt",
+ directory);
+
+ FILE* log =vm::fopen(name, "ab");
+ if (log) {
+#ifdef ARCH_x86_32
+ void* ip = reinterpret_cast<void*>(e->ContextRecord->Eip);
+ void* base = reinterpret_cast<void*>(e->ContextRecord->Ebp);
+ void* stack = reinterpret_cast<void*>(e->ContextRecord->Esp);
+ void* thread = reinterpret_cast<void*>(e->ContextRecord->Ebx);
+#elif defined ARCH_x86_64
+ void* ip = reinterpret_cast<void*>(e->ContextRecord->Rip);
+ void* base = reinterpret_cast<void*>(e->ContextRecord->Rbp);
+ void* stack = reinterpret_cast<void*>(e->ContextRecord->Rsp);
+ void* thread = reinterpret_cast<void*>(e->ContextRecord->Rbx);
+#endif
+
+ HMODULE module;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ static_cast<LPCSTR>(ip),
+ &module))
+ {
+ GetModuleFileName(module, name, MAX_PATH);
+ } else {
+ module = 0;
+ }
+
+ fprintf(log, "timestamp %" LLD
+ " code %ld ip %p base %p stack %p thread %p module %s\n",
+ (static_cast<int64_t>(tb.time) * 1000) + static_cast
+ <int64_t>(tb.millitm),
+ e->ExceptionRecord->ExceptionCode,
+ ip, base, stack, thread, module ? name : "(unknown)");
+
+ HINSTANCE dbghelp = LoadLibrary("dbghelp.dll");
+
+ if (dbghelp) {
+ SymInitializeType SymInitialize = reinterpret_cast
+ <SymInitializeType>(GetProcAddress(dbghelp, "SymInitialize"));
+
+ SymFromAddrType SymFromAddr = reinterpret_cast
+ <SymFromAddrType>(GetProcAddress(dbghelp, "SymFromAddr"));
+
+ if (SymInitialize and SymFromAddr) {
+ HANDLE process = GetCurrentProcess();
+
+ SymInitialize(process, 0, TRUE);
+
+ const unsigned maxTrace = 100;
+ void* stack[maxTrace];
+
+ unsigned frames = RtlCaptureStackBackTrace(0, maxTrace, stack, 0);
+
+ const unsigned maxName = 256;
+ SYMBOL_INFO* symbol = static_cast<SYMBOL_INFO*>
+ (calloc(sizeof(SYMBOL_INFO) + maxName * sizeof(char), 1));
+
+ symbol->MaxNameLen = maxName - 1;
+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+
+ for(unsigned i = 0; i < frames; ++i) {
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ static_cast<LPCSTR>(stack[i]),
+ &module))
+ {
+ GetModuleFileName(module, name, MAX_PATH);
+ } else {
+ module = 0;
+ }
+
+ SymFromAddr(process, reinterpret_cast<uintptr_t>(stack[i]), 0,
+ symbol);
+
+ fprintf(log, " %s in %s - %p\n", symbol->Name,
+ module ? name : "(unknown)", reinterpret_cast<void*>
+ (symbol->Address));
+ }
+
+ free(symbol);
+ }
+ }
+
+ fflush(log);
+ fclose(log);
+ }
+}
+
LONG CALLBACK handleException(LPEXCEPTION_POINTERS e)
{
SignalRegistrar::Handler* handler = 0;
@@ -180,22 +306,38 @@ LONG CALLBACK handleException(LPEXCEPTION_POINTERS e)
bool jump = handler->handleSignal(&ip, &base, &stack, &thread);
+ if (jump) {
#ifdef ARCH_x86_32
- e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip);
- e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base);
- e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack);
- e->ContextRecord->Ebx = reinterpret_cast<DWORD>(thread);
+ e->ContextRecord->Eip = reinterpret_cast<DWORD>(ip);
+ e->ContextRecord->Ebp = reinterpret_cast<DWORD>(base);
+ e->ContextRecord->Esp = reinterpret_cast<DWORD>(stack);
+ e->ContextRecord->Ebx = reinterpret_cast<DWORD>(thread);
#elif defined ARCH_x86_64
- e->ContextRecord->Rip = reinterpret_cast<DWORD64>(ip);
- e->ContextRecord->Rbp = reinterpret_cast<DWORD64>(base);
- e->ContextRecord->Rsp = reinterpret_cast<DWORD64>(stack);
- e->ContextRecord->Rbx = reinterpret_cast<DWORD64>(thread);
+ e->ContextRecord->Rip = reinterpret_cast<DWORD64>(ip);
+ e->ContextRecord->Rbp = reinterpret_cast<DWORD64>(base);
+ e->ContextRecord->Rsp = reinterpret_cast<DWORD64>(stack);
+ e->ContextRecord->Rbx = reinterpret_cast<DWORD64>(thread);
#endif
- if (jump) {
return EXCEPTION_CONTINUE_EXECUTION;
} else if (SignalRegistrar::Data::instance->crashDumpDirectory) {
- dump(e, SignalRegistrar::Data::instance->crashDumpDirectory);
+ // We only generate a crash dump if exception occurred in code
+ // belonging to the current executable. If the exception
+ // occurred in a library, there may be a handler available to
+ // handle it, in which case it is premature to assume we're
+ // going to crash. Generating a full memory dump on each such
+ // event is time consuming and eats up disk space, so we'd
+ // prefer to avoid it unless we're really crashing.
+ HMODULE module;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ static_cast<LPCSTR>(ip),
+ &module)
+ and module == GetModuleHandle(0))
+ {
+ dump(e, SignalRegistrar::Data::instance->crashDumpDirectory);
+ } else {
+ logException(e, SignalRegistrar::Data::instance->crashDumpDirectory);
+ }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment