好的,所以想象一下我的断点objc_exception_throw
刚刚触发。我坐在调试器提示符下,我想获得有关异常对象的更多信息。我在哪里找到它?
好的,所以想象一下我的断点objc_exception_throw
刚刚触发。我坐在调试器提示符下,我想获得有关异常对象的更多信息。我在哪里找到它?
Answers:
异常对象作为第一个参数传入objc_exception_throw
。LLDB提供了$arg1
..$argn
变量来引用正确的调用约定中的参数,从而使打印异常详细信息变得简单:
(lldb) po $arg1
(lldb) po [$arg1 name]
(lldb) po [$arg1 reason]
objc_exception_throw
执行这些命令之前,请确保在调用堆栈中选择框架。请参阅WWDC15会话视频中的“高级调试和地址清理器”,以查看在舞台上执行的操作。
过时的信息
如果您使用的是GDB,则引用第一个参数的语法取决于您所运行的体系结构的调用约定。如果您是在实际的iOS设备上调试,则指向该对象的指针位于register中r0
。要打印或向其发送消息,请使用以下简单语法:
(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]
在iPhone Simulator上,所有函数参数都在堆栈上传递,因此语法更加可怕。我能构造的最短表达式是*(id *)($ebp + 8)
。为了减轻痛苦,我建议使用便捷变量:
(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]
您还可以$exception
通过向断点添加命令列表来在触发断点时自动进行设置objc_exception_throw
。
(请注意,在我测试过的所有情况下,断点命中时,eax
and对象中都存在异常对象edx
。不过,我不确定情况是否总是如此。)
从以下评论中添加:
在lldb中,为其选择堆栈框架objc_exception_throw
,然后输入以下命令:
(lldb) po *(id *)($esp + 4)
objc_exception_throw
中展开序幕前,以下对我有用:po *(id *)($esp + 4)
。
objc_exception_throw
)。
po $eax
在模拟器中为我工作,作为$r0
设备上的when挂件。
在例外框架中使用的新模拟器(iOS 8、64位)xcode 6 im上: objc_exception_throw
po $rax
在32位元中:
po $eax
什么是rax?
Rax是一个64位寄存器,替代了旧的eax
如何找到所有寄存器?
register read
在撰写本文时,这篇文章是我在Google上获得的最高评价:lldb print exception。因此,我将此答案添加到lldb和x86_64帐户中。
我尝试使用查找异常,但po $eax
失败了error: Couldn't materialize struct: Couldn't read eax (materialize)
。链接文档中较早答案中描述的其他尝试也失败了。
关键是我必须首先单击objc_exception_throw
主线程中的框架。lldb不在该帧中开始。
在我所有的搜索和以下示例中,此博客条目都是第一种以对我有用的方式来解释问题的文章。它更现代,将于2012年8月发布。
如果有catch语句,请在其中放置一个断点,然后可以在该点检查异常对象。
如果没有catch语句,请继续。
您将在终端中收到如下消息:
由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:' * -[__ NSPlaceholderDictionary initWithObjects:forKeys:count:]:尝试从对象[0]中插入零对象
但是,您可能正在寻找一种无需继续检查就可以对其进行检查的方法,因为当应用程序终止时,您将丢失漂亮的堆栈跟踪。
为此,听起来弗诺德的答案是最好的,但我无法使其在LLDB中正常工作。