LLDB(Swift):将原始地址转换为可用类型
LLDB (Swift): Casting Raw Address into Usable Type
是否有 LLDB 命令可以将原始地址转换为可用的 Swift class?
例如:
(lldb) po 0x7df67c50 as MKPinAnnotationView
我知道这个地址指向一个 MKPinAnnotationView,但它不在我可以 select 的框架中。但是,我想将原始地址转换为 MKPinAnnotationView,以便我可以检查它的属性。这可能吗?
您可以使用 Swift 的 unsafeBitCast
函数将地址转换为对象实例:
(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self)
(lldb) po $pin
然后您可以像往常一样使用 $pin
– 访问属性、调用方法等。
查看这篇文章了解更多信息:Swift Memory Dumping。
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,以下是对我有用的方法。 (这是基于 。)
(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)
在Xcode8.2.1和Swift3下,lldb命令po或p 不适用于类型变量。您将需要使用 swift 命令 print 来检查类型化对象实例的属性。 (感谢!)例如:
expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
感谢以上所有答案,unsafeBitCast 也适用于 Xcode 8.3.2 / Swift 3 / macOS / Cocoa 应用程序。
记住当前实例的地址
(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 源代码的堆栈帧之一而不是汇编程序堆栈帧之一。
当应用程序通过单击 Pause 按钮暂停或异常停止时,很可能会发生这种情况。通过相应地选择堆栈帧,让 lldb 推断出正确的编程语言。
对于自定义 类 您需要导入您的项目
expr -l Swift -- import MyTestProject
expr -l Swift -- let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
Objective-C版本
po ((MKPinAnnotationView *)0x7df67c50).alpha
最简单的方法,swift4
expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
po
是一个别名,这意味着它可以被覆盖。您可以通过使用 objc:
处理十六进制地址来覆盖 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
。它处理对象地址,并且还有其他一些改进。
当您的 LLDB 会话在 Swift 上下文中启动时, 完美运行。但是,在某些情况下,您可能会在断点 outside a Swift 上下文中停止;例如,当它是 Objective-C API 的符号断点时,或者当处于 Debug View Hierarchy 模式时(至少从 Xcode 11.4 开始)。
error: unknown type name 'let'
error: use of undeclared identifier 'unsafeBitCast'
在这种情况下,您需要使用 Objective-C:
的旧方法
e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50
现在您可以随意使用 $pin
。
我花了更长的时间才弄明白我想承认。它类似于@afinlayson 的回答,但有更好的解释(我希望!)和固定语法
如果您想使用 Xcode 的视图层次调试器检查对象的属性,那么这将起作用:
默认情况下,您处于 objc 上下文中,因此您必须将其切换到 Swift 上下文
- 首先导入你的项目(如果你想使用那里定义的一些 classes)
expr -l Swift -- import <YOUR PROJECT NAME>
- 使用它的内存地址将对象转换为任何你想要的 class
expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: <YOUR PROJECT NAME>.<YOUR CUSTOM CLASS NAME>.self)
- 从对象中访问任何你想要的值
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
其中 e -O --
在 obj-c 上下文中相当于 lldb 中的 po
。
是否有 LLDB 命令可以将原始地址转换为可用的 Swift class?
例如:
(lldb) po 0x7df67c50 as MKPinAnnotationView
我知道这个地址指向一个 MKPinAnnotationView,但它不在我可以 select 的框架中。但是,我想将原始地址转换为 MKPinAnnotationView,以便我可以检查它的属性。这可能吗?
您可以使用 Swift 的 unsafeBitCast
函数将地址转换为对象实例:
(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self)
(lldb) po $pin
然后您可以像往常一样使用 $pin
– 访问属性、调用方法等。
查看这篇文章了解更多信息:Swift Memory Dumping。
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,以下是对我有用的方法。 (这是基于
(lldb) expr -l Swift -- import UIKit
(lldb) expr -l Swift -- let $nav = unsafeBitCast(0x1030ff000, to: UINavigationController.self)
在Xcode8.2.1和Swift3下,lldb命令po或p 不适用于类型变量。您将需要使用 swift 命令 print 来检查类型化对象实例的属性。 (感谢
expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
感谢以上所有答案,unsafeBitCast 也适用于 Xcode 8.3.2 / Swift 3 / macOS / Cocoa 应用程序。
记住当前实例的地址
(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 源代码的堆栈帧之一而不是汇编程序堆栈帧之一。
当应用程序通过单击 Pause 按钮暂停或异常停止时,很可能会发生这种情况。通过相应地选择堆栈帧,让 lldb 推断出正确的编程语言。
对于自定义 类 您需要导入您的项目
expr -l Swift -- import MyTestProject
expr -l Swift -- let $vc = unsafeBitCast(0x7fad22c066d0, ViewController.self)
expr -l Swift -- print($vc.view)
Objective-C版本
po ((MKPinAnnotationView *)0x7df67c50).alpha
最简单的方法,swift4
expr unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
po
是一个别名,这意味着它可以被覆盖。您可以通过使用 objc:
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
。它处理对象地址,并且还有其他一些改进。
error: unknown type name 'let'
error: use of undeclared identifier 'unsafeBitCast'
在这种情况下,您需要使用 Objective-C:
的旧方法e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50
现在您可以随意使用 $pin
。
我花了更长的时间才弄明白我想承认。它类似于@afinlayson 的回答,但有更好的解释(我希望!)和固定语法
如果您想使用 Xcode 的视图层次调试器检查对象的属性,那么这将起作用: 默认情况下,您处于 objc 上下文中,因此您必须将其切换到 Swift 上下文
- 首先导入你的项目(如果你想使用那里定义的一些 classes)
expr -l Swift -- import <YOUR PROJECT NAME>
- 使用它的内存地址将对象转换为任何你想要的 class
expr -l Swift -- let $vc = unsafeBitCast(0x7fb7c51cb270, to: <YOUR PROJECT NAME>.<YOUR CUSTOM CLASS NAME>.self)
- 从对象中访问任何你想要的值
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
其中 e -O --
在 obj-c 上下文中相当于 lldb 中的 po
。