Xcode / LLDB:如何获得刚刚抛出exception的信息?

好吧,想象一下, objc_exception_throw中的断点刚刚被触发。 我坐在debugging器提示符处,我想获得更多关于exception对象的信息。 我在哪里find它?

exception对象作为第一个parameter passing给objc_exception_throw 。 LLDB提供$arg1 .. $argnvariables来引用正确的调用约定中的参数,使得打印exception详细信息变得简单:

 (lldb) po $arg1 (lldb) po [$arg1 name] (lldb) po [$arg1 reason] 

在执行这些命令之前,请确保在调用堆栈中selectobjc_exception_throw帧。 请参阅WWDC15会话video中的“高级debugging和地址清除程序”以查看在舞台上执行的操作。

过时的信息

如果您使用的是GDB,则引用第一个参数的语法取决于您正在运行的体系结构的调用约定。 如果您在实际的iOS设备上进行debugging,则指向该对象的指针位于寄存器r0 。 要打印或发送消息,请使用以下简单的语法:

 (gdb) po $r0 (gdb) po [$r0 name] (gdb) po [$r0 reason] 

在iPhone模拟器上,所有的函数参数都在栈上传递,所以语法更糟糕。 我可以构造的最短expression式是*(id *)($ebp + 8) 。 为了减轻痛苦,我build议使用一个方便的variables:

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

只要通过将命令列表添加到objc_exception_throw断点来触发断点,您也可以自动设置$exception

(请注意,在我testing过的所有情况下,在断点发生时, eaxedx寄存器中也存在exception对象,但我不确定情况总是如此。

从下面的评论添加:

lldb中 ,为objc_exception_throwselect堆栈帧,然后input以下命令:

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

在新的模拟器(iOS objc_exception_throw位)Xcode 6即时通讯使用exception帧: objc_exception_throw

 po $rax 

在32bit:

 po $eax 

什么是rax?

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

如何find所有的寄存器?

 register read 

来源维基百科

在写这篇文章的时候,这个post是我顶级的Google hit: lldb print exception 。 因此,我将这个答案join了lldb和x86_64。

我试图find使用po $eax的exception失败, error: Couldn't materialize struct: Couldn't read eax (materialize) 。 在早期答案的链接文件中描述的其他尝试也失败了。

关键是我不得不在我的主线程中首先点击objc_exception_throw框架。 lldb在这个框架中没有开始。

在我所有的search和下面的例子中, 这个博客是第一个用我的方式解释事物的。 这是更现代的,在2012年8月发布。

检查这个地方,它会告诉你如何处理这些错误:

http://www.markj.net/debugging-tip-objc_exception_throw-breakpoint/

它向你展示了如何添加断点并找出它在你的代码中发生的地方。 那会告诉你那个东西在哪里

如果你有一个catch语句,在那里放一个断点,你可以在那个地方检查exception对象。

如果您没有捕捉说明,请继续。

你会在terminal上看到这样的信息:

终止应用程序由于未捕获的exception'NSInvalidArgumentException',原因:' * – [__ NSPlaceholderDictionary initWithObjects:forKeys:count:]:试图从对象插入nil对象[0]'

但是 ,您可能正在寻找一种无需继续检查的方法,因为在应用程序终止时您将失去良好的堆栈跟踪。

为此,Fnord的答案似乎是最好的,但我无法在LLDB中工作。