在使用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内存查看器时,将其作为基数10和十六进制值进行尝试时,似乎并不是存储在那里的对象。我得到的结果如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
,这是我选择得到结果的。{/ p >
我特别关注的例外是通过调用-[UIStoryboard instantiateViewControllerWithIdentifier:]
编辑:如果我手动创建NSException并@throw
,我可以使用po $rax
查看它。我注意到在这种情况下,调用堆栈的第0帧是objc_exception_throw
。我已经编辑了标题,以指定我要询问的例外类型。
答案 0 :(得分:3)
ObjC异常的正常过程是系统调用objc_exception_throw传递异常对象以启动异常。但是在幕后,ObjC使用了与C ++用来实现堆栈实际展开的相同的异常抛出机制。因此objc_exception_throw将转向并调用__cxa_throw - 这也恰好是C ++异常起点。
当ObjC这样做时,抛出__cxa_throw的对象 - 恰好是它的第一个参数 - 是一个ObjC对象。但是系统的某些部分偶尔会抛出真正的C ++异常。如果你在没有先在objc_exception_throw中停止的情况下停在__cxa_throw中,那将是一个C ++异常对象而不是NSException,而po
对它们没有任何作用。
顺便说一下,当你在__cxa_throw中停止时,堆栈还没有解开,所以如果你很好奇的话,回溯应该会告诉你是谁抛出异常。
总而言之,如果您只想查看ObjC异常,请不要停在__cxa_throw,只需停在objc_exception_throw。在__cxa_throw处停止不会添加任何信息,并且会导致您必须从您关注的ObjC中对虚假的纯C ++异常进行排序。
在Xcode中,您可以通过选择ObjC异常断点而不是“All Exceptions”来完成此操作。在命令行lldb中,使用以下命令执行此操作:
(lldb) break set -E objc