What's a stack trace?
Whenever one of your methods gets called, it puts this onto the stack. A stack trace is a way of finding out which class and method your app crashed in, which often narrows down the bug to a single line.
Of course to do this, the stack trace needs to be readable, rather than a whole load of hex numbers.
Check out atos.
To prevent this happening again, you could interpret this Call Stack using atos.
See the Stack Traces page of the Cocoa Dev wiki for a discussion and code on how to convert these numbers into meaningful methods.
You'll need to figure out a way of integrating this with the crash reporter. I use UKCrashReporter and I've modified Uli's code so that if there's an uncaught exception it adds the readable stack trace onto the crash report.
Code Sample
I've taken inspiration from the ESStackTrace class and here's what I do:
-(void)logAndSaveStackTrace {
NSString *stackTrace = [[self userInfo] objectForKey:NSStackTraceKey];
NSString *atosCommand;
if (stackTrace) {
// If the stack trace key is present, pull out the addresses and convert to method names using atos.
atosCommand = [NSString stringWithFormat:@"/usr/bin/atos -p %d %@ | tail -n +3 | head -n +%d | c++filt | cat -n",
[[NSProcessInfo processInfo] processIdentifier],
stackTrace,
([[stackTrace componentsSeparatedByString:@" "] count] - 4)];
} else {
// If there isn't a stack trace key or it's nil, try and work out the stack using the internal callStackReturn addresses method.
NSArray *stackTraceArray = [self callStackReturnAddresses];
atosCommand = [NSString stringWithFormat:@"/usr/bin/atos -p %d %@",
[[NSProcessInfo processInfo] processIdentifier],
[stackTraceArray componentsJoinedByString:@" "]];
}
NSString *readableStackTrace = [ShellTask executeShellCommandSynchronously:atosCommand];
NSString *exceptionMessageForCrashReport = [NSString stringWithFormat:@"An exception of type %s occured.\n%s\nStack trace:\n%@",
[[self name] cStringUsingEncoding:NSUTF8StringEncoding],
[[self reason] cStringUsingEncoding:NSUTF8StringEncoding],
readableStackTrace];
[[NSUserDefaults standardUserDefaults] setObject:exceptionMessageForCrashReport forKey:@"uncaughtExceptionReport"];
[[NSUserDefaults standardUserDefaults] synchronize];
// Log the exception to the console too.
NSLog(@"%@", exceptionMessageForCrashReport);
}
Dependencies Ahoy!
Of course, one of the problems with this approach is that you're introducing a dependency on atos. I've been told that it's installed as standard on 10.5 and later, but this might be wrong. Eventually I'm going to make a little installer which adds atos if my app can't find it.