LLDB无法检查变量(在Xcode中)

安东·特罗帕斯科(Anton Tropashko)

特别是该print命令通常(失败率80-90%)不起作用

我已经验证过:https//developer.apple.com/library/content/qa/qa1947/_index.html

例子1

(lldb)p prevMsg

错误:无法实现:无法获取runOnce的值:从值中提取数据失败错误:在DoExecute中出错,无法PrepareToExecuteJITExpression

示例2一个更典型的示例使您步入计算的泥潭:

(lldb)p activeNetworkRequests

错误:执行被中断,原因:EXC_BAD_ACCESS(代码= 1,地址= 0x1700530)。该过程已返回到表达式求值之前的状态。

自Xcode 7起,这种情况似乎变得越来越糟。

受闭包的封闭函数限制的打印变量特别无望。

代码库不小,大约15K行。在这里隔离并复制所有代码是不切实际的。

肯定其他人正在经历这种情况吗?

更新:有人告诉我表达式的优点--unwind-on-error = 0-问题中的变量,大概是example2

更新2:

码:

Util.log("Returning \(key) from file cache", [.Caches])

输出:

08:03:11.201 v2.0.64d other TwoStageCache.swift objectForKey(_:completion:)[95]: Returning https://example.server.com/Storage/Retrieve?FileName=accounts/[email protected]/resource/47a58660-26d1-11e7-8e7f-c9f4cd679b03.html from file cache

(因此,值key可以)

(lldb) fr var key
(URL) key = unable to read data
(lldb) print key
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x1d787583).
The process has been returned to the state before expression evaluation.

如果我们看一下崩溃:

(lldb) expression --unwind-on-error=0 -- key

libobjc.A.dylib`objc_retain:
    0x22562b0 <+0>:  pushl  %ebp
    0x22562b1 <+1>:  movl   %esp, %ebp
    0x22562b3 <+3>:  subl   $0x8, %esp
    0x22562b6 <+6>:  calll  0x22562bb                 ; <+11>
    0x22562bb <+11>: popl   %ecx
    0x22562bc <+12>: movl   0x8(%ebp), %eax
    0x22562bf <+15>: testl  %eax, %eax
    0x22562c1 <+17>: je     0x22562e1                 ; <+49>
    0x22562c3 <+19>: movl   (%eax), %edx
->  0x22562c5 <+21>: testb  $0x2, 0x10(%edx)

从:

1 $__lldb_expr(UnsafeMutablePointer<Any>) -> ()
2 Beta Viewer`@objc AppDelegate.init() -> AppDelegate:
3 sharedEnchantment`partial apply for TwoStageCache.(objectForKey(URL, completion : (imgData : Data?, err : BBError?) -> ()) -> ()).(closure #1)
4 sharedEnchantment`thunk:
吉姆·英厄姆(Jim Ingham)

抱歉,论文很抱歉,但是希望这些信息值得阅读...

lldb有两种查看变量(*)的方式:printframe variable

print并不是真正地主要用于打印变量-这只是其实际作用的副作用。print是一个别名,expression它使您有更多的含义:完整表达式评估程序,它将在您在代码中停止的位置运行您传递的表达式。

它构建一个上下文,该上下文模拟当前pc上的代码(包括Class / Protocol上下文),然后获取您传递的代码段,在该上下文中进行编译,即JIT的结果,将JIT编码的代码插入您所使用的流程中调试并运行它。这是非常强大的功能-您可以更改值,在程序中调用函数,引入新函数,新类型等。但是也有很多机制可以使它正常运行,而迅速地使用其中的一些机制很难正确处理。

frame variable只能打印当前帧中的-g局部变量和自变量(带有标志,它也可以打印全局变量和静态变量)。它不能调用函数,也不能执行其他任何幻想的事情print它确实了解变量访问语法的有限子集,因此:

(lldb)框架变量foo.bar.baz

将工作。但是在幕后,所有需要做的就是读取调试信息,以找到变量,变量的类型以及它在内存中的位置,然后可以从该信息中提取值。因此它可以更快,更强大地完成工作-这是人们通常要求print的工作的很大一部分

请注意,frame variable通过使用-O标志,您可以为要访问的变量获取“对象打印” ,并且它支持与结果相同的格式设置选项print对于上下文,Xcode的“ Locals”视图大致等效于call frame variable

我倾向于使用frame variable简单的本地打印,但是即使您希望使用一个命令来满足您的所有需求(也就是这样)print,也很高兴知道print由于某种原因而失败会导致故障。

回到您的示例...

示例1:printSwift中的一件事是将所有可见的局部变量引入表达式的上下文中,因此它们可供您的代码使用。示例1中的错误是因为无法实现局部变量之一-也许它只是由协议一致性指定的,而我们无法弄清楚它到底是什么-因此我们无法构建上下文,这意味着解析或JIT步骤失败。print代码对这种类型的故障进行了预扫描,并忽略了失败的本地人,但是您发现了这种扫描遗漏的情况。

frame variable可能也无法打印,runOnce但是由于它不取决于当前上下文,因此无法执行操作不会影响您打印其他变量的能力。

如果您可以重现此问题,即使您无法将项目提供给我们,我们也经常可以从lldb的调试日志中了解发生了什么。因此,将调试会话驱动到打印将失败的位置,然后执行以下操作:

(lldb) log enable -f /tmp/lldb-log.txt lldb expr types

然后运行失败的表达式。然后获取该日志,并按以下说明提交错误:

https://swift.org/contributing/#reporting-bugs

示例2:activeNetworkRequests是否是一个属性?这些要求我们调用“ get”方法来访问它们,并且我已经看到了lldb不能发出正确调用属性getter的代码的几种情况。上面的日志将向我们显示发出的代码,我们也许可以从那里知道出了什么问题。当然,如果您可以做一个测试用例,则可以发送总是最好的错误,但这通常是不可能的...

(*)对于gdb用户,这与info localsvrs非常接近print...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章