From e7906c93a70c53b45dddd397dd26070aea28c0d7 Mon Sep 17 00:00:00 2001 From: Rosalie Wanders Date: Thu, 27 Feb 2025 18:33:31 +0100 Subject: [PATCH] RMG: add minidump handler in main.cpp --- Source/RMG/main.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/Source/RMG/main.cpp b/Source/RMG/main.cpp index 26cffdbd..0f29a84c 100644 --- a/Source/RMG/main.cpp +++ b/Source/RMG/main.cpp @@ -17,7 +17,11 @@ #include #include -#ifndef _WIN32 +#ifdef _WIN32 +#include +#include +#include +#else #include #endif @@ -42,10 +46,79 @@ static void message_handler(QtMsgType type, const QMessageLogContext &context, c std::cerr << msg.toStdString() << std::endl; } +#ifdef _WIN32 +typedef BOOL (WINAPI* ptr_MiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, + PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, + PMINIDUMP_CALLBACK_INFORMATION); +static void show_error(const char* error) +{ + MessageBoxA(nullptr, error, "RMG Crash Handler", MB_OK | MB_ICONERROR); +} + +static LONG WINAPI exception_handler(_EXCEPTION_POINTERS* ExceptionInfo) +{ + HMODULE dbgHelpModule = LoadLibraryA("Dbghelp.dll"); + if (dbgHelpModule == nullptr) + { + show_error("Failed to find Dbghelp.dll!"); + return EXCEPTION_CONTINUE_SEARCH; + } + + ptr_MiniDumpWriteDump miniDumpWriteDump = + (ptr_MiniDumpWriteDump)GetProcAddress(dbgHelpModule, "MiniDumpWriteDump"); + if (miniDumpWriteDump == nullptr) + { + show_error("Failed to retrieve MiniDumpWriteDump from Dbghelp.dll!"); + return EXCEPTION_CONTINUE_SEARCH; + } + + wchar_t dump_filename[MAX_PATH+1] = {0}; + DWORD filename_len = GetModuleFileNameW(nullptr, dump_filename, MAX_PATH); + if (filename_len <= 0) + { + show_error("Failed to retrieve path of current process!"); + return EXCEPTION_CONTINUE_SEARCH; + } + + if (filename_len >= MAX_PATH) + { // replace .exe with .dmp + wcscpy((dump_filename + (filename_len - 4)), L".dmp"); + } + else + { // append .dmp to .exe + wcscpy((dump_filename + filename_len), L".dmp"); + } + + HANDLE hDumpFile = CreateFileW(dump_filename, GENERIC_WRITE, FILE_SHARE_WRITE, + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + + if (hDumpFile != INVALID_HANDLE_VALUE) + { + _MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; + exceptionInfo.ThreadId = GetCurrentThreadId(); + exceptionInfo.ExceptionPointers = ExceptionInfo; + exceptionInfo.ClientPointers = FALSE; + + BOOL ret = miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hDumpFile, MiniDumpNormal, &exceptionInfo, + nullptr, nullptr); + if (!ret) + { + show_error("Crash detected, failed to save minidump file!"); + } + } + + // we've saved the minidump, + // now we can crash safely + return EXCEPTION_CONTINUE_SEARCH; +} +#else static void signal_handler(int sig) { QGuiApplication::quit(); } +#endif // _WIN32 // // Exported Functions @@ -56,7 +129,12 @@ int main(int argc, char **argv) // install message handler qInstallMessageHandler(message_handler); -#ifndef _WIN32 +#ifdef _WIN32 + // on Windows, to aid with crash debugging + // we'll install a crash handler and + // write out a minidump there + SetUnhandledExceptionFilter(exception_handler); +#else // on Linux we need to install signal handlers, // so we can exit cleanly when the user presses // i.e control+c