Alastair’s Place

Software development, Cocoa, Objective-C, life. Stuff like that.

Symbolicating OS X Crash Logs

iOS developers have it easy; to symbolicate an iOS crash log, they can drop the log onto the Organiser window in Xcode, and — in theory at least — it will be symbolicated for them.

But on OS X, this doesn’t work. Moreover, the symbolicatecrash Perl script that iOS developers could use as an alternative doesn’t understand OS X crash logs and so will refuse to process them.

You could try using Peter Hosey’s Symbolicator package, but it’s a bit buggy — looking at the code, Peter has misunderstood the “slide”, and it also can’t cope with Xcode archives containing multiple dSYMs. I did contemplate fixing it and submitting a patch, but while I don’t want to be unkind to Peter, I think I’d end up rewriting rather too much of it in the process.

You could also try LLDB’s symbolicator, which you use like this:

$ lldb
(lldb) command script import lldb.macosx.crashlog
"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help
"malloc_info", "ptr_refs", "cstr_refs", and "objc_refs" commands have been installed, use the "--help" options on these commands for detailed help.
(lldb) crashlog /path/to/crash.log

This is actually really rather neat, or it would be if it worked. Unlike other symbolicators, it annotates the backtrace with your actual source code (and/or in some cases disassembly) so that you can see where the crash took place. Additionally, if you run it as above, within lldb itself, it will set up the memory map as if your program was loaded. Very cool.

You will note that I said if it worked. Because, out of the box, it does not. The first problem is that the version shipped by Apple relies on a script, dsymForUUID, that is not provided and whose behaviour is not documented anywhere. I wrote something that should be suitable and put it up on PyPI so you can install it with e.g.

$ sudo -H pip install dsymForUUID

(But wait… you might not need to.)

The second problem is that it’s also a bit broken. It chokes on some crash logs because they contain tab characters rather than spaces, and it also only loads the __TEXT segment in the correct place, which makes for a bit of fun if you need to poke around in one of the other segments.

Anyway, I filed a bug report today about all of this, with a patch attached to it that fixes these problems. I’ve also put a copy of the fixed crashlog.py file here so you can download and use it.

In addition to the usage shown on the lldb website, you can, in fact, invoke it directly from the Terminal prompt, e.g.

$ crashlog.py /path/to/crash.log

which is a very convenient way to use it in many cases. Likewise, if you want to use this version rather than the built-in one, you just need to make sure it’s in your PYTHONPATH, then you can do

$ lldb
(lldb) command script import crashlog

to use it in lldb.

The fixed version does not require dsymForUUID, and indeed it’s rather faster without it, but it can use a dsymForUUID script if you happen to have one (e.g. because you work at Apple). To use it with your custom dsymForUUID, you need to set the DSYMFORUUID environment variable to the full path of your script.

Update 2016-05-04

I found an interesting bug in the symbolicator; I’ve uploaded a new crashlog.py script that fixes it.

Update 2016-05-31

I’ve moved crashlog.py to Bitbucket, and added support for symbolicating the output of the sample command.