127 lines
3.9 KiB
Plaintext
127 lines
3.9 KiB
Plaintext
|
#import "PLCrashReporter.h"
|
||
|
#import "CrashReporter.h"
|
||
|
#include <mach-o/ldsyms.h>
|
||
|
|
||
|
extern "C" NSString* UnityGetCrashReportsPath();
|
||
|
|
||
|
|
||
|
static NSUncaughtExceptionHandler* gsCrashReporterUEHandler = NULL;
|
||
|
|
||
|
extern "C" uint8_t* UnityGetAppLoadAddress()
|
||
|
{
|
||
|
// _mh_execute_header points to a mach header, and is located right at the address of where the
|
||
|
// app is loaded.
|
||
|
return (uint8_t*)&_mh_execute_header;
|
||
|
}
|
||
|
|
||
|
extern "C" const uint8_t * UnityGetAppLoadCommandAddress()
|
||
|
{
|
||
|
return (const uint8_t*)(&_mh_execute_header + 1);
|
||
|
}
|
||
|
|
||
|
extern "C" int UnityGetAppLoadCommandCount()
|
||
|
{
|
||
|
return _mh_execute_header.ncmds;
|
||
|
}
|
||
|
|
||
|
static void SavePendingCrashReport()
|
||
|
{
|
||
|
if (![[UnityPLCrashReporter sharedReporter] hasPendingCrashReport])
|
||
|
return;
|
||
|
|
||
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||
|
NSError *error;
|
||
|
|
||
|
if (![fm createDirectoryAtPath: UnityGetCrashReportsPath() withIntermediateDirectories: YES attributes: nil error: &error])
|
||
|
{
|
||
|
::printf("CrashReporter: could not create crash report directory: %s\n", [[error localizedDescription] UTF8String]);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NSData *data = [[UnityPLCrashReporter sharedReporter] loadPendingCrashReportDataAndReturnError: &error];
|
||
|
if (data == nil)
|
||
|
{
|
||
|
::printf("CrashReporter: failed to load crash report data: %s\n", [[error localizedDescription] UTF8String]);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NSString* file = [UnityGetCrashReportsPath() stringByAppendingPathComponent: @"crash-"];
|
||
|
unsigned long long seconds = (unsigned long long)[[NSDate date] timeIntervalSince1970];
|
||
|
file = [file stringByAppendingString: [NSString stringWithFormat: @"%llu", seconds]];
|
||
|
file = [file stringByAppendingString: @".plcrash"];
|
||
|
if ([data writeToFile: file atomically: YES])
|
||
|
{
|
||
|
::printf("CrashReporter: saved pending crash report.\n");
|
||
|
if (![[UnityPLCrashReporter sharedReporter] purgePendingCrashReportAndReturnError: &error])
|
||
|
{
|
||
|
::printf("CrashReporter: couldn't remove pending report: %s\n", [[error localizedDescription] UTF8String]);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
::printf("CrashReporter: couldn't save crash report.\n");
|
||
|
}
|
||
|
|
||
|
// Now copy out a pending version that we can delete if/when we send it
|
||
|
file = [UnityGetCrashReportsPath() stringByAppendingPathComponent: @"crash-pending.plcrash"];
|
||
|
if ([data writeToFile: file atomically: YES])
|
||
|
{
|
||
|
::printf("CrashReporter: saved copy of pending crash report.\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
::printf("CrashReporter: couldn't save copy of pending crash report.\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void InitCrashReporter()
|
||
|
{
|
||
|
NSError *error;
|
||
|
|
||
|
UnityInstallPostCrashCallback();
|
||
|
if ([[UnityPLCrashReporter sharedReporter] enableCrashReporterAndReturnError: &error])
|
||
|
::printf("CrashReporter: initialized\n");
|
||
|
else
|
||
|
NSLog(@"CrashReporter: could not enable crash reporter: %@", error);
|
||
|
|
||
|
SavePendingCrashReport();
|
||
|
}
|
||
|
|
||
|
static void UncaughtExceptionHandler(NSException *exception)
|
||
|
{
|
||
|
NSLog(@"Uncaught exception: %@: %@\n%@", [exception name], [exception reason], [exception callStackSymbols]);
|
||
|
if (gsCrashReporterUEHandler)
|
||
|
gsCrashReporterUEHandler(exception);
|
||
|
}
|
||
|
|
||
|
static void InitObjCUEHandler()
|
||
|
{
|
||
|
// Crash reporter sets its own handler, so we have to save it and call it manually
|
||
|
gsCrashReporterUEHandler = NSGetUncaughtExceptionHandler();
|
||
|
NSSetUncaughtExceptionHandler(&UncaughtExceptionHandler);
|
||
|
}
|
||
|
|
||
|
void InitCrashHandling()
|
||
|
{
|
||
|
#if ENABLE_CUSTOM_CRASH_REPORTER
|
||
|
InitCrashReporter();
|
||
|
#endif
|
||
|
|
||
|
#if ENABLE_OBJC_UNCAUGHT_EXCEPTION_HANDLER
|
||
|
InitObjCUEHandler();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// This function will be called when AppDomain.CurrentDomain.UnhandledException event is triggered.
|
||
|
// When running on device the app will do a hard crash and it will generate a crash log.
|
||
|
extern "C" void CrashedCheckBelowForHintsWhy()
|
||
|
{
|
||
|
#if ENABLE_IOS_CRASH_REPORTING || ENABLE_CUSTOM_CRASH_REPORTER
|
||
|
// Make app crash hard here
|
||
|
__builtin_trap();
|
||
|
|
||
|
// Just in case above doesn't work
|
||
|
abort();
|
||
|
#endif
|
||
|
}
|