Re: [rfc] expose gdb values to python

Tom Tromey
2008-10-05T00:00:43Z

>>>>> "Daniel" == Daniel Jacobowitz <drow@false.org> writes:

Daniel> WDYT about making this work anyway - and using a documented namespace
Daniel> for any methods we add? Then the common case will be able to use the
Daniel> attributes safely.

In practice, I don't mind how it works now. I wrote a few
pretty-printers (appended for your viewing pleasure) and I found that
the array syntax is not a real impediment. If anything, the
dereference method is more of a pain.

FYI -- on the current python branch, Value already has a few more
methods: address, cast, and type.

I guess I wouldn't mind a mangling scheme if it were unobtrusive enough.

Tom

# Pretty-printers for libstc++.

def printstdlist(val):
"Print a std::list"
itype = val.type().template_argument(0)
nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer()
head = val['_M_impl']['_M_node']
base = head['_M_next']
head = head.address()
max = gdb.get_parameter('print elements')
n = 0
result = []
while base != head and (max == 0 or n < max):
elt = base.cast(nodetype).dereference()
datum = elt['_M_data']
result.append ('[%d] = %s' % (n, str (datum)))
n = n + 1
base = elt['_M_next']
if len (result) == 0:
result.append('<<empty list>>')
return "\n".join(result)

def printstdvector(val):
"Print a std::vector"
start = val['_M_impl']['_M_start']
finish = val['_M_impl']['_M_finish']
end = val['_M_impl']['_M_end_of_storage']
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)

def printstdstring(val):
"Print a std::string"
return val['_M_dataplus']['_M_p']

gdb.pretty_printers['^std::list<.*>$'] = printstdlist
gdb.pretty_printers['^std::vector<.*>$'] = printstdvector
gdb.pretty_printers['^std::map<.*>$'] = printstdmap
gdb.pretty_printers['^std::set<.*>$'] = printstdset
gdb.pretty_printers['^std::basic_string<char.*>$'] = printstdstring
gdb.pretty_printers['^std::stack<.*>$'] = printstdstack
gdb.pretty_printers['^std::queue<.*>$'] = printstdstack