diff --git a/src/system/windows/signal.cpp b/src/system/windows/signal.cpp index 23d57b99b5..2b16aee7d0 100644 --- a/src/system/windows/signal.cpp +++ b/src/system/windows/signal.cpp @@ -155,6 +155,53 @@ 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(e->ContextRecord->Eip); + void* base = reinterpret_cast(e->ContextRecord->Ebp); + void* stack = reinterpret_cast(e->ContextRecord->Esp); + void* thread = reinterpret_cast(e->ContextRecord->Ebx); +#elif defined ARCH_x86_64 + void* ip = reinterpret_cast(e->ContextRecord->Rip); + void* base = reinterpret_cast(e->ContextRecord->Rbp); + void* stack = reinterpret_cast(e->ContextRecord->Rsp); + void* thread = reinterpret_cast(e->ContextRecord->Rbx); +#endif + + HMODULE module; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + static_cast(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(tb.time) * 1000) + + static_cast(tb.millitm), + e->ExceptionRecord->ExceptionCode, + ip, + base, + stack, + thread, + module ? name : "(unknown)"); + + fflush(log); + fclose(log); + } +} + LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) { SignalRegistrar::Handler* handler = 0; @@ -180,22 +227,36 @@ 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(ip); - e->ContextRecord->Ebp = reinterpret_cast(base); - e->ContextRecord->Esp = reinterpret_cast(stack); - e->ContextRecord->Ebx = reinterpret_cast(thread); + e->ContextRecord->Eip = reinterpret_cast(ip); + e->ContextRecord->Ebp = reinterpret_cast(base); + e->ContextRecord->Esp = reinterpret_cast(stack); + e->ContextRecord->Ebx = reinterpret_cast(thread); #elif defined ARCH_x86_64 - e->ContextRecord->Rip = reinterpret_cast(ip); - e->ContextRecord->Rbp = reinterpret_cast(base); - e->ContextRecord->Rsp = reinterpret_cast(stack); - e->ContextRecord->Rbx = reinterpret_cast(thread); + e->ContextRecord->Rip = reinterpret_cast(ip); + e->ContextRecord->Rbp = reinterpret_cast(base); + e->ContextRecord->Rsp = reinterpret_cast(stack); + e->ContextRecord->Rbx = reinterpret_cast(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(ip), + &module) and module == GetModuleHandle(0)) { + dump(e, SignalRegistrar::Data::instance->crashDumpDirectory); + } else { + logException(e, SignalRegistrar::Data::instance->crashDumpDirectory); + } } }