Breakpad for windows

This enables breakpad Windows support **only**.

The scope of this was limited to allow for inclusion into 0.0.4 release.
Breakpad for now is a Windows-only functionality, as this platform has
largest audience and is the only one that has no system-provided stack
tracing utility.

Upon crash, breakpad will try to create a dump and save current game,
present user with some vital information, then open explorer on the
created files for user convenience, asking him/her to create a new
issue with OpenRCT2 on Github.
This commit is contained in:
Michał Janiszewski 2016-04-07 00:10:12 +02:00
parent e28de49a34
commit 17bc485fb5
9 changed files with 128 additions and 38 deletions

View File

@ -87,6 +87,7 @@
<ClCompile Include="src\openrct2.c" />
<ClCompile Include="src\peep\peep.c" />
<ClCompile Include="src\peep\staff.c" />
<ClCompile Include="src\platform\crash.cpp" />
<ClCompile Include="src\platform\linux.c" />
<ClCompile Include="src\platform\posix.c" />
<ClCompile Include="src\platform\shared.c" />
@ -261,6 +262,7 @@
<ClInclude Include="src\openrct2.h" />
<ClInclude Include="src\peep\peep.h" />
<ClInclude Include="src\peep\staff.h" />
<ClInclude Include="src\platform\crash.h" />
<ClInclude Include="src\platform\platform.h" />
<ClInclude Include="src\rct1.h" />
<ClInclude Include="src\rct2.h" />
@ -329,20 +331,21 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)lib\include;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
<OutDir>$(SolutionDir)bin\</OutDir>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
<LinkIncremental />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)lib\include;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
<OutDir>$(SolutionDir)bin\</OutDir>
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<DisableSpecificWarnings>4091;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
@ -363,6 +366,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<DisableSpecificWarnings>4091;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<WarningLevel>Level3</WarningLevel>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
@ -388,4 +392,4 @@
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>

View File

@ -587,6 +587,7 @@
<ClCompile Include="src\core\textinputbuffer.c">
<Filter>Source\Core</Filter>
</ClCompile>
<ClCompile Include="src\platform\crash.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\management\award.h">
@ -896,5 +897,6 @@
<ClInclude Include="src\core\textinputbuffer.h">
<Filter>Source\Core</Filter>
</ClInclude>
<ClInclude Include="src\platform\crash.h" />
</ItemGroup>
</Project>
</Project>

View File

@ -14,7 +14,7 @@ Import-Module "$scriptsPath\common.psm1" -DisableNameChecking
# Constants
$libsUrl = "https://openrct2.website/files/openrct2-libs-vs2015.zip"
$libsVersion = 6
$libsVersion = 7
# Get paths
$rootPath = Get-RootPath

View File

