views:

122

answers:

3

OK, so imagine that my breakpoint in objc_exception_throw has just triggered. I'm sitting at the debugger prompt, and I want to get some more information about the exception object. Where do I find it?

+4  A: 

Good article explaining how to debug your exception:

http://www.cocoadev.com/index.pl?DebuggingTechniques

Sheehan Alam
+1 Nice article
Steve
+1 for the useful reference, thanks! [It hasn't got the correct answer to my question, though.]
Fnord
+1 This article does have the answer you're looking far. Look under the "Breaking on Exceptions" section see the line that starts "When stopping at objc_exception_throw the exception object is stored in $edx..."
TechZen
@TechZen: Unfortunately that answer is incorrect. The exception object is not guaranteed to be in either `edx` or `eax`: it's an argument to the function, so on Intel x86 it's passed in on the stack. (Unless I'm gravely mistaken, `edx` and `eax` are scratch registers inherited from the caller, which by accident often seem to contain the same value. Relying on this seems unwise to me.)
Fnord
It's not an argument, its the address of an object. You wanted the exception object and that is where its address is stored. No matter what route you take to it, you end up with the address in that register. Calling po on $edx should print the exception object. If it does not, then your not getting the object because the app lost it.
TechZen
Interesting! But — looking at the disassembly — why does the function itself repeatedly load the address of the exception object from 0x8(%ebp), instead of just referring to %edx?
Fnord
+1  A: 

Check this place out it will tell you how to deal with those errors:

http://www.markj.net/debugging-tip-objc_exception_throw-breakpoint/

It shows you how to add break points and figure out where its happening in you code. That will show you where that thing is.

thyrgle
+1  A: 

The exception object is passed in as the first argument to objc_exception_throw. The syntax to refer to it depends on the calling conventions of the architecture you're running on. If you're debugging on an actual iOS device, the pointer to the object is in register r0. To print it or send messages to it, use the following simple syntax:

(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]

On the iPhone Simulator, all function arguments are passed on the stack, so the syntax is considerably more horrible. The shortest expression I could construct that gets to it is *(id *)($ebp + 8). To make things less painful, I suggest using a convenience variable:

(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]

You can also set $exception automatically whenever the breakpoint is triggered by adding a command list to the objc_exception_throw breakpoint.

(Note that in all cases I tested, the exception object was also present in the eax and edx registers at the time the breakpoint hit. I'm not sure that'll always be the case, though.)

Fnord