LLDB (Swift): Casting Raw Address into Usable Type

前端 未结 11 758
天涯浪人
天涯浪人 2020-11-27 09:30

Is there an LLDB command that can cast a raw address into a usable Swift class?

For example:

(lldb) po 0x7df67c50 as MKPinAnnotationView
相关标签:
11条回答
  • 2020-11-27 09:37

    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
    

    Then you can work with $pin as usual – access properties, call methods, etc.

    Check out this article for more information: Swift Memory Dumping.

    0 讨论(0)
  • 2020-11-27 09:42

    It took me longer to figure out that I'd like to admit. It's similar to @afinlayson answer, but with better explanation (I hope!) and fixed syntax

    If you want to check properties of an objects using Xcode’s view hierarchy debugger then this will work: You’re in objc context by default so you’ll have to switch it to Swift context

    1. First import your project (if you want to use some of the classes defined there)

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

    1. Cast object using it’s memory address to whatever class you want

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

    1. Access any value you want from the object

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

    Example:

    expr -l Swift -- import Football

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

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

    0 讨论(0)
  • 2020-11-27 09:44

    @Xi Chen's answer works perfectly when your LLDB session was started in a Swift context. However, in some cases you might have stopped in a breakpoint outside a Swift context; for example, when it's a symbolic breakpoint to Objective-C API, or when in Debug View Hierarchy mode (at least as of Xcode 11.4).

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

    In that case, you'll need to do it the old way using Objective-C:

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

    and now you can use $pin as you would.

    0 讨论(0)
  • 2020-11-27 09:47

    The lldb format for expression seems to have changed in Xcode 7.3. The following got me started:

    (lldb) expr -l Swift -- import UIKit
    (lldb) expr -l Swift -- let $view = unsafeBitCast(0x7fb75d8349c0, UIView.self)
    
    0 讨论(0)
  • 2020-11-27 09:48

    po is an alias, which means it can be overridden. You can override po by handling hex addresses using objc:

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

    To see what effect this has, you can tell lldb to expand these aliases:

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

    Also I have created https://github.com/kastiglione/swift_po, which is a substitute po for Swift. It handles object addresses, and has a few other improvements too.

    0 讨论(0)
  • 2020-11-27 09:49

    Thanks to all the answers above, unsafeBitCast also works well with Xcode 8.3.2 / Swift 3 / macOS / Cocoa Application.

    Memorize an address of current instance

    (lldb) p tabView.controlTint
    (NSControlTint) $R10 = defaultControlTint
    
    (lldb) p self
    (LearningStoryboard.NSTabViewController) $R11 = 0x00006080000e2280 {
    .....
    

    Later, examine them

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

    If something like this happens

    (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'
    

    make sure that choose one of the stack frames of Swift source code rather than assembler one.

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

    0 讨论(0)
提交回复
热议问题