@ -39,7 +39,7 @@
#include "util/sawyercoding.h"
#include "util/util.h"
#include "world/mapgen.h"
#include "platform/breakpad.h"
#include "platform/crash.h"
#if defined(__unix__)
#include <sys/mman.h>
@ -185,6 +185,12 @@ bool openrct2_initialise()
return false;
}
// Exception handling - breakpad
// Uses user data directory for storing dumps
CExceptionHandler eh;
// never free
eh = newCExceptionHandlerSimple();
if (!openrct2_setup_rct2_segment()) {
log_fatal("Unable to load RCT2 data sector");
return false;
@ -264,12 +270,6 @@ bool openrct2_initialise()
*/
void openrct2_launch()
{
#ifdef USE_BREAKPAD
CExceptionHandler eh;
// never free
eh = newCExceptionHandlerSimple();
#endif // USE_BREAKPAD
if (openrct2_initialise()) {
RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) = 0;
if((gOpenRCT2StartupAction == STARTUP_ACTION_TITLE) && gConfigGeneral.play_intro)

View File

@ -1,19 +0,0 @@
#include "breakpad.h"
#ifdef USE_BREAKPAD
#include "client/linux/handler/exception_handler.h"
#include <stdio.h>
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded) {
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
extern "C" CExceptionHandler newCExceptionHandlerSimple(void)
{
printf("init Simple breakpad\n");
google_breakpad::MinidumpDescriptor descriptor("/tmp");
//google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
return reinterpret_cast<void*>(new google_breakpad::ExceptionHandler(descriptor, NULL, dumpCallback, NULL, true, -1));
}
#endif // USE_BREAKPAD

105
src/platform/crash.cpp Normal file
View File

@ -0,0 +1,105 @@
extern "C" {
#include "platform.h"
#include "../localisation/language.h"
#include "../scenario.h"
}
#include "crash.h"
#include <SDL_platform.h>
#ifdef USE_BREAKPAD
#include <stdio.h>
#ifdef __WINDOWS__
#include <breakpad/client/windows/handler/exception_handler.h>
#include <string>
#include <ShlObj.h>
#define BREAKPAD_PATH "."
#else
#error Breakpad support not implemented yet for this platform
#endif __WINDOWS__
#ifdef __LINUX__
#include <breakpad/client/linux/handler/exception_handler.h>
#define BREAKPAD_PATH "/tmp"
#endif __LINUX__
static bool dumpCallback(const wchar_t *dump_path, const wchar_t *minidump_id, void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion, bool succeeded) {
if (!succeeded) {
const char *msg = "Failed to create the dump. Nothing left to do. Please file an issue with OpenRCT2 on Github and provide latest save.";
log_fatal(msg);
MessageBoxA(NULL, msg, "OpenRCT2", MB_OK);
return succeeded;
}
char *buffer_path = widechar_to_utf8(dump_path);
char *buffer_minidump = widechar_to_utf8(minidump_id);
char dump_file_path[MAX_PATH];
char save_file_path[MAX_PATH];
sprintf(dump_file_path, "%s%s.dmp", buffer_path, buffer_minidump);
sprintf(save_file_path, "%s%s.sv6", buffer_path, buffer_minidump);
log_fatal("Dump path: %s", buffer_path);
log_fatal("minidump id: %s", buffer_minidump);
log_fatal("Version: %s", OPENRCT2_VERSION);
log_fatal("Commit: %s", OPENRCT2_COMMIT_SHA1_SHORT);
SDL_RWops* rw = SDL_RWFromFile(save_file_path, "wb+");
bool saved = false;
if (rw != NULL) {
scenario_save(rw, 0x80000000);
saved = true;
SDL_RWclose(rw);
}
char message[MAX_PATH * 2];
sprintf(message, "A crash has occurred and dump was created at %s. Please create an issue with OpenRCT2 on Github and provide the dump and %s. Version: %s, Commit: %s",
dump_file_path, saved ? save_file_path : "latest save", OPENRCT2_VERSION, OPENRCT2_COMMIT_SHA1_SHORT);
// Cannot use platform_show_messagebox here, it tries to set parent window already dead.
MessageBoxA(NULL, message, "OpenRCT2", MB_OK);
HRESULT coinit_result = CoInitialize(NULL);
if (coinit_result == S_OK) {
//ShellExecute(NULL, "explore", message, NULL, NULL, 5);
ITEMIDLIST *pidl = ILCreateFromPath(buffer_path);
ITEMIDLIST *files[2];
files[0] = ILCreateFromPath(dump_file_path);
int files_count = 1;
if (saved) {
files[1] = ILCreateFromPath(save_file_path);
files_count = 2;
}
if (pidl) {
HRESULT res = SHOpenFolderAndSelectItems(pidl, files_count, (LPCITEMIDLIST *)files, 0);
ILFree(pidl);
ILFree(files[0]);
if (saved) {
ILFree(files[1]);
}
}
CoUninitialize();
}
free(buffer_path);
free(buffer_minidump);
return succeeded;
}
#endif // USE_BREAKPAD
extern "C" CExceptionHandler newCExceptionHandlerSimple(void)
{
#ifdef USE_BREAKPAD
char path[MAX_PATH];
platform_get_user_directory(path, NULL);
wchar_t *wpath_buffer = utf8_to_widechar(path);
std::wstring wpath(wpath_buffer);
free(wpath_buffer);
// Path must exist and be RW!
return reinterpret_cast<void*>(new google_breakpad::ExceptionHandler(
wpath,
0,
dumpCallback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL,
MiniDumpNormal,
L"openrct2-bpad", // using non-null pipe name here lets breakpad try setting OOP crash handling
0 ));
#else // USE_BREAKPAD
return nullptr;
#endif // USE_BREAKPAD
}

View File

@ -1,7 +1,6 @@
#ifndef _OPENRCT2_BREAKPAD_
#define _OPENRCT2_BREAKPAD_
#ifndef _OPENRCT2_CRASH_
#define _OPENRCT2_CRASH_
#ifdef USE_BREAKPAD
typedef void* CExceptionHandler;
#ifdef __cplusplus
@ -12,6 +11,5 @@ CExceptionHandler newCExceptionHandlerSimple(void);
#ifdef __cplusplus
}
#endif
#endif // USE_BREAKPAD
#endif /* _OPENRCT2_BREAKPAD_ */
#endif /* _OPENRCT2_CRASH_ */

View File

@ -811,7 +811,7 @@ void platform_free()
SDL_Quit();
}
void platform_start_text_input(char* buffer, int max_length)
void platform_start_text_input(utf8* buffer, int max_length)
{
// TODO This doesn't work, and position could be improved to where text entry is
SDL_Rect rect = { 10, 10, 100, 100 };

View File

@ -573,7 +573,7 @@ void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory)
}
}
void platform_show_messagebox(char *message)
void platform_show_messagebox(utf8 *message)
{
MessageBoxA(windows_get_window_handle(), message, "OpenRCT2", MB_OK);
}