Archive for January, 2008

Application Specific Information in Leopard Crash Reports

Friday, January 4th, 2008

Mac OS X Leopard added a lot of new features in the Crash Reporter giving much better crash reports in a number of situations. One of these enhancements you’ll see in applications like DashboardClient is that crash logs can contain an “Application Specific Information” section, with any text that application wants to appear in the crash log. Naturally the ability to add information to the crash report is currently Apple-only secret sauce. So how do they do it?

Searching for Some Clues

First up let’s take a look at what the application specific information looks like in a crash log.

Process:         DashboardClient [3786]
Path:            /System/Library/CoreServices/
Version:         1.5 (1.5)
Build Info:      Dock-5880000~1
Code Type:       X86 (Native)
Parent Process:  Dock [96353]

Date/Time:       2007-11-07 11:46:49.476 +1100
OS Version:      Mac OS X 10.5 (9A581)
Report Version:  6

Exception Codes: KERN_INVALID_ADDRESS at 0x00000000c56c0db3
Crashed Thread:  0

Application Specific Information:
/Library/Widgets/World Clock.wdgt/
/Library/Widgets/World Clock.wdgt/


Further information with the usual backtrace and image information is shown below this part of the crash log.

OK, so now we know that the DashboardClient can put application specific information into the crash log, let’s take a look at the symbols that DashboardClient references:

$ nm DashboardClient
         U ___CFConstantStringClassReference
000161fc D ___crashreporter_info__
         U __kLSASNKey

Aha! Here we’ve got a symbol that looks pretty likely. It’s a data symbol (the D after the address) not a function symbol so it’s not something we need to call to tell the crash reporter something.

Some Experiments

Given that this seems to be a data pointer let’s take a logical jump that it’s probably going to be a pointer to some data: most likely the string of data that will be displayed in the crash log. Given this assumption, it’s time to try some code.

 *  crashinfo.c
 *  AppSpecificCrashInfo
 *  Created by Andrew Wellington on 27/12/07.
 *  Copyright 2007 Andrew Wellington. All rights reserved.


int main (int argc, char *argv[])
    char **theAppSpecificInfo = NULL;
    theAppSpecificInfo = dlsym(RTLD_DEFAULT, "__crashreporter_info__");

    if (theAppSpecificInfo)
        *theAppSpecificInfo = "My Hovercraft is full of Eels";

    /* Crash with a null dereference */
    char *crasher = 0;
    *crasher = 0;

Let’s compile this:

$ gcc -o crashinfo crashinfo.c -framework CoreFoundation

Note that we’re linking to CoreFoundation as that’s the framework that contains the crash reporter symbol. If you don’t link to CoreFoundation the symbol lookup will fail and return NULL.

Time to try and run this:

$ ./crashinfo 
Bus error

Our test crashed as expected, now did it create a crash log with the information we’re expecting? Open up Console from the Utilities folder then find the crash log for “crashinfo”.

Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000000
Crashed Thread:  0

Application Specific Information:
My Hovercraft is full of Eels

Excellent, we’ve found our crash report and the application specific information is there. So it seems all we need to do is set the symbol to a pointer to a standard C string containing the information that we want.

A Few Thoughts

If you want to use this facility in your application there are some things you should be aware of:

Other frameworks might try and overwrite this value. If you do decide to use this, keep another reference to any dynamically allocated memory. This way you can free it if another framework overwrites the pointer and doesn’t leak memory.

You probably should limit any use of this feature to a subset of Mac OS X versions. At the very least you should only do this for Mac OS X 10.5 (on older versions the symbol either won’t exist, or it might do something totally different, and newer versions could be totally different again and this is an undocumented trick).

If another framework overwrites the data you might not get your application specific information so you still need to be able to extract as much information from crash reports by yourself as you can. This can provide more information than before, but it’s certainly not guaranteed to be there.

After working this out myself, I found a patch Apple adds to Samba on Mac OS X 10.5 that explains this in some detail: The most important thing to note from that patch is this part:

 * NOTE: this is an unsupported interface and the
CrashReporter team reserve
 * the right to change it at any time.

So I guess the answer there is: now you know how to do it, don’t. Enjoy 🙂