Eric Stotch
Eric Stotch

Reputation: 241

How do I get the inner value to use as an array for gdb pretty print?

I wrote a pretty printer for InnerStruct which shows the array as 2 elements and the values correctly. I also made a joke one for TestStruct2, However I have no idea how to make TestStruct contain the same contents as InnerStruct. I have no idea how to access array.nestedVariables from gdb/python. How do I write this so TestStruct gives the same results as InnerStruct?

Source

struct InnerStruct
{
    int buffer[100];
    int len;
};
struct TestStruct
{
    InnerStruct array;
};
struct TestStruct2
{
    InnerStruct array;
};

int main() {
    TestStruct s;
    s.array.buffer[0] = 5;
    s.array.buffer[1] = 8;
    s.array.len=2;
    TestStruct2 s2;
    s2.array.buffer[0] = 5;
    s2.array.buffer[1] = 8;
    s2.array.len=2;
    return 0;
}

.gdbinit

python

pp = gdb.printing.RegexpCollectionPrettyPrinter("pp")

class InnerStructPrinter:
    "Print a InnerStruct"

    class _iterator:
        def __init__ (self, start, finish):
            self.item = start
            self.finish = finish
            self.count = 0

        def __iter__ (self):
            return self

        def __next__ (self):
            count = self.count
            self.count = self.count + 1
            if self.item == self.finish:
                raise StopIteration
            elt = self.item.dereference()
            self.item = self.item + 1
            return ('[%d]' % count, elt)

        def next (self):
            return self.__next__()

    def __init__ (self, val):
        self.val = val

    def children (self):
        start = self.val['buffer'][0].address
        return self._iterator(start, start + self.val['len'])

    def to_string (self):
        len = self.val['len']
        return '%s of length %d' % (self.val.type, len)

    def display_hint (self):
        return 'array'

pp.add_printer('InnerStruct', '^InnerStruct$', InnerStructPrinter)

class TestStruct2Printer:
    "Print a TestStruct2"

    def __init__ (self, val):
        self.val = val

    def to_string (self):
        return "Array of"

    def children(self):
        yield ('0', 'fake')
        yield ('1', 'val')

    def display_hint (self):
        return 'array'

pp.add_printer('TestStruct2', '^TestStruct2$', TestStruct2Printer)

gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
end

Upvotes: 5

Views: 622

Answers (1)

dumbass
dumbass

Reputation: 27214

I don’t see a reason why adding this wouldn’t be sufficient.

class TestStructPrinter(InnerStructPrinter):
    def __init__(self, val):
        super().__init__(val['array'])

pp.add_printer('TestStruct', '^TestStruct$', TestStructPrinter)

In other words, the sub-fields are accessed simply as val['field']['subfield']. The subclassing is something of a hack, but you get the idea.

Sample session:

(gdb) show version 
GNU gdb (Debian 9.2-1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
[…]
(gdb) python print(sys.version)
3.8.6 (default, Sep 25 2020, 09:36:53) 
[GCC 10.2.0]
(gdb) print s
$1 = InnerStruct of length 2 = {5, 8}
(gdb) print s.array
$2 = InnerStruct of length 2 = {5, 8}

This seems a rather silly thing to do, though: a debugger is supposed to help you tell types apart. By making TestStruct and InnerStruct print out the same, it will instead mislead the user into thinking one type is being used instead of the other, and have them attempt to access, say, s.buffer instead of s.array.buffer.

Upvotes: 2

Related Questions