Xcode / LLDB:如何获得刚刚抛出exception的信息?
好吧,想象一下, objc_exception_throw
中的断点刚刚被触发。 我坐在debugging器提示符处,我想获得更多关于exception对象的信息。 我在哪里find它?
exception对象作为第一个parameter passing给objc_exception_throw
。 LLDB提供$arg1
.. $argn
variables来引用正确的调用约定中的参数,使得打印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过的所有情况下,在断点发生时, eax
和edx
寄存器中也存在exception对象,但我不确定情况总是如此。
从下面的评论添加:
在lldb中 ,为objc_exception_throw
select堆栈帧,然后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中工作。