简体   繁体   中英

XCode / LLDB: po $eax and po $r0 only display ints for __cxa_throw exceptions?

In researching debugging exceptions using LLDB, I found the following article and thread, as well as others giving the same information:

https://www.natashatherobot.com/xcode-debugging-trick/

Xcode/LLDB: How to get information about an exception that was just thrown?

When trying variations of these, the best I can get is an int as a result:

(lldb) po $rax

106377751137688

When plugging this into the Xcode memory viewer, trying it as both a base-10 and hex value, there didn't seem to be an object stored there. I get results such as B8 0B 0C 16 01 00 00 00 03... followed by zeros as far as the eye can see. I've tried calling methods like description on the int as if it were an address, casting it as NSException* , which yield the result:

error: Execution was interrupted, reason: Attempted to dereference an invalid ObjC Object or send it an unrecognized selector. The process has been returned to the state before expression evaluation.

Was there a recent change to LLDB that would have broken the expected functionality? I'm using Xcode 9.2 and a mix of swift and objective-c. It might also be worth noting that I don't see the frame objc_exception_throw in the call stack, but rather __cxa_throw at frame 0, which is what I select to get a result.

The exception in particular I'm looking at is generated by a call to -[UIStoryboard instantiateViewControllerWithIdentifier:]

EDIT: If I manually create an NSException and @throw it, I can view it with po $rax . I noticed in this case, frame 0 of the call stack is objc_exception_throw . I've edited the title to specify the type of exception I'm asking about.

The normal course of an ObjC exception is that the system calls objc_exception_throw passing in the exception object to start the exception. But under the covers, ObjC uses the same exception throwing mechanism that C++ uses to implement the actual unwinding of the stack. So objc_exception_throw will turn around and call __cxa_throw - which also happens to be the C++ exception start point.

When ObjC does this, the object thrown at __cxa_throw - which happens to be its first argument - is an ObjC object. But there are also parts of the system that throw real C++ exceptions on occasion. If you stop in __cxa_throw without first stopping in objc_exception_throw, that's going to be a C++ exception object NOT an NSException, and po does nothing for them.

BTW, when you stop in __cxa_throw the stack hasn't been unwound yet, so the backtrace should show you who is throwing the exception, if you are curious.

In sum, if you want to only see ObjC exceptions, don't stop at the __cxa_throw, just stop at objc_exception_throw. Stopping at __cxa_throw won't add any information, and will cause you to have to sort the spurious pure C++ exceptions from the ObjC ones you care about.

In Xcode, you do this by choosing the ObjC exception breakpoint not "All Exceptions". In command line lldb, do this with:

(lldb) break set -E objc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM