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
断点添加命令列表。
(请注意,在我测试的所有情况下,异常对象在断点命中时也存在于eax
和edx
寄存器中。不过,我不确定情况是否总是如此。 )
从下面的评论中添加:
在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 时,如何获取测试中抛出的异常的完整堆栈跟踪?