LLDB (Swift): Casting Raw Address into Usable Type

是否有 LLDB 命令可以将原始地址转换为可用的 Swift 类?

For example:

(lldb) po 0x7df67c50 as MKPinAnnotationView

我知道这个地址指向一个 MKPinAnnotationView,但它不在我可以选择的框架中。但是,我想将原始地址转换为 MKPinAnnotationView,以便检查它的属性。这可能吗?

32555 次浏览

You can use Swift's unsafeBitCast function to cast an address to an object instance:

(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self)
(lldb) po $pin

然后您可以像往常一样使用 $pin-访问属性、调用方法等。

查看这篇文章了解更多信息: 快速内存转储

expression的 lldb 格式似乎在 Xcode 7.3中发生了变化:

(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $view = unsafeBitCast(0x7fb75d8349c0, UIView.self)

至于 Xcode 8/Swift 3,以下是对我有效的方法(这是基于 @ sfaxon 的回答的)

(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)

在 Xcode 8.2.1和 Swift 3下,lldb 命令 警察< em > p 不能用于类型化变量。您将需要使用 Swift 命令 < em > print 来检查类型化对象实例的属性。(感谢 Cbowns 的回答!)例如:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)

感谢上面的所有答案,< em > unsafeBitCast 也可以很好地与 Xcode 8.3.2/Swift 3/macOS/Cocoa Application 一起工作。

记住当前实例的地址

(lldb) p tabView.controlTint
(NSControlTint) $R10 = defaultControlTint


(lldb) p self
(LearningStoryboard.NSTabViewController) $R11 = 0x00006080000e2280 {
.....

稍后,检查他们

(lldb) p unsafeBitCast(0x00006080000e2280, to: NSTabViewController.self).tabView.controlTint
(NSControlTint) $R20 = graphiteControlTint


(lldb) p $R11.tabView.controlTint
(NSControlTint) $R21 = graphiteControlTint

如果发生这种事

(lldb) p unsafeBitCast(0x00006080000e2280, to: NSTabViewController.self).tabView.controlTint
error: use of undeclared identifier 'to'


(lldb) p $R11.tabView.controlTint
error: use of undeclared identifier '$R11'

确保选择 Swift 源代码的堆栈框架而不是汇编框架。

It is likely to happen when the application was paused by clicking a 暂停 button or stopped with an exception. By choosing a stack frame accordingly, let lldb infer a proper programing language.

对于自定义类,您需要导入项目

expr -l Swift -- import MyTestProject
expr -l Swift --  let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)

目标 C 版本

po ((MKPinAnnotationView *)0x7df67c50).alpha

最简单的方法,迅捷4

expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)

po是一个别名,这意味着它可以被覆盖。您可以通过使用 objecc 处理十六进制地址来覆盖 po:

command regex po
s/(0x[[:xdigit:]]+)/expression -l objc -O -- %1/
s/(.+)/expression -O -- %1/

要了解这样做的效果,可以告诉 lldb 展开这些别名:

(lldb) settings set interpreter.expand-regex-aliases true

我还创建了 https://github.com/kastiglione/swift_po,它是 Swift 的替代 po。它处理对象地址,还有一些其他的改进。

@ XiChen 的回答 在您的 LLDB 会话在 Swift 上下文中启动时非常有效。但是,在某些情况下,您可能已经在断点 在外面中停止了 Swift 上下文; 例如,当它是 Objective-C API 的符号断点时,或者在调试视图层次结构模式下(至少在 Xcode 11.4中)。

error: unknown type name 'let'
error: use of undeclared identifier 'unsafeBitCast'

在这种情况下,您需要使用 Objective-C 按照旧的方法进行操作:

e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50

现在你可以像以前一样使用 $pin了。

我花了很长时间才想明白。它类似于@afinlayson 的回答,但是有更好的解释(我希望!)和固定的语法

If you want to check properties of an objects using Xcode’s view hierarchy debugger then this will work: 默认情况下,您处于对象上下文中,因此必须将其切换到 Swift 上下文

  1. 首先导入您的项目(如果您想使用那里定义的一些类)

expr -l Swift -- import <YOUR PROJECT NAME>

  1. 使用对象的内存地址将对象强制转换为所需的任何类

expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: <YOUR PROJECT NAME>.<YOUR CUSTOM CLASS NAME>.self)

  1. 从对象访问所需的任何值

expr -l Swift -- print($vc.<PROPERTY NAME>)

示例:

expr -l Swift -- import Football

expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: Football.Ball.self)

expr -l Swift -- print($vc.velocity)

当在 Swift lldb 上下文中处理 NSObject子类(如 MKPinAnnotationView)时,可以说使用这个1-liner 更容易故意切换回 obj-c lldb 上下文:

e -O -l objc -- 0x7df67c50

在 obj-c 上下文中,其中 e -O --等效于 lldb 中的 po