This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
Re: [patch] Fix glitches with libstdc++ pretty printers
- From: Tom Tromey <tromey at redhat dot com>
- To: ppluzhnikov at google dot com (Paul Pluzhnikov)
- Cc: archer at sourceware dot org
- Date: Wed, 15 Oct 2008 16:52:12 -0600
- Subject: Re: [patch] Fix glitches with libstdc++ pretty printers
- References: <20081015222935.0439C3A6AF5@localhost>
- Reply-to: Tom Tromey <tromey at redhat dot com>
>>>>> "Paul" == Paul Pluzhnikov <ppluzhnikov@google.com> writes:
Paul> Using Tom's pretty printers from:
Paul> http://sourceware.org/ml/gdb-patches/2008-10/msg00123.html
FYI -- I randomly change these as I work on the pretty-printing code.
I've appended my current file. You can see how some of the MI-style
printers are written here.
I guess I could check this in temporarily so we could share.
I don't want to ship this with gdb, since I think it belongs in
libstdc++. But, in the interim it is nice if we can all be
up-to-date. What do you think?
Paul> I am not making a test case for this, because there are some more
Paul> glitches to fix, and I'd rather have a single test for everything.
I haven't written any pretty-printing tests yet anyhow. That is on my
to-do list, as is finishing the documentation on writing a
pretty-printer.
This patch is ok, thanks.
Tom
# Pretty-printers for libstc++.
class StdListPrinter:
"Print a std::list"
class _iterator:
def __init__(self, nodetype, head):
self.nodetype = nodetype
self.base = head['_M_next']
self.head = head.address()
self.count = 0
def __iter__(self):
return self
def next(self):
if self.base == self.head:
raise StopIteration
elt = self.base.cast(self.nodetype).dereference()
self.base = elt['_M_next']
count = self.count
self.count = self.count + 1
return ('[%d]' % count, elt['_M_data'])
def children(self, val):
itype = val.type().template_argument(0)
nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer()
return self._iterator(nodetype, val['_M_impl']['_M_node'])
def header(self, val):
if val['_M_impl']['_M_node'].address() == val['_M_impl']['_M_node']['_M_next']:
return 'empty std::list'
return 'std::list'
class StdVectorPrinter:
"Print a std::vector"
class _iterator:
def __init__ (self, start, finish):
self.item = start
self.finish = finish
self.count = 0
def __iter__(self):
return self
def next(self):
if self.item == self.finish:
raise StopIteration
count = self.count
self.count = self.count + 1
elt = self.item.dereference()
self.item = self.item + 1
return ('[%d]' % count, elt)
def children(self, val):
return self._iterator(val['_M_impl']['_M_start'],
val['_M_impl']['_M_finish'])
def header(self, val):
start = val['_M_impl']['_M_start'],
finish = val['_M_impl']['_M_finish']
end = val['_M_impl']['_M_end_of_storage']
return ('std::vector of length %d, capacity %d'
% (int (finish - start), int (end - start)))
# def printstdvector(val):
# max = gdb.get_parameter('print elements')
# result = []
# result.append('std::vector of length %d, capacity %d'
# % (int (finish - start), int (end - start)))
# i = 0
# while start < finish and (max == 0 or i < max):
# result.append('[%d] = %s' % (i, str(start.dereference())))
# start = start + 1
# i = i + 1
# return "\n".join(result)
def printstdstack(val):
"Print a std::stack or std::queue"
# Maybe we should print stack and queue in opposite orders?
cur = val['c']['_M_impl']['_M_start']['_M_cur']
finish = val['c']['_M_impl']['_M_finish']['_M_cur']
i = 0
max = gdb.get_parameter('print elements')
result = ['std::stack or std::queue of size %d' % int (finish -cur)]
while cur != finish and (max == 0 or i < max):
result.append('[%d] = %s' % (i, str (cur.dereference())))
cur = cur + 1
i = i + 1
return "\n".join(result)
def rbtree_to_list(val):
"Turn an rbtree into a size and a list of elements."
maxprint = gdb.get_parameter('print elements')
size = val['_M_t']['_M_impl']['_M_node_count']
if maxprint == 0 or maxprint > size:
maxprint = size
node = val['_M_t']['_M_impl']['_M_header']['_M_left']
i = 0
result = []
while i < maxprint:
result.append(node)
if node.dereference()['_M_right']:
node = node.dereference()['_M_right']
while node.dereference()['_M_left']:
node = node.dereference()['_M_left']
else:
parent = node.dereference()['_M_parent']
while node == parent.dereference()['_M_right']:
node = parent
parent = parent.dereference()['_M_parent']
if node.dereference()['_M_right'] != parent:
node = parent
i = i + 1
return (size, result)
def printstdmap(val):
"Print a std::map"
keytype = val.type().template_argument(0)
valuetype = val.type().template_argument(1)
nodetype = gdb.Type('std::_Rb_tree_node< std::pair< const %s, %s > >' % (keytype, valuetype))
nodetype = nodetype.pointer()
(size, nodes) = rbtree_to_list (val)
result = ['std::map with %d elements' % int (size)]
for node in nodes:
pair = node.cast(nodetype).dereference()['_M_value_field']
result.append('[%s] = %s' % (str (pair['first']), str (pair['second'])))
return "\n".join(result)
def printstdset(val):
"Print a std::set"
keytype = val.type().template_argument(0)
nodetype = gdb.Type("std::_Rb_tree_node< %s >" % keytype).pointer()
(size, nodes) = rbtree_to_list (val)
result = ['std::set with %d elements' % int (size)]
for node in nodes:
elt = node.cast(nodetype).dereference()['_M_value_field']
result.append(' %s' % str (elt))
return "\n".join(result)
class StdStringPrinter:
def to_string(self, val):
"Print a std::string"
return val['_M_dataplus']['_M_p']
def children(self, val):
return ()
gdb.cli_pretty_printers['^std::basic_string<char.*>$'] = StdStringPrinter()
gdb.mi_pretty_printers['^std::basic_string<char.*>$'] = StdStringPrinter
gdb.cli_pretty_printers['^std::list<.*>$'] = StdListPrinter()
gdb.mi_pretty_printers['^std::list<.*>$'] = StdListPrinter
gdb.cli_pretty_printers['^std::vector<.*>$'] = StdVectorPrinter()
gdb.mi_pretty_printers['^std::vector<.*>$'] = StdVectorPrinter
gdb.cli_pretty_printers['^std::map<.*>$'] = printstdmap
gdb.cli_pretty_printers['^std::set<.*>$'] = printstdset
gdb.cli_pretty_printers['^std::stack<.*>$'] = printstdstack
gdb.cli_pretty_printers['^std::queue<.*>$'] = printstdstack