84

好的,想象一下我的断点objc_exception_throw刚刚触发。我正坐在调试器提示符旁,我想获得有关异常对象的更多信息。我在哪里可以找到它?

4

4 回答 4

163

异常对象作为第一个参数传入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 模拟器上,所有函数参数都在堆栈上传递,因此语法要可怕得多。我可以构造的最短表达式是*(id *)($ebp + 8). 为了让事情不那么痛苦,我建议使用一个方便的变量:

(gdb) set $exception = *(id *)($ebp + 8)
(gdb) po $exception
(gdb) po [$exception name]
(gdb) po [$exception reason]

您还可以$exception通过向断点添加命令列表来在触发断点时自动设置objc_exception_throw

(请注意,在我测试的所有情况下,断点命中时异常对象也存在于eaxedx寄存器中。不过,我不确定情况是否总是如此。)

从下面的评论中添加:

lldb中,选择堆栈帧objc_exception_throw,然后输入以下命令:

(lldb) po *(id *)($esp + 4)
于 2010-07-25T04:02:57.113 回答
12

在异常框架中使用的新模拟器(iOS 8、64 位)xcode 6 上:objc_exception_throw

po $rax

32位:

po $eax

什么是拉克斯?

Rax 是一个 64 位的寄存器,取代了旧的 eax

如何找到所有的寄存器?

register read

来源维基百科

于 2014-09-30T08:24:08.403 回答
7

在撰写本文时,这篇文章是我在 Google 上的热门搜索:lldb print exception。因此,我添加了这个答案来解释 lldb 和 x86_64。

我尝试使用po $eaxfailed with查找异常error: Couldn't materialize struct: Couldn't read eax (materialize)。早期答案的链接文档中描述的其他尝试也失败了。

关键是我必须首先单击objc_exception_throw主线程中的框架。lldb不会在该帧中开始。

在我所有的搜索和后续示例中,这篇博客文章是第一个以对我有用的方式解释事物的文章。它更现代,于 2012 年 8 月发布。

于 2013-04-10T19:37:20.247 回答
1

如果您有一个 catch 语句,请在其中放置一个断点,然后您可以在该点检查异常对象。

如果您没有 catch 语句,请继续。

您将在终端中收到如下消息:

由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“ * -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]:尝试从对象 [0] 插入 nil 对象”

但是,您可能正在寻找一种方法来检查它而无需继续,因为当应用程序终止时您会丢失漂亮的堆栈跟踪。

为此,听起来 Fnord 的答案是最好的,但我无法让它在 LLDB 中工作。

于 2013-05-15T11:20:47.913 回答