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

Posted

技术标签:

【中文标题】Xcode/LLDB:如何获取有关刚刚抛出的异常的信息?【英文标题】:Xcode/LLDB: How to get information about an exception that was just thrown? 【发布时间】:2011-03-20 15:52:11 【问题描述】:

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

【问题讨论】:

记住,这个异常刚刚被抛出,它的描述还没有打印在控制台上。 看看这个问题:***.com/questions/711650 【参考方案1】:

异常对象作为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 断点添加命令列表。

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

从下面的评论中添加:

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

(lldb) po *(id *)($esp + 4)

【讨论】:

如何在 lldb 中做到这一点?我收到一个错误“错误:对 'id' 的引用不明确” 您能提供此信息的来源吗?我想了解更多有关它的信息 目前,在 LLDB 中使用 objc_exception_throw 时,以下对我有用:po *(id *)($esp + 4). 这成功了!但是,直到我选择堆栈帧 0 后它才起作用。 (objc_exception_throw)。 po $eax 在模拟器中为我工作,在设备上作为$r0 的挂件。【参考方案2】:

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

po $rax

32 位:

po $eax

什么是 rax?

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

如何找到所有的寄存器?

register read

Source wikipedia

【讨论】:

嗯...在 Xcode 6.1 中,我得到: (lldb) po $rax 错误:无法实现:无法读取寄存器 rax 的值 执行时出错,不能t PrepareToExecuteJITExpression @bradheintz 模拟器或设备?我用 6.0.1 试过这个 您能否为此提供指向您的来源的链接?谢谢! 我刚刚在 lldb 中写道:注册读取。然后有了这个信息,我们知道异常帧中的第一个寄存器保存了异常消息。 好的,我找到了一些文档:rax 是一个 64 位寄存器:在 64 位长模式下,您可以使用 64 位寄存器(例如 rax 代替 eax,rbx 代替 ebx 等。) 【参考方案3】:

如果你有一个 catch 语句,在里面放一个断点,你可以在那个点检查异常对象。

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

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

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

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

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

【讨论】:

【参考方案4】:

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

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

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

在我所有的搜索和后续示例中,this blog entry 是第一个以对我有用的方式解释事物的人。它更现代,于 2012 年 8 月发布。

【讨论】:

以上是关于Xcode/LLDB:如何获取有关刚刚抛出的异常的信息?的主要内容,如果未能解决你的问题,请参考以下文章

java中如何获取throws抛出的异常,并且把异常打印到指定的jsp页面

使用 sbt 和 testng 时,如何获取测试中抛出的异常的完整堆栈跟踪?

在java中捕获所有抛出的异常?

抛出异常时如何获取 JavaScript 堆栈跟踪?

如何使用 Aspectj 捕获和抑制 Java 类抛出的异常

如何识别抛出的特定异常