diff --git a/Source/Bugsnag.h b/Source/Bugsnag.h index 853f73d4..581f2e67 100644 --- a/Source/Bugsnag.h +++ b/Source/Bugsnag.h @@ -201,4 +201,7 @@ static NSString *_Nonnull const BugsnagSeverityInfo = @"info"; + (NSDateFormatter *_Nonnull)payloadDateFormatter; ++ (void)setSuspendThreadsForUserReported:(BOOL)suspendThreadsForUserReported; ++ (void)setReportWhenDebuggerIsAttached:(BOOL)reportWhenDebuggerIsAttached; + @end diff --git a/Source/Bugsnag.m b/Source/Bugsnag.m index a6094df1..613c2885 100644 --- a/Source/Bugsnag.m +++ b/Source/Bugsnag.m @@ -30,6 +30,7 @@ #import "BugsnagNotifier.h" #import "BugsnagSink.h" #import "BugsnagLogger.h" +#import "BSG_KSCrash.h" static BugsnagNotifier* bsg_g_bugsnag_notifier = NULL; @@ -186,6 +187,14 @@ + (NSDateFormatter *)payloadDateFormatter { return formatter; } ++ (void)setSuspendThreadsForUserReported:(BOOL)suspendThreadsForUserReported { + [[BSG_KSCrash sharedInstance] setSuspendThreadsForUserReported:suspendThreadsForUserReported]; +} + ++ (void)setReportWhenDebuggerIsAttached:(BOOL)reportWhenDebuggerIsAttached { + [[BSG_KSCrash sharedInstance] setReportWhenDebuggerIsAttached:reportWhenDebuggerIsAttached]; +} + @end // diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h index 470f4bc2..e8156bad 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h @@ -190,6 +190,21 @@ typedef enum stackTrace:(NSArray*) stackTrace terminateProgram:(BOOL) terminateProgram; +/** If YES, user reported exceptions will suspend all threads during report generation. + * All threads will be suspended while generating a crash report for a user + * reported exception. + * + * Default: YES + */ +@property(nonatomic,readwrite,assign) BOOL suspendThreadsForUserReported; + +/** If YES, reports will be sent even if a debugger is attached + * + * Default: NO + */ +@property(nonatomic,readwrite,assign) BOOL reportWhenDebuggerIsAttached; + + @end //! Project version number for BSG_KSCrashFramework. diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m index bb6726b4..4f9b5242 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m @@ -107,6 +107,8 @@ @implementation BSG_KSCrash @synthesize catchZombies = _catchZombies; @synthesize doNotIntrospectClasses = _doNotIntrospectClasses; @synthesize maxStoredReports = _maxStoredReports; +@synthesize suspendThreadsForUserReported = _suspendThreadsForUserReported; +@synthesize reportWhenDebuggerIsAttached = _reportWhenDebuggerIsAttached; // ============================================================================ @@ -180,6 +182,8 @@ - (id) initWithReportFilesDirectory:(NSString *)reportFilesDirectory self.introspectMemory = YES; self.catchZombies = NO; self.maxStoredReports = 5; + self.suspendThreadsForUserReported = YES; + self.reportWhenDebuggerIsAttached = NO; } return self; @@ -260,6 +264,16 @@ - (void) setCatchZombies:(bool)catchZombies bsg_kscrash_setCatchZombies(catchZombies); } +- (void)setSuspendThreadsForUserReported:(BOOL) suspendThreadsForUserReported { + _suspendThreadsForUserReported = suspendThreadsForUserReported; + bsg_kscrash_setSuspendThreadsForUserReported(suspendThreadsForUserReported); +} + +- (void)setReportWhenDebuggerIsAttached:(BOOL)reportWhenDebuggerIsAttached { + _reportWhenDebuggerIsAttached = reportWhenDebuggerIsAttached; + bsg_kscrash_setReportWhenDebuggerIsAttached(reportWhenDebuggerIsAttached); +} + - (void) setDoNotIntrospectClasses:(NSArray *)doNotIntrospectClasses { _doNotIntrospectClasses = doNotIntrospectClasses; diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c index a074d119..fb9475e9 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c @@ -290,3 +290,11 @@ void bsg_kscrash_reportUserException(const char* name, stackTrace, terminateProgram); } + +void bsg_kscrash_setSuspendThreadsForUserReported(bool suspendThreadsForUserReported) { + crashContext()->crash.suspendThreadsForUserReported = suspendThreadsForUserReported; +} + +void bsg_kscrash_setReportWhenDebuggerIsAttached(bool reportWhenDebuggerIsAttached) { + crashContext()->crash.reportWhenDebuggerIsAttached = reportWhenDebuggerIsAttached; +} diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h index 29087eff..b55470f1 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h @@ -195,6 +195,22 @@ void bsg_kscrash_reportUserException(const char* name, const char* lineOfCode, const char* stackTrace, bool terminateProgram); + + +/** If YES, user reported exceptions will suspend all threads during report generation. + * All threads will be suspended while generating a crash report for a user + * reported exception. + * + * Default: YES + */ +void bsg_kscrash_setSuspendThreadsForUserReported(bool suspendThreadsForUserReported); + +/** If YES, user reported exceptions even if a debugger is attached + * + * Default: NO + */ +void bsg_kscrash_setReportWhenDebuggerIsAttached(bool reportWhenDebuggerIsAttached); + #ifdef __cplusplus } diff --git a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c index 75d77760..dc8a77bc 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c +++ b/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.c @@ -2182,7 +2182,10 @@ void bsg_kscrashreport_writeStandardReport(BSG_KSCrash_Context* const crashConte crashContext->config.crashID, crashContext->config.processName); - bsg_kscrw_i_writeBinaryImages(writer, BSG_KSCrashField_BinaryImages); + // Don't write the binary images for user reported crashes to improve performance + if (crashContext->crash.crashType != BSG_KSCrashTypeUserReported) { // TODO!!! + bsg_kscrw_i_writeBinaryImages(writer, BSG_KSCrashField_BinaryImages); + } bsg_kscrw_i_writeProcessState(writer, BSG_KSCrashField_ProcessState); @@ -2205,13 +2208,16 @@ void bsg_kscrashreport_writeStandardReport(BSG_KSCrash_Context* const crashConte writer->beginObject(writer, BSG_KSCrashField_Crash); { - bsg_kscrw_i_writeAllThreads(writer, - BSG_KSCrashField_Threads, - &crashContext->crash, - crashContext->config.introspectionRules.enabled, - crashContext->config.searchThreadNames, - crashContext->config.searchQueueNames); - bsg_kscrw_i_writeError(writer, BSG_KSCrashField_Error, &crashContext->crash); + // Don't write the threads for user reported crashes to improve performance + if (crashContext->crash.crashType != BSG_KSCrashTypeUserReported) { // TODO!!! + bsg_kscrw_i_writeAllThreads(writer, + BSG_KSCrashField_Threads, + &crashContext->crash, + crashContext->config.introspectionRules.enabled, + crashContext->config.searchThreadNames, + crashContext->config.searchQueueNames); + bsg_kscrw_i_writeError(writer, BSG_KSCrashField_Error, &crashContext->crash); + } } writer->endContainer(writer); diff --git a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c index 6a2c1ed6..201325c6 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c +++ b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c @@ -102,12 +102,15 @@ static bool bsg_g_threads_are_running = true; BSG_KSCrashType bsg_kscrashsentry_installWithContext(BSG_KSCrash_SentryContext* context, BSG_KSCrashType crashTypes, - void (*onCrash)(void)) -{ - if(bsg_ksmachisBeingTraced()) - { - BSG_KSLOGBASIC_WARN("KSCrash: App is running in a debugger. Only user reported events will be handled."); - crashTypes = BSG_KSCrashTypeUserReported; + void (*onCrash)(void)) { + if (bsg_ksmachisBeingTraced()) { + if (context->reportWhenDebuggerIsAttached) { + BSG_KSLOG_WARN("KSCrash: App is running in a debugger. Crash handling is enabled via configuration."); + BSG_KSLOG_INFO("Installing handlers with context %p, crash types 0x%x.", context, crashTypes); + } else { + BSG_KSLOG_WARN("KSCrash: App is running in a debugger. Only user reported events will be handled."); + crashTypes = BSG_KSCrashTypeUserReported; + } } else { diff --git a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h index 621b129d..3ced5541 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h +++ b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h @@ -58,7 +58,12 @@ typedef struct BSG_KSCrash_SentryContext /** Called by the crash handler when a crash is detected. */ void (*onCrash)(void); - + + /** If true, will suspend threads for user reported exceptions. */ + bool suspendThreadsForUserReported; + + /** If true, will send reports even if debugger is attached. */ + bool reportWhenDebuggerIsAttached; // Implementation defined values. Caller does not initialize these. diff --git a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c index 71afefd8..cb0c2012 100644 --- a/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c +++ b/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c @@ -65,8 +65,10 @@ void bsg_kscrashsentry_reportUserException(const char* name, { bsg_kscrashsentry_beginHandlingCrash(bsg_g_context); - BSG_KSLOG_DEBUG("Suspending all threads"); - bsg_kscrashsentry_suspendThreads(); + if (bsg_g_context->suspendThreadsForUserReported) { + BSG_KSLOG_DEBUG("Suspending all threads"); + bsg_kscrashsentry_suspendThreads(); + } BSG_KSLOG_DEBUG("Fetching call stack."); int callstackCount = 100;