2016-05-04 19:24:41 +02:00
# pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2 , an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors , a full list can be found in contributors . md
* For more information , visit https : //github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* A full copy of the GNU General Public License can be found in licence . txt
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# pragma endregion
2016-04-07 00:10:12 +02:00
# include <SDL_platform.h>
2016-04-10 00:30:10 +02:00
# include "crash.h"
2016-04-07 00:10:12 +02:00
# ifdef USE_BREAKPAD
# include <stdio.h>
2016-04-10 00:30:10 +02:00
# if defined(__WINDOWS__)
# include <breakpad/client/windows/handler/exception_handler.h>
# include <string>
# include <ShlObj.h>
# elif defined(__LINUX__)
# include <breakpad/client/linux/handler/exception_handler.h>
# define BREAKPAD_PATH " / tmp"
2016-04-07 00:10:12 +02:00
# else
2016-04-10 00:30:10 +02:00
# error Breakpad support not implemented yet for this platform
# endif
2016-04-07 00:10:12 +02:00
2016-04-09 19:21:40 +02:00
extern " C " {
2016-04-10 00:30:10 +02:00
# include "../localisation/language.h"
# include "../scenario.h"
# include "platform.h"
}
# include "../core/Console.hpp"
# define WSZ(x) L"" x
static bool OnCrash ( const wchar_t * dumpPath ,
const wchar_t * miniDumpId ,
void * context ,
EXCEPTION_POINTERS * exinfo ,
MDRawAssertionInfo * assertion ,
bool succeeded )
{
if ( ! succeeded )
{
2016-04-10 20:51:44 +02:00
constexpr const char * DumpFailedMessage = " Failed to create the dump. Nothing left to do. Please file an issue with OpenRCT2 on Github and provide latest save. " ;
2016-04-10 00:30:10 +02:00
printf ( " %s \n " , DumpFailedMessage ) ;
2016-05-11 13:25:21 +02:00
if ( ! gOpenRCT2SilentBreakpad )
{
MessageBoxA ( NULL , DumpFailedMessage , OPENRCT2_NAME , MB_OK | MB_ICONERROR ) ;
}
2016-04-10 00:30:10 +02:00
return succeeded ;
}
wchar_t dumpFilePath [ MAX_PATH ] ;
wchar_t saveFilePath [ MAX_PATH ] ;
wsprintfW ( dumpFilePath , L " %s%s.dmp " , dumpPath , miniDumpId ) ;
wsprintfW ( saveFilePath , L " %s%s.sv6 " , dumpPath , miniDumpId ) ;
wprintf ( L " Dump Path: %s \n " , dumpFilePath ) ;
wprintf ( L " Dump Id: %s \n " , miniDumpId ) ;
wprintf ( L " Version: %s \n " , WSZ ( OPENRCT2_VERSION ) ) ;
wprintf ( L " Commit: %s \n " , WSZ ( OPENRCT2_COMMIT_SHA1_SHORT ) ) ;
utf8 * saveFilePathUTF8 = widechar_to_utf8 ( saveFilePath ) ;
SDL_RWops * rw = SDL_RWFromFile ( saveFilePathUTF8 , " wb+ " ) ;
free ( saveFilePathUTF8 ) ;
bool savedGameDumped = false ;
if ( rw ! = NULL ) {
scenario_save ( rw , 0x80000000 ) ;
savedGameDumped = true ;
SDL_RWclose ( rw ) ;
}
2016-05-11 13:25:21 +02:00
if ( gOpenRCT2SilentBreakpad )
{
return succeeded ;
}
2016-04-10 20:51:44 +02:00
constexpr const wchar_t * MessageFormat = L " A crash has occurred and dump was created at \n %s. \n \n Please create an issue with OpenRCT2 on Github and provide the dump and save. \n \n Version: %s \n Commit: %s " ;
2016-04-10 00:30:10 +02:00
wchar_t message [ MAX_PATH * 2 ] ;
swprintf_s ( message ,
MessageFormat ,
dumpFilePath ,
WSZ ( OPENRCT2_VERSION ) ,
WSZ ( OPENRCT2_COMMIT_SHA1_SHORT ) ) ;
// Cannot use platform_show_messagebox here, it tries to set parent window already dead.
MessageBoxW ( NULL , message , WSZ ( OPENRCT2_NAME ) , MB_OK | MB_ICONERROR ) ;
HRESULT coInitializeResult = CoInitialize ( NULL ) ;
if ( SUCCEEDED ( coInitializeResult ) )
{
ITEMIDLIST * pidl = ILCreateFromPathW ( dumpPath ) ;
ITEMIDLIST * files [ 2 ] ;
uint32 numFiles = 0 ;
files [ numFiles + + ] = ILCreateFromPathW ( dumpFilePath ) ;
if ( savedGameDumped )
{
files [ numFiles + + ] = ILCreateFromPathW ( saveFilePath ) ;
}
if ( pidl ! = nullptr ) {
HRESULT result = SHOpenFolderAndSelectItems ( pidl , numFiles , ( LPCITEMIDLIST * ) files , 0 ) ;
ILFree ( pidl ) ;
for ( uint32 i = 0 ; i < numFiles ; i + + )
{
ILFree ( files [ i ] ) ;
}
}
CoUninitialize ( ) ;
}
// Return whether the dump was successful
return succeeded ;
2016-04-09 19:21:40 +02:00
}
2016-04-10 00:30:10 +02:00
static std : : wstring GetDumpDirectory ( )
{
char userDirectory [ MAX_PATH ] ;
platform_get_user_directory ( userDirectory , NULL ) ;
wchar_t * userDirectoryW = utf8_to_widechar ( userDirectory ) ;
auto result = std : : wstring ( userDirectoryW ) ;
free ( userDirectoryW ) ;
2016-04-07 00:10:12 +02:00
2016-04-10 00:30:10 +02:00
return result ;
2016-04-07 00:10:12 +02:00
}
2016-04-10 00:30:10 +02:00
2016-04-07 00:10:12 +02:00
# endif // USE_BREAKPAD
2016-04-10 00:30:10 +02:00
// Using non-null pipe name here lets breakpad try setting OOP crash handling
2016-04-10 20:51:44 +02:00
constexpr const wchar_t * PipeName = L " openrct2-bpad " ;
2016-04-10 00:30:10 +02:00
extern " C " CExceptionHandler crash_init ( )
2016-04-07 00:10:12 +02:00
{
# ifdef USE_BREAKPAD
2016-04-10 00:30:10 +02:00
// Path must exist and be RW!
auto exHandler = new google_breakpad : : ExceptionHandler (
GetDumpDirectory ( ) ,
0 ,
OnCrash ,
0 ,
google_breakpad : : ExceptionHandler : : HANDLER_ALL ,
MiniDumpWithDataSegs ,
PipeName ,
0 ) ;
return reinterpret_cast < CExceptionHandler > ( exHandler ) ;
2016-04-07 00:10:12 +02:00
# else // USE_BREAKPAD
2016-04-10 00:30:10 +02:00
return nullptr ;
2016-04-07 00:10:12 +02:00
# endif // USE_BREAKPAD
}