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

Amo*_*ant 4 xcode objective-c ios lldb

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

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

Xcode/LLDB:如何获取有关刚刚引发的异常的信息?

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

(lldb) po $rax

106377751137688
Run Code Online (Sandbox Code Playgroud)

当将其插入 Xcode 内存查看器时,尝试将其作为基数 10 和十六进制值,那里似乎没有存储对象。我得到的结果是B8 0B 0C 16 01 00 00 00 03...肉眼可见的后面跟着零的结果。我尝试过像descriptionint 上那样调用方法,就好像它是一个地址一样,将其转换为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.
Run Code Online (Sandbox Code Playgroud)

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

我正在查看的异常是通过调用生成的-[UIStoryboard instantiateViewControllerWithIdentifier:]

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

Jim*_*ham 5

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 异常断点而不是“所有异常”来执行此操作。在命令行 lldb 中,执行以下操作:

(lldb) break set -E objc
Run Code Online (Sandbox Code Playgroud)