129

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

For example:

(lldb) po 0x7df67c50 as MKPinAnnotationView

I know that this address points to a MKPinAnnotationView, but it is not in a frame that I can select. But, I want to cast the raw address into a MKPinAnnotationView so that I can examine its properties. Is this possible?

0

13 Answers 13

218

Under Xcode 8.2.1 and Swift 3, the lldb command po or p won't work with the typed variable. You will need to use the swift command print to examine the properties of the typed object instance. (Thanks to cbowns's answer!) E.g.:

expr -l Swift -- import UIKit
expr -l Swift -- let $pin = unsafeBitCast(0x7df67c50, to: MKPinAnnotationView.self)
expr -l Swift -- print($pin.alpha)
Sign up to request clarification or add additional context in comments.

6 Comments

This really shouldn't be so hard
This was a little counter intuitive. I thought I didn't need to type the (lldb) in my console. But it didn't work without that.
Is there a way to do this in objective-c?
I keep getting back at this. I probably should create a lldb alias for expr -l Swift -- ..
As was mentioned in a different answer to this question, typing settings set target.language swift once is enough to avoid expr -l Swift -- in subsequent commands.
|
62

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.

5 Comments

For the first statement i think you forgot the 'expr' or 'expression'. Otherwise it is working great!
I'm getting "error: use of undeclared identifier 'unsafeBitCast'" in Xcode 7.2.
Besides that error (@devios) there's another error it shows in 7.3.1: "error: unknown type name 'let'"
Note that depending on context you might need to switch lldb to Swift mode first using (lldb) settings set target.language swift. Also, in some cases (e.g. when breaking outside of your app's module while casting to a type from your app) you might need to follow that with a e import MyApp
That doesn't seem to work for tagged pointers. Short NSString, NSIndexPath, NSNumber etc. are implemented as tagged pointers where the content is part of the pointer itself.
28

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)

Comments

24

For Custom Classes you need to import your project

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

3 Comments

I'm getting error: no such module "MyProjectName". Any thoughts how to fix this?
@AlexanderStepanishin try setting the thread/stack path, Example: "MyApp > Thread 1 > 12 main"
@AlexanderStepanishin you need to hit a breakpoint. It won't work if you interrupt the flow by pressing the Debug Memory Graph button in xCode.
22

Objective-C version

po ((MKPinAnnotationView *)0x7df67c50).alpha

1 Comment

This worked perfectly for me. In my case I was in the Debug View Hierarchy view, right clicked on a view, then selected Print description of.... That gave me a memory address and type I could drop into the code above. Nice to know that the visual debugger puts the console into an Obj-C frame.
13

As of Xcode 8/Swift 3, here's what worked for me. (This is based off @sfaxon's answer.)

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

Comments

11

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.

Comments

9

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)

Comments

7

@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.

Comments

4

The easiest way, swift 4

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

1 Comment

Works for swift 5 as well
3

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.

1 Comment

from your link, expression -l objc -O -- 0x76543210 is just the response for me, and it doesn't need to know the variable class from the adress!
2

When in Swift lldb context and dealing with NSObject subclass such as MKPinAnnotationView it's arguably easier to deliberately switch back to obj-c lldb context using this 1-liner:

e -O -l objc -- 0x7df67c50

where e -O -- is equivalent to po in lldb when in obj-c context.

Comments

0

I managed to make it work using this command in my .lldbinit file:

command regex ps 's/^([^[:space:]]+)[[:space:]]+([^[:space:]]+)[[:space:]]+([^[:space:]]+)$/expression -l Swift -- import UIKit; let pointer = UnsafeRawPointer(bitPattern: %1)!; let this = unsafeBitCast(pointer, to: %2.self); print(%3)/'

And I'm using it like this:

(lldb) ps 0x6000007a5bc0 CAGradientLayer this
<CAGradientLayer: 0x6000007a5bc0>
() $R1 = {}

(lldb) ps 0x6000007a5bc0 CAGradientLayer this.bounds
(0.0, 0.0, 61.333333333333336, 22.666666666666668)
() $R0 = {}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.