How’s that for a subject line?
Ok, so I’ve been tuning up the latest version of NewsBee and the working is going well. The only problem is I had this strange little bug that caused the app to crash every few weeks.
Application Specific Information:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM insertObject:atIndex:]: index 27 beyond bounds [0 .. 23]'
terminate called throwing an exception
Now, I recalled back in the mists of time that there was a nice way to take an OSX crash log and extract the line number, but for some reason I couldn’t make my brain give me the information beyond the fact that I needed to use atos. Now that I’ve unraveled the bits and pieces I already knew, I figured I’d drop it in a blog post so that I could recall it later (when I inevitably forget once more).
What is this “atos” of which you speak?
The atos command converts numeric addresses to their symbolic equivalents. If full debug symbol information is available, for example in a .app.dSYM sitting beside a .app, then the output of atos will include file name and source line number information. Mac OS X Developer Tools Reference
Buh? Don’t worry, that’s just some fancy talk from the Apple docs. What it means is that if you give atos your application’s binary and a starting memory address it can tell you things about related memory addresses, including the source file and line number.
Great, so how do I use it?
To begin, open up your crash log and scroll all the way down to the “Binary Images” section. You should see the name of your application on the first line. The very first HEX number is the starting address:
0x10ae52000 - 0x10ae69fff +com.iphonespaz.NewsBee (1.2 - 1.2) <95951DBD-40CA-3658-8E5C-5EC3E41C00B4> /Users/USER/Desktop/NewsBee-1.2.app/Contents/MacOS/NewsBee
0x10af1e000 - 0x10af27fe7 libcldcpuengine.dylib (2.2.16) /System/Library/Frameworks/OpenCL.framework/Libraries/libcldcpuengine.dylib
In this case, the number I need is 0x10ae52000. Yay!
Next, I need the address where the bad things happened in my app. To get this, scroll up to the top of your crash log and look for the “Application Specific Backtrace” section. There are probably a number of lines here, but what you want to locate is the specific call out for your app.
Application Specific Backtrace 1:
0 CoreFoundation 0x00007fff88955b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff887ba3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8890627a -[__NSArrayM insertObject:atIndex:] + 282
3 AppKit 0x00007fff8a6f9794 -[NSMenu insertItem:atIndex:] + 505
4 NewsBee 0x000000010ae5e276 NewsBee + 49782
From the example above, I want to grab 0x000000010ae5e276. This tells me where my app tried to be bad an insert items out of turn. Now, I’m ready to put it all together and get the mystery reveal on the offending source code.
$ atos -o NewsBee-1.2.app/Contents/MacOS/NewsBee -l 0x10ae52000 0x000000010ae5e276
got symbolicator for NewsBee-1.2.app/Contents/MacOS/NewsBee, base address 100000000
-[newsBeeController _loadMenu:] (in NewsBee) (newsBeeController.m:325)
In the first line, I’ve provided the command. The “o” option is for the binary. In this case, I’m looking at the NewsBee app and drilling down to the compiled executable. The “l” option is used to specify the load address I want atos to use when bringing the binary into memory. The final number is the place where the code went wonky.
On execution, atos loads up the binary and helpfully repeats my explanation above in obfuscated language. Then, it’s kind enough to tell me right where the problem is: line 325 in newsBeeController.m. As it turns out, the problem is happening right where I expected it to be (the _loadMenu function), but knowing for sure is awesome because the error itself is difficult to replicate.
Of course, everything I’ve said here can be gleaned by simply reading the man page for atos, but why do that when you can google, right?