好的,假设我的 objc_exception_throw
断点刚刚触发了。我正在调试器提示符处,想要获取有关异常对象的更多信息。我在哪里可以找到它?
好的,假设我的 objc_exception_throw
断点刚刚触发了。我正在调试器提示符处,想要获取有关异常对象的更多信息。我在哪里可以找到它?
异常对象作为第一个参数传递给 objc_exception_throw
。 LLDB 提供了 $arg1
..$argn
变量以引用正确调用约定中的参数,从而可以简单地打印异常详细信息:
(lldb) po $arg1
(lldb) po [$arg1 name]
(lldb) po [$arg1 reason]
在执行这些命令之前,请确保在调用堆栈中选择objc_exception_throw
帧。请参阅WWDC15会话视频中的“高级调试和地址污点分析器”以查看此过程的演示。
已过时信息
如果你正在使用GDB,那么引用第一个参数的语法取决于你运行的体系结构的调用约定。如果你在实际的iOS设备上进行调试,则对象的指针在寄存器r0
中。要打印它或向它发送消息,请使用以下简单语法:
(gdb) po $r0
(gdb) po [$r0 name]
(gdb) po [$r0 reason]
在iPhone模拟器上,所有的函数参数都是通过栈传递的,因此语法相当可怕。我能构造的最短表达式是*(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
和edx
寄存器中。但我不确定这种情况是否总是如此。)
以下为从下面评论中添加的内容:
在 LLDB 中,选择objc_exception_throw
的堆栈帧,然后输入这个命令:
(lldb) po *(id *)($esp + 4)
po *(id *)($esp + 4)
,可以捕获 objc_exception_throw
异常。 - wbyoungobjc_exception_throw
)。 - funrollpo $eax
对我很有用,作为设备上的 $r0
的替代品。 - monkeydomobjc_exception_throw
。po $rax
在32位系统中:
po $eax
什么是rax?
rax是一个64位寄存器,用于替代旧版的eax。
如何查找所有寄存器?
register read
po (NSException*)$eax
po (NSException*)$rax
- Rickster在撰写本文时,我的Google搜索结果中排名最高的是“lldb打印异常”。因此,我添加了这个答案来解决lldb和x86_64的问题。
我的尝试使用po $eax
查找异常失败了,出现了error: Couldn't materialize struct: Couldn't read eax (materialize)
的错误。之前其他回答中提到的尝试也都失败了。
关键在于,我必须先点击我的主线程中的objc_exception_throw
帧。 lldb不会直接进入该帧。
在我所有的搜索和按照之前的例子操作后,这篇博客文章是第一篇以一种对我有效的方式解释的文章。它更加现代化,发布于2012年8月。