1

In ObjC++, I just use po $x0 to print the first argument of a function. If it's an object, it will display it in detail.

However, in Swift when I do this for an swift object, I got an error:

po $x0
error: <EXPR>:6:1: cannot find '$x0' in scope
$x0
^~~

How can I print the detail of it?

3
  • 1
    Please edit your post to only ask one question. Right now I see two questions: "how to print the first argument" and "how to print an object given an address". Commented Aug 14 at 14:36
  • First argument of a function is self, no? just po self Commented Aug 15 at 7:29
  • po self is only going to work if you have debug information for the frame in which you are stopped. There are situations where you'd really like to know what self is when stopped in code you don't have debug information for - e.g. you are crashing in a system library. Commented Aug 15 at 18:50

2 Answers 2

2

Assuming you are trying to print the details of a class, you can do:

p unsafeBitCast(UnsafeRawPointer(bitPattern: <address here>), to: AnyObject.self)

Replace <address here> with your desired address.

For reading things in registers, you can use register read as said by Jim Ingham. It is still possible to use the $-prefixed variables if you use expr -l objc. Example:

(lldb) expr -l objc -- $arg1
(unsigned long) $0 = 105553181632000
(lldb) p unsafeBitCast(UnsafeRawPointer(bitPattern: 105553181632000), to: AnyObject.self)
(Foo.SomeClass) 0x0000600003e56600 (property1 = "Property", property2 = "Property", property3 = "Property")

I would also suggest using the dump global function, which pretty-prints the properties of the object.

(lldb) p dump(unsafeBitCast(UnsafeRawPointer(bitPattern: 105553181632000), to: AnyObject.self))
▿ Foo.SomeClass #0
  - property1: "Property"
  - property2: "Property"
  - property3: "Property"
(Foo.SomeClass) 0x0000600003e56600 (property1 = "Property", property2 = "Property", property3 = "Property")

For structs, you will need to know the type of the struct in order to unsafeBitCast, since there are no metadata about its type stored in memory. Bigs structs also can get moved onto the heap, which further complicates things.

Sign up to request clarification or add additional context in comments.

5 Comments

v -L 0x000000016fdff0a8: (testSwift.Person) self = { 0x000000016fdff0a8: name = "Alice" 0x000000016fdff0b8: age = 25 }
p unsafeBitCast(UnsafeRawPointer(bitPattern: 0x000000016fdff0a8), to: AnyObject.self) error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x6563696c60). The process has been returned to the state before expression evaluation.
seems doesn't work for me
@demonguy From the output of v, it seems like Person is a struct? As I said, you cannot do this without knowing the type.
You're right. Person is a struct
2

The problem is that there isn't a natural way to give registers a type in the swift TypeSystem, so the register-name variables aren't available in swift expressions. You can, however, use register read to get the value of the register, and use that value in the po expression.

If you want to actually print the contents of a swift class object that you only have the address of, you will indeed need to cast it to the appropriate type. Because pointers aren't a first class entity in swift, that's a bit more tedious than it is in C based languages.

But one of the special behaviors of the po command - that is: "print object description" - is that if the expression you pass it resolves to an Int literal, lldb will treat that as an Any, and call debugDescription on that. This only works for swift classes, however, not for structs.

So for instance, if you have:

class Foo : CustomDebugStringConvertible {
  var a = 100
  var debugDescription: String {
    return "a: \(a)"
  }
}

func doSomething() -> Int {
  let myFoo = Foo()
  return myFoo.a
}

print(doSomething())

You can at least get the object description from just the object's location, for instance:

(lldb) b s -p return
Breakpoint 1: 2 locations.
(lldb) run
Process 80234 launched: '/tmp/has_addr' (arm64)
Process 80234 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
    frame #0: 0x0000000100000a64 has_addr`has_addr.doSomething() -> Swift.Int at has_addr.swift:10
   7    
   8    func doSomething() -> Int {
   9      let myFoo = Foo()
-> 10     return myFoo.a
                       ^
   11   }
   12   
   13   print(doSomething())
Target 0: (has_addr) stopped.
(lldb) v -L
scalar: (has_addr.Foo) myFoo = 0x0000000ae2c012c0 {
0x0000000ae2c012d0:   a = 100
}
(lldb) po 0x0000000ae2c012c0
a: 100

4 Comments

It seems that I have to know the class of the object, or it's impossible to dump it
I amended the answer to show that while in the case of p you do need to know the type, if you JUST want the object description - that's what you are asking for by using po - that isn't necessary.
(lldb) v -L 0x000000016fdff0a8: (testSwift.Person) self = { 0x000000016fdff0a8: name = "Alice" 0x000000016fdff0b8: age = 25 } \n\n (lldb) po 0x000000016fdff0a8 error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x6563696c60). The process has been returned to the state before expression evaluation. It seems doesn't work for me
This is exactly the same trick you were taking advantage of in ObjC. In that case, lldb casts the integer value to an id and shows you the result of (roughly) expr [(id) 0x12345 debugDescription].

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.