Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit 9dee84e5400950c1fdfaecdb9923f73e15b461ae 0 parents
@devinross devinross authored
Showing with 3,105 additions and 0 deletions.
  1. +15 −0 .gitignore
  2. +109 −0 CrashReporter/CrashReportSender.h
  3. +875 −0 CrashReporter/CrashReportSender.m
  4. +1 −0  CrashReporter/CrashReporter.framework/CrashReporter
  5. +1 −0  CrashReporter/CrashReporter.framework/Headers
  6. +1 −0  CrashReporter/CrashReporter.framework/Resources
  7. BIN  CrashReporter/CrashReporter.framework/Versions/A/CrashReporter
  8. +199 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/CrashReporter.h
  9. +154 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReport.h
  10. +53 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportApplicationInfo.h
  11. +80 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportBinaryImageInfo.h
  12. +53 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportExceptionInfo.h
  13. +51 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportFormatter.h
  14. +85 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h
  15. +60 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportSignalInfo.h
  16. +117 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportSystemInfo.h
  17. +62 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportTextFormatter.h
  18. +114 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportThreadInfo.h
  19. +59 −0 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReporter.h
  20. +22 −0 CrashReporter/CrashReporter.framework/Versions/A/Resources/Info.plist
  21. +1 −0  CrashReporter/CrashReporter.framework/Versions/Current
  22. +11 −0 License.txt
  23. +49 −0 README.mdown
  24. +933 −0 symbolicatecrash
