diff --git a/CHANGELOG.md b/CHANGELOG.md index 848fa53787a..e53ceff802e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - Properties on SentryOptions that had no effect on the WithoutUIKit variant are now removed from the API (#6644) - Removes the SentryOptions.inAppExclude property because it had no effect (#6646) - Removes segment property on SentryUser, SentryBaggage, and SentryTraceContext (#5638) +- Removes local symbolication when `debug=True` which fixes various deadlocks (#6562) - Removes deprecated TraceContext initializers (#6348) - Removes deprecated user feedback API, this is replaced with the new feedback API (#5591) - Removes `enablePerformanceV2` option and makes this the default. The app start duration will now finish when the first frame is drawn instead of when the OS posts the UIWindowDidBecomeVisibleNotification. (#6008) diff --git a/Sentry.xcodeproj/project.pbxproj b/Sentry.xcodeproj/project.pbxproj index 8d48bfba522..3e98255b447 100644 --- a/Sentry.xcodeproj/project.pbxproj +++ b/Sentry.xcodeproj/project.pbxproj @@ -254,7 +254,6 @@ 63FE711B20DA4C1000CDBAE8 /* SentryCrashString.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701420DA4C1000CDBAE8 /* SentryCrashString.c */; }; 63FE711D20DA4C1000CDBAE8 /* SentryCrashCPU_arm64.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701520DA4C1000CDBAE8 /* SentryCrashCPU_arm64.c */; }; 63FE711F20DA4C1000CDBAE8 /* SentryCrashObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE701620DA4C1000CDBAE8 /* SentryCrashObjC.h */; }; - 63FE712120DA4C1000CDBAE8 /* SentryCrashSymbolicator.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701720DA4C1000CDBAE8 /* SentryCrashSymbolicator.c */; }; 63FE712320DA4C1000CDBAE8 /* SentryCrashID.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE701820DA4C1000CDBAE8 /* SentryCrashID.h */; }; 63FE712520DA4C1000CDBAE8 /* SentryCrashSignalInfo.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701920DA4C1000CDBAE8 /* SentryCrashSignalInfo.c */; }; 63FE712720DA4C1000CDBAE8 /* SentryCrashThread.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE701A20DA4C1000CDBAE8 /* SentryCrashThread.c */; }; @@ -283,7 +282,6 @@ 63FE715720DA4C1100CDBAE8 /* SentryCrashThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703220DA4C1000CDBAE8 /* SentryCrashThread.h */; }; 63FE715920DA4C1100CDBAE8 /* SentryCrashCPU_x86_32.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE703320DA4C1000CDBAE8 /* SentryCrashCPU_x86_32.c */; }; 63FE715B20DA4C1100CDBAE8 /* SentryCrashSignalInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703420DA4C1000CDBAE8 /* SentryCrashSignalInfo.h */; }; - 63FE715D20DA4C1100CDBAE8 /* SentryCrashSymbolicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703520DA4C1000CDBAE8 /* SentryCrashSymbolicator.h */; }; 63FE715F20DA4C1100CDBAE8 /* SentryCrashID.c in Sources */ = {isa = PBXBuildFile; fileRef = 63FE703620DA4C1000CDBAE8 /* SentryCrashID.c */; }; 63FE716320DA4C1100CDBAE8 /* SentryCrashDynamicLinker.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703820DA4C1000CDBAE8 /* SentryCrashDynamicLinker.h */; }; 63FE716520DA4C1100CDBAE8 /* SentryCrashMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 63FE703920DA4C1000CDBAE8 /* SentryCrashMemory.h */; }; @@ -1592,7 +1590,6 @@ 63FE701420DA4C1000CDBAE8 /* SentryCrashString.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashString.c; sourceTree = ""; }; 63FE701520DA4C1000CDBAE8 /* SentryCrashCPU_arm64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashCPU_arm64.c; sourceTree = ""; }; 63FE701620DA4C1000CDBAE8 /* SentryCrashObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashObjC.h; sourceTree = ""; }; - 63FE701720DA4C1000CDBAE8 /* SentryCrashSymbolicator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashSymbolicator.c; sourceTree = ""; }; 63FE701820DA4C1000CDBAE8 /* SentryCrashID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashID.h; sourceTree = ""; }; 63FE701920DA4C1000CDBAE8 /* SentryCrashSignalInfo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashSignalInfo.c; sourceTree = ""; }; 63FE701A20DA4C1000CDBAE8 /* SentryCrashThread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashThread.c; sourceTree = ""; }; @@ -1621,7 +1618,6 @@ 63FE703220DA4C1000CDBAE8 /* SentryCrashThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryCrashThread.h; path = ../../../Sentry/include/SentryCrashThread.h; sourceTree = ""; }; 63FE703320DA4C1000CDBAE8 /* SentryCrashCPU_x86_32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashCPU_x86_32.c; sourceTree = ""; }; 63FE703420DA4C1000CDBAE8 /* SentryCrashSignalInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashSignalInfo.h; sourceTree = ""; }; - 63FE703520DA4C1000CDBAE8 /* SentryCrashSymbolicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashSymbolicator.h; sourceTree = ""; }; 63FE703620DA4C1000CDBAE8 /* SentryCrashID.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SentryCrashID.c; sourceTree = ""; }; 63FE703820DA4C1000CDBAE8 /* SentryCrashDynamicLinker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SentryCrashDynamicLinker.h; path = ../../../Sentry/include/SentryCrashDynamicLinker.h; sourceTree = ""; }; 63FE703920DA4C1000CDBAE8 /* SentryCrashMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SentryCrashMemory.h; sourceTree = ""; }; @@ -3371,8 +3367,6 @@ 63FE701C20DA4C1000CDBAE8 /* SentryCrashStackCursor.h */, 63FE701420DA4C1000CDBAE8 /* SentryCrashString.c */, 63FE702C20DA4C1000CDBAE8 /* SentryCrashString.h */, - 63FE701720DA4C1000CDBAE8 /* SentryCrashSymbolicator.c */, - 63FE703520DA4C1000CDBAE8 /* SentryCrashSymbolicator.h */, 63FE701E20DA4C1000CDBAE8 /* SentryCrashSysCtl.c */, 63FE703D20DA4C1000CDBAE8 /* SentryCrashSysCtl.h */, 63FE701A20DA4C1000CDBAE8 /* SentryCrashThread.c */, @@ -5243,7 +5237,6 @@ 639FCF981EBC7B9700778193 /* SentryEvent.h in Headers */, 03F84D2527DD414C008FE43F /* SentryThreadState.hpp in Headers */, 8E4E7C6D25DAAAFE006AB9E2 /* SentryTransaction.h in Headers */, - 63FE715D20DA4C1100CDBAE8 /* SentryCrashSymbolicator.h in Headers */, FAE2DABA2E1F318900262307 /* SentryProfilingSwiftHelpers.h in Headers */, D8ACE3CF2762187D00F5A213 /* SentryFileIOTrackingIntegration.h in Headers */, FA27ECA12EBA325A00F2ECF7 /* SentryTraceContext+Private.h in Headers */, @@ -6067,7 +6060,6 @@ 63FE716720DA4C1100CDBAE8 /* SentryCrashCPU.c in Sources */, 63FE717320DA4C1100CDBAE8 /* SentryCrashC.c in Sources */, 6293F5752D422A95002BC3BD /* SentryStacktraceCodable.swift in Sources */, - 63FE712120DA4C1000CDBAE8 /* SentryCrashSymbolicator.c in Sources */, 627C77892D50B6840055E966 /* SentryBreadcrumbCodable.swift in Sources */, 63FE70D720DA4C1000CDBAE8 /* SentryCrashMonitor_MachException.c in Sources */, 7B96572226830D2400C66E25 /* SentryScopeSyncC.c in Sources */, diff --git a/Sources/Sentry/SentryCrashReportConverter.m b/Sources/Sentry/SentryCrashReportConverter.m index 7097414c8c8..0195d351ee8 100644 --- a/Sources/Sentry/SentryCrashReportConverter.m +++ b/Sources/Sentry/SentryCrashReportConverter.m @@ -307,15 +307,13 @@ - (SentryFrame *)stackFrameAtIndex:(NSInteger)frameIndex inThreadIndex:(NSIntege = (uintptr_t)[frameDictionary[@"instruction_addr"] unsignedLongLongValue]; NSDictionary *binaryImage = [self binaryImageForAddress:instructionAddress]; SentryFrame *frame = [[SentryFrame alloc] init]; - frame.symbolAddress = sentry_formatHexAddress(frameDictionary[@"symbol_addr"]); + // The symbol address is not known, so it defaults to 0 + frame.symbolAddress = @"0x0000000000000000"; frame.instructionAddress = sentry_formatHexAddress(frameDictionary[@"instruction_addr"]); frame.imageAddress = sentry_formatHexAddress(binaryImage[@"image_addr"]); frame.package = binaryImage[@"name"]; BOOL isInApp = [self.inAppLogic isInApp:binaryImage[@"name"]]; frame.inApp = @(isInApp); - if (frameDictionary[@"symbol_name"]) { - frame.function = frameDictionary[@"symbol_name"]; - } return frame; } diff --git a/Sources/Sentry/SentryCrashStackEntryMapper.m b/Sources/Sentry/SentryCrashStackEntryMapper.m index 78066fb1fda..f826330d981 100644 --- a/Sources/Sentry/SentryCrashStackEntryMapper.m +++ b/Sources/Sentry/SentryCrashStackEntryMapper.m @@ -25,36 +25,15 @@ - (SentryFrame *)sentryCrashStackEntryToSentryFrame:(SentryCrashStackEntry)stack { SentryFrame *frame = [[SentryFrame alloc] init]; - if (stackEntry.symbolAddress != 0) { - frame.symbolAddress = sentry_formatHexAddressUInt64(stackEntry.symbolAddress); - } - frame.instructionAddress = sentry_formatHexAddressUInt64(stackEntry.address); - if (stackEntry.symbolName != NULL) { - frame.function = [NSString stringWithCString:stackEntry.symbolName - encoding:NSUTF8StringEncoding]; - } - - // If there is no symbolication, because debug was disabled - // we get image from the cache. - if (stackEntry.imageAddress == 0 && stackEntry.imageName == NULL) { - SentryBinaryImageInfo *info = [SentryDependencyContainer.sharedInstance.binaryImageCache - imageByAddress:(uint64_t)stackEntry.address]; - - frame.imageAddress = sentry_formatHexAddressUInt64(info.address); - frame.package = info.name; - frame.inApp = @([self.inAppLogic isInApp:info.name]); - } else { - frame.imageAddress = sentry_formatHexAddressUInt64(stackEntry.imageAddress); + // Get image from the cache. + SentryBinaryImageInfo *info = [SentryDependencyContainer.sharedInstance.binaryImageCache + imageByAddress:(uint64_t)stackEntry.address]; - if (stackEntry.imageName != NULL) { - NSString *imageName = [NSString stringWithCString:stackEntry.imageName - encoding:NSUTF8StringEncoding]; - frame.package = imageName; - frame.inApp = @([self.inAppLogic isInApp:imageName]); - } - } + frame.imageAddress = sentry_formatHexAddressUInt64(info.address); + frame.package = info.name; + frame.inApp = @([self.inAppLogic isInApp:info.name]); return frame; } diff --git a/Sources/Sentry/SentryDefaultThreadInspector.m b/Sources/Sentry/SentryDefaultThreadInspector.m index d6abeb394db..7b5446304b6 100644 --- a/Sources/Sentry/SentryDefaultThreadInspector.m +++ b/Sources/Sentry/SentryDefaultThreadInspector.m @@ -3,7 +3,6 @@ #import "SentryCrashStackCursor.h" #include "SentryCrashStackCursor_MachineContext.h" #import "SentryCrashStackEntryMapper.h" -#include "SentryCrashSymbolicator.h" #import "SentryFrame.h" #import "SentryOptions.h" #import "SentryStacktrace.h" @@ -32,7 +31,7 @@ @interface SentryDefaultThreadInspector () // async-signal-safe. unsigned int getStackEntriesFromThread(SentryCrashThread thread, struct SentryCrashMachineContext *context, - SentryCrashStackEntry *buffer, unsigned int maxEntries, bool asyncUnsafeSymbolicate) + SentryCrashStackEntry *buffer, unsigned int maxEntries) { sentrycrashmc_getContextForThread(thread, context, NO); SentryCrashStackCursor stackCursor; @@ -43,10 +42,8 @@ @interface SentryDefaultThreadInspector () while (stackCursor.advanceCursor(&stackCursor)) { if (entries == maxEntries) break; - if (asyncUnsafeSymbolicate == false || stackCursor.symbolicate(&stackCursor)) { - buffer[entries] = stackCursor.stackEntry; - entries++; - } + buffer[entries] = stackCursor.stackEntry; + entries++; } return entries; @@ -56,12 +53,10 @@ @implementation SentryDefaultThreadInspector - (id)initWithStacktraceBuilder:(SentryStacktraceBuilder *)stacktraceBuilder andMachineContextWrapper:(id)machineContextWrapper - symbolicate:(BOOL)symbolicate { if (self = [super init]) { self.stacktraceBuilder = stacktraceBuilder; self.machineContextWrapper = machineContextWrapper; - self.symbolicate = symbolicate; } return self; } @@ -74,13 +69,11 @@ - (instancetype)initWithOptions:(SentryOptions *_Nullable)options [[SentryCrashStackEntryMapper alloc] initWithInAppLogic:inAppLogic]; SentryStacktraceBuilder *stacktraceBuilder = [[SentryStacktraceBuilder alloc] initWithCrashStackEntryMapper:crashStackEntryMapper]; - stacktraceBuilder.symbolicate = options.debug; id machineContextWrapper = [[SentryCrashDefaultMachineContextWrapper alloc] init]; return [self initWithStacktraceBuilder:stacktraceBuilder - andMachineContextWrapper:machineContextWrapper - symbolicate:options.debug]; + andMachineContextWrapper:machineContextWrapper]; } - (SentryStacktrace *)stacktraceForCurrentThreadAsyncUnsafe @@ -143,8 +136,6 @@ - (SentryStacktrace *)stacktraceForCurrentThreadAsyncUnsafe thread_act_array_t suspendedThreads = NULL; mach_msg_type_number_t numSuspendedThreads = 0; - bool symbolicate = self.symbolicate; - // SentryThreadInspector is crashing when there is too many threads. // We add a limit of 70 threads because in test with up to 100 threads it seems fine. // We are giving it an extra safety margin. @@ -164,7 +155,7 @@ - (SentryStacktrace *)stacktraceForCurrentThreadAsyncUnsafe for (int i = 0; i < numSuspendedThreads; i++) { if (suspendedThreads[i] != currentThread) { int numberOfEntries = getStackEntriesFromThread(suspendedThreads[i], context, - threadsInfos[i].stackEntries, MAX_STACKTRACE_LENGTH, symbolicate); + threadsInfos[i].stackEntries, MAX_STACKTRACE_LENGTH); threadsInfos[i].stackLength = numberOfEntries; } else { // We can't use 'getStackEntriesFromThread' to retrieve stack frames from the diff --git a/Sources/Sentry/SentryStacktraceBuilder.m b/Sources/Sentry/SentryStacktraceBuilder.m index 2753abb83d3..206930ca869 100644 --- a/Sources/Sentry/SentryStacktraceBuilder.m +++ b/Sources/Sentry/SentryStacktraceBuilder.m @@ -3,7 +3,6 @@ #import "SentryCrashStackCursor_MachineContext.h" #import "SentryCrashStackCursor_SelfThread.h" #import "SentryCrashStackEntryMapper.h" -#import "SentryCrashSymbolicator.h" #import "SentryFrame.h" #import "SentryLogC.h" #import "SentryStacktrace.h" @@ -24,7 +23,6 @@ - (id)initWithCrashStackEntryMapper:(SentryCrashStackEntryMapper *)crashStackEnt { if (self = [super init]) { self.crashStackEntryMapper = crashStackEntryMapper; - self.symbolicate = NO; } return self; } @@ -41,10 +39,8 @@ - (SentryStacktrace *)retrieveStacktraceFromCursor:(SentryCrashStackCursor)stack // skip the marker frame continue; } - if (self.symbolicate == NO || stackCursor.symbolicate(&stackCursor)) { - frame = [self.crashStackEntryMapper mapStackEntryWithCursor:stackCursor]; - [frames addObject:frame]; - } + frame = [self.crashStackEntryMapper mapStackEntryWithCursor:stackCursor]; + [frames addObject:frame]; } return [SentryStacktraceBuilder buildStacktraceFromFrames:frames]; @@ -96,7 +92,6 @@ - (nullable SentryStacktrace *)buildStacktraceForCurrentThreadAsyncUnsafe SENTRY_LOG_DEBUG(@"Building async-unsafe stack trace..."); SentryCrashStackCursor stackCursor; sentrycrashsc_initSelfThread(&stackCursor, 0); - stackCursor.symbolicate = sentrycrashsymbolicator_symbolicate_async_unsafe; return [self retrieveStacktraceFromCursor:stackCursor]; } diff --git a/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m b/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m index 5118e920218..8be261fdd41 100644 --- a/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m +++ b/Sources/Sentry/SentryUseNSExceptionCallstackWrapper.m @@ -1,6 +1,5 @@ #import "SentryUseNSExceptionCallstackWrapper.h" #import "SentryCrashStackEntryMapper.h" -#import "SentryCrashSymbolicator.h" #import "SentryOptions+Private.h" #import "SentrySDK+Private.h" #import "SentryStacktraceBuilder.h" @@ -40,12 +39,15 @@ - (instancetype)initWithName:(NSExceptionName)aName SentryCrashStackEntryMapper *crashStackToEntryMapper = [self buildCrashStackToEntryMapper]; NSMutableArray *frames = [NSMutableArray array]; - // Iterate over all the addresses, symbolicate and create a SentryFrame + // Iterate over all the addresses and create a SentryFrame [self.returnAddressesArray enumerateObjectsUsingBlock:^(NSNumber *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { SentryCrashStackCursor stackCursor; stackCursor.stackEntry.address = [obj unsignedLongValue]; - sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr(&stackCursor); + stackCursor.stackEntry.imageName = nil; + stackCursor.stackEntry.imageAddress = 0; + stackCursor.stackEntry.symbolAddress = 0; + stackCursor.stackEntry.symbolName = nil; [frames addObject:[crashStackToEntryMapper sentryCrashStackEntryToSentryFrame:stackCursor.stackEntry]]; diff --git a/Sources/Sentry/include/SentryCrashDynamicLinker.h b/Sources/Sentry/include/SentryCrashDynamicLinker.h index 1940953a7b3..5676b7e4fe3 100644 --- a/Sources/Sentry/include/SentryCrashDynamicLinker.h +++ b/Sources/Sentry/include/SentryCrashDynamicLinker.h @@ -97,26 +97,6 @@ uint32_t sentrycrashdl_imageNamed(const char *const imageName, bool exactMatch); */ const uint8_t *sentrycrashdl_imageUUID(const char *const imageName, bool exactMatch); -/** - * ATTENTION: This method isn't async-safe as it accesses @c _dyld_get_image_header, which acquires - * a lock. We plan on removing this method with - * https://github.com/getsentry/sentry-cocoa/issues/2996. - * - * - * This method searches the dynamic loader for information about any image - * containing the specified address. It may not be entirely successful in - * finding information, in which case any fields it could not find will be set - * to NULL. - * - * Unlike dladdr(), this method does not make use of locks, and does not call - * async-unsafe functions. - * - * @param address The address to search for. - * @param info Gets filled out by this function. - * @return true if at least some information was found. - */ -bool sentrycrashdl_dladdr(const uintptr_t address, Dl_info *const info); - void sentrycrashdl_getCrashInfo(uint64_t address, SentryCrashBinaryImage *buffer); void sentrycrashdl_initialize(void); diff --git a/Sources/Sentry/include/SentryDefaultThreadInspector.h b/Sources/Sentry/include/SentryDefaultThreadInspector.h index c87ab32426b..d92e2265ddc 100644 --- a/Sources/Sentry/include/SentryDefaultThreadInspector.h +++ b/Sources/Sentry/include/SentryDefaultThreadInspector.h @@ -15,8 +15,7 @@ NS_ASSUME_NONNULL_BEGIN SENTRY_NO_INIT - (id)initWithStacktraceBuilder:(SentryStacktraceBuilder *)stacktraceBuilder - andMachineContextWrapper:(id)machineContextWrapper - symbolicate:(BOOL)symbolicate; + andMachineContextWrapper:(id)machineContextWrapper; - (instancetype)initWithOptions:(SentryOptions *_Nullable)options; diff --git a/Sources/Sentry/include/SentryStacktraceBuilder.h b/Sources/Sentry/include/SentryStacktraceBuilder.h index 866b8b0c091..132f8c9fd3c 100644 --- a/Sources/Sentry/include/SentryStacktraceBuilder.h +++ b/Sources/Sentry/include/SentryStacktraceBuilder.h @@ -15,12 +15,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SentryStacktraceBuilder : NSObject SENTRY_NO_INIT -/** - * Whether the stack trace frames should be fully symbolicated - * or only contain instruction address and binary image. - */ -@property (nonatomic) BOOL symbolicate; - - (id)initWithCrashStackEntryMapper:(SentryCrashStackEntryMapper *)crashStackEntryMapper; /** diff --git a/Sources/SentryCrash/Recording/SentryCrashDoctor.m b/Sources/SentryCrash/Recording/SentryCrashDoctor.m index 90739c617d9..2c7c4f440b8 100644 --- a/Sources/SentryCrash/Recording/SentryCrashDoctor.m +++ b/Sources/SentryCrash/Recording/SentryCrashDoctor.m @@ -262,30 +262,6 @@ - (NSDictionary *)basicRegistersFromThreadReport:(NSDictionary *)threadReport return basic; } -- (NSDictionary *)lastInAppStackEntry:(NSDictionary *)report -{ - NSString *executableName = [self mainExecutableNameForReport:report]; - NSDictionary *crashedThread = [self crashedThreadReport:report]; - NSArray *backtrace = [self backtraceFromThreadReport:crashedThread]; - for (NSDictionary *entry in backtrace) { - NSString *objectName = [entry objectForKey:@SentryCrashField_ObjectName]; - if ([objectName isEqualToString:executableName]) { - return entry; - } - } - return nil; -} - -- (NSDictionary *)lastStackEntry:(NSDictionary *)report -{ - NSDictionary *crashedThread = [self crashedThreadReport:report]; - NSArray *backtrace = [self backtraceFromThreadReport:crashedThread]; - if ([backtrace count] > 0) { - return [backtrace objectAtIndex:0]; - } - return nil; -} - - (BOOL)isInvalidAddress:(NSDictionary *)errorReport { NSDictionary *machError = [errorReport objectForKey:@SentryCrashField_Mach]; @@ -329,25 +305,6 @@ - (BOOL)isMemoryCorruption:(NSDictionary *)report } } - NSArray *backtrace = [self backtraceFromThreadReport:crashedThread]; - for (NSDictionary *entry in backtrace) { - NSString *objectName = [entry objectForKey:@SentryCrashField_ObjectName]; - NSString *symbolName = [entry objectForKey:@SentryCrashField_SymbolName]; - if ([symbolName isEqualToString:@"objc_autoreleasePoolPush"]) { - return YES; - } - if ([symbolName isEqualToString:@"free_list_checksum_botch"]) { - return YES; - } - if ([symbolName isEqualToString:@"szone_malloc_should_clear"]) { - return YES; - } - if ([symbolName isEqualToString:@"lookUpMethod"] && - [objectName isEqualToString:@"libobjc.A.dylib"]) { - return YES; - } - } - return NO; } @@ -359,8 +316,6 @@ - (BOOL)wasProgramTerminationRequested:(NSDictionary *)errorReport - (SentryCrashDoctorFunctionCall *)lastFunctionCall:(NSDictionary *)report { SentryCrashDoctorFunctionCall *function = [[SentryCrashDoctorFunctionCall alloc] init]; - NSDictionary *lastStackEntry = [self lastStackEntry:report]; - function.name = [lastStackEntry objectForKey:@SentryCrashField_SymbolName]; NSDictionary *crashedThread = [self crashedThreadReport:report]; NSDictionary *notableAddresses = @@ -425,13 +380,11 @@ - (BOOL)isStackOverflow:(NSDictionary *)crashedThreadReport - (NSString *)diagnoseCrash:(NSDictionary *)report { @try { - NSString *lastFunctionName = - [[self lastInAppStackEntry:report] objectForKey:@SentryCrashField_SymbolName]; NSDictionary *crashedThreadReport = [self crashedThreadReport:report]; NSDictionary *errorReport = [self errorReport:report]; if ([self isStackOverflow:crashedThreadReport]) { - return [NSString stringWithFormat:@"Stack overflow in %@", lastFunctionName]; + return [NSString stringWithFormat:@"Stack overflow"]; } NSString *crashType = [errorReport objectForKey:@SentryCrashField_Type]; diff --git a/Sources/SentryCrash/Recording/SentryCrashReport.c b/Sources/SentryCrash/Recording/SentryCrashReport.c index 6debdd9db21..72205a3e40c 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReport.c +++ b/Sources/SentryCrash/Recording/SentryCrashReport.c @@ -799,20 +799,6 @@ writeBacktrace(const SentryCrashReportWriter *const writer, const char *const ke while (stackCursor->advanceCursor(stackCursor)) { writer->beginObject(writer, NULL); { - if (stackCursor->symbolicate(stackCursor)) { - if (stackCursor->stackEntry.imageName != NULL) { - writer->addStringElement(writer, SentryCrashField_ObjectName, - sentrycrashfu_lastPathEntry(stackCursor->stackEntry.imageName)); - } - writer->addUIntegerElement(writer, SentryCrashField_ObjectAddr, - stackCursor->stackEntry.imageAddress); - if (stackCursor->stackEntry.symbolName != NULL) { - writer->addStringElement(writer, SentryCrashField_SymbolName, - stackCursor->stackEntry.symbolName); - } - writer->addUIntegerElement(writer, SentryCrashField_SymbolAddr, - stackCursor->stackEntry.symbolAddress); - } writer->addUIntegerElement( writer, SentryCrashField_InstructionAddr, stackCursor->stackEntry.address); } diff --git a/Sources/SentryCrash/Recording/SentryCrashReportFields.h b/Sources/SentryCrash/Recording/SentryCrashReportFields.h index 96b8ce5df45..60a091f3439 100644 --- a/Sources/SentryCrash/Recording/SentryCrashReportFields.h +++ b/Sources/SentryCrash/Recording/SentryCrashReportFields.h @@ -77,11 +77,6 @@ #pragma mark - Backtrace - #define SentryCrashField_InstructionAddr "instruction_addr" -#define SentryCrashField_LineOfCode "line_of_code" -#define SentryCrashField_ObjectAddr "object_addr" -#define SentryCrashField_ObjectName "object_name" -#define SentryCrashField_SymbolAddr "symbol_addr" -#define SentryCrashField_SymbolName "symbol_name" #pragma mark - Stack Dump - diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c b/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c index f26902f7277..da2e49af741 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashDynamicLinker.c @@ -218,24 +218,6 @@ imageIndexContainingAddress(const uintptr_t address) return UINT_MAX; } -/** Get the segment base address of the specified image. - * - * This is required for any symtab command offsets. - * - * @param idx The image index. - * @return The image's base address, or 0 if none was found. - */ -static uintptr_t -segmentBaseOfImageIndex(const uint32_t idx) -{ - const struct mach_header *header = _dyld_get_image_header(idx); - const sentry_segment_command_t *segCmd = getSegmentCommand(header, SEG_LINKEDIT); - if (segCmd != NULL) { - return (uintptr_t)(segCmd->vmaddr - segCmd->fileoff); - } - return 0; -} - uint32_t sentrycrashdl_imageNamed(const char *const imageName, bool exactMatch) { @@ -283,99 +265,6 @@ sentrycrashdl_imageUUID(const char *const imageName, bool exactMatch) return NULL; } -bool -sentrycrashdl_dladdr(const uintptr_t address, Dl_info *const info) -{ - info->dli_fname = NULL; - info->dli_fbase = NULL; - info->dli_sname = NULL; - info->dli_saddr = NULL; - - const uint32_t idx = imageIndexContainingAddress(address); - - const struct mach_header *header = NULL; - uintptr_t imageVMAddrSlide = 0; - uintptr_t segmentBase = 0; - - if (idx == SENTRY_DYLD_INDEX) { - // Handle dyld manually - header = sentryDyldHeader; - if (header == NULL) { - return false; - } - - // Calculate dyld slide from __TEXT vmaddr - SentrySegmentAddress textSegment = getSegmentAddress(header, SEG_TEXT); - uintptr_t vmaddr = textSegment.start; - if (vmaddr != 0) { - imageVMAddrSlide = (uintptr_t)header - vmaddr; - segmentBase = (uintptr_t)header; - } - - info->dli_fname = "dyld"; - } else if (idx != UINT_MAX) { - // Normal image path - header = _dyld_get_image_header(idx); - imageVMAddrSlide = (uintptr_t)_dyld_get_image_vmaddr_slide(idx); - segmentBase = segmentBaseOfImageIndex(idx) + imageVMAddrSlide; - info->dli_fname = _dyld_get_image_name(idx); - } else { - return false; - } - const uintptr_t addressWithSlide = address - imageVMAddrSlide; - if (segmentBase == 0) { - return false; - } - - info->dli_fbase = (void *)header; - - // Find symbol tables and get whichever symbol is closest to the address. - const nlist_t *bestMatch = NULL; - uintptr_t bestDistance = ULONG_MAX; - uintptr_t cmdPtr = firstCmdAfterHeader(header); - if (cmdPtr == 0) { - return false; - } - for (uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) { - const struct load_command *loadCmd = (struct load_command *)cmdPtr; - if (loadCmd->cmd == LC_SYMTAB) { - const struct symtab_command *symtabCmd = (struct symtab_command *)cmdPtr; - const nlist_t *symbolTable = (nlist_t *)(segmentBase + symtabCmd->symoff); - const uintptr_t stringTable = segmentBase + symtabCmd->stroff; - - for (uint32_t iSym = 0; iSym < symtabCmd->nsyms; iSym++) { - // If n_value is 0, the symbol refers to an external object. - if (symbolTable[iSym].n_value != 0) { - uintptr_t symbolBase = symbolTable[iSym].n_value; - uintptr_t currentDistance = addressWithSlide - symbolBase; - if ((addressWithSlide >= symbolBase) && (currentDistance <= bestDistance)) { - bestMatch = symbolTable + iSym; - bestDistance = currentDistance; - } - } - } - if (bestMatch != NULL) { - info->dli_saddr = (void *)(bestMatch->n_value + imageVMAddrSlide); - if (bestMatch->n_desc == 16) { - // This image has been stripped. The name is meaningless, - // and almost certainly resolves to "_mh_execute_header" - info->dli_sname = NULL; - } else { - info->dli_sname - = (char *)((intptr_t)stringTable + (intptr_t)bestMatch->n_un.n_strx); - if (*info->dli_sname == '_') { - info->dli_sname++; - } - } - break; - } - } - cmdPtr += loadCmd->cmdsize; - } - - return true; -} - static bool isValidCrashInfoMessage(const char *str) { diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c index 3f42e83a584..238aa5aad53 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.c @@ -25,7 +25,6 @@ #include "SentryCrashStackCursor.h" #include "SentryCrashCPU.h" -#include "SentryCrashSymbolicator.h" #include #include "SentryAsyncSafeLog.h" @@ -46,17 +45,12 @@ sentrycrashsc_resetCursor(SentryCrashStackCursor *cursor) cursor->state.currentDepth = 0; cursor->state.hasGivenUp = false; cursor->stackEntry.address = 0; - cursor->stackEntry.imageAddress = 0; - cursor->stackEntry.imageName = NULL; - cursor->stackEntry.symbolAddress = 0; - cursor->stackEntry.symbolName = NULL; } void sentrycrashsc_initCursor(SentryCrashStackCursor *cursor, void (*resetCursor)(SentryCrashStackCursor *), bool (*advanceCursor)(SentryCrashStackCursor *)) { - cursor->symbolicate = sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr; cursor->advanceCursor = advanceCursor != NULL ? advanceCursor : g_advanceCursor; cursor->resetCursor = resetCursor != NULL ? resetCursor : sentrycrashsc_resetCursor; cursor->resetCursor(cursor); diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h index 0805ddaf2cd..f4e7d3fc031 100644 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h +++ b/Sources/SentryCrash/Recording/Tools/SentryCrashStackCursor.h @@ -79,10 +79,6 @@ typedef struct SentryCrashStackCursor { /** Advance the cursor to the next stack entry. */ bool (*advanceCursor)(struct SentryCrashStackCursor *); - /** Attempt to symbolicate the current address, filling in the fields in - * stackEntry. */ - bool (*symbolicate)(struct SentryCrashStackCursor *); - /** Internal context-specific information. */ void *context[SentryCrashSC_CONTEXT_SIZE]; } SentryCrashStackCursor; diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.c b/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.c deleted file mode 100644 index ed6b9e026e0..00000000000 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.c +++ /dev/null @@ -1,105 +0,0 @@ -// Adapted from: https://github.com/kstenerud/KSCrash -// -// SentryCrashSymbolicator.c -// -// Copyright (c) 2016 Karl Stenerud. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall remain in place -// in this source code. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#include "SentryCrashSymbolicator.h" -#include "SentryCrashDynamicLinker.h" -#import - -/** Remove any pointer tagging from an instruction address - * On armv7 the least significant bit of the pointer distinguishes - * between thumb mode (2-byte instructions) and normal mode (4-byte - * instructions). On arm64 all instructions are 4-bytes wide so the two least - * significant bytes should always be 0. On x86_64 and i386, instructions are - * variable length so all bits are signficant. - */ -#if defined(__arm__) -# define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(1UL)) -#elif defined(__arm64__) -# define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(3UL)) -#else -# define DETAG_INSTRUCTION_ADDRESS(A) (A) -#endif - -/** Step backwards by one instruction. - * The backtrace of an objective-C program is expected to contain return - * addresses not call instructions, as that is what can easily be read from - * the stack. This is not a problem except for a few cases where the return - * address is inside a different symbol than the call address. - */ -#define CALL_INSTRUCTION_FROM_RETURN_ADDRESS(A) (DETAG_INSTRUCTION_ADDRESS((A)) - 1) - -static bool -symbolicate_internal(SentryCrashStackCursor *cursor, bool useDlAddr) -{ - if (cursor->stackEntry.address == SentryCrashSC_ASYNC_MARKER) { - cursor->stackEntry.imageAddress = 0; - cursor->stackEntry.imageName = 0; - cursor->stackEntry.symbolAddress = 0; - cursor->stackEntry.symbolName = "__sentrycrash__async_marker__"; - return true; - } - - Dl_info symbolsBuffer; - - bool symbols_succeed = false; - - if (useDlAddr) { - symbols_succeed = dladdr((void *)cursor->stackEntry.address, &symbolsBuffer) != 0; - } else { - // sentrycrashdl_dladdr isn't async safe, but we've been using it for - // crashes since the beginning. We plan on removing it with - // https://github.com/getsentry/sentry-cocoa/issues/2996. - symbols_succeed = sentrycrashdl_dladdr( - CALL_INSTRUCTION_FROM_RETURN_ADDRESS(cursor->stackEntry.address), &symbolsBuffer); - } - - if (symbols_succeed) { - cursor->stackEntry.imageAddress = (uintptr_t)symbolsBuffer.dli_fbase; - cursor->stackEntry.imageName = symbolsBuffer.dli_fname; - cursor->stackEntry.symbolAddress = (uintptr_t)symbolsBuffer.dli_saddr; - cursor->stackEntry.symbolName = symbolsBuffer.dli_sname; - return true; - } - - cursor->stackEntry.imageAddress = 0; - cursor->stackEntry.imageName = 0; - cursor->stackEntry.symbolAddress = 0; - cursor->stackEntry.symbolName = 0; - return false; -} - -bool -sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr(SentryCrashStackCursor *cursor) -{ - // Symbolicate using `sentrycrashdl_dladdr` note this is not async-signal-safe - return symbolicate_internal(cursor, false); -} - -bool -sentrycrashsymbolicator_symbolicate_async_unsafe(SentryCrashStackCursor *cursor) -{ - // Symbolicate using `dladdr` note this is not async-signal-safe - return symbolicate_internal(cursor, true); -} diff --git a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.h b/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.h deleted file mode 100644 index 07d93bece74..00000000000 --- a/Sources/SentryCrash/Recording/Tools/SentryCrashSymbolicator.h +++ /dev/null @@ -1,52 +0,0 @@ -// Adapted from: https://github.com/kstenerud/KSCrash -// -// SentryCrashSymbolicator.h -// -// Copyright (c) 2016 Karl Stenerud. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall remain in place -// in this source code. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -#ifndef SentryCrashSymbolicator_h -#define SentryCrashSymbolicator_h - -#import "SentryCrashStackCursor.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Symbolicate a stack cursor. - * - * @param cursor The cursor to symbolicate. - * - * @return True if successful. - */ -bool sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr(SentryCrashStackCursor *cursor); - -/** Same as ``sentrycrashsymbolicator_symbolicate_async_unsafe_sentryDlAddr`` but faster. - */ -bool sentrycrashsymbolicator_symbolicate_async_unsafe(SentryCrashStackCursor *cursor); - -#ifdef __cplusplus -} -#endif - -#endif // SentryCrashSymbolicator_h diff --git a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift index dd9729621e3..498526b25fd 100644 --- a/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/ANR/SentryANRTrackingIntegrationTests.swift @@ -99,7 +99,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.type, "App Hanging") XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -140,7 +139,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.type, "App Hang Fully Blocked") XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -182,7 +180,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNil(ex.mechanism?.data) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -224,7 +221,6 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(ex.value, "App hanging for at least 4500 ms.") XCTAssertNil(ex.mechanism?.data) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) @@ -384,20 +380,9 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertTrue(mechanismData.isEmpty) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) - - let threads = try XCTUnwrap(event?.threads) - - // Sometimes during tests its possible to have one thread without frames - // We just need to make sure we retrieve frame information for at least one other thread than the main thread - let threadsWithFrames = threads.filter { - ($0.stacktrace?.frames.count ?? 0) >= 1 - }.count - - XCTAssertTrue(threadsWithFrames > 1, "Not enough threads with frames") XCTAssertEqual(event?.debugMeta?.count, 1) let eventDebugImage = try XCTUnwrap(event?.debugMeta?.first) @@ -443,21 +428,10 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertTrue(mechanismData.isEmpty) XCTAssertNotNil(ex.stacktrace) - XCTAssertEqual(ex.stacktrace?.frames.first?.function, "main") XCTAssertEqual(ex.stacktrace?.snapshot?.boolValue, true) XCTAssertEqual(try XCTUnwrap(event?.threads?.first).current?.boolValue, true) XCTAssertEqual(event?.isAppHangEvent, true) - let threads = try XCTUnwrap(event?.threads) - - // Sometimes during tests its possible to have one thread without frames - // We just need to make sure we retrieve frame information for at least one other thread than the main thread - let threadsWithFrames = threads.filter { - ($0.stacktrace?.frames.count ?? 0) >= 1 - }.count - - XCTAssertTrue(threadsWithFrames > 1, "Not enough threads with frames") - XCTAssertEqual(event?.debugMeta?.count, 1) let eventDebugImage = try XCTUnwrap(event?.debugMeta?.first) XCTAssertEqual(eventDebugImage.debugID, TestData.debugImage.debugID) @@ -744,14 +718,12 @@ class SentryANRTrackingIntegrationTests: SentrySDKIntegrationTestsBase { if addThreads { let frame1 = Sentry.Frame() - frame1.function = "Second_frame_function" let thread1 = SentryThread(threadId: 0) thread1.stacktrace = SentryStacktrace(frames: [frame1], registers: [:]) thread1.current = true let frame2 = Sentry.Frame() - frame2.function = "main" let thread2 = SentryThread(threadId: 1) thread2.stacktrace = SentryStacktrace(frames: [frame2], registers: [:]) diff --git a/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift b/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift index 57709284438..ae8abead82a 100644 --- a/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/MetricKit/SentryMetricKitIntegrationTests.swift @@ -201,7 +201,6 @@ final class SentryMetricKitIntegrationTests: SentrySDKIntegrationTestsBase { XCTAssertEqual(1, sentryFrames.count) let frame = sentryFrames.first - XCTAssertNil(frame?.function) XCTAssertEqual("0x000000021f1a0001", frame?.imageAddress) XCTAssertEqual("libsystem_pthread.dylib", frame?.package) XCTAssertFalse(frame?.inApp?.boolValue ?? true) diff --git a/Tests/SentryTests/Protocol/SentryFrameTests.swift b/Tests/SentryTests/Protocol/SentryFrameTests.swift index af23841d910..b6dab6aea95 100644 --- a/Tests/SentryTests/Protocol/SentryFrameTests.swift +++ b/Tests/SentryTests/Protocol/SentryFrameTests.swift @@ -13,7 +13,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, actual["symbol_addr"] as? String) XCTAssertEqual(frame.fileName, actual["filename"] as? String) - XCTAssertEqual(frame.function, actual["function"] as? String) XCTAssertEqual(frame.module, actual["module"] as? String) XCTAssertEqual(frame.lineNumber, actual["lineno"] as? NSNumber) XCTAssertEqual(frame.columnNumber, actual["colno"] as? NSNumber) @@ -39,7 +38,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, actual["symbol_addr"] as? String) XCTAssertEqual(frame.fileName, actual["filename"] as? String) - XCTAssertEqual(frame.function, actual["function"] as? String) XCTAssertEqual(frame.module, actual["module"] as? String) XCTAssertEqual(frame.lineNumber, actual["lineno"] as? NSNumber) XCTAssertEqual(frame.columnNumber, actual["colno"] as? NSNumber) @@ -66,7 +64,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, decoded.symbolAddress) XCTAssertEqual(frame.fileName, decoded.fileName) - XCTAssertEqual(frame.function, decoded.function) XCTAssertEqual(frame.module, decoded.module) XCTAssertEqual(frame.lineNumber, decoded.lineNumber) XCTAssertEqual(frame.columnNumber, decoded.columnNumber) @@ -93,7 +90,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertEqual(frame.symbolAddress, decoded.symbolAddress) XCTAssertEqual(frame.fileName, decoded.fileName) - XCTAssertEqual(frame.function, decoded.function) XCTAssertEqual(frame.module, decoded.module) XCTAssertEqual(frame.lineNumber, decoded.lineNumber) XCTAssertEqual(frame.columnNumber, decoded.columnNumber) @@ -120,7 +116,6 @@ class SentryFrameTests: XCTestCase { // Assert XCTAssertNil(decoded.symbolAddress) XCTAssertNil(decoded.fileName) - XCTAssertNil(decoded.function) XCTAssertNil(decoded.module) XCTAssertNil(decoded.lineNumber) XCTAssertNil(decoded.columnNumber) diff --git a/Tests/SentryTests/SentryClientTests.swift b/Tests/SentryTests/SentryClientTests.swift index 7f2b466823f..dcfbc92314f 100644 --- a/Tests/SentryTests/SentryClientTests.swift +++ b/Tests/SentryTests/SentryClientTests.swift @@ -2229,15 +2229,7 @@ class SentryClientTests: XCTestCase { XCTAssertEqual(actual.threads?[0].isMain, true) // Make sure the stacktrace is not empty XCTAssertGreaterThan(actual.threads?[0].stacktrace?.frames.count ?? 0, 1) - // We will need to update it if the test class / module changes - let testMangledName = "$s11SentryTests0a6ClientB0C011testCaptureA16WrappedExceptionyyKF" - let frameWithTestFunction = actual.threads?[0].stacktrace?.frames.first { frame in - frame.function == testMangledName - } - XCTAssertNotNil(frameWithTestFunction, "Mangled name for testCaptureSentryWrappedException not found in stacktrace") - // Last frame should always be `__exceptionPreprocess` - XCTAssertEqual(actual.threads?[0].stacktrace?.frames.last?.function, "__exceptionPreprocess") #else throw XCTSkip("Test is disabled for this OS version") #endif // os(macOS) diff --git a/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m b/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m index a1942ff4fee..7df110f8061 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m +++ b/Tests/SentryTests/SentryCrash/SentryCrashDynamicLinkerTests.m @@ -47,73 +47,6 @@ - (void)testImageIndexContainingAddressWhenDyldIsNotSet XCTAssertEqual(index, UINT_MAX, @"Address should be found in dyld"); } -- (void)testDyldAddressLookup -{ - sentrycrashdl_initialize(); - - void *dyldAddress = (void *)&_dyld_image_count; - - Dl_info info; - bool result = sentrycrashdl_dladdr((uintptr_t)dyldAddress, &info); - XCTAssertTrue(result, @"dladdr should succeed for dyld address"); - XCTAssert(info.dli_fbase != NULL, @"Base address should not be NULL"); - XCTAssert(info.dli_fname != NULL, @"Image name should not be NULL"); - - XCTAssertTrue(strstr(info.dli_fname, "dyld") != NULL, @"Image name should contain 'dyld'"); - - XCTAssert(info.dli_sname != NULL, @"Symbol name should not be NULL"); - XCTAssertTrue(strstr(info.dli_sname, "_dyld_image_count") != NULL, - @"Symbol name should contain '_dyld_image_count'"); - - XCTAssert(info.dli_saddr != NULL, @"Symbol address should not be NULL"); - XCTAssertEqual(info.dli_saddr, dyldAddress, @"Symbol address should match the input address"); -} - -#if TARGET_OS_IOS -- (void)testUIKitAddressLookup -{ - // Get a known function from UIKit - void *uiKitAddress = (void *)&UIApplicationMain; - - Dl_info info; - bool result = sentrycrashdl_dladdr((uintptr_t)uiKitAddress, &info); - XCTAssertTrue(result, @"dladdr should succeed for UIKit address"); - XCTAssert(info.dli_fbase != NULL, @"Base address should not be NULL"); - XCTAssert(info.dli_fname != NULL, @"Image name should not be NULL"); - - XCTAssertTrue(strstr(info.dli_fname, "UIKit") != NULL, @"Image name should contain 'UIKit'"); - - XCTAssert(info.dli_sname != NULL, @"Symbol name should not be NULL"); - XCTAssertTrue(strstr(info.dli_sname, "UIApplicationMain") != NULL, - @"Symbol name should contain 'UIApplicationMain'"); - - XCTAssert(info.dli_saddr != NULL, @"Symbol address should not be NULL"); - XCTAssertEqual(info.dli_saddr, uiKitAddress, @"Symbol address should match the input address"); -} -#endif - -- (void)testKnownAddressLookup -{ - // Any function in Sentry will do - void *testAddress = (void *)&sentrycrashdl_clearDyld; - - Dl_info info; - bool result = sentrycrashdl_dladdr((uintptr_t)testAddress, &info); - XCTAssertTrue(result, @"dladdr should succeed for test bundle address"); - XCTAssert(info.dli_fbase != NULL, @"Base address should not be NULL"); - XCTAssert(info.dli_fname != NULL, @"Image name should not be NULL"); - - XCTAssertTrue( - strstr(info.dli_fname, "Sentry") != NULL, @"Image name should contain 'SentryTests'"); - - XCTAssert(info.dli_sname != NULL, @"Symbol name should not be NULL"); - XCTAssertTrue(strstr(info.dli_sname, "sentrycrashdl_clearDyld") != NULL, - @"Symbol name should contain 'sentrycrashdl_clearDyld'"); - - XCTAssert(info.dli_saddr != NULL, @"Symbol address should not be NULL"); - XCTAssertEqual(info.dli_saddr, testAddress, @"Symbol address should match the input address"); -} - // vmaddrs changes by platform, so we cannot use a static value - (uintptr_t)findDyldAddress { diff --git a/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift b/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift index 221977e05d9..b9472326be3 100644 --- a/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryCrashStackEntryMapperTests.swift @@ -18,24 +18,6 @@ class SentryCrashStackEntryMapperTests: XCTestCase { super.tearDown() clearTestState() } - - func testSymbolAddress() { - var cursor = SentryCrashStackCursor() - cursor.stackEntry.symbolAddress = 2_391_813_104 - - let frame = sut.mapStackEntry(with: cursor) - - XCTAssertEqual("0x000000008e902bf0", frame.symbolAddress ?? "") - } - - func testSymbolAddress_IsZero() { - var cursor = SentryCrashStackCursor() - cursor.stackEntry.symbolAddress = 0 - - let frame = sut.mapStackEntry(with: cursor) - - XCTAssertNil(frame.symbolAddress) - } func testInstructionAddress() { var cursor = SentryCrashStackCursor() @@ -45,45 +27,6 @@ class SentryCrashStackEntryMapperTests: XCTestCase { XCTAssertEqual("0x000000008fd09c40", frame.instructionAddress ?? "") } - - func testSymbolNameIsNull() { - let frame = sut.mapStackEntry(with: SentryCrashStackCursor()) - - XCTAssertNil(frame.function) - } - - func testSymbolName() { - let symbolName = "-[SentryCrash symbolName]" - var cursor = SentryCrashStackCursor() - - let cString = symbolName.cString(using: String.Encoding.utf8) - cString?.withUnsafeBufferPointer { bufferPointer in - cursor.stackEntry.symbolName = bufferPointer.baseAddress - let frame = sut.mapStackEntry(with: cursor) - XCTAssertEqual(symbolName, frame.function) - } - } - - func testImageName() { - let imageName = "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 13.4.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" - let frame = getFrameWithImageName(imageName: imageName) - - XCTAssertEqual(imageName, frame.package) - } - - func testImageAddress() { - var cursor = SentryCrashStackCursor() - cursor.stackEntry.imageAddress = 2_488_998_912 - - let frame = sut.mapStackEntry(with: cursor) - - XCTAssertEqual("0x00000000945b1c00", frame.imageAddress ?? "") - } - - func testIsInApp() { - let frame = getFrameWithImageName(imageName: "/private/var/containers/Bundle/Application/03D20FB6-852C-4DD3-B69C-3231FB41C2B1/iOS-Swift.app/\(self.bundleExecutable)") - XCTAssertEqual(true, frame.inApp) - } func testImageFromCache() { let image = createCrashBinaryImage(2_488_998_912) @@ -104,19 +47,6 @@ class SentryCrashStackEntryMapperTests: XCTestCase { SentryDependencyContainer.sharedInstance().binaryImageCache.stop() } - - private func getFrameWithImageName(imageName: String) -> Frame { - var cursor = SentryCrashStackCursor() - - let cString = imageName.cString(using: String.Encoding.utf8) - var result: Frame = Frame() - cString?.withUnsafeBufferPointer { bufferPointer in - cursor.stackEntry.imageName = bufferPointer.baseAddress - result = sut.mapStackEntry(with: cursor) - } - - return result - } private func createCrashBinaryImage(_ address: UInt) -> SentryCrashBinaryImage { let name = "Expected Name at \(address)" diff --git a/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift b/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift index 441e0e834ab..243073a2318 100644 --- a/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryDefaultThreadInspectorTests.swift @@ -9,16 +9,14 @@ class SentryDefaultThreadInspectorTests: XCTestCase { var stacktraceBuilder = TestSentryStacktraceBuilder(crashStackEntryMapper: SentryCrashStackEntryMapper(inAppLogic: SentryInAppLogic(inAppIncludes: []))) var keepThreadAlive = true - func getSut(testWithRealMachineContextWrapper: Bool = false, symbolicate: Bool = true) -> SentryDefaultThreadInspector { + func getSut(testWithRealMachineContextWrapper: Bool = false) -> SentryDefaultThreadInspector { let machineContextWrapper = testWithRealMachineContextWrapper ? SentryCrashDefaultMachineContextWrapper() : testMachineContextWrapper as SentryCrashMachineContextWrapper let stacktraceBuilder = testWithRealMachineContextWrapper ? SentryStacktraceBuilder(crashStackEntryMapper: SentryCrashStackEntryMapper(inAppLogic: SentryInAppLogic(inAppIncludes: []))) : self.stacktraceBuilder - stacktraceBuilder.symbolicate = symbolicate - return SentryDefaultThreadInspector( stacktraceBuilder: stacktraceBuilder, - andMachineContextWrapper: machineContextWrapper, symbolicate: symbolicate + andMachineContextWrapper: machineContextWrapper ) } } @@ -114,7 +112,7 @@ class SentryDefaultThreadInspectorTests: XCTestCase { let expect = expectation(description: "Read every thread") expect.expectedFulfillmentCount = 10 - let sut = self.fixture.getSut(testWithRealMachineContextWrapper: true, symbolicate: false) + let sut = self.fixture.getSut(testWithRealMachineContextWrapper: true) for _ in 0..<10 { @@ -209,18 +207,16 @@ class SentryDefaultThreadInspectorTests: XCTestCase { XCTAssertNotNil(stackTrace2) XCTAssertGreaterThan(stackTrace.frames.count, 0) XCTAssertNotEqual(stackTrace.frames.first?.instructionAddress, "0x0000000000000000") - XCTAssertNotEqual(stackTrace.frames.first?.function, "") } func testStackTrackForCurrentThreadAsyncUnsafe_NoSymbolication() { - guard let stackTrace = fixture.getSut(testWithRealMachineContextWrapper: true, symbolicate: false).stacktraceForCurrentThreadAsyncUnsafe() else { + guard let stackTrace = fixture.getSut(testWithRealMachineContextWrapper: true).stacktraceForCurrentThreadAsyncUnsafe() else { XCTFail("Stack Trace not found") return } XCTAssertNotNil(stackTrace) XCTAssertGreaterThan(stackTrace.frames.count, 0) - XCTAssertNil(stackTrace.frames.first?.function) } func testOnlyCurrentThreadHasStacktrace() throws { diff --git a/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift b/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift index a27bec99fda..3ffc9d93c32 100644 --- a/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift +++ b/Tests/SentryTests/SentryCrash/SentryStacktraceBuilderTests.swift @@ -10,7 +10,6 @@ class SentryStacktraceBuilderTests: XCTestCase { var sut: SentryStacktraceBuilder { SentryDependencyContainer.sharedInstance().reachability = TestSentryReachability() let res = SentryStacktraceBuilder(crashStackEntryMapper: SentryCrashStackEntryMapper(inAppLogic: SentryInAppLogic(inAppIncludes: []))) - res.symbolicate = true return res } } @@ -46,33 +45,28 @@ class SentryStacktraceBuilderTests: XCTestCase { // deterministic tests here. Therefore we just make sure they are // filled with some values. for frame in actual.frames { - XCTAssertNotNil(frame.symbolAddress) - XCTAssertNotNil(frame.function) XCTAssertNotNil(frame.imageAddress) XCTAssertNotNil(frame.instructionAddress) } } - func testFramesDontContainBuilderFunction() { - let actual = fixture.sut.buildStacktraceForCurrentThread() - - let result = actual.frames.contains { frame in - return frame.function?.contains("buildStacktraceForCurrentThread") ?? false - } - - XCTAssertFalse(result, "The stacktrace should not contain the function that builds the stacktrace") - } - func testFramesOrder() throws { // -- Act -- let actual = fixture.sut.buildStacktraceForCurrentThread() // -- Assert -- - // Make sure the first 4 frames contain main - let isMainInFirstFrames = actual.frames[...3].contains(where: { $0.function == "main" }) + // Make sure the first 4 frames contain an address close to the main function + let isMainInFirstFrames = actual.frames[...3].contains(where: { frame in + let inst = Int(frame.instructionAddress?.replacingOccurrences(of: "0x", with: "") ?? "", radix: 16) ?? 0 + #if targetEnvironment(simulator) + return name(for: inst) == "start_sim" + #else + return name(for: inst) == "start" + #endif + }) XCTAssertTrue( isMainInFirstFrames, - "Expected frames to be ordered from caller to callee (xctest's main expected in first few frames). Found instead:\n\(actual.frames.map({ " - \($0.function ?? "")" }).joined(separator: "\n"))" + "Expected frames to be ordered from caller to callee (xctest's main expected in first few frames)." ) } @@ -145,10 +139,24 @@ class SentryStacktraceBuilderTests: XCTestCase { private func innerFrame2() async -> Int { let needed = ["firstFrame", "innerFrame1", "innerFrame2"] let actual = fixture.sut.buildStacktraceForCurrentThreadAsyncUnsafe()! - let filteredFrames = actual.frames - .compactMap({ $0.function }) + let symbolNames = actual.frames + .compactMap({ $0.instructionAddress?.replacingOccurrences(of: "0x", with: "") }) + .compactMap { Int($0, radix: 16) } + .compactMap { addr in + name(for: addr) + } + let filteredFrames = symbolNames .filter { needed.contains(where: $0.contains) } print("\(Date()) [Sentry] [TEST] returning filtered frames.") return filteredFrames.count } + + private func name(for addr: Int) -> String? { + var sym = Dl_info() + dladdr(UnsafeMutableRawPointer(bitPattern: addr), &sym) + if let symName = sym.dli_sname { + return String(cString: symName) + } + return nil + } } diff --git a/Tests/SentryTests/SentryCrash/TestThreadInspector.swift b/Tests/SentryTests/SentryCrash/TestThreadInspector.swift index e0aa7062e65..0a9b3b4238e 100644 --- a/Tests/SentryTests/SentryCrash/TestThreadInspector.swift +++ b/Tests/SentryTests/SentryCrash/TestThreadInspector.swift @@ -10,7 +10,7 @@ class TestDefaultThreadInspector: SentryDefaultThreadInspector { let inAppLogic = SentryInAppLogic(inAppIncludes: []) let crashStackEntryMapper = SentryCrashStackEntryMapper(inAppLogic: inAppLogic) let stacktraceBuilder = SentryStacktraceBuilder(crashStackEntryMapper: crashStackEntryMapper) - return TestDefaultThreadInspector(stacktraceBuilder: stacktraceBuilder, andMachineContextWrapper: SentryCrashDefaultMachineContextWrapper(), symbolicate: false) + return TestDefaultThreadInspector(stacktraceBuilder: stacktraceBuilder, andMachineContextWrapper: SentryCrashDefaultMachineContextWrapper()) } override func stacktraceForCurrentThreadAsyncUnsafe() -> SentryStacktrace? { diff --git a/Tests/SentryTests/SentryCrashReportConverterTests.m b/Tests/SentryTests/SentryCrashReportConverterTests.m index cae05ffb0fb..2ada582492b 100644 --- a/Tests/SentryTests/SentryCrashReportConverterTests.m +++ b/Tests/SentryTests/SentryCrashReportConverterTests.m @@ -56,7 +56,7 @@ - (void)testConvertReport SentryException *exception = event.exceptions.firstObject; XCTAssertEqualObjects( - exception.stacktrace.frames.lastObject.symbolAddress, @"0x000000010014c1ec"); + exception.stacktrace.frames.lastObject.symbolAddress, @"0x0000000000000000"); XCTAssertEqualObjects( exception.stacktrace.frames.lastObject.instructionAddress, @"0x000000010014caa4"); XCTAssertEqualObjects( diff --git a/Tests/SentryTests/Transaction/SentrySpanTests.swift b/Tests/SentryTests/Transaction/SentrySpanTests.swift index 409f3e183de..8f4e8f93baf 100644 --- a/Tests/SentryTests/Transaction/SentrySpanTests.swift +++ b/Tests/SentryTests/Transaction/SentrySpanTests.swift @@ -470,8 +470,6 @@ class SentrySpanTests: XCTestCase { XCTAssertNotNil(serialization["data"]) let callStack = (serialization["data"] as? [String: Any])?["call_stack"] as? [[String: Any]] XCTAssertNotNil(callStack) - XCTAssertEqual(callStack?.first?["function"] as? String, TestData.mainFrame.function) - XCTAssertEqual(callStack?.last?["function"] as? String, TestData.testFrame.function) } func testSanitizeData() { diff --git a/develop-docs/DECISIONS.md b/develop-docs/DECISIONS.md index db4ab097d3e..e9708c8a42a 100644 --- a/develop-docs/DECISIONS.md +++ b/develop-docs/DECISIONS.md @@ -1,5 +1,13 @@ # Decision Log +## No local symbolication of crashes + +Date: Nov 7th, 2025 +Contributors: @noahsmartin, @philipphofmann + +We decided to remove local symbolication when capturing a crash. The existing local symbolication was not signal-safe and caused deadlocks (https://github.com/getsentry/sentry-cocoa/issues/6560). +It is possible to implement local symbolication that does not cause deadlocks; however, it would be a debug-only feature, since in production apps should have their symbols stripped and only available in the dSYM. Therefore, to quickly fix the issue, we decided to remove all unsafe local symbolication in v9. The addition of signal-safe symbolication for binaries with symbols can always be added in a future minor version. + ## Not capturing screenshots for crashes Date: April 21st 2022