【问题标题】:LLDB fails to examine variables (in Xcode)LLDB 无法检查变量(在 Xcode 中)
【发布时间】:2017-10-02 16:32:41
【问题描述】:

尤其是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 -- variable-in-question 的优点,大概是 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/person@domain.com/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:

【问题讨论】:

  • 使用po [yourVariable]
  • 在某些情况下有效,谢天谢地(?)产生的详细输出比 p 少。我必须积累更多关于 po 与 p 的统计数据
  • 在这种情况下什么是“key”?它是 ivar、局部变量、参数等吗?它的类型是什么?您可以执行“frame var -L key”来打印调试信息告诉我们的位置。显然那不是它所在的位置,这就是表达式在尝试访问它时崩溃的原因。但问题是在这种情况下,为什么我们认为它不是。如果您可以向 swift.org 提交错误,那可能是一个更好的论坛来来回调查此问题。

标签: swift xcode lldb


【解决方案1】:

提前为这篇文章感到抱歉,但希望这些信息值得一读......

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

print 并不是真正主要用于打印变量 - 这只是它实际作用的副作用。 printexpression 的别名,它让您更了解它是什么:一个完整​​的表达式求值器,它运行您在代码中停止时传递的表达式。

它构建一个上下文来模拟当前 pc 上的代码(包括类/协议上下文),然后获取你传递给它的 sn-p,在该上下文中编译它,JIT 是结果,插入 JIT ed 代码进入您正在调试的进程并运行它。这非常强大——你可以在程序中更改值、调用函数、引入新函数、新类型等。但是也有很多机制只是为了让它运行,而快速运行这些机制中的一些机制是很棘手的.

frame variable 只能打印当前帧中的局部变量和参数(使用 -g 标志它还可以打印全局变量和静态变量)。它不能调用函数,或者print 可以做的任何其他花哨的事情。它确实理解变量访问语法的有限子集,所以:

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

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

注意,您可以使用-O 标志为使用frame variable 访问的变量获取“对象打印”,它支持与print 相同的结果格式选项。对于上下文,Xcode“Locals”视图大致相当于调用frame variable

我倾向于使用 frame variable 进行简单的本地打印,但即使您喜欢使用一个命令来满足您的所有需求 - 这将是 print - 很高兴知道如果 print 失败了会有一个后备出于某种原因。

回到你的例子……

示例 1:print 在 Swift 中所做的其中一件事是将所有可见的局部变量引入到表达式的上下文中,以便您的代码可以使用它们。示例 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 locals vrs。 print...

【讨论】:

  • 难怪print varname有时会这么慢。在第一次运行到达断点时,我发现 15 秒并不罕见。
  • 这很好,但问题仍然难以解决。查看修改
  • frame 变量显然有更少的绳索挂在自己身上,因为它与 p & po 不同,它可以在有和没有 -L 的情况下工作
  • (lldb) po durationSeconds error: &lt;EXPR&gt;:3:1: error: use of unresolved identifier 'durationSeconds' ... 所以 ... (lldb) frame variable durationSeconds (Float64) durationSeconds = &lt;variable not available&gt;
  • frame var 错误是因为该变量当前没有已知位置。在优化的代码中,如果一个变量没有被使用,优化器的工作就是确保它不会为它浪费空间。即使在 -Onone 下,Swift 也理所当然地会进行更多的代码优化,因此在 -Onone 上使用 Swift 比在 -O0 下使用 C 系列语言时,您会更频繁地看到不知道位置的变量。
猜你喜欢
  • 2021-05-21
  • 2020-02-22
  • 2016-08-11
  • 1970-01-01
  • 2016-07-10
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 2018-06-23
相关资源
最近更新 更多