#import "PLCrashReporter.h" #import "CrashReporter.h" #include 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 }