Po in Lldb with Swift

po in LLDB with swift

That error sounds like it might be because DWARF is not telling LLDB where to find your self object. Given the nature of Swift, LLDB needs to know the type of self in order to be able to inject an expression inside your local scope.
One way to find out if that is your problem is to do at the LLDB prompt:

(lldb) frame variable -L self

You are probably going to not see a location for it. Worth filling a bug report for, just to track your specific repro case.

Anyway, to get to the bulk of your question. In Swift, there is no language-sanctioned mechanism for "print description" like for ObjC, so while you can type po self, unless self is an Objective-C type, you will pretty much see the same thing that "p self" or even "frame variable self" would tell you - which is entirely based on the LLDB data formatters mechanism. If you want to hook into that to customize the way your Swift objects look, the obligatory reference is: http://lldb.llvm.org/varformats.html

How to override what's printed for lldb po command, for a swift enum?

You're comparing apples and oranges, to some extent. po and CustomStringConvertible aren't really very closely related.

CustomStringConvertible and description dictate what you see when you convert the object to a String (hence the name). So in the debugger what you want to do is say po String(testEnum). (Or don't use lldb at all; just print to the console from the running program, using print(testEnum); that's really what CustomStringConvertible is for.)

The display when you say po testEnum has to do with how the enum is reflected. If you don't like that, you would want to implement CustomReflectable — but I don't believe you really want to do that, as I shall argue in a moment. First, an example:

enum TestEnum : CustomStringConvertible, CustomReflectable {
case Value1(test:Int)

var description: String {
return "Test Enum"
}

func customMirror() -> Mirror {
return Mirror(reflecting:self.description)
}

}

Now po testEnum will yield Test Enum. But... why? Do you really want to throw away the splendid mirroring that an enum gives you nowadays? For the whole first year of Swift's life, we complained that po on an enum gave no information at all, not even what case it was; here you are learning not only the case but also the associated value of that case. It seems terribly retrograde, not to say self-defeating, to want to eliminate that.

How to use _printHierarchy in LLDB console with Swift?

You point out how one shows the view controller hierarchy with:

po [[[UIWindow keyWindow] rootViewController] _printHierarchy]

You then say:

This works only if you are debugging code on Objective C. In Swift, however, this doesn't work.

Actually, this depends a little upon how you pause the execution of your Swift program. The issue is that the expression command (which po uses) will use Swift expressions in Swift frames, and Objective-C expressions in Objective-C frames. Thus this means that the po behavior varies depending upon how the execution pauses:

  • You can, for example, press the "pause" button while the app is running:

    pause

    If you do this, you will be able to use the above po syntax with the Objective-C expression without incident.

  • If, on the other hand, you set a breakpoint inside your Swift code, you'll be in a Swift frame when you get to the (lldb) prompt. But you can explicitly tell the expression command that you want to use the Objective-C syntax with the -l (or --language) option:

    expr -l objc++ -O -- [[[UIWindow keyWindow] rootViewController] _printHierarchy]

This ability to specify the language in the expr command is discussed in WWDC 2014 video Advanced Swift Debugging in LLDB.

What's the difference between p and po in Xcode's LLDB debugger?

Strip debug symbols during copy

In most answers they advice to set optimization to "none" but forget that this option should be set to NO (at least for debug configuration).

po Swift String unresolved identifier

This is most likely a bug in the debug information output. You can check this by grabbing the PC, for instance from register read pc, and then doing:

(lldb) image lookup -va <PC VALUE>

That will print a bunch of stuff, but the last entries will be all the variables currently visible to the debugger, and where they live (in registers or memory.) If you don't see the variable there, then the debug information must have told lldb that the variable is not currently live.

If you can reproduce this in some example code you can make available, please file a bug with bug reporter.apple.com.

What happens when you print a Swift object (po) in lldb?

There's a known issue that Printable is ignored by the Swift REPL (i.e., anything in a Playground or run by xcrun swift at the command line) but recognized by the compiler (compiled apps in the simulator or xcrun swiftc).

For example, here's the code of "foo.swift":

struct Person : Printable {
let name: String

var description: String {
return "\(name)"
}
}

let me = Person(name: "Nate")
println(me)

If I run it using the REPL, I get this:

$ xcrun swift foo.swift 
foo.Person

But if I compile it first, and then run it, it uses the description computed property:

$ xcrun -sdk macosx swiftc foo.swift ; ./foo
Nate

The DebugPrintable protocol is useful if you want to be able to use the debugPrint and debugPrintln functions -- in compiled code, they print out an instance's debugDescription property.

Evaluate Swift expressions in LLDB

Working with Swift code in LLDB /h3>

Most Swift code can be executed as part of LLDB if it's part of the stdlib with the right syntax. The key is to prefix type names with the symbol identifier $. I've used $ even for variable names here (new LLDB improvements make this unnecessary) because I prefer to distinguish LLDB definitions.

Extensions /h4>

With improvements to LLDB, you can actually copy-paste the Swift code directly after expression.

I've added an example for your extension with $ symbols for clarity:

(lldb) expression
extension Collection where Self.Element == Int {
var $elementsOver30: [Self.Element]? {
return self.filter { $0 > 30 }
}
}
(lldb) po [32,31,4].$elementsOver30
▿ Optional<Array<Int>>
▿ some : 2 elements
- 0 : 32
- 1 : 31

Pressing Enter after expression prompts a multi-line evaluation where we can input the remaining Swift code.

Structs/Class definitions /h4>
(lldb) expression
struct $Person {
let name: String
}
(lldb) po let $pranav = $Person.init(name: "pranav")
(lldb) po $pranav
▿ $Person
- name : "pranav"

Reading a Swift instance from memory

Sometimes, we need to read Swift code using Objective-C in LLDB. For example, if we have a Swift file with a View Controller:

class LoginViewController: UIViewController {
...
}

We can print the dynamic type of the result of a memory address as follows:

(lldb) expr -O --language objc -- 0x14160c260
<SharedSettings.LoginViewController: 0x14160c260>

View Swift docs /h4>

Use type lookup to read a minified version of the type definitions:

(lldb) type lookup Equatable
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Swift.Bool
}
extension Swift.Equatable {
static func != (lhs: Self, rhs: Self) -> Swift.Bool
}


Related Topics



Leave a reply



Submit