From ea03747ace70fccd01e3d2989351e789cd875eac Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Thu, 31 Jan 2013 20:17:52 +0000 Subject: [PATCH] - updated to add initial support for google-breakpad exception handling --- mk/windoze/glest_game.vcxproj | 8 +- mk/windoze/libstreflop.vcxproj | 4 +- mk/windoze/shared_lib.vcxproj | 4 +- source/glest_game/main/main.cpp | 113 +++++++++++++++++- .../sources/platform/win32/platform_util.cpp | 45 +++++-- 5 files changed, 152 insertions(+), 22 deletions(-) diff --git a/mk/windoze/glest_game.vcxproj b/mk/windoze/glest_game.vcxproj index 1231d5d7..8692cbcf 100644 --- a/mk/windoze/glest_game.vcxproj +++ b/mk/windoze/glest_game.vcxproj @@ -115,16 +115,16 @@ Speed false false - ../../source/shared_lib/include/graphics;../../source/shared_lib/include/graphics/gl;../../source/shared_lib/include/platform;../../source/shared_lib/include/platform/win32;../../source/shared_lib/include/sound;../../source/shared_lib/include/sound/ds8;../../source/shared_lib/include/util;../../source/shared_lib/include/lua;../../source/shared_lib/include/xml;../../source/shared_lib/include/xml/rapidxml;../../source/glest_game/ai;../../source/glest_game/facilities;../../source/glest_game/game;../../source/glest_game/global;../../source/glest_game/graphics;../../source/glest_game/gui;../../source/glest_game/main;../../source/glest_game/menu;../../source/glest_game/network;../../source/glest_game/sound;../../source/glest_game/type_instances;../../source/glest_game/types;../../source/glest_game/world;../../source/windows_deps/include;../../source/windows_deps/xerces-c-3.1.1/src;../../source/windows_deps/SDL-1.2.15/include;../../source/shared_lib/include/platform/sdl;../../source/shared_lib/include/sound/openal;../../source/windows_deps/openal-soft-1.14/include;../../source/shared_lib/include/platform/posix;../../source/shared_lib/include/streflop;../../source/shared_lib/include/platform/common;../../source/windows_deps/curl-7.21.3/include;../../source/shared_lib/include/map;../../source/windows_deps/libircclient/include;../../source/windows_deps/glew-1.7.0/include + ../../source/shared_lib/include/graphics;../../source/shared_lib/include/graphics/gl;../../source/shared_lib/include/platform;../../source/shared_lib/include/platform/win32;../../source/shared_lib/include/sound;../../source/shared_lib/include/sound/ds8;../../source/shared_lib/include/util;../../source/shared_lib/include/lua;../../source/shared_lib/include/xml;../../source/shared_lib/include/xml/rapidxml;../../source/glest_game/ai;../../source/glest_game/facilities;../../source/glest_game/game;../../source/glest_game/global;../../source/glest_game/graphics;../../source/glest_game/gui;../../source/glest_game/main;../../source/glest_game/menu;../../source/glest_game/network;../../source/glest_game/sound;../../source/glest_game/type_instances;../../source/glest_game/types;../../source/glest_game/world;../../source/windows_deps/include;../../source/windows_deps/xerces-c-3.1.1/src;../../source/windows_deps/SDL-1.2.15/include;../../source/shared_lib/include/platform/sdl;../../source/shared_lib/include/sound/openal;../../source/windows_deps/openal-soft-1.14/include;../../source/shared_lib/include/platform/posix;../../source/shared_lib/include/streflop;../../source/shared_lib/include/platform/common;../../source/windows_deps/curl-7.21.3/include;../../source/shared_lib/include/map;../../source/windows_deps/libircclient/include;../../source/windows_deps/glew-1.7.0/include;../../source/windows_deps/google-breakpad\trunk\src\client\windows\handler;../../source/windows_deps/google-breakpad\trunk\src\ %(AdditionalUsingDirectories) - WIN32;NDEBUG;_WINDOWS;XML_LIBRARY;USE_PCH=1;_CRT_SECURE_NO_WARNINGS;USE_STREFLOP;STREFLOP_SSE;LIBM_COMPILING_FLT32;CURL_STATICLIB;UNICODE;XERCES_STATIC_LIBRARY;GLEW_STATIC;ZLIB_WINAPI;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;XML_LIBRARY;USE_PCH=1;_CRT_SECURE_NO_WARNINGS;USE_STREFLOP;STREFLOP_SSE;LIBM_COMPILING_FLT32;CURL_STATICLIB;UNICODE;XERCES_STATIC_LIBRARY;GLEW_STATIC;ZLIB_WINAPI;HAVE_GOOGLE_BREAKPAD;%(PreprocessorDefinitions) true Async MultiThreaded true StreamingSIMDExtensions Precise - $(IntDir)$(TargetName).pdb + $(OutDir)$(TargetName).pdb Level3 ProgramDatabase 4018;4244;4250;4503;%(DisableSpecificWarnings) @@ -132,7 +132,7 @@ true - dsound.lib;dxguid.lib;glew32s.lib;libogg_static.lib;libvorbis_static.lib;libvorbisfile_static.lib;opengl32.lib;glu32.lib;wsock32.lib;libglest.lib;mmc.lib;lua.lib;xerces-c_static_3.lib;Dbghelp.lib;libpng15.lib;jpeg.lib;zlibstat.lib;sdl.lib;sdlmain.lib;winmm.lib;openal32.lib;iphlpapi.lib;libstreflop.lib;libcurl.lib;ws2_32.lib;libircclient.lib;freetype244MT.lib;ftgl_static.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + dsound.lib;dxguid.lib;glew32s.lib;libogg_static.lib;libvorbis_static.lib;libvorbisfile_static.lib;opengl32.lib;glu32.lib;wsock32.lib;libglest.lib;mmc.lib;lua.lib;xerces-c_static_3.lib;Dbghelp.lib;libpng15.lib;jpeg.lib;zlibstat.lib;sdl.lib;sdlmain.lib;winmm.lib;openal32.lib;iphlpapi.lib;libstreflop.lib;libcurl.lib;ws2_32.lib;libircclient.lib;freetype244MT.lib;ftgl_static.lib;libeay32.lib;ssleay32.lib;crash_generation_client.lib;exception_handler.lib;common.lib;processor_bits.lib;%(AdditionalDependencies) ../../source/windows_deps/lib;../../build/$(Configuration)/libglest;../../source/shared_lib/sources/streflop/libstreflop;$(DXSDK_DIR)/lib/x86;../../source/windows_deps/Microsoft DirectX SDK %28November 2007%29/Lib/x86;%(AdditionalLibraryDirectories) %(IgnoreSpecificDefaultLibraries) true diff --git a/mk/windoze/libstreflop.vcxproj b/mk/windoze/libstreflop.vcxproj index 2fe76ac5..2872c42b 100644 --- a/mk/windoze/libstreflop.vcxproj +++ b/mk/windoze/libstreflop.vcxproj @@ -93,7 +93,7 @@ Speed false ..\..\source\shared_lib\include\streflop\libm\flt-32;..\..\source\shared_lib\include\streflop\libm\headers;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_PCH=1;USE_STREFLOP;STREFLOP_SSE;LIBM_COMPILING_FLT32;%(PreprocessorDefinitions) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_PCH=1;USE_STREFLOP;STREFLOP_SSE;LIBM_COMPILING_FLT32;HAVE_GOOGLE_BREAKPAD;%(PreprocessorDefinitions) true Async MultiThreaded @@ -101,7 +101,7 @@ StreamingSIMDExtensions Precise true - $(IntDir)$(ProjectName).pdb + $(OutDir)$(ProjectName).pdb Level3 ProgramDatabase true diff --git a/mk/windoze/shared_lib.vcxproj b/mk/windoze/shared_lib.vcxproj index 12b6d70d..82e29994 100644 --- a/mk/windoze/shared_lib.vcxproj +++ b/mk/windoze/shared_lib.vcxproj @@ -96,7 +96,7 @@ Speed false ../../source/shared_lib/include;../../source/shared_lib/include/graphics;../../source/shared_lib/include/graphics/gl;../../source/shared_lib/include/platform;../../source/shared_lib/include/sound;../../source/shared_lib/include/sound/ds8;../../source/shared_lib/include/util;../../source/shared_lib/include/lua;../../source/shared_lib/include/xml;../../source/windows_deps/include;../../source/windows_deps/xerces-c-3.1.1/src;../../source/windows_deps/xerces-c-3.1.1/src/xercesc/xinclude;../../source/windows_deps/lpng1510;../../source/windows_deps/jpeg-8a;../../source/windows_deps/SDL-1.2.15/include;../../source/windows_deps/openal-soft-1.14/include;../../source/shared_lib/include/sound/openal;../../source/shared_lib/include/platform/posix;../../source/shared_lib/include/streflop;../../source/shared_lib/include/streflop/libm_flt32_source;../../source/shared_lib/include/platform/common;../../source/windows_deps/curl-7.21.3/include;../../source/shared_lib/include/map;../../source/shared_lib/include/platform/miniupnpc;../../source/shared_lib/include/libircclient/include;../../source/shared_lib/include/feathery_ftp;../../source/windows_deps/ftgl-2.1.3-rc5/src;../../source/windows_deps/freetype-2.4.4/include;../../source/windows_deps/glew-1.7.0/include;../../source/shared_lib/include/graphics/md5;../../source/shared_lib/include/graphics/freetype-gl;../../source/shared_lib/include/streflop/softfloat;../../source/shared_lib/include/xml/rapidxml;../../source/shared_lib/include/platform/sdl;../../source/shared_lib/include/platform/win32;../../source/windows_deps/vlc-2.0.1/include;../../source/windows_deps/fribidi-0.19.5/lib;../../source/windows_deps/fribidi-0.19.5/charset - WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_PCH=1;USE_STREFLOP;STREFLOP_SSE;STREFLOP_RANDOM_GEN_SIZE=32;LIBM_COMPILING_FLT32;CURL_STATICLIB;UNICODE;USE_FTGL;TA3D_PLATFORM_MSVC;TA3D_PLATFORM_WINDOWS;STATICLIB;USE_FREETYPEGL;XERCES_STATIC_LIBRARY;ZLIB_WINAPI;HAS_LIBVLC;HAVE_FRIBIDI;%(PreprocessorDefinitions) + WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;USE_PCH=1;USE_STREFLOP;STREFLOP_SSE;STREFLOP_RANDOM_GEN_SIZE=32;LIBM_COMPILING_FLT32;CURL_STATICLIB;UNICODE;USE_FTGL;TA3D_PLATFORM_MSVC;TA3D_PLATFORM_WINDOWS;STATICLIB;USE_FREETYPEGL;XERCES_STATIC_LIBRARY;ZLIB_WINAPI;HAS_LIBVLC;HAVE_FRIBIDI;HAVE_GOOGLE_BREAKPAD;%(PreprocessorDefinitions) true Async MultiThreaded @@ -104,7 +104,7 @@ StreamingSIMDExtensions Precise true - $(IntDir)$(ProjectName).pdb + $(OutDir)$(ProjectName).pdb Level3 ProgramDatabase 4250;%(DisableSpecificWarnings) diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index eacf7782..50d4fb8f 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -15,6 +15,10 @@ #include #endif +#ifdef HAVE_GOOGLE_BREAKPAD +#include "exception_handler.h" +#endif + #include "math_wrapper.h" #include "main.h" @@ -56,7 +60,7 @@ #include #endif -#ifdef WIN32 +#if defined WIN32 && !defined(HAVE_GOOGLE_BREAKPAD) #if defined(__WIN32__) && !defined(__GNUC__) #include #endif @@ -78,7 +82,7 @@ #include "conversion.h" #include "leak_dumper.h" -#ifdef WIN32 +#if defined(WIN32) && !defined(HAVE_GOOGLE_BREAKPAD) #ifndef _DEBUG #ifndef __GNUC__ @@ -112,6 +116,10 @@ static FileCRCPreCacheThread *preCacheThread = NULL; static string runtimeErrorMsg = ""; #endif +#ifdef HAVE_GOOGLE_BREAKPAD +std::auto_ptr errorHandlerPtr; +#endif + class NavtiveLanguageNameListCacheGenerator : public SimpleTaskCallbackInterface { virtual void simpleTask(BaseThread *callingThread) { Lang &lang = Lang::getInstance(); @@ -470,7 +478,7 @@ void stackdumper(unsigned int type, EXCEPTION_POINTERS *ep, bool fatalExit) { // ===================================================== // class ExceptionHandler // ===================================================== -#if defined(__WIN32__) && !defined(__GNUC__) +#if defined(WIN32) && !defined(__GNUC__) void ExceptionHandler::handle(LPEXCEPTION_POINTERS pointers) { string msg = "#1 An error occurred and " + string(mg_app_name) + " will close.\nPlease report this bug to: " + string(mailString); msg += ", attaching the generated " + getCrashDumpFileName()+ " file."; @@ -1406,6 +1414,24 @@ void setupLogging(Config &config, bool haveSpecialOutputCommandLineOption) { endPathWithSlash(userData); } +#ifdef HAVE_GOOGLE_BREAKPAD + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#1 In setting up errorHandlerPtr->set_dump_path [%p]...\n",errorHandlerPtr.get()); + if(errorHandlerPtr.get() != NULL) { + string dumpFilePath; + if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") { + dumpFilePath = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey); + } + else { + dumpFilePath = userData; + } + + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#2 In setting up errorHandlerPtr->set_dump_path...\n"); + wstring dumpfilepath = utf8_decode(dumpFilePath); + if(SystemFlags::VERBOSE_MODE_ENABLED) wprintf(L"Hooking up google_breakpad::ExceptionHandler to save dmp files to [%s]...\n",dumpfilepath.c_str()); + errorHandlerPtr->set_dump_path(dumpfilepath); + } +#endif + string debugLogFile = config.getString("DebugLogFile",""); if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") { debugLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugLogFile; @@ -4901,6 +4927,8 @@ int glestMain(int argc, char** argv) { } //throw megaglest_runtime_error("Test!"); + //printf("About to throw an exception...\n"); + //throw 123; //main loop while(program->isShutdownApplicationEnabled() == false && Shared::Platform::Window::handleEvent()) { @@ -5077,6 +5105,7 @@ int glestMain(int argc, char** argv) { ExceptionHandler::handleRuntimeError(ex.c_str(),true); } +#if !defined(HAVE_GOOGLE_BREAKPAD) catch(...) { if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) { soundThreadManager = (program != NULL ? program->getSoundThreadManager(true) : NULL); @@ -5089,6 +5118,7 @@ int glestMain(int argc, char** argv) { ExceptionHandler::handleRuntimeError("Unknown error [main]!",true); } +#endif cleanupCRCThread(); @@ -5139,10 +5169,86 @@ void handleSIGSEGV(int sig) { } #endif +#if defined(HAVE_GOOGLE_BREAKPAD) + +// Callback when minidump written. +static bool MinidumpCallback(const wchar_t *dump_path, + const wchar_t *minidump_id, + void *context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) { + printf("\n======= In MinidumpCallback...\n"); + wprintf(L"\n***ERROR details captured:\nCrash minidump folder: %s\nfile: %s.dmp\nSucceeded: %d\n", (dump_path != NULL ? dump_path : L"(null)"),(minidump_id != NULL ? minidump_id : L"(null)"),succeeded); + +#ifdef WIN32 + wchar_t szBuf[8096]; + _snwprintf(szBuf,8096,L"An unhandled error was detected.\n\nA crash dump file has been created in the folder:\n%s\nCrash dump filename is: %s.dmp",dump_path,minidump_id); + MessageBox(NULL, szBuf, L"Unhandled error", MB_OK|MB_SYSTEMMODAL); + +#endif + + return succeeded; +} +#endif + +#ifdef WIN32 +void EnableCrashingOnCrashes() { + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } +} +#endif + int glestMainWrapper(int argc, char** argv) { //setlocale(LC_ALL, "zh_TW.UTF-8"); //setlocale(LC_ALL, ""); +#ifdef WIN32 + EnableCrashingOnCrashes(); +#endif + +#if defined(HAVE_GOOGLE_BREAKPAD) +/* + handler = new ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name, + const CustomClientInfo* custom_info); +*/ + + // See this link about swallowed exceptions in Win 7: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/ + //DWORD dwFlags; + //if (GetProcessUserModeExceptionPolicy(&dwFlags)) { + // SetProcessUserModeExceptionPolicy(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); // turn off bit 1 + //} + + //if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Hooking up google_breakpad::ExceptionHandler...\n"); + wstring dumpfilepath = utf8_decode("."); + //google_breakpad::ExceptionHandler handler(dumpfilepath, NULL, MinidumpCallback, NULL, true); + errorHandlerPtr.reset(new google_breakpad::ExceptionHandler(dumpfilepath, NULL, MinidumpCallback, NULL, true)); +// ExceptionHandler(const wstring& dump_path, +// FilterCallback filter, +// MinidumpCallback callback, +// void* callback_context, +// int handler_types); + +#endif + #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__FreeBSD__) && !defined(BSD) //#ifdef DEBUG //printf("MTRACE will be called...\n"); @@ -5151,6 +5257,7 @@ int glestMainWrapper(int argc, char** argv) { #endif #ifdef WIN32_STACK_TRACE + printf("Hooking up WIN32_STACK_TRACE...\n"); __try { #endif diff --git a/source/shared_lib/sources/platform/win32/platform_util.cpp b/source/shared_lib/sources/platform/win32/platform_util.cpp index bc986d66..aedf1118 100644 --- a/source/shared_lib/sources/platform/win32/platform_util.cpp +++ b/source/shared_lib/sources/platform/win32/platform_util.cpp @@ -37,17 +37,29 @@ PlatformExceptionHandler *PlatformExceptionHandler::thisPointer= NULL; // Constructs object and convert lpaszString to Unicode LPWSTR Ansi2WideString(LPCSTR lpaszString) { LPWSTR lpwszString(NULL); - int nLen = ::lstrlenA(lpaszString) + 1; - lpwszString = new WCHAR[nLen]; - if (lpwszString == NULL) { - return lpwszString; + + if(lpaszString != NULL) { + int nLen = ::lstrlenA(lpaszString) + 1; + lpwszString = new WCHAR[nLen]; + if (lpwszString == NULL) { + return lpwszString; + } + + memset(lpwszString, 0, nLen * sizeof(WCHAR)); + + if (::MultiByteToWideChar(CP_ACP, 0, lpaszString, nLen, lpwszString, nLen) == 0) { + // Conversation failed + return lpwszString; + } } + else { + int nLen = 1; + lpwszString = new WCHAR[nLen]; + if (lpwszString == NULL) { + return lpwszString; + } - memset(lpwszString, 0, nLen * sizeof(WCHAR)); - - if (::MultiByteToWideChar(CP_ACP, 0, lpaszString, nLen, lpwszString, nLen) == 0) { - // Conversation failed - return lpwszString; + memset(lpwszString, 0, nLen * sizeof(WCHAR)); } return lpwszString; @@ -55,7 +67,12 @@ LPWSTR Ansi2WideString(LPCSTR lpaszString) { // Convert a wide Unicode string to an UTF8 string std::string utf8_encode(const std::wstring &wstr) { - int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); + if(wstr.length() == 0) { + std::string wstrTo; + return wstrTo; + } + + int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); std::string strTo( size_needed, 0 ); WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL); replaceAll(strTo, "/", "\\"); @@ -66,6 +83,10 @@ std::string utf8_encode(const std::wstring &wstr) { // Convert an UTF8 string to a wide Unicode String std::wstring utf8_decode(const std::string &str) { + if(str.length() == 0) { + std::wstring wstrTo; + return wstrTo; + } string friendly_path = str; replaceAll(friendly_path, "/", "\\"); replaceAll(friendly_path, "\\\\", "\\"); @@ -126,7 +147,7 @@ LONG WINAPI PlatformExceptionHandler::handler(LPEXCEPTION_POINTERS pointers){ lExceptionInformation.ExceptionPointers= pointers; lExceptionInformation.ClientPointers= false; -#if defined(__WIN32__) && !defined(__GNUC__) +#if !defined(__GNUC__) MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), @@ -148,7 +169,9 @@ LONG WINAPI PlatformExceptionHandler::handler(LPEXCEPTION_POINTERS pointers){ void PlatformExceptionHandler::install(string dumpFileName){ thisPointer= this; this->dumpFileName= dumpFileName; +#if !defined(HAVE_GOOGLE_BREAKPAD) SetUnhandledExceptionFilter(handler); +#endif } string PlatformExceptionHandler::getStackTrace() {