diff --git a/daemon/main.cpp b/daemon/main.cpp index 66e6d0872..0e2f78b98 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -16,6 +16,7 @@ #ifdef _WIN32 #define wmin(x, y) (((x) < (y)) ? (x) : (y)) #define MIN wmin +extern "C" void win32_signal_handler(int); #endif struct llarp_main *ctx = 0; @@ -116,6 +117,7 @@ main(int argc, char *argv[]) if(startWinsock()) return -1; SetConsoleCtrlHandler(handle_signal_win32, TRUE); + signal(SIGSEGV, win32_signal_handler); #endif #ifdef LOKINET_DEBUG diff --git a/llarp/metrics/metrictank_publisher.cpp b/llarp/metrics/metrictank_publisher.cpp index 1f76c770b..ab9a98597 100644 --- a/llarp/metrics/metrictank_publisher.cpp +++ b/llarp/metrics/metrictank_publisher.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #endif diff --git a/llarp/path/path_context.cpp b/llarp/path/path_context.cpp index 84a19f575..b2460f84b 100644 --- a/llarp/path/path_context.cpp +++ b/llarp/path/path_context.cpp @@ -164,15 +164,14 @@ namespace llarp HopHandler_ptr PathContext::GetByUpstream(const RouterID& remote, const PathID_t& id) { - auto own = MapGet( - m_OurPaths, id, - [](const PathSet_ptr) -> bool { - // TODO: is this right? - return true; - }, - [remote, id](PathSet_ptr p) -> HopHandler_ptr { - return p->GetByUpstream(remote, id); - }); + auto own = MapGet(m_OurPaths, id, + [](const PathSet_ptr) -> bool { + // TODO: is this right? + return true; + }, + [remote, id](PathSet_ptr p) -> HopHandler_ptr { + return p->GetByUpstream(remote, id); + }); if(own) return own; diff --git a/llarp/win32/win32_intrnl.c b/llarp/win32/win32_intrnl.c index 38ced0549..0b016e85a 100644 --- a/llarp/win32/win32_intrnl.c +++ b/llarp/win32/win32_intrnl.c @@ -570,3 +570,106 @@ SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) CloseHandle(hThread); } #endif + +#ifdef _WIN32 +// Generate a core dump if we crash. Finally. +// Unix-style, we just leave a file named "core" in +// the user's working directory. Gets overwritten if +// a new crash occurs. +#include +#ifdef _MSC_VER +#pragma comment(lib, "dbghelp.lib") +#endif + +HRESULT +GenerateCrashDump(MINIDUMP_TYPE flags, EXCEPTION_POINTERS *seh) +{ + HRESULT error = S_OK; + MINIDUMP_USER_STREAM_INFORMATION info = {0}; + MINIDUMP_USER_STREAM *streamPtr = NULL; + MINIDUMP_USER_STREAM stream = {0}; + + // get the time + SYSTEMTIME sysTime = {0}; + GetSystemTime(&sysTime); + + // get the computer name + char compName[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD compNameLen = ARRAYSIZE(compName); + GetComputerNameA(compName, &compNameLen); + + // This information is written to a core dump user stream + char extra_info[1024] = {0}; + snprintf(extra_info, 1024, + "hostname=%s;datetime=%02u-%02u-%02u_%02u-%02u-%02u", compName, + sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, + sysTime.wMinute, sysTime.wSecond); + + // open the file + HANDLE hFile = + CreateFileA("core", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if(hFile == INVALID_HANDLE_VALUE) + { + error = GetLastError(); + error = HRESULT_FROM_WIN32(error); + return error; + } + + // get the process information + HANDLE hProc = GetCurrentProcess(); + DWORD procID = GetCurrentProcessId(); + + // if we have SEH info, package it up + MINIDUMP_EXCEPTION_INFORMATION sehInfo = {0}; + MINIDUMP_EXCEPTION_INFORMATION *sehPtr = NULL; + + // Collect hostname and time + info.UserStreamCount = 1; + info.UserStreamArray = streamPtr; + streamPtr = &stream; + stream.Type = CommentStreamA; + stream.BufferSize = strlen(extra_info) + 1; + stream.Buffer = extra_info; + + if(seh) + { + sehInfo.ThreadId = GetCurrentThreadId(); + sehInfo.ExceptionPointers = seh; + sehInfo.ClientPointers = FALSE; + sehPtr = &sehInfo; + } + + // generate the crash dump + BOOL result = + MiniDumpWriteDump(hProc, procID, hFile, flags, sehPtr, &info, NULL); + if(!result) + { + error = (HRESULT)GetLastError(); // already an HRESULT + } + + // close the file + CloseHandle(hFile); + return error; +} + +// ok try a UNIX-style signal handler +__declspec(noreturn) void win32_signal_handler(int s) +{ + MessageBox(NULL, + "A fatal error has occurred. A core dump was generated and " + "dropped in the daemon's working directory. Please create an " + "issue at https://github.com/loki-network/loki-project, and " + "attach the core dump for further assistance.", + "Fatal Error", MB_ICONHAND); + GenerateCrashDump( + MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo + | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo + | MiniDumpWithUnloadedModules | MiniDumpWithFullAuxiliaryState + | MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation, + NULL); + exit(127); +} +#endif \ No newline at end of file diff --git a/win32-setup/dbghelp32.dll b/win32-setup/dbghelp32.dll new file mode 100644 index 000000000..62d850863 Binary files /dev/null and b/win32-setup/dbghelp32.dll differ diff --git a/win32-setup/dbghelp64.dll b/win32-setup/dbghelp64.dll new file mode 100644 index 000000000..f3bd78ff9 Binary files /dev/null and b/win32-setup/dbghelp64.dll differ diff --git a/win32-setup/lokinet-win32.iss b/win32-setup/lokinet-win32.iss index 46722785a..6767b8a34 100644 --- a/win32-setup/lokinet-win32.iss +++ b/win32-setup/lokinet-win32.iss @@ -68,11 +68,14 @@ Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescrip #ifdef SINGLE_ARCH Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "{#DevPath}build\liblokinet-shared.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "dbghelp64.dll"; DestDir: "{app}\dbghelp.dll"; Flags: ignoreversion #else Source: "{#DevPath}build\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64 Source: "{#DevPath}build\liblokinet-shared.dll"; DestDir: "{app}"; Flags: ignoreversion 32bit; Check: not IsWin64 +Source: "dbghelp32.dll"; DestName: "dbghelp.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not IsWin64 Source: "{#DevPath}build64\lokinet.exe"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64 Source: "{#DevPath}build64\liblokinet-shared.dll"; DestDir: "{app}"; Flags: ignoreversion 64bit; Check: IsWin64 +Source: "dbghelp64.dll"; DestDir: "{app}"; DestName: "dbghelp.dll"; Flags: ignoreversion; Check: IsWin64 #endif ; UI has landed! #ifndef RELEASE