Crazy Croutons

“Y'all need to get your shit together! You hear me, humans? Your shit is all outta whack! You're all over the place like a bunch of crazy croutons and tomatoes in a crazy salad!” *



Patrick Renner's
public bookmarks on weird stories, beautiful products, loud music and stunning images.


flickr.com/photos/iptrk

Twitter Logo twitter.com/iptrkpm

Pomfort Logo
pomfort.com   

Debugging NSExceptions without debugger

Let’s assume your client reports unexpected behavior of your Cocoa application and the reason is an uncaught exception. If this exception isn’t handled at all, the application crashes and you get a nice stack trace in Apple’s crash report. But sometimes the AppKit catches the exception quite top-level (for example above delegate calls or bindings) and just quits the current runloop with very few log output. The result could be something like

*** -[NSPlaceholderString initWithString:]: nil argument

in the console log. But how do you know where that comes from without a stack trace?

In the Controlling a Program’s Response to Exceptions document Apple documents a great feature of the exception handling system of Cocoa: You can set the logging of exceptions (handled or not) via the defaults-system of Mac OS X:

defaults write NSGlobalDomain NSExceptionHandlingMask 320

enables logging of a stack trace for every caught or uncaught NSException raised in any application - including yours. What you get is a stack trace of hex-addresses, so the final step is using the atos tool to translate the hex addresses to method names.

If you didn’t strip symbols, you can for example start the application and type

$ atos -p 22700 0x90426c0b

where 22700 is your app’s pid and 0x90426c0b an address from the stack trace (using it with pid works more reliably for me than using it with -o on the executable).

The cool thing is: Your client can do that with just one command in the Terminal app and a quick look into the Console app. No gdb, no extra debug versions. But don’t forget to unset the debug option, as the log gets quite full with all the system-wide exceptions.