XCode / LLDB:po $eax 和 po $r0 只显示 __cxa_throw 异常的整数?

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

在使用 LLDB 研究调试异常时,我发现了以下文章和主题,以及其他提供相同信息的文章:

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

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

尝试这些的变体时,我能得到的最好结果是一个整数:

(lldb) po $rax

106377751137688

将其插入 Xcode 内存查看器时,尝试将其作为 base-10 和十六进制值,似乎没有 object 存储在那里。我得到诸如 B8 0B 0C 16 01 00 00 00 03... 之类的结果,在眼睛所能看到的范围内,后跟零。我试过在 int 上调用像 description 这样的方法,就好像它是一个地址一样,将其转换为 NSException*,结果是:

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.

最近对 LLDB 的更改是否会破坏预期的功能?我正在使用 Xcode 9.2 以及 swift 和 objective-c 的混合版本。可能还值得注意的是,我没有在调用堆栈中看到 objc_exception_throw 帧,而是在第 0 帧看到 __cxa_throw,这就是我 select 得到的结果。

我正在查看的异常是由对 -[UIStoryboard instantiateViewControllerWithIdentifier:]

的调用生成的

编辑:如果我手动创建一个 NSException 并 @throw 它,我可以用 po $rax 查看它。我注意到在这种情况下,调用堆栈的第 0 帧是 objc_exception_throw。我编辑了标题以指定我要询问的异常类型。

ObjC异常的正常过程是系统调用objc_exception_throw传入异常对象启动异常。但在幕后,ObjC 使用与 C++ 相同的异常抛出机制来实现堆栈的实际展开。所以 objc_exception_throw 将转身调用 __cxa_throw - 这也恰好是 C++ 异常的起点。

当 ObjC 执行此操作时,在 __cxa_throw 抛出的对象(恰好是它的第一个参数)是一个 ObjC 对象。但是系统的某些部分有时会抛出真正的 C++ 异常。如果您在 __cxa_throw 中停止而没有首先在 objc_exception_throw 中停止,那将是一个 C++ 异常对象而不是 NSException,并且 po 不会为它们做任何事情。

顺便说一句,当你在 __cxa_throw 停止时,堆栈还没有展开,所以如果你好奇的话,回溯应该会告诉你是谁在抛出异常。

总之,如果您只想查看 ObjC 异常,请不要停在 __cxa_throw,只需停在 objc_exception_throw。停在 __cxa_throw 不会添加任何信息,并且会导致您必须将虚假的纯 C++ 异常与您关心的 ObjC 异常进行排序。

在 Xcode 中,您可以通过选择 ObjC 异常断点而不是 "All Exceptions" 来执行此操作。在命令行 lldb 中,使用以下命令执行此操作:

(lldb) break set -E objc