15 .gitignore
@@ -0,0 +1,15 @@
+# xcode noise
+build
+TapkuLibrary/build/**
+TapkuLibraryDemo/build/**
+*.pbxuser
+*.perspectivev3
+*.mode1v3
+
+# old skool
+.svn
+.cvs
+
+# osx noise
+.DS_Store
+#profile
109 CrashReporter/CrashReportSender.h
@@ -0,0 +1,109 @@
+/*
+ * Author: Andreas Linde <mail@andreaslinde.de>
+ * Kent Sutherland
+ *
+ * Copyright (c) 2009 Andreas Linde & Kent Sutherland. All rights reserved.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#define kCrashReportAnalyzerStarted @"CrashReportAnalyzerStarted" // flags if the crashlog analyzer is started. since this may crash we need to track it
+#define kCrashReportActivated @"CrashReportActivated" // flags if the crashreporter is activated at all
+#define kAutomaticallySendCrashReports @"AutomaticallySendCrashReports" // flags if the crashreporter should automatically send crashes without asking the user again
+
+typedef enum CrashAlertType {
+ CrashAlertTypeSend = 0,
+ CrashAlertTypeFeedback = 1,
+} CrashAlertType;
+
+typedef enum CrashReportStatus {
+ CrashReportStatusFailureVersionDiscontinued = -30, // This app version is set to discontinued, no new crash reports accepted by the server
+ CrashReportStatusFailureXMLSenderVersionNotAllowed = -21, // XML: Sender ersion string contains not allowed characters, only alphanumberical including space and . are allowed
+ CrashReportStatusFailureXMLVersionNotAllowed = -20, // XML: Version string contains not allowed characters, only alphanumberical including space and . are allowed
+ CrashReportStatusFailureSQLAddSymbolicateTodo = -18, // SQL for adding a symoblicate todo entry in the database failed
+ CrashReportStatusFailureSQLAddCrashlog = -17, // SQL for adding crash log in the database failed
+ CrashReportStatusFailureSQLAddVersion = -16, // SQL for adding a new version in the database failed
+ CrashReportStatusFailureSQLCheckVersionExists = -15, // SQL for checking if the version is already added in the database failed
+ CrashReportStatusFailureSQLAddPattern = -14, // SQL for creating a new pattern for this bug and set amount of occurrances to 1 in the database failed
+ CrashReportStatusFailureSQLCheckBugfixStatus = -13, // SQL for checking the status of the bugfix version in the database failed
+ CrashReportStatusFailureSQLUpdatePatternOccurances = -12, // SQL for updating the occurances of this pattern in the database failed
+ CrashReportStatusFailureSQLFindKnownPatterns = -11, // SQL for getting all the known bug patterns for the current app version in the database failed
+ CrashReportStatusFailureSQLSearchAppName = -10, // SQL for finding the bundle identifier in the database failed
+ CrashReportStatusFailureInvalidPostData = -3, // the post request didn't contain valid data
+ CrashReportStatusFailureInvalidIncomingData = -2, // incoming data may not be added, because e.g. bundle identifier wasn't found
+ CrashReportStatusFailureDatabaseNotAvailable = -1, // database cannot be accessed, check hostname, username, password and database name settings in config.php
+ CrashReportStatusUnknown = 0,
+ CrashReportStatusAssigned = 1,
+ CrashReportStatusSubmitted = 2,
+ CrashReportStatusAvailable = 3,
+} CrashReportStatus;
+
+// This protocol is used to send the image updates
+@protocol CrashReportSenderDelegate <NSObject>
+
+@optional
+
+-(NSString *) crashReportUserID; // Return the userid the crashreport should contain, empty by default
+-(NSString *) crashReportContact; // Return the contact value (e.g. email) the crashreport should contain, empty by default
+-(NSString *) crashReportDescription; // Return the description the crashreport should contain, empty by default
+
+-(void) connectionOpened; // Invoked when the internet connection is started, to let the app enable the activity indicator
+-(void) connectionClosed; // Invoked when the internet connection is closed, to let the app disable the activity indicator
+
+@end
+
+@interface CrashReportSender : NSObject <NSXMLParserDelegate> {
+ NSTimer *_submitTimer;
+
+ NSMutableString *_contentOfProperty;
+ CrashReportStatus _serverResult;
+
+ BOOL _crashReportActivated;
+ BOOL _crashReportFeedbackActivated;
+
+ int _crashReportAnalyzerStarted;
+ NSString *_crashesDir;
+
+ int _amountCrashes;
+ BOOL _crashIdenticalCurrentVersion;
+
+ id <CrashReportSenderDelegate> _delegate;
+
+ NSMutableArray *_crashFiles;
+
+ NSURL *_submissionURL;
+ NSMutableData *_responseData;
+ NSInteger _statusCode;
+}
+
++ (CrashReportSender *)sharedCrashReportSender;
+
+- (void)sendCrashReportToURL:(NSURL *)submissionURL delegate:(id <CrashReportSenderDelegate>)delegate activateFeedback:(BOOL)activateFeedback;
+
+- (BOOL) hasPendingCrashReport;
+- (NSString*) getLastCrashReport;
+
+@end
875 CrashReporter/CrashReportSender.m
@@ -0,0 +1,875 @@
+/*
+ * Author: Andreas Linde <mail@andreaslinde.de>
+ * Kent Sutherland
+ *
+ * Copyright (c) 2009 Andreas Linde & Kent Sutherland. All rights reserved.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <CrashReporter/CrashReporter.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import "CrashReportSender.h"
+
+#define USER_AGENT @"CrashReportSender/1.0"
+
+@interface CrashReportSender ()
+
+- (void)attemptCrashReportSubmission;
+- (void)showCrashStatusMessage;
+
+- (void)handleCrashReport;
+- (void)_cleanCrashReports;
+- (void)_sendCrashReports;
+
+- (NSString *)_crashLogStringForReport:(PLCrashReport *)report;
+- (void)_postXML:(NSString*)xml toURL:(NSURL*)url;
+- (BOOL)_isSubmissionHostReachable;
+
+- (BOOL)hasPendingCrashReport;
+- (void)wentOnline:(NSNotification *)note;
+
+@end
+
+@implementation CrashReportSender
+
++ (CrashReportSender *)sharedCrashReportSender
+{
+ static CrashReportSender *crashReportSender = nil;
+
+ if (crashReportSender == nil) {
+ crashReportSender = [[CrashReportSender alloc] init];
+ }
+
+ return crashReportSender;
+}
+
+- (id) init
+{
+ self = [super init];
+
+ if ( self != nil)
+ {
+ _serverResult = -1;
+ _amountCrashes = 0;
+ _crashIdenticalCurrentVersion = YES;
+ _crashReportFeedbackActivated = NO;
+ _delegate = nil;
+
+ NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kCrashReportAnalyzerStarted];
+ if (testValue == nil)
+ {
+ _crashReportAnalyzerStarted = 0;
+ } else {
+ _crashReportAnalyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kCrashReportAnalyzerStarted];
+ }
+
+ testValue = nil;
+ testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kCrashReportActivated];
+ if (testValue == nil)
+ {
+ _crashReportActivated = YES;
+ [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kCrashReportActivated];
+ } else {
+ _crashReportActivated = [[NSUserDefaults standardUserDefaults] boolForKey:kCrashReportActivated];
+ }
+
+ if (_crashReportActivated)
+ {
+ _crashFiles = [[NSMutableArray alloc] init];
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
+ _crashesDir = [[NSString stringWithFormat:@"%@", [[paths objectAtIndex:0] stringByAppendingPathComponent:@"/crashes/"]] retain];
+
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if (![fm fileExistsAtPath:_crashesDir])
+ {
+ NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: 0755] forKey: NSFilePosixPermissions];
+ NSError *theError = NULL;
+
+ [fm createDirectoryAtPath:_crashesDir withIntermediateDirectories: YES attributes: attributes error: &theError];
+ }
+
+ PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
+ NSError *error;
+
+ // Check if we previously crashed
+ if ([crashReporter hasPendingCrashReport])
+ [self handleCrashReport];
+
+ // Enable the Crash Reporter
+ if (![crashReporter enableCrashReporterAndReturnError: &error])
+ NSLog(@"Warning: Could not enable crash reporter: %@", error);
+ }
+ }
+ return self;
+}
+
+
+- (void) dealloc
+{
+ [super dealloc];
+ [_crashesDir release];
+ [_crashFiles release];
+ if (_submitTimer != nil)
+ {
+ [_submitTimer invalidate];
+ [_submitTimer release];
+ }
+}
+
+
+- (BOOL)hasPendingCrashReport
+{
+ if (_crashReportActivated)
+ {
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ if ([_crashFiles count] == 0 && [fm fileExistsAtPath:_crashesDir])
+ {
+ NSString *file;
+ NSError *error = nil;
+
+ NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath: _crashesDir];
+
+ while (file = [dirEnum nextObject])
+ {
+ NSDictionary *fileAttributes = [fm attributesOfItemAtPath:[_crashesDir stringByAppendingPathComponent:file] error:&error];
+ if ([[fileAttributes objectForKey:NSFileSize] intValue] > 0)
+ {
+ [_crashFiles addObject:file];
+ }
+ }
+ }
+
+ if ([_crashFiles count] > 0)
+ {
+ _amountCrashes = [_crashFiles count];
+ return YES;
+ }
+ else
+ return NO;
+ } else
+ return NO;
+}
+
+- (void)sendCrashReportToURL:(NSURL *)submissionURL delegate:(id <CrashReportSenderDelegate>)delegate activateFeedback:(BOOL)activateFeedback;
+{
+ if ([self hasPendingCrashReport])
+ {
+ [_submissionURL autorelease];
+ _submissionURL = [submissionURL copy];
+
+ _crashReportFeedbackActivated = activateFeedback;
+ _delegate = delegate;
+
+ if (_submitTimer == nil) {
+ _submitTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(attemptCrashReportSubmission) userInfo:nil repeats:NO];
+ }
+ }
+}
+
+- (void)registerOnline
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(wentOnline:)
+ name:@"kNetworkReachabilityChangedNotification"
+ object:nil];
+}
+
+- (void)unregisterOnline
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:@"kNetworkReachabilityChangedNotification"
+ object:nil];
+}
+
+- (void)wentOnline:(NSNotification *)note
+{
+ [self unregisterOnline];
+ [self attemptCrashReportSubmission];
+}
+
+- (void)attemptCrashReportSubmission
+{
+ _submitTimer = nil;
+
+ if (![self _isSubmissionHostReachable]) {
+ [self registerOnline];
+ } else if ([self hasPendingCrashReport]) {
+ [self unregisterOnline];
+
+ if (![[NSUserDefaults standardUserDefaults] boolForKey: kAutomaticallySendCrashReports]) {
+ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"CrashDataFoundTitle", @"Title showing in the alert box when crash report data has been found")
+ message:NSLocalizedString(@"CrashDataFoundDescription", @"Description explaining that crash data has been found and ask the user if the data might be uplaoded to the developers server")
+ delegate:self
+ cancelButtonTitle:NSLocalizedString(@"No", @"")
+ otherButtonTitles:NSLocalizedString(@"Yes", @""), NSLocalizedString(@"Always", @""), nil];
+
+ [alertView setTag: CrashAlertTypeSend];
+ [alertView show];
+ [alertView release];
+ } else {
+ [self _sendCrashReports];
+ }
+ }
+}
+
+
+- (void) showCrashStatusMessage
+{
+ UIAlertView *alertView;
+
+ _amountCrashes--;
+ if (_crashReportFeedbackActivated && _amountCrashes == 0 && _serverResult >= CrashReportStatusAssigned && _crashIdenticalCurrentVersion)
+ {
+ // show some feedback to the user about the crash status
+
+ switch (_serverResult) {
+ case CrashReportStatusAssigned:
+ alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedString(@"CrashResponseTitle", @"Title for the alertview giving feedback about the crash")
+ message: NSLocalizedString(@"CrashResponseNextRelease", @"Full text telling the bug is fixed and will be available in an upcoming release")
+ delegate: self
+ cancelButtonTitle: NSLocalizedString(@"Ok", @"")
+ otherButtonTitles: nil];
+ break;
+ case CrashReportStatusSubmitted:
+ alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedString(@"CrashResponseTitle", @"Title for the alertview giving feedback about the crash")
+ message: NSLocalizedString(@"CrashResponseWaitingApple", @"Full text telling the bug is fixed and the new release is waiting at Apple for approval")
+ delegate: self
+ cancelButtonTitle: NSLocalizedString(@"Ok", @"")
+ otherButtonTitles: nil];
+ break;
+ case CrashReportStatusAvailable:
+ alertView = [[UIAlertView alloc] initWithTitle: NSLocalizedString(@"CrashResponseTitle", @"Title for the alertview giving feedback about the crash")
+ message: NSLocalizedString(@"CrashResponseAvailable", @"Full text telling the bug is fixed and an update is available in the AppStore for download")
+ delegate: self
+ cancelButtonTitle: NSLocalizedString(@"Ok", @"")
+ otherButtonTitles: nil];
+ break;
+ default:
+ alertView = nil;
+ break;
+ }
+
+ if (alertView != nil)
+ {
+ [alertView setTag: CrashAlertTypeFeedback];
+ [alertView show];
+ [alertView release];
+ }
+ }
+}
+
+
+#pragma mark -
+#pragma mark UIAlertView Delegate
+
+- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
+{
+ if ([alertView tag] == CrashAlertTypeSend)
+ {
+ switch (buttonIndex) {
+ case 0:
+ [self _cleanCrashReports];
+ break;
+ case 1:
+ [self _sendCrashReports];
+ break;
+ case 2:
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAutomaticallySendCrashReports];
+
+ [self _sendCrashReports];
+ break;
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark NSXMLParser Delegate
+
+#pragma mark NSXMLParser
+
+- (void)parseXMLFileAtURL:(NSString *)url parseError:(NSError **)error
+{
+ NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
+ // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
+ [parser setDelegate:self];
+ // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
+ [parser setShouldProcessNamespaces:NO];
+ [parser setShouldReportNamespacePrefixes:NO];
+ [parser setShouldResolveExternalEntities:NO];
+
+ [parser parse];
+
+ NSError *parseError = [parser parserError];
+ if (parseError && error) {
+ *error = parseError;
+ }
+
+ [parser release];
+}
+
+- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
+{
+ if (qName)
+ {
+ elementName = qName;
+ }
+
+ if ([elementName isEqualToString:@"result"]) {
+ _contentOfProperty = [NSMutableString string];
+ }
+}
+
+- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
+{
+ if (qName)
+ {
+ elementName = qName;
+ }
+
+ if ([elementName isEqualToString: @"result"]) {
+ if ([_contentOfProperty intValue] > _serverResult) {
+ _serverResult = [_contentOfProperty intValue];
+ } else {
+ CrashReportStatus errorcode = [_contentOfProperty intValue];
+ NSLog(@"CrashReporter ended in error code: %i", errorcode);
+ }
+ }
+}
+
+
+- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
+{
+ if (_contentOfProperty)
+ {
+ // If the current element is one whose content we care about, append 'string'
+ // to the property that holds the content of the current element.
+ if (string != nil)
+ {
+ [_contentOfProperty appendString:string];
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark Private
+
+- (void)_cleanCrashReports
+{
+ NSError *error;
+
+ NSFileManager *fm = [NSFileManager defaultManager];
+
+ for (int i=0; i < [_crashFiles count]; i++)
+ {
+ [fm removeItemAtPath:[_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]] error:&error];
+ }
+ [_crashFiles removeAllObjects];
+}
+
+
+- (NSString*) getLastCrashReport
+{
+ NSError *error;
+ NSString *xml;
+ //NSString *userid = @"";
+ //NSString *contact = @"";
+ //NSString *description = @"";
+
+
+
+ for (int i=0; i < [_crashFiles count]; i++)
+ {
+ NSString *filename = [_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]];
+ NSData *crashData = [NSData dataWithContentsOfFile:filename];
+
+ if ([crashData length] > 0)
+ {
+ PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease];
+
+ NSString *crashLogString = [self _crashLogStringForReport:report];
+
+ if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] != NSOrderedSame)
+ {
+ _crashIdenticalCurrentVersion = NO;
+ }
+
+ /*
+
+ xml = [NSString stringWithFormat:@"<crash><applicationname>%s</applicationname><bundleidentifier>%@</bundleidentifier><systemversion>%@</systemversion><senderversion>%@</senderversion><version>%@</version><userid>%@</userid><contact>%@</contact><description>%@</description><log><![CDATA[%@]]></log></crash>",
+ [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String],
+ report.applicationInfo.applicationIdentifier,
+ [[UIDevice currentDevice] systemVersion],
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
+ report.applicationInfo.applicationVersion,
+ userid,
+ contact,
+ description,
+ crashLogString];
+ */
+ xml = crashLogString;
+
+ //[self _postXML:xml toURL:_submissionURL];
+ }
+ }
+
+ [self _cleanCrashReports];
+ return xml;
+}
+
+
+- (void)_sendCrashReports
+{
+ NSError *error;
+
+ NSString *userid = @"";
+ NSString *contact = @"";
+ NSString *description = @"";
+
+ if (_delegate != nil && [_delegate respondsToSelector:@selector(crashReportUserID)])
+ {
+ userid = [_delegate crashReportUserID];
+ }
+
+ if (_delegate != nil && [_delegate respondsToSelector:@selector(crashReportContact)])
+ {
+ contact = [_delegate crashReportContact];
+ }
+
+ if (_delegate != nil && [_delegate respondsToSelector:@selector(crashReportDescription)])
+ {
+ description = [_delegate crashReportDescription];
+ }
+
+
+ for (int i=0; i < [_crashFiles count]; i++)
+ {
+ NSString *filename = [_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]];
+ NSData *crashData = [NSData dataWithContentsOfFile:filename];
+
+ if ([crashData length] > 0)
+ {
+ PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease];
+
+ NSString *crashLogString = [self _crashLogStringForReport:report];
+
+ if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] != NSOrderedSame)
+ {
+ _crashIdenticalCurrentVersion = NO;
+ }
+
+ NSString *xml = [NSString stringWithFormat:@"<crash><applicationname>%s</applicationname><bundleidentifier>%@</bundleidentifier><systemversion>%@</systemversion><senderversion>%@</senderversion><version>%@</version><userid>%@</userid><contact>%@</contact><description>%@</description><log><![CDATA[%@]]></log></crash>",
+ [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String],
+ report.applicationInfo.applicationIdentifier,
+ [[UIDevice currentDevice] systemVersion],
+ [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
+ report.applicationInfo.applicationVersion,
+ userid,
+ contact,
+ description,
+ crashLogString];
+
+ [self _postXML:xml toURL:_submissionURL];
+ }
+ }
+
+ [self _cleanCrashReports];
+}
+
+
+- (NSString *)_crashLogStringForReport:(PLCrashReport *)report
+{
+ NSMutableString *xmlString = [NSMutableString string];
+
+ /* Header */
+ boolean_t lp64;
+
+ /* Map to apple style OS nane */
+ const char *osName;
+ switch (report.systemInfo.operatingSystem) {
+ case PLCrashReportOperatingSystemiPhoneOS:
+ osName = "iPhone OS";
+ break;
+ case PLCrashReportOperatingSystemiPhoneSimulator:
+ osName = "Mac OS X";
+ break;
+ default:
+ osName = "iPhone OS";
+ break;
+ }
+
+ /* Map to Apple-style code type */
+ NSString *codeType;
+ switch (report.systemInfo.architecture) {
+ case PLCrashReportArchitectureARM:
+ codeType = @"ARM (Native)";
+ lp64 = false;
+ break;
+ case PLCrashReportArchitectureX86_32:
+ codeType = @"X86";
+ lp64 = false;
+ break;
+ case PLCrashReportArchitectureX86_64:
+ codeType = @"X86-64";
+ lp64 = true;
+ break;
+ case PLCrashReportArchitecturePPC:
+ codeType = @"PPC";
+ lp64 = false;
+ break;
+ default:
+ codeType = @"ARM (Native)";
+ lp64 = false;
+ break;
+ }
+
+ [xmlString appendString:@"Incident Identifier: [TODO]\n"];
+ [xmlString appendString:@"CrashReporter Key: [TODO]\n"];
+
+ /* Application and process info */
+ {
+ NSString *unknownString = @"???";
+
+ NSString *processName = unknownString;
+ NSString *processId = unknownString;
+ NSString *processPath = unknownString;
+ NSString *parentProcessName = unknownString;
+ NSString *parentProcessId = unknownString;
+
+ /* Process information was not available in earlier crash report versions */
+ if (report.hasProcessInfo) {
+ /* Process Name */
+ if (report.processInfo.processName != nil)
+ processName = report.processInfo.processName;
+
+ /* PID */
+ processId = [[NSNumber numberWithUnsignedInteger: report.processInfo.processID] stringValue];
+
+ /* Process Path */
+ if (report.processInfo.processPath != nil)
+ processPath = report.processInfo.processPath;
+
+ /* Parent Process Name */
+ if (report.processInfo.parentProcessName != nil)
+ parentProcessName = report.processInfo.parentProcessName;
+
+ /* Parent Process ID */
+ parentProcessId = [[NSNumber numberWithUnsignedInteger: report.processInfo.parentProcessID] stringValue];
+ }
+
+ [xmlString appendFormat: @"Process: %@ [%@]\n", processName, processId];
+ [xmlString appendFormat: @"Path: %@\n", processPath];
+ [xmlString appendFormat: @"Identifier: %@\n", report.applicationInfo.applicationIdentifier];
+ [xmlString appendFormat: @"Version: %@\n", report.applicationInfo.applicationVersion];
+ [xmlString appendFormat: @"Code Type: %@\n", codeType];
+ [xmlString appendFormat: @"Parent Process: %@ [%@]\n", parentProcessName, parentProcessId];
+ }
+
+ [xmlString appendString:@"\n"];
+
+ /* System info */
+ [xmlString appendFormat:@"Date/Time: %s\n", [[report.systemInfo.timestamp description] UTF8String]];
+ [xmlString appendFormat:@"OS Version: %s %s\n", osName, [report.systemInfo.operatingSystemVersion UTF8String]];
+ [xmlString appendString:@"Report Version: 104\n"];
+
+ [xmlString appendString:@"\n"];
+
+ /* Exception code */
+ [xmlString appendFormat:@"Exception Type: %s\n", [report.signalInfo.name UTF8String]];
+ [xmlString appendFormat:@"Exception Codes: %@ at 0x%" PRIx64 "\n", report.signalInfo.code, report.signalInfo.address];
+
+ for (PLCrashReportThreadInfo *thread in report.threads) {
+ if (thread.crashed) {
+ [xmlString appendFormat: @"Crashed Thread: %ld\n", (long) thread.threadNumber];
+ break;
+ }
+ }
+
+ [xmlString appendString:@"\n"];
+
+ if (report.hasExceptionInfo) {
+ [xmlString appendString:@"Application Specific Information:\n"];
+ [xmlString appendFormat: @"*** Terminating app due to uncaught exception '%@', reason: '%@'\n",
+ report.exceptionInfo.exceptionName, report.exceptionInfo.exceptionReason];
+ [xmlString appendString:@"\n"];
+ }
+
+ /* Threads */
+ PLCrashReportThreadInfo *crashed_thread = nil;
+ for (PLCrashReportThreadInfo *thread in report.threads) {
+ if (thread.crashed) {
+ [xmlString appendFormat: @"Thread %ld Crashed:\n", (long) thread.threadNumber];
+ crashed_thread = thread;
+ } else {
+ [xmlString appendFormat: @"Thread %ld:\n", (long) thread.threadNumber];
+ }
+ for (NSUInteger frame_idx = 0; frame_idx < [thread.stackFrames count]; frame_idx++) {
+ PLCrashReportStackFrameInfo *frameInfo = [thread.stackFrames objectAtIndex: frame_idx];
+ PLCrashReportBinaryImageInfo *imageInfo;
+
+ /* Base image address containing instrumention pointer, offset of the IP from that base
+ * address, and the associated image name */
+ uint64_t baseAddress = 0x0;
+ uint64_t pcOffset = 0x0;
+ NSString *imageName = @"\?\?\?";
+
+ imageInfo = [report imageForAddress: frameInfo.instructionPointer];
+ if (imageInfo != nil) {
+ imageName = [imageInfo.imageName lastPathComponent];
+ baseAddress = imageInfo.imageBaseAddress;
+ pcOffset = frameInfo.instructionPointer - imageInfo.imageBaseAddress;
+ }
+
+ [xmlString appendFormat: @"%-4ld%-36s0x%08" PRIx64 " 0x%" PRIx64 " + %" PRId64 "\n",
+ (long) frame_idx, [imageName UTF8String], frameInfo.instructionPointer, baseAddress, pcOffset];
+ }
+ [xmlString appendString: @"\n"];
+ }
+
+ /* Registers */
+ if (crashed_thread != nil) {
+ [xmlString appendFormat: @"Thread %ld crashed with %@ Thread State:\n", (long) crashed_thread.threadNumber, codeType];
+
+ int regColumn = 1;
+ for (PLCrashReportRegisterInfo *reg in crashed_thread.registers) {
+ NSString *reg_fmt;
+
+ /* Use 32-bit or 64-bit fixed width format for the register values */
+ if (lp64)
+ reg_fmt = @"%6s:\t0x%016" PRIx64 " ";
+ else
+ reg_fmt = @"%6s:\t0x%08" PRIx64 " ";
+
+ [xmlString appendFormat: reg_fmt, [reg.registerName UTF8String], reg.registerValue];
+
+ if (regColumn % 4 == 0)
+ [xmlString appendString: @"\n"];
+ regColumn++;
+ }
+
+ if (regColumn % 3 != 0)
+ [xmlString appendString: @"\n"];
+
+ [xmlString appendString: @"\n"];
+ }
+
+ /* Images */
+ [xmlString appendFormat:@"Binary Images:\n"];
+
+ for (PLCrashReportBinaryImageInfo *imageInfo in report.images) {
+ NSString *uuid;
+ /* Fetch the UUID if it exists */
+ if (imageInfo.hasImageUUID)
+ uuid = imageInfo.imageUUID;
+ else
+ uuid = @"???";
+
+ NSString *device = @"\?\?\? (\?\?\?)";
+
+#ifdef _ARM_ARCH_6
+ device = @"armv6";
+#endif
+
+#ifdef _ARM_ARCH_7
+ device = @"armv7";
+#endif
+
+ /* base_address - terminating_address file_name identifier (<version>) <uuid> file_path */
+ [xmlString appendFormat:@"0x%" PRIx64 " - 0x%" PRIx64 " %@ %@ <%@> %@\n",
+ imageInfo.imageBaseAddress,
+ imageInfo.imageBaseAddress + imageInfo.imageSize,
+ [imageInfo.imageName lastPathComponent],
+ device,
+ uuid,
+ imageInfo.imageName];
+ }
+
+ return xmlString;
+}
+
+- (void)_postXML:(NSString*)xml toURL:(NSURL*)url
+{
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
+ NSString *boundary = @"----FOO";
+
+ [request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
+ [request setValue:USER_AGENT forHTTPHeaderField:@"User-Agent"];
+ [request setTimeoutInterval: 15];
+ [request setHTTPMethod:@"POST"];
+ NSString *contentType = [NSString stringWithFormat:@"multipart/form-data, boundary=%@", boundary];
+ [request setValue:contentType forHTTPHeaderField:@"Content-type"];
+
+ NSMutableData *postBody = [NSMutableData data];
+ [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:[@"Content-Disposition: form-data; name=\"xmlstring\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+ [request setHTTPBody:postBody];
+
+ _serverResult = CrashReportStatusUnknown;
+ _statusCode = 200;
+
+ //Release when done in the delegate method
+ _responseData = [[NSMutableData alloc] init];
+
+ if (_delegate != nil && [_delegate respondsToSelector:@selector(connectionOpened)])
+ {
+ [_delegate connectionOpened];
+ }
+
+ [[NSURLConnection connectionWithRequest:request delegate:self] retain];
+}
+
+#pragma mark NSURLConnection Delegate
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
+{
+ if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
+ _statusCode = [(NSHTTPURLResponse *)response statusCode];
+ }
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
+{
+ [_responseData appendData:data];
+}
+
+- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
+{
+ [_responseData release];
+ _responseData = nil;
+ [connection autorelease];
+
+ if (_delegate != nil && [_delegate respondsToSelector:@selector(connectionClosed)])
+ {
+ [_delegate connectionClosed];
+ }
+
+ [self showCrashStatusMessage];
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection
+{
+ if (_statusCode >= 200 && _statusCode < 400)
+ {
+ NSXMLParser *parser = [[NSXMLParser alloc] initWithData:_responseData];
+ // Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
+ [parser setDelegate:self];
+ // Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
+ [parser setShouldProcessNamespaces:NO];
+ [parser setShouldReportNamespacePrefixes:NO];
+ [parser setShouldResolveExternalEntities:NO];
+
+ [parser parse];
+
+ [parser release];
+ }
+
+ [_responseData release];
+ _responseData = nil;
+ [connection autorelease];
+
+ if (_delegate != nil && [_delegate respondsToSelector:@selector(connectionClosed)])
+ {
+ [_delegate connectionClosed];
+ }
+
+ [self showCrashStatusMessage];
+}
+
+#pragma mark PLCrashReporter
+
+//
+// Called to handle a pending crash report.
+//
+- (void) handleCrashReport
+{
+ PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
+ NSError *error;
+
+ // Try loading the crash report
+ NSData *crashData = [NSData dataWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]];
+
+ NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
+
+ if (crashData == nil) {
+ NSLog(@"Could not load crash report: %@", error);
+ goto finish;
+ } else {
+ [crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
+ }
+
+ // check if the next call ran successfully the last time
+ if (_crashReportAnalyzerStarted == 0)
+ {
+ // mark the start of the routine
+ _crashReportAnalyzerStarted = 1;
+ [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_crashReportAnalyzerStarted] forKey:kCrashReportAnalyzerStarted];
+
+ // We could send the report from here, but we'll just print out
+ // some debugging info instead
+ PLCrashReport *report = [[[PLCrashReport alloc] initWithData: [crashData retain] error: &error] autorelease];
+ if (report == nil) {
+ NSLog(@"Could not parse crash report");
+ goto finish;
+ }
+ }
+
+ // Purge the report
+finish:
+ // mark the end of the routine
+ _crashReportAnalyzerStarted = 0;
+ [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_crashReportAnalyzerStarted] forKey:kCrashReportAnalyzerStarted];
+
+ [crashReporter purgePendingCrashReport];
+ return;
+}
+
+#pragma mark Reachability
+
+- (BOOL)_isSubmissionHostReachable
+{
+ SCNetworkReachabilityFlags flags;
+ SCNetworkReachabilityRef reachabilityRef = nil;
+
+ if (![_submissionURL host] || ![[_submissionURL host] length]) {
+ return NO;
+ }
+
+ reachabilityRef = SCNetworkReachabilityCreateWithName(NULL, [[_submissionURL host] UTF8String]);
+
+ if (!reachabilityRef) {
+ return NO;
+ }
+
+ BOOL gotFlags = SCNetworkReachabilityGetFlags(reachabilityRef, &flags);
+
+ if (reachabilityRef != nil)
+ CFRelease(reachabilityRef);
+
+ return gotFlags && flags & kSCNetworkReachabilityFlagsReachable && (flags & kSCNetworkReachabilityFlagsIsWWAN || !(flags & kSCNetworkReachabilityFlagsConnectionRequired));
+}
+
+@end
1  CrashReporter/CrashReporter.framework/CrashReporter
1  CrashReporter/CrashReporter.framework/Headers
1  CrashReporter/CrashReporter.framework/Resources
BIN  CrashReporter/CrashReporter.framework/Versions/A/CrashReporter
Binary file not shown
199 CrashReporter/CrashReporter.framework/Versions/A/Headers/CrashReporter.h
@@ -0,0 +1,199 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#ifdef __APPLE__
+#import <AvailabilityMacros.h>
+#endif
+
+#import "PLCrashReporter.h"
+#import "PLCrashReport.h"
+#import "PLCrashReportTextFormatter.h"
+
+/**
+ * @defgroup functions Crash Reporter Functions Reference
+ */
+
+/**
+ * @defgroup types Crash Reporter Data Types Reference
+ */
+
+/**
+ * @defgroup constants Crash Reporter Constants Reference
+ */
+
+/**
+ * @defgroup plcrash_internal Crash Reporter Internal Documentation
+ */
+
+/**
+ * @defgroup enums Enumerations
+ * @ingroup constants
+ */
+
+/**
+ * @defgroup globals Global Variables
+ * @ingroup constants
+ */
+
+/**
+ * @defgroup exceptions Exceptions
+ * @ingroup constants
+ */
+
+/* Exceptions */
+extern NSString *PLCrashReporterException;
+
+/* Error Domain and Codes */
+extern NSString *PLCrashReporterErrorDomain;
+
+/**
+ * NSError codes in the Plausible Crash Reporter error domain.
+ * @ingroup enums
+ */
+typedef enum {
+ /** An unknown error has occured. If this
+ * code is received, it is a bug, and should be reported. */
+ PLCrashReporterErrorUnknown = 0,
+
+ /** An Mach or POSIX operating system error has occured. The underlying NSError cause may be fetched from the userInfo
+ * dictionary using the NSUnderlyingErrorKey key. */
+ PLCrashReporterErrorOperatingSystem = 1,
+
+ /** The crash report log file is corrupt or invalid */
+ PLCrashReporterErrorCrashReportInvalid = 2,
+} PLCrashReporterError;
+
+
+/* Library Imports */
+#import "PLCrashReporter.h"
+#import "PLCrashReport.h"
+#import "PLCrashReportTextFormatter.h"
+
+/**
+ * @mainpage Plausible Crash Reporter
+ *
+ * @section intro_sec Introduction
+ *
+ * Plausile CrashReporter implements in-process crash reporting on the iPhone and Mac OS X.
+ *
+ * The following features are supported:
+ *
+ * - Implemented as an in-process signal handler.
+ * - Does not interfer with debugging in gdb..
+ * - Handles both uncaught Objective-C exceptions and fatal signals (SIGSEGV, SIGBUS, etc).
+ * - Full thread state for all active threads (backtraces, register dumps) is provided.
+ *
+ * If your application crashes, a crash report will be written. When the application is next run, you may check for a
+ * pending crash report, and submit the report to your own HTTP server, send an e-mail, or even introspect the
+ * report locally.
+ *
+ * @section intro_encoding Crash Report Format
+ *
+ * Crash logs are encoded using <a href="http://code.google.com/p/protobuf/">google protobuf</a>, and may be decoded
+ * using the provided PLCrashReport API. Additionally, the include plcrashutil handles conversion of binary crash reports to the
+ * symbolicate-compatible iPhone text format.
+ *
+ * @section doc_sections Documentation Sections
+ * - @subpage example_usage_iphone
+ * - @subpage error_handling
+ */
+
+/**
+ * @page example_usage_iphone Example iPhone Usage
+ *
+ * @code
+ * //
+ * // Called to handle a pending crash report.
+ * //
+ * - (void) handleCrashReport {
+ * PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
+ * NSData *crashData;
+ * NSError *error;
+ *
+ * // Try loading the crash report
+ * crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error];
+ * if (crashData == nil) {
+ * NSLog(@"Could not load crash report: %@", error);
+ * goto finish;
+ * }
+ *
+ * // We could send the report from here, but we'll just print out
+ * // some debugging info instead
+ * PLCrashReport *report = [[[PLCrashReport alloc] initWithData: crashData error: &error] autorelease];
+ * if (report == nil) {
+ * NSLog(@"Could not parse crash report");
+ * goto finish;
+ * }
+ *
+ * NSLog(@"Crashed on %@", report.systemInfo.timestamp);
+ * NSLog(@"Crashed with signal %@ (code %@, address=0x%" PRIx64 ")", report.signalInfo.name,
+ * report.signalInfo.code, report.signalInfo.address);
+ *
+ * // Purge the report
+ * finish:
+ * [crashReporter purgePendingCrashReport];
+ * return;
+ * }
+ *
+ * // from UIApplicationDelegate protocol
+ * - (void) applicationDidFinishLaunching: (UIApplication *) application {
+ * PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
+ * NSError *error;
+ *
+ * // Check if we previously crashed
+ * if ([crashReporter hasPendingCrashReport])
+ * [self handleCrashReport];
+
+ * // Enable the Crash Reporter
+ * if (![crashReporter enableCrashReporterAndReturnError: &error])
+ * NSLog(@"Warning: Could not enable crash reporter: %@", error);
+ *
+ * }
+ * @endcode
+ *
+ */
+
+/**
+ * @page error_handling Error Handling Programming Guide
+ *
+ * Where a method may return an error, Plausible Crash Reporter provides access to the underlying
+ * cause via an optional NSError argument.
+ *
+ * All returned errors will be a member of one of the below defined domains, however, new domains and
+ * error codes may be added at any time. If you do not wish to report on the error cause, many methods
+ * support a simple form that requires no NSError argument.
+ *
+ * @section Error Domains, Codes, and User Info
+ *
+ * @subsection crashreporter_errors Crash Reporter Errors
+ *
+ * Any errors in Plausible Crash Reporter use the #PLCrashReporterErrorDomain error domain, and and one
+ * of the error codes defined in #PLCrashReporterError.
+ */
154 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReport.h
@@ -0,0 +1,154 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2010 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "PLCrashReportSystemInfo.h"
+#import "PLCrashReportApplicationInfo.h"
+#import "PLCrashReportProcessInfo.h"
+#import "PLCrashReportSignalInfo.h"
+#import "PLCrashReportThreadInfo.h"
+#import "PLCrashReportBinaryImageInfo.h"
+#import "PLCrashReportExceptionInfo.h"
+
+/**
+ * @ingroup constants
+ * Crash file magic identifier */
+#define PLCRASH_REPORT_FILE_MAGIC "plcrash"
+
+/**
+ * @ingroup constants
+ * Crash format version byte identifier. Will not change outside of the introduction of
+ * an entirely new crash log format. */
+#define PLCRASH_REPORT_FILE_VERSION 1
+
+/**
+ * @ingroup types
+ * Crash log file header format.
+ *
+ * Crash log files start with 7 byte magic identifier (#PLCRASH_REPORT_FILE_MAGIC),
+ * followed by a single unsigned byte version number (#PLCRASH_REPORT_FILE_VERSION).
+ * The crash log message format itself is extensible, so this version number will only
+ * be incremented in the event of an incompatible encoding or format change.
+ */
+struct PLCrashReportFileHeader {
+ /** Crash log magic identifier, not NULL terminated */
+ const char magic[7];
+
+ /** Crash log encoding/format version */
+ const uint8_t version;
+
+ /** File data */
+ const uint8_t data[];
+} __attribute__((packed));
+
+
+/**
+ * @internal
+ * Private decoder instance variables (used to hide the underlying protobuf parser).
+ */
+typedef struct _PLCrashReportDecoder _PLCrashReportDecoder;
+
+@interface PLCrashReport : NSObject {
+@private
+ /** Private implementation variables (used to hide the underlying protobuf parser) */
+ _PLCrashReportDecoder *_decoder;
+
+ /** System info */
+ PLCrashReportSystemInfo *_systemInfo;
+
+ /** Application info */
+ PLCrashReportApplicationInfo *_applicationInfo;
+
+ /** Process info */
+ PLCrashReportProcessInfo *_processInfo;
+
+ /** Signal info */
+ PLCrashReportSignalInfo *_signalInfo;
+
+ /** Thread info (PLCrashReportThreadInfo instances) */
+ NSArray *_threads;
+
+ /** Binary images (PLCrashReportBinaryImageInfo instances */
+ NSArray *_images;
+
+ /** Exception information (may be nil) */
+ PLCrashReportExceptionInfo *_exceptionInfo;
+}
+
+- (id) initWithData: (NSData *) encodedData error: (NSError **) outError;
+
+- (PLCrashReportBinaryImageInfo *) imageForAddress: (uint64_t) address;
+
+/**
+ * System information.
+ */
+@property(nonatomic, readonly) PLCrashReportSystemInfo *systemInfo;
+
+/**
+ * Application information.
+ */
+@property(nonatomic, readonly) PLCrashReportApplicationInfo *applicationInfo;
+
+/**
+ * YES if process information is available.
+ */
+@property(nonatomic, readonly) BOOL hasProcessInfo;
+
+/**
+ * Process information. Only available in later (v1.1+) crash report format versions. If not available,
+ * will be nil.
+ */
+@property(nonatomic, readonly) PLCrashReportProcessInfo *processInfo;
+
+/**
+ * Signal information. This provides the signal and signal code of the fatal signal.
+ */
+@property(nonatomic, readonly) PLCrashReportSignalInfo *signalInfo;
+
+/**
+ * Thread information. Returns a list of PLCrashReportThreadInfo instances.
+ */
+@property(nonatomic, readonly) NSArray *threads;
+
+/**
+ * Binary image information. Returns a list of PLCrashReportBinaryImageInfo instances.
+ */
+@property(nonatomic, readonly) NSArray *images;
+
+/**
+ * YES if exception information is available.
+ */
+@property(nonatomic, readonly) BOOL hasExceptionInfo;
+
+/**
+ * Exception information. Only available if a crash was caused by an uncaught exception,
+ * otherwise nil.
+ */
+@property(nonatomic, readonly) PLCrashReportExceptionInfo *exceptionInfo;
+
+@end
53 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportApplicationInfo.h
@@ -0,0 +1,53 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface PLCrashReportApplicationInfo : NSObject {
+@private
+ /** Application identifier */
+ NSString *_applicationIdentifier;
+
+ /** Application version */
+ NSString *_applicationVersion;
+}
+
+- (id) initWithApplicationIdentifier: (NSString *) applicationIdentifier
+ applicationVersion: (NSString *) applicationVersion;
+
+/**
+ * The application identifier. This is usually the application's CFBundleIdentifier value.
+ */
+@property(nonatomic, readonly) NSString *applicationIdentifier;
+
+/**
+ * The application version. This is usually the application's CFBundleVersion value.
+ */
+@property(nonatomic, readonly) NSString *applicationVersion;
+
+@end
80 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportBinaryImageInfo.h
@@ -0,0 +1,80 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface PLCrashReportBinaryImageInfo : NSObject {
+@private
+ /** Base image address */
+ uint64_t _baseAddress;
+
+ /** Image segment size */
+ uint64_t _imageSize;
+
+ /** Name of binary image */
+ NSString *_imageName;
+
+ /** If the UUID is available */
+ BOOL _hasImageUUID;
+
+ /** 128-bit object UUID. May be nil. */
+ NSString *_imageUUID;
+}
+
+- (id) initWithImageBaseAddress: (uint64_t) baseAddress
+ imageSize: (uint64_t) imageSize
+ imageName: (NSString *) imageName
+ imageUUID: (NSString *) imageUUID;
+
+/**
+ * Image base address.
+ */
+@property(nonatomic, readonly) uint64_t imageBaseAddress;
+
+/**
+ * Segment size.
+ */
+@property(nonatomic, readonly) uint64_t imageSize;
+
+/**
+ * Image name (absolute path)
+ */
+@property(nonatomic, readonly) NSString *imageName;
+
+
+/**
+ * YES if this image has an associated UUID.
+ */
+@property(nonatomic, readonly) BOOL hasImageUUID;
+
+/**
+ * 128-bit object UUID (matches Mach-O DWARF dSYM files). May be nil if unavailable.
+ */
+@property(nonatomic, readonly) NSString *imageUUID;
+
+@end
53 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportExceptionInfo.h
@@ -0,0 +1,53 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+
+@interface PLCrashReportExceptionInfo : NSObject {
+@private
+ /** Name */
+ NSString *_name;
+
+ /** Reason */
+ NSString *_reason;
+}
+
+- (id) initWithExceptionName: (NSString *) name reason: (NSString *) reason;
+
+/**
+ * The exception name.
+ */
+@property(nonatomic, readonly) NSString *exceptionName;
+
+/**
+ * The exception reason.
+ */
+@property(nonatomic, readonly) NSString *exceptionReason;
+
+@end
51 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportFormatter.h
@@ -0,0 +1,51 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2010 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "PLCrashReport.h"
+
+/**
+ * A crash report formatter accepts a PLCrashReport and formats according to implementation-specified rules (such
+ * as implementing text output support), writing the formatted result to a given output stream.
+ */
+@protocol PLCrashReportFormatter
+
+/**
+ * Format the provided @a report.
+ *
+ * @param report Report to be formatted.
+ * @param outError A pointer to an NSError object variable. If an error occurs, this pointer will contain an error
+ * object indicating why the pending crash report could not be formatted. If no error occurs, this parameter will
+ * be left unmodified. You may specify nil for this parameter, and no error information will be provided.
+ *
+ * @return Returns the formatted report data on success, or nil on failure.
+ */
+- (NSData *) formatReport: (PLCrashReport *) report error: (NSError **) outError;
+
+@end
85 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportProcessInfo.h
@@ -0,0 +1,85 @@
+/*
+ * Author: Damian Morris <damian@moso.com.au>
+ *
+ * Copyright (c) 2010 MOSO Corporation, Pty Ltd.
+ * Copyright (c) 2010 Plausible Labs Cooperative, Inc.
+ *
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface PLCrashReportProcessInfo : NSObject {
+@private
+ /** Process name */
+ NSString *_processName;
+
+ /** Process ID */
+ NSUInteger _processID;
+
+ /** Process path */
+ NSString* _processPath;
+
+ /** Parent process name */
+ NSString *_parentProcessName;
+
+ /** Parent process ID */
+ NSUInteger _parentProcessID;
+}
+
+- (id) initWithProcessName: (NSString *) processName
+ processID: (NSUInteger) processID
+ processPath: (NSString *) processPath
+ parentProcessName: (NSString *) parentProcessName
+ parentProcessID: (NSUInteger) parentProcessID;
+
+/**
+ * The process name. This value may not be included in the crash report, in which case this property
+ * will be nil.
+ */
+@property(nonatomic, readonly) NSString *processName;
+
+/**
+ * The process ID.
+ */
+@property(nonatomic, readonly) NSUInteger processID;
+
+/**
+ * The path to the process executable. This value may not be included in the crash report, in which case this property
+ * will be nil.
+ */
+@property(nonatomic, readonly) NSString *processPath;
+
+/**
+ * The parent process name. This value may not be included in the crash report, in which case this property
+ * will be nil.
+ */
+@property(nonatomic, readonly) NSString *parentProcessName;
+
+/**
+ * The parent process ID.
+ */
+@property(nonatomic, readonly) NSUInteger parentProcessID;
+
+@end
60 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportSignalInfo.h
@@ -0,0 +1,60 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface PLCrashReportSignalInfo : NSObject {
+@private
+ /** Signal name */
+ NSString *_name;
+
+ /** Signal code */
+ NSString *_code;
+
+ /** Fauling instruction or address */
+ uint64_t _address;
+}
+
+- (id) initWithSignalName: (NSString *) name code: (NSString *) code address: (uint64_t) address;
+
+/**
+ * The signal name.
+ */
+@property(nonatomic, readonly) NSString *name;
+
+/**
+ * The signal code.
+ */
+@property(nonatomic, readonly) NSString *code;
+
+/**
+ * The faulting instruction or address.
+ */
+@property(nonatomic, readonly) uint64_t address;
+
+@end
117 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportSystemInfo.h
@@ -0,0 +1,117 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ * @ingroup constants
+ *
+ * Indicates the Operating System under which a Crash Log was generated.
+ *
+ * @internal
+ * These enum values match the protobuf values. Keep them synchronized.
+ */
+typedef enum {
+ /** Mac OS X. */
+ PLCrashReportOperatingSystemMacOSX = 0,
+
+ /** iPhone OS */
+ PLCrashReportOperatingSystemiPhoneOS = 1,
+
+ /** iPhone Simulator (Mac OS X with additional simulator-specific runtime libraries) */
+ PLCrashReportOperatingSystemiPhoneSimulator = 2
+} PLCrashReportOperatingSystem;
+
+/**
+ * @ingroup constants
+ *
+ * Indicates the architecture under which a Crash Log was generated.
+ *
+ * @internal
+ * These enum values match the protobuf values. Keep them synchronized.
+ */
+typedef enum {
+ /** x86-32. */
+ PLCrashReportArchitectureX86_32 = 0,
+
+ /** x86-64 */
+ PLCrashReportArchitectureX86_64 = 1,
+
+ /** ARM */
+ PLCrashReportArchitectureARM = 2,
+
+ /** PPC */
+ PLCrashReportArchitecturePPC = 3
+} PLCrashReportArchitecture;
+
+
+extern PLCrashReportOperatingSystem PLCrashReportHostOperatingSystem;
+extern PLCrashReportArchitecture PLCrashReportHostArchitecture;
+
+@interface PLCrashReportSystemInfo : NSObject {
+@private
+ /** Operating system */
+ PLCrashReportOperatingSystem _operatingSystem;
+
+ /** Operating system version */
+ NSString *_osVersion;
+
+ /** Architecture */
+ PLCrashReportArchitecture _architecture;
+
+ /** Date crash report was generated. May be nil if the date is unknown. */
+ NSDate *_timestamp;
+}
+
+- (id) initWithOperatingSystem: (PLCrashReportOperatingSystem) operatingSystem
+ operatingSystemVersion: (NSString *) operatingSystemVersion
+ architecture: (PLCrashReportArchitecture) architecture
+ timestamp: (NSDate *) timestamp;
+
+/**
+ * The operating system.
+ */
+@property(nonatomic, readonly) PLCrashReportOperatingSystem operatingSystem;
+
+/**
+ * The operating system's release version.
+ */
+@property(nonatomic, readonly) NSString *operatingSystemVersion;
+
+/**
+ * Architecture.
+ */
+@property(nonatomic, readonly) PLCrashReportArchitecture architecture;
+
+/**
+ * Date and time that the crash report was generated. This may
+ * be unavailable, and this property will be nil.
+ */
+@property(nonatomic, readonly) NSDate *timestamp;
+
+@end
62 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportTextFormatter.h
@@ -0,0 +1,62 @@
+/*
+ * Authors:
+ * Landon Fuller <landonf@plausiblelabs.com>
+ * Damian Morris <damian@moso.com.au>
+ *
+ * Copyright (c) 2008-2010 Plausible Labs Cooperative, Inc.
+ * Copyright (c) 2010 MOSO Corporation, Pty Ltd.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+
+#import <Foundation/Foundation.h>
+
+#import "PLCrashReportFormatter.h"
+
+/**
+ * Supported text output formats.
+ *
+ * @ingroup enums
+ */
+typedef enum {
+ /** An iOS-compatible crash log text format. Compatible with the crash logs generated by the device and available
+ * through iTunes Connect. */
+ PLCrashReportTextFormatiOS = 0
+} PLCrashReportTextFormat;
+
+
+@interface PLCrashReportTextFormatter : NSObject <PLCrashReportFormatter> {
+@private
+ /** Text output format. */
+ PLCrashReportTextFormat _textFormat;
+
+ /** Encoding to use for string output. */
+ NSStringEncoding _stringEncoding;
+}
+
++ (NSString *) stringValueForCrashReport: (PLCrashReport *) report withTextFormat: (PLCrashReportTextFormat) textFormat;
+
+- (id) initWithTextFormat: (PLCrashReportTextFormat) textFormat stringEncoding: (NSStringEncoding) stringEncoding;
+
+@end
114 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReportThreadInfo.h
@@ -0,0 +1,114 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface PLCrashReportStackFrameInfo : NSObject {
+@private
+ /** Frame instruction pointer. */
+ uint64_t _instructionPointer;
+}
+
+- (id) initWithInstructionPointer: (uint64_t) instructionPointer;
+
+/**
+ * Frame's instruction pointer.
+ */
+@property(nonatomic, readonly) uint64_t instructionPointer;
+
+@end
+
+
+@interface PLCrashReportRegisterInfo : NSObject {
+@private
+ /** Register name */
+ NSString *_registerName;
+
+ /** Register value */
+ uint64_t _registerValue;
+}
+
+- (id) initWithRegisterName: (NSString *) registerName registerValue: (uint64_t) registerValue;
+
+/**
+ * Register name.
+ */
+@property(nonatomic, readonly) NSString *registerName;
+
+/**
+ * Register value.
+ */
+@property(nonatomic, readonly) uint64_t registerValue;
+
+@end
+
+
+@interface PLCrashReportThreadInfo : NSObject {
+@private
+ /** The thread number. Should be unique within a given crash log. */
+ NSInteger _threadNumber;
+
+ /** Ordered list of PLCrashReportStackFrame instances */
+ NSArray *_stackFrames;
+
+ /** YES if this thread crashed. */
+ BOOL _crashed;
+
+ /** List of PLCrashReportRegister instances. Will be empty if _crashed is NO. */
+ NSArray *_registers;
+}
+
+- (id) initWithThreadNumber: (NSInteger) threadNumber
+ stackFrames: (NSArray *) stackFrames
+ crashed: (BOOL) crashed
+ registers: (NSArray *) registers;
+
+/**
+ * Application thread number.
+ */
+@property(nonatomic, readonly) NSInteger threadNumber;
+
+/**
+ * Thread backtrace. Provides an array of PLCrashReportStackFrame instances.
+ * The array is ordered, last callee to first.
+ */
+@property(nonatomic, readonly) NSArray *stackFrames;
+
+/**
+ * If this thread crashed, set to YES.
+ */
+@property(nonatomic, readonly) BOOL crashed;
+
+/**
+ * State of the general purpose and related registers, as a list of
+ * PLCrashReportRegister instances. If this thead did not crash (crashed returns NO),
+ * this list will be empty.
+ */
+@property(nonatomic, readonly) NSArray *registers;
+
+@end
59 CrashReporter/CrashReporter.framework/Versions/A/Headers/PLCrashReporter.h
@@ -0,0 +1,59 @@
+/*
+ * Author: Landon Fuller <landonf@plausiblelabs.com>
+ *
+ * Copyright (c) 2008-2009 Plausible Labs Cooperative, Inc.
+ * 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 be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface PLCrashReporter : NSObject {
+@private
+ /** YES if the crash reporter has been enabled */
+ BOOL _enabled;
+
+ /** Application identifier */
+ NSString *_applicationIdentifier;
+
+ /** Application version */
+ NSString *_applicationVersion;
+
+ /** Path to the crash reporter internal data directory */
+ NSString *_crashReportDirectory;
+}
+
++ (PLCrashReporter *) sharedReporter;
+
+- (BOOL) hasPendingCrashReport;
+
+- (NSData *) loadPendingCrashReportData;
+- (NSData *) loadPendingCrashReportDataAndReturnError: (NSError **) outError;
+
+- (BOOL) purgePendingCrashReport;
+- (BOOL) purgePendingCrashReportAndReturnError: (NSError **) outError;
+
+- (BOOL) enableCrashReporter;
+- (BOOL) enableCrashReporterAndReturnError: (NSError **) outError;
+
+@end
22 CrashReporter/CrashReporter.framework/Versions/A/Resources/Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>CrashReporter</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.CrashReporter</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>CrashReporter</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
1  CrashReporter/CrashReporter.framework/Versions/Current
11 License.txt
@@ -0,0 +1,11 @@
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+   http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
49 README.mdown
@@ -0,0 +1,49 @@
+CrashReporter
+=============
+This repository is intended to help iOS developers easily put crash report emailing in their application.
+
+### Setup Your Application To Send Crash Reports
+
+Put this code in your application delegate:
+
+
+
+ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ ...
+
+ if([MFMailComposeViewController canSendMail] && [[CrashReportSender sharedCrashReportSender] hasPendingCrashReport]){
+
+ NSString *crashReport = [[CrashReportSender sharedCrashReportSender] getLastCrashReport];
+ MFMailComposeViewController *vc = [[MFMailComposeViewController alloc] init];
+ [vc setToRecipients:[NSArray arrayWithObject:@"YOUR_EMAIL@HERE.COM"]];
+ [vc setSubject:@"App Crash"];
+ vc.mailComposeDelegate = self;
+ NSData *data = [crashReport dataUsingEncoding:NSUTF8StringEncoding];
+
+ NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+ [formatter setDateStyle:NSDateFormatterShortStyle];
+ [formatter setTimeStyle:NSDateFormatterNoStyle];
+ NSString *date = [formatter stringFromDate:[NSDate date]];
+ [formatter release];
+
+ [vc addAttachmentData:data mimeType:@"text/xml" fileName:[NSString stringWithFormat:@"%@.crash",date]];
+ [navigationController presentModalViewController:vc animated:YES];
+ [vc release];
+ }
+
+ }
+ - (void) mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error{
+ [[CentralViewController sharedInstance] dismissModalViewControllerAnimated:YES];
+ }
+
+
+### Making sense of crash report
+
+Once you get the crash report, use symbolicatecrash to symbolize the crash report to make sense out of the file.
+`./symbolicatecrash "Report.crash"`
+
+### Links
+
+* [Creator's Homepage](http://devinsheaven.com)
+* [Creator's iOS framework](https://github.com/devinross/tapkulibrary)
+* [MacDevCrashReports](http://macdevcrashreports.com/)
933 symbolicatecrash
@@ -0,0 +1,933 @@
+#!/usr/bin/perl
+#
+# This script parses a crashdump file and attempts to resolve addresses into function names.
+#
+# It finds symbol-rich binaries by:
+# a) searching in Spotlight to find .dSYM files by UUID, then finding the executable from there.
+# That finds the symbols for binaries that a developer has built with "DWARF with dSYM File".
+# b) searching in various SDK directories.
+#
+# Copyright (c) 2008-2009 Apple Inc.. All Rights Reserved.
+#
+#
+
+use strict;
+use warnings;
+use Getopt::Std;
+use Cwd qw(realpath);
+
+#############################
+
+# Forward definitons
+sub usage();
+
+#############################
+
+# read and parse command line
+my %opt;
+$Getopt::Std::STANDARD_HELP_VERSION = 1;
+
+getopts('Ahvo:',\%opt);
+
+usage() if $opt{'h'};
+
+#############################
+
+# have this thing to de-HTMLize Leopard-era plists
+my %entity2char = (
+ # Some normal chars that have special meaning in SGML context
+ amp => '&', # ampersand
+ 'gt' => '>', # greater than
+ 'lt' => '<', # less than
+ quot => '"', # double quote; this " character in the comment keeps Xcode syntax coloring happy
+ apos => "'", # single quote '
+ );
+
+# Array of all the supported architectures.
+my %architectures = (
+ ARM => "armv6",
+ X86 => "i386",
+ "X86-64" => "x86_64",
+ PPC => "ppc",
+ "PPC-64" => "ppc64",
+ "ARMV4T" => "armv4t",
+ "ARMV5" => "armv5",
+ "ARMV6" => "armv6",
+ "ARMV7" => "armv7",
+);
+#############################
+
+
+my $devToolsPath = `/usr/bin/xcode-select -print-path`;
+chomp $devToolsPath;
+
+# Find otool from the latest iphoneos
+my $otool = `xcrun -sdk iphoneos -find otool`;
+chomp($otool);
+my $atos = `xcrun -sdk iphoneos -find atos`;
+chomp($atos);
+
+if ( ! -f $otool ) {
+ # if that doesn't exist, then assume the PDK was installed
+ $otool = "/usr/bin/otool";
+ $atos = "/usr/bin/atos";
+}
+print STDERR "otool path is '$otool'\n" if $opt{v};
+print STDERR "atos path is '$atos'\n" if $opt{v};
+
+# quotemeta makes the paths such that -f can't be used
+$devToolsPath = quotemeta($devToolsPath);
+$otool = quotemeta($otool);
+$atos = quotemeta($atos);
+
+
+#############################
+# run the script
+
+symbolicate_log(@ARGV);
+
+
+#############################
+
+# begin subroutines
+
+sub HELP_MESSAGE() {
+ usage();
+}
+
+sub usage() {
+print STDERR <<EOF;
+usage:
+ $0 [-Ah] [-o <OUTPUT_FILE>] LOGFILE [SYMBOL_PATH ...]
+
+ Symbolicates a crashdump LOGFILE which may be "-" to refer to stdin. By default,
+ all heuristics will be employed in an attempt to symbolicate all addresses.
+ Additional symbol files can be found under specified directories.
+
+Options:
+
+ -A Only symbolicate the application, not libraries
+ -o If specified, the symbolicated log will be written to OUTPUT_FILE (defaults to stdout)
+ -h Display this message
+ -v Verbose
+EOF
+exit 1;
+}
+
+##############
+
+sub getSymbolDirPaths {
+ my ($osBuild) = @_;
+
+ my @devToolsPaths = ($devToolsPath);
+
+ my @foundPaths = `mdfind -onlyin / "kMDItemCFBundleIdentifier == 'com.apple.Xcode'"`;
+
+ foreach my $foundPath (@foundPaths) {
+ chomp $foundPath;
+ $foundPath =~ s/\/Applications\/Xcode.app$//;
+ $foundPath = quotemeta($foundPath);
+ if( $foundPath ne $devToolsPath ) {
+ push(@devToolsPaths, $foundPath);
+ }
+ }
+
+ my @result = ();
+
+ foreach my $foundDevToolsPath (@devToolsPaths) {
+ my $symbolDirs = $foundDevToolsPath . '\/Platforms\/*\.platform/DeviceSupport\/*\/Symbols*';
+ my @pathResults = grep { -e && -d && !/Simulator/ } glob $symbolDirs;
+ print STDERR "Symbol directory paths: @pathResults\n" if $opt{v};
+ push(@result, @pathResults);
+ }
+
+ my @pathsForOSbuild = grep { /\($osBuild\)/ } @result;
+ if ( @pathsForOSbuild >= 1) {
+ print STDERR "Symbol directory path(s) for build $osBuild: @pathsForOSbuild\n" if $opt{v};
+ return @pathsForOSbuild;
+ } else {
+ # hmm, didn't find a path for the specific build, so return all the paths we got.
+ return @result;
+ }
+}
+
+sub getSymbolPathFor_searchpaths {
+ my ($bin,$path,$build,@extra_search_paths) = @_;
+ my @result;
+ for my $item (@extra_search_paths)
+ {
+ my $glob = "";
+
+ $glob .= quotemeta($item) . '\/' . quotemeta($bin) . "*";
+ $glob .= " " . quotemeta($item) . '\/*\/' . quotemeta($bin) . "*";
+ $glob .= " " . quotemeta($item) . quotemeta($path) . "*";
+
+ #print STDERR "\nSearching [$glob]..." if $opt{v};
+ push(@result, grep { -e && (! -d) } glob $glob);
+ }
+
+ print STDERR "\nSearching [@result]..." if $opt{v};
+ return @result;
+}
+
+sub getSymbolPathFor_uuid{
+ my ($uuid, $uuidsPath) = @_;
+ $uuid or return undef;
+ $uuid =~ /(.{4})(.{4})(.{4})(.{4})(.{4})(.{4})(.{8})/;
+ return Cwd::realpath("$uuidsPath/$1/$2/$3/$4/$5/$6/$7");
+}
+
+# Look up a dsym file by UUID in Spotlight, then find the executable from the dsym.
+sub getSymbolPathFor_dsymUuid{
+ my ($uuid,$arch) = @_;
+ $uuid or return undef;
+
+ # Convert a uuid from the crash log, like "c42a118d722d2625f2357463535854fd",
+ # to canonical format like "C42A118D-722D-2625-F235-7463535854FD".
+ my $myuuid = uc($uuid); # uuid's in Spotlight database are all uppercase
+ $myuuid =~ /(.{8})(.{4})(.{4})(.{4})(.{12})/;
+ $myuuid = "$1-$2-$3-$4-$5";
+
+ # Do the search in Spotlight.
+ my $cmd = "mdfind \"com_apple_xcode_dsym_uuids == $myuuid\"";
+ print STDERR "Running $cmd\n" if $opt{v};
+ my $dsymdir = `$cmd`;
+ chomp $dsymdir;
+ $dsymdir or return undef;
+ $dsymdir = quotemeta($dsymdir); # quote the result to handle spaces in path and executable names
+ print STDERR "dsym directory: $dsymdir\n" if $opt{v};
+
+ # Find the executable from the dsym.
+ $dsymdir =~ /(.*)\/(.*).dSYM/;
+ my $pathToDsym = $1;
+ my $dsymBaseName = $2;
+ my $executable = $dsymBaseName;
+ $executable =~ s/\..*//g; # strip off the suffix, if any
+
+ chop($executable);
+ my @paths = glob "$pathToDsym/$dsymBaseName/{,$executable,Contents/MacOS/$executable}";
+ print STDERR "paths: @paths\n" if $opt{v};
+
+ my @executablePath = grep { -x && ! -d } glob "$pathToDsym/$dsymBaseName/{,$executable,Contents/MacOS/$executable}";
+ my $executableCount = @executablePath;
+ if ( $executableCount > 1 ) {
+ print STDERR "Found more than one executable for a dsym: @executablePath\n" if $opt{v};
+ }
+ if ( $executableCount >= 1 ) {
+ if ( !matchesUUID($executablePath[0], $uuid, $arch) ) {
+ print STDERR "UUID doesn't match dsym for executable $executablePath[0]\n" if $opt{v};
+ } else {
+ print STDERR "Found executable $executablePath[0]\n" if $opt{v};
+ return $executablePath[0];
+ }
+ }
+ print STDERR "Did not find executable for dsym\n" if $opt{v};
+ return undef;
+}
+
+#########
+
+sub matchesUUID
+{
+ my ($path, $uuid, $arch) = @_;
+
+ if ( ! -f $path ) {
+ print STDERR "## $path doesn't exist " if $opt{v};
+ return 0;
+ }
+
+ my $TEST_uuid = `$otool -arch $arch -l "$path"`;
+
+ if ( $TEST_uuid =~ /uuid ((0x[0-9A-Fa-f]{2}\s+?){16})/ || $TEST_uuid =~ /uuid ([^\s]+)\s/ ) {
+ my $test = $1;
+
+ if ( $test =~ /^0x/ ) {
+ # old style 0xnn 0xnn 0xnn ... on two lines
+ $test = join("", split /\s*0x/, $test);
+
+ $test =~ s/0x//g; ## remove 0x
+ $test =~ s/\s//g; ## remove spaces
+ } else {
+ # new style XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
+ $test =~ s/-//g; ## remove -
+ $test = lc($test);
+ }
+
+ if ( $test eq $uuid ) {
+ ## See that it isn't stripped. Even fully stripped apps have one symbol, so ensure that there is more than one.
+ my ($nlocalsym) = $TEST_uuid =~ /nlocalsym\s+([0-9A-Fa-f]+)/;
+ my ($nextdefsym) = $TEST_uuid =~ /nextdefsym\s+([0-9A-Fa-f]+)/;
+ my $totalsym = $nextdefsym + $nlocalsym;
+ print STDERR "\nNumber of symbols in $path: $nextdefsym + $nlocalsym = $totalsym\n" if $opt{v};
+ return 1 if ( $totalsym > 1 );
+
+ print STDERR "## $path appears to be stripped, skipping.\n" if $opt{v};
+ } else {
+ print STDERR "Given UUID $uuid for '$path' is really UUID $test\n" if $opt{v};
+ }
+ } else {
+ print "Can't understand the output from otool ($TEST_uuid)";
+ }
+
+ return 0;
+}
+
+
+sub getSymbolPathFor {
+ my ($path,$build,$uuid,$arch,@extra_search_paths) = @_;
+
+ # derive a few more parameters...
+ my $bin = ($path =~ /^.*?([^\/]+)$/)[0]; # basename
+
+ # This setting can be tailored for a specific environment. If it's not present, oh well...
+ my $uuidsPath = "/Volumes/Build/UUIDToSymbolMap";
+ if ( ! -d $uuidsPath ) {
+ #print STDERR "No '$uuidsPath' path visible." if $opt{v};
+ }
+
+ # First try the simplest route, looking for a UUID match.
+ my $out_path;
+ $out_path = getSymbolPathFor_uuid($uuid, $uuidsPath);
+ undef $out_path if ( defined($out_path) && !length($out_path) );
+
+ print STDERR "--[$out_path] " if defined($out_path) and $opt{v};
+ print STDERR "--[undef] " if !defined($out_path) and $opt{v};
+
+ if ( !defined($out_path) || !matchesUUID($out_path, $uuid, $arch)) {
+ undef $out_path;
+
+ for my $func (
+ \&getSymbolPathFor_searchpaths,
+ ) {
+ my @out_path_arr = &$func($bin,$path,$build,@extra_search_paths);
+ if(@out_path_arr) {
+ foreach my $temp_path (@out_path_arr) {
+
+ print STDERR "--[$temp_path] " if defined($temp_path) and $opt{v};
+ print STDERR "--[undef] " if !defined($temp_path) and $opt{v};
+
+ if ( defined($temp_path) && matchesUUID($temp_path, $uuid, $arch) ) {
+ $out_path = $temp_path;
+ @out_path_arr = {};
+ } else {
+ undef $temp_path;
+ print STDERR "-- NO MATCH\n" if $opt{v};
+ }
+ }
+ } else {
+ print STDERR "-- NO MATCH\n" if $opt{v};
+ }
+
+ last if defined $out_path;
+ }
+ }
+ # if $out_path is defined here, then we have already verified that the UUID matches
+ if ( !defined($out_path) ) {
+ undef $out_path;
+ if ($path =~ m/^\/System\// || $path =~ m/^\/usr\//) {
+ # Don't use Spotlight to try to find dsym by UUID for system dylibs, since they won't have dsyms.
+ # We get here if the host system no longer has an SDK whose frameworks match the UUIDs in the crash logs.
+ print STDERR "NOT searching in Spotlight for dsym with UUID of $path\n" if $opt{v};
+ } else {
+ print STDERR "Searching in Spotlight for dsym with UUID of $path\n" if $opt{v};
+ $out_path = getSymbolPathFor_dsymUuid($uuid, $arch);
+ undef $out_path if ( defined($out_path) && !length($out_path) );
+ }
+ }
+
+ if (defined($out_path)) {
+ print STDERR "-- MATCH\n" if $opt{v};
+ return $out_path;
+ }
+
+ print STDERR "## Warning: Can't find any unstripped binary that matches version of $path\n" if $opt{v};
+ print STDERR "\n" if $opt{v};
+
+ return undef;
+}
+
+###########################
+# crashlog parsing
+###########################
+
+# options:
+# - regex: don't escape regex metas in name
+# - continuous: don't reset pos when done.
+# - multiline: expect content to be on many lines following name
+sub parse_section {
+ my ($log_ref, $name, %arg ) = @_;
+ my $content;
+
+ $name = quotemeta($name)
+ unless $arg{regex};
+
+ # content is thing from name to end of line...
+ if( $$log_ref =~ m{ ^($name)\: [[:blank:]]* (.*?) $ }mgx ) {
+ $content = $2;
+ $name = $1;
+
+ # or thing after that line.
+ if($arg{multiline}) {
+ $content = $1 if( $$log_ref =~ m{
+ \G\n # from end of last thing...
+ (.*?)
+ (?:\n\s*\n|$) # until next blank line or the end
+ }sgx );
+ }
+ }
+
+ pos($$log_ref) = 0
+ unless $arg{continuous};
+
+ return ($name,$content) if wantarray;
+ return $content;
+}
+
+# convenience method over above
+sub parse_sections {
+ my ($log_ref,$re,%arg) = @_;
+
+ my ($name,$content);
+ my %sections = ();
+
+ while(1) {
+ ($name,$content) = parse_section($log_ref,$re, regex=>1,continuous=>1,%arg);
+ last unless defined $content;
+ $sections{$name} = $content;
+ }
+
+ pos($$log_ref) = 0;
+ return \%sections;
+}
+
+sub parse_images {
+ my ($log_ref, $report_version) = @_;
+
+ my $section = parse_section($log_ref,'Binary Images Description',multiline=>1);
+ if (!defined($section)) {
+ $section = parse_section($log_ref,'Binary Images',multiline=>1); # new format
+ }
+ if (!defined($section)) {
+ die "Error: Can't find \"Binary Images\" section in log file";