lldb

How can I access synthetic children whose names have special characters in LLDB?


Consider this program.cpp:

struct Foo {
  int field1;
  int field2;
};

int main() {
  Foo foo{.field1 = -1, .field2 = -2};
  return 0;
}

I've implemented a custom LLDB data formatter for the Foo type:

class Foo:
    def __init__(self, valobj, internal_dict):
        self.valobj = valobj

    def num_children(self):
        return 2

    def get_child_index(self, name):
        match name:
            case "bar":
                return 0
            case "[baz]":
                return 1

    def get_child_at_index(self, idx):
        match idx:
            case 0:
                return self.bar
            case 1:
                return self.baz

    def update(self):
        self.bar = self.valobj.GetChildMemberWithName("field1").Clone("bar")
        self.baz = self.valobj.GetChildMemberWithName("field2").Clone("[baz]")

    def has_children(self):
        return True


def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand("type synthetic add Foo -l example.Foo")

As you can see, one of these children is named bar which has no special characters, and the other is named [baz] which does have special characters.

I can access bar just fine:

$ clang++ -g program.cpp -o program && lldb ./program
(lldb) command script import example.py
(lldb) b program.cpp:8
(lldb) run
(lldb) v 
(Foo) foo = (bar = -1, [baz] = -2)
(lldb) v foo.bar
(int) foo.bar = -1

But I can't figure out how to access [baz]. Here's what I've tried:

(lldb) v foo.[baz]
error: incomplete expression path after "foo" in "foo.[baz]"
(lldb) v foo.'[baz]'
error: incomplete expression path after "foo" in "foo.[baz]"
(lldb) v foo."[baz]"
error: incomplete expression path after "foo" in "foo.[baz]"
(lldb) v foo.\[baz\]
error: "\" is not a member of "(Foo) foo"

Using LLDB, how can I access a synthetic child whose name contains special characters?


Addendum regarding pointers: a hacky workaround is to just refer to the children by their indices of their names:

(lldb) v foo[0]
(int) foo[0] = -1
(lldb) v foo[1]
(int) foo[1] = -2

But then I don't know what to do if foo is a pointer:

struct Foo {
  int field1;
  int field2;
};

int main() {
  Foo *foo = new Foo{.field1 = -1, .field2 = -2};
  return 0;
}
(lldb) v foo->bar
(int) foo->bar = -1
(lldb) foo->[1]
error: 'foo-' is not a valid command.
(lldb) v foo->[1]
error: incomplete expression path after "foo" in "foo->[1]"
(lldb) v (*foo)[1]
error: no variable named '(*foo)' found in this frame
(lldb) v *foo[1]
error: not a pointer or reference type: (Foo) *(foo)

Solution

  • It's not the most convenient, but you can always use Python:

    (lldb) script
    Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
    >>> lldb.frame.FindVariable("foo").GetChildMemberWithName("bar")
    (int) bar = -1
    >>> lldb.frame.FindVariable("foo").GetChildMemberWithName("[baz]")
    (int) [baz] = -2
    >>> ^D
    now exiting InteractiveConsole...
    (lldb)