LLDB(Swift):将原始地址转换为可用类型

jar*_*kes 79 ios lldb swift

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

例如:

(lldb) po 0x7df67c50 as MKPinAnnotationView
Run Code Online (Sandbox Code Playgroud)

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

小智 121

在Xcode 8.2.1和Swift 3下,lldb命令pop不适用于类型变量.您将需要使用swift命令print来检查键入的对象实例的属性.(感谢cbowns的回答!)例如:

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

  • 这真的不应该那么难 (24认同)
  • 正如这个问题的另一个答案中提到的,输入“settings set target.language swift”一次就足以避免在后续命令中出现“expr -l Swift --”。 (3认同)
  • 在Objective-C中有办法做到这一点吗? (2认同)

gre*_*heo 44

您可以使用Swift的unsafeBitCast函数将地址强制转换为对象实例:

(lldb) e let $pin = unsafeBitCast(0x7df67c50, MKPinAnnotationView.self)
(lldb) po $pin
Run Code Online (Sandbox Code Playgroud)

然后你可以$pin照常使用 - 访问属性,调用方法等.

查看这篇文章了解更多信息:Swift Memory Dumping.

  • 除了那个错误(@devios)之外,还有另一个错误,它在7.3.1中显示:"错误:未知类型名称'let'" (8认同)
  • 我收到"错误:在Xcode 7.2中使用未声明的标识符'unsafeBitCast'". (2认同)
  • 注意,根据上下文,您可能首先需要使用(lldb)settings set target.language swift将lldb切换到Swift模式。另外,在某些情况下(例如,在从应用程序转换为类型时打破应用程序模块的范围时),您可能需要使用`e import MyApp`来遵循它。 (2认同)

sfa*_*xon 25

lldb格式expression似乎在XCode 7.3中已经改变.以下让我开始:

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


cbo*_*wns 12

从Xcode 8/Swift 3开始,这对我有用.(这是基于@sfaxon的回答.)

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


小智 12

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

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

  • @AlexanderStepanishin 尝试设置线程/堆栈路径,示例:“MyApp > Thread 1 > 12 main” (2认同)

Tor*_*ora 9

感谢上面的所有答案,unsafeBitCast也适用于Xcode 8.3.2/Swift 3/macOS/Cocoa应用程序.

记住当前实例的地址

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

(lldb) p self
(LearningStoryboard.NSTabViewController) $R11 = 0x00006080000e2280 {
.....
Run Code Online (Sandbox Code Playgroud)

后来,检查一下

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

(lldb) p $R11.tabView.controlTint
(NSControlTint) $R21 = graphiteControlTint
Run Code Online (Sandbox Code Playgroud)

如果发生这样的事情

(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'
Run Code Online (Sandbox Code Playgroud)

确保选择一个Swift源代码的堆栈帧而不是汇编器.

当通过单击" 暂停"按钮暂停应用程序或因异常而停止应用程序时,可能会发生这种情况.通过相应地选择堆栈帧,让lldb推断出正确的编程语言.


Gob*_*obe 7

当您的 LLDB 会话在 Swift 上下文中启动时,@Xi Chen 的回答非常有效。但是,在某些情况下,您可能会在Swift 上下文之外的断点停止;例如,当它是 Objective-C API 的符号断点时,或者处于 Debug View Hierarchy 模式时(至少从 Xcode 11.4 开始)。

error: unknown type name 'let'
error: use of undeclared identifier 'unsafeBitCast'
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您需要使用 Objective-C 以旧方式执行此操作:

e MKPinAnnotationView *$pin = (MKPinAnnotationView *)0x7df67c50
Run Code Online (Sandbox Code Playgroud)

现在您可以随意使用了$pin


Bar*_*nat 7

我花了更长的时间才弄清楚我愿意承认。它类似于@afinlayson 的答案,但有更好的解释(我希望!)和固定的语法

如果您想使用 Xcode 的视图层次结构调试器检查对象的属性,那么这将起作用:默认情况下您处于 objc 上下文中,因此您必须将其切换到 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)


小智 6

Objective-C版本

po ((MKPinAnnotationView *)0x7df67c50).alpha
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说非常有效。就我而言,我位于“调试视图层次结构”视图中,右键单击视图,然后选择“打印...的描述”。这给了我一个内存地址和类型,我可以将其放入上面的代码中。很高兴知道可视化调试器将控制台放入 Obj-C 框架中。 (4认同)