Skip to content
This repository has been archived by the owner on Feb 19, 2020. It is now read-only.

Commit

Permalink
Merge branch 'release/3.5.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
DerAndereAndi committed Feb 12, 2014
2 parents 328be7d + 4c9a268 commit 15d57cc
Show file tree
Hide file tree
Showing 20 changed files with 513 additions and 111 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ build
!default.xcworkspace
!project.xcworkspace
xcuserdata
xccheckout
profile
*.moved-aside

Expand Down
11 changes: 10 additions & 1 deletion Classes/BITAuthenticator.m
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ - (BOOL) handleOpenURL:(NSURL *) url
NSString *const kAuthorizationHost = @"authorize";
NSString *urlScheme = _urlScheme ? : [NSString stringWithFormat:@"ha%@", self.appIdentifier];
if(!([[url scheme] isEqualToString:urlScheme] && [[url host] isEqualToString:kAuthorizationHost])) {
BITHockeyLog(@"URL scheme for authentication doesn't match!");
return NO;
}

Expand Down Expand Up @@ -611,6 +612,7 @@ - (BOOL) handleOpenURL:(NSURL *) url
}

if(installationIdentifier){
BITHockeyLog(@"Authentication succeeded.");
if(NO == self.restrictApplicationUsage) {
[self dismissAuthenticationControllerAnimated:YES completion:nil];
}
Expand All @@ -622,6 +624,7 @@ - (BOOL) handleOpenURL:(NSURL *) url
}
} else {
//reset token
BITHockeyLog(@"Resetting authentication token");
[self storeInstallationIdentifier:nil withType:self.identificationType];
self.identified = NO;
if(self.identificationCompletion) {
Expand Down Expand Up @@ -693,6 +696,8 @@ - (void)processFullSizeImage {
return;
}

BITHockeyLog(@"Processing full size image for possible authentication");

unsigned char *buffer, *source;
source = (unsigned char *)malloc((unsigned long)fs.st_size);
if (read(fd, source, (unsigned long)fs.st_size) != fs.st_size) {
Expand Down Expand Up @@ -720,7 +725,8 @@ - (void)processFullSizeImage {
length = ntohl(length);

buffer += 4;
name = (unsigned char *)malloc(4);
name = (unsigned char *)malloc(5);
name[4] = 0;
memcpy(name, buffer, 4);

buffer += 4;
Expand Down Expand Up @@ -754,7 +760,10 @@ - (void)processFullSizeImage {
free(source);

if (result) {
BITHockeyLog(@"Authenticating using full size image information: %@", result);
[self handleOpenURL:[NSURL URLWithString:result] sourceApplication:nil annotation:nil];
} else {
BITHockeyLog(@"No authentication information found");
}
}

Expand Down
14 changes: 14 additions & 0 deletions Classes/BITCrashManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,20 @@ typedef NS_ENUM(NSUInteger, BITCrashManagerStatus) {
@property (nonatomic, assign, getter=isMachExceptionHandlerEnabled) BOOL enableMachExceptionHandler;


/**
* Enable on device symbolication for system symbols
*
* By default, the SDK does not symbolicate on the device, since this can
* take a few seconds at each crash. Also note that symbolication on the
* device might not be able to retrieve all symbols.
*
* Enable if you want to analyze crashes on unreleased OS versions.
*
* Default: _NO_
*/
@property (nonatomic, assign, getter=isOnDeviceSymbolicationEnabled) BOOL enableOnDeviceSymbolication;


/**
* Set the callbacks that will be executed prior to program termination after a crash has occurred
*
Expand Down
29 changes: 14 additions & 15 deletions Classes/BITCrashManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,7 @@ - (id)init {
[[NSUserDefaults standardUserDefaults] setInteger:_crashManagerStatus forKey:kBITCrashManagerStatus];
}

// temporary directory for crashes grabbed from PLCrashReporter
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
_crashesDir = [[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER];

if (![self.fileManager fileExistsAtPath:_crashesDir]) {
NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: 0755] forKey: NSFilePosixPermissions];
NSError *theError = NULL;

[self.fileManager createDirectoryAtPath:_crashesDir withIntermediateDirectories: YES attributes: attributes error: &theError];
}

_crashesDir = bit_settingsDir();
_settingsFile = [_crashesDir stringByAppendingPathComponent:BITHOCKEY_CRASH_SETTINGS];
_analyzerInProgressFile = [_crashesDir stringByAppendingPathComponent:BITHOCKEY_CRASH_ANALYZER];

Expand Down Expand Up @@ -308,7 +298,8 @@ - (void) unregisterObservers {
* @return The userID value
*/
- (NSString *)userIDForCrashReport {
NSString *userID = @"";
// first check the global keychain storage
NSString *userID = [self stringValueFromKeychainForKey:kBITHockeyMetaUserID] ?: @"";

#if HOCKEYSDK_FEATURE_AUTHENTICATOR
// if we have an identification from BITAuthenticator, use this as a default.
Expand Down Expand Up @@ -337,7 +328,8 @@ - (NSString *)userIDForCrashReport {
* @return The userName value
*/
- (NSString *)userNameForCrashReport {
NSString *username = @"";
// first check the global keychain storage
NSString *username = [self stringValueFromKeychainForKey:kBITHockeyMetaUserName] ?: @"";

if (self.delegate && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) {
username = [self.delegate userNameForCrashManager:self] ?: @"";
Expand All @@ -358,7 +350,8 @@ - (NSString *)userNameForCrashReport {
* @return The userEmail value
*/
- (NSString *)userEmailForCrashReport {
NSString *useremail = @"";
// first check the global keychain storage
NSString *useremail = [self stringValueFromKeychainForKey:kBITHockeyMetaUserEmail] ?: @"";

#if HOCKEYSDK_FEATURE_AUTHENTICATOR
// if we have an identification from BITAuthenticator, use this as a default.
Expand Down Expand Up @@ -667,8 +660,14 @@ - (void)startManager {
if (self.isMachExceptionHandlerEnabled) {
signalHandlerType = PLCrashReporterSignalHandlerTypeMach;
}

PLCrashReporterSymbolicationStrategy symbolicationStrategy = PLCrashReporterSymbolicationStrategyNone;
if (self.isOnDeviceSymbolicationEnabled) {
symbolicationStrategy = PLCrashReporterSymbolicationStrategyAll;
}

BITPLCrashReporterConfig *config = [[BITPLCrashReporterConfig alloc] initWithSignalHandlerType: signalHandlerType
symbolicationStrategy: PLCrashReporterSymbolicationStrategyAll];
symbolicationStrategy: symbolicationStrategy];
self.plCrashReporter = [[BITPLCrashReporter alloc] initWithConfiguration: config];

// Check if we previously crashed
Expand Down
193 changes: 191 additions & 2 deletions Classes/BITCrashReportTextFormatter.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@

#import <CrashReporter/CrashReporter.h>

#import <mach-o/dyld.h>
#import <mach-o/getsect.h>
#import <mach-o/ldsyms.h>
#import <dlfcn.h>
#import <Availability.h>

#if defined(__OBJC2__)
#define SEL_NAME_SECT "__objc_methname"
#else
#define SEL_NAME_SECT "__cstring"
#endif

#import "BITCrashReportTextFormatter.h"

/*
Expand Down Expand Up @@ -67,6 +79,112 @@ static NSInteger bit_binaryImageSort(id binary1, id binary2, void *context) {
return NSOrderedSame;
}

/**
* Validates that the given @a string terminates prior to @a limit.
*/
static const char *safer_string_read (const char *string, const char *limit) {
const char *p = string;
do {
if (p >= limit || p+1 >= limit) {
return NULL;
}
p++;
} while (*p != '\0');

return string;
}

/*
* The relativeAddress should be `<ecx/rsi/r1/x1 ...> - <image base>`, extracted from the crash report's thread
* and binary image list.
*
* For the (architecture-specific) registers to attempt, see:
* http://sealiesoftware.com/blog/archive/2008/09/22/objc_explain_So_you_crashed_in_objc_msgSend.html
*/
static const char *findSEL (const char *imageName, NSString *imageUUID, uint64_t relativeAddress) {
unsigned int images_count = _dyld_image_count();
for (unsigned int i = 0; i < images_count; ++i) {
intptr_t slide = _dyld_get_image_vmaddr_slide(i);
const struct mach_header *header = _dyld_get_image_header(i);
const struct mach_header_64 *header64 = (const struct mach_header_64 *) header;
const char *name = _dyld_get_image_name(i);

/* Image disappeared? */
if (name == NULL || header == NULL)
continue;

/* Check if this is the correct image. If we were being even more careful, we'd check the LC_UUID */
if (strcmp(name, imageName) != 0)
continue;

/* Determine whether this is a 64-bit or 32-bit Mach-O file */
BOOL m64 = NO;
if (header->magic == MH_MAGIC_64)
m64 = YES;

NSString *uuidString = nil;
const uint8_t *command;
uint32_t ncmds;

if (m64) {
command = (const uint8_t *)(header64 + 1);
ncmds = header64->ncmds;
} else {
command = (const uint8_t *)(header + 1);
ncmds = header->ncmds;
}
for (uint32_t idx = 0; idx < ncmds; ++idx) {
const struct load_command *load_command = (const struct load_command *)command;
if (load_command->cmd == LC_UUID) {
const struct uuid_command *uuid_command = (const struct uuid_command *)command;
const uint8_t *uuid = uuid_command->uuid;
uuidString = [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
uuid[8], uuid[9], uuid[10], uuid[11],
uuid[12], uuid[13], uuid[14], uuid[15]]
lowercaseString];
break;
} else {
command += load_command->cmdsize;
}
}

// Check if this is the correct image by comparing the UUIDs
if (!uuidString || ![uuidString isEqualToString:imageUUID])
continue;

/* Fetch the __objc_methname section */
const char *methname_sect;
uint64_t methname_sect_size;
if (m64) {
methname_sect = getsectdatafromheader_64(header64, SEG_TEXT, SEL_NAME_SECT, &methname_sect_size);
} else {
uint32_t meth_size_32;
methname_sect = getsectdatafromheader(header, SEG_TEXT, SEL_NAME_SECT, &meth_size_32);
methname_sect_size = meth_size_32;
}

/* Apply the slide, as per getsectdatafromheader(3) */
methname_sect += slide;

if (methname_sect == NULL) {
return NULL;
}

/* Calculate the target address within this image, and verify that it is within __objc_methname */
const char *target = ((const char *)header) + relativeAddress;
const char *limit = methname_sect + methname_sect_size;
if (target < methname_sect || target >= limit) {
return NULL;
}

/* Read the actual method name */
return safer_string_read(target, limit);
}

return NULL;
}

/**
* Formats PLCrashReport data as human-readable text.
Expand Down Expand Up @@ -282,13 +400,51 @@ + (NSString *)stringValueForCrashReport:(BITPLCrashReport *)report crashReporter

[text appendString: @"\n"];

BITPLCrashReportThreadInfo *crashed_thread = nil;
for (BITPLCrashReportThreadInfo *thread in report.threads) {
if (thread.crashed) {
crashed_thread = thread;
break;
}
}

/* Uncaught Exception */
if (report.hasExceptionInfo) {
[text appendFormat: @"Application Specific Information:\n"];
[text appendFormat: @"*** Terminating app due to uncaught exception '%@', reason: '%@'\n",
report.exceptionInfo.exceptionName, report.exceptionInfo.exceptionReason];

[text appendString: @"\n"];
} else if (crashed_thread != nil) {
// try to find the selector in case this was a crash in obj_msgSend
// we search this wether the crash happend in obj_msgSend or not since we don't have the symbol!

NSString *foundSelector = nil;

// search the registers value for the current arch
#if TARGET_IPHONE_SIMULATOR
if (lp64) {
foundSelector = [[self class] selectorForRegisterWithName:@"rsi" ofThread:crashed_thread report:report];
if (foundSelector == NULL)
foundSelector = [[self class] selectorForRegisterWithName:@"rdx" ofThread:crashed_thread report:report];
} else {
foundSelector = [[self class] selectorForRegisterWithName:@"ecx" ofThread:crashed_thread report:report];
}
#else
if (lp64) {
foundSelector = [[self class] selectorForRegisterWithName:@"x1" ofThread:crashed_thread report:report];
} else {
foundSelector = [[self class] selectorForRegisterWithName:@"r1" ofThread:crashed_thread report:report];
if (foundSelector == NULL)
foundSelector = [[self class] selectorForRegisterWithName:@"r2" ofThread:crashed_thread report:report];
}
#endif

if (foundSelector) {
[text appendFormat: @"Application Specific Information:\n"];
[text appendFormat: @"Selector name found in current argument registers: %@\n", foundSelector];
[text appendString: @"\n"];
}
}

/* If an exception stack trace is available, output an Apple-compatible backtrace. */
Expand All @@ -308,12 +464,10 @@ + (NSString *)stringValueForCrashReport:(BITPLCrashReport *)report crashReporter
}

/* Threads */
BITPLCrashReportThreadInfo *crashed_thread = nil;
NSInteger maxThreadNum = 0;
for (BITPLCrashReportThreadInfo *thread in report.threads) {
if (thread.crashed) {
[text appendFormat: @"Thread %ld Crashed:\n", (long) thread.threadNumber];
crashed_thread = thread;
} else {
[text appendFormat: @"Thread %ld:\n", (long) thread.threadNumber];
}
Expand Down Expand Up @@ -417,6 +571,41 @@ + (NSString *)stringValueForCrashReport:(BITPLCrashReport *)report crashReporter
return text;
}

/**
* Return the selector string of a given register name
*
* @param regName The name of the register to use for getting the address
* @param thread The crashed thread
* @param images NSArray of binary images
*
* @return The selector as a C string or NULL if no selector was found
*/
+ (NSString *)selectorForRegisterWithName:(NSString *)regName ofThread:(BITPLCrashReportThreadInfo *)thread report:(BITPLCrashReport *)report {
// get the address for the register
uint64_t regAddress = 0;

for (BITPLCrashReportRegisterInfo *reg in thread.registers) {
if ([reg.registerName isEqualToString:regName]) {
regAddress = reg.registerValue;
break;
}
}

if (regAddress == 0)
return nil;

BITPLCrashReportBinaryImageInfo *imageForRegAddress = [report imageForAddress:regAddress];
if (imageForRegAddress) {
// get the SEL
const char *foundSelector = findSEL([imageForRegAddress.imageName UTF8String], imageForRegAddress.imageUUID, regAddress - (uint64_t)imageForRegAddress.imageBaseAddress);

return [NSString stringWithUTF8String:foundSelector];
}

return nil;
}


/**
* Returns an array of app UUIDs and their architecture
* As a dictionary for each element
Expand Down
Loading

0 comments on commit 15d57cc

Please sign in to comment.