# 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 __init__(self, val): self.val = val def children(self): itype = self.val.type().template_argument(0) nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer() return self._iterator(nodetype, self.val['_M_impl']['_M_node']) def to_string(self): if self.val['_M_impl']['_M_node'].address() == self.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 __init__(self, val): self.val = val def children(self): return self._iterator(self.val['_M_impl']['_M_start'], self.val['_M_impl']['_M_finish']) def to_string(self): start = self.val['_M_impl']['_M_start'] finish = self.val['_M_impl']['_M_finish'] end = self.val['_M_impl']['_M_end_of_storage'] return ('std::vector of length %d, capacity %d' % (int (finish - start), int (end - start))) def display_hint(self): return 'whatever' class StdStackOrQueuePrinter: "Print a std::stack or std::queue" def __init__ (self, typename, val): self.typename = typename self.visualizer = gdb.get_default_visualizer(val['c']) def children (self): return self.visualizer.children() def to_string (self): return '%s wrapping: %s' % (self.typename, self.visualizer.to_string()) class RbtreeIterator: def __init__(self, rbtree): self.size = rbtree['_M_t']['_M_impl']['_M_node_count'] self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] self.count = 0 def __iter__(self): return self def __len__(self): return int (self.size) def next(self): if self.count == self.size: raise StopIteration result = self.node self.count = self.count + 1 if self.count < self.size: # Compute the next node. node = self.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 self.node = node return result class StdMapPrinter: "Print a std::map or std::multimap" # Turn an RbtreeIterator into a pretty-print iterator. class _iter: def __init__(self, rbiter, type): self.rbiter = rbiter self.count = 0 self.type = type def __iter__(self): return self def next(self): if self.count % 2 == 0: n = self.rbiter.next() n = n.cast(self.type).dereference()['_M_value_field'] self.pair = n item = n['first'] else: item = self.pair['second'] result = ('[%d]' % self.count, item) self.count = self.count + 1 return result def __init__ (self, typename, val): self.typename = typename self.val = val self.iter = RbtreeIterator (val) def to_string (self): return '%s with %d elements' % (self.typename, len (self.iter)) def children (self): keytype = self.val.type().template_argument(0) valuetype = self.val.type().template_argument(1) nodetype = gdb.Type('std::_Rb_tree_node< std::pair< const %s, %s > >' % (keytype, valuetype)) nodetype = nodetype.pointer() return self._iter (self.iter, nodetype) def display_hint (self): return 'map' class StdSetPrinter: "Print a std::set or std::multiset" # Turn an RbtreeIterator into a pretty-print iterator. class _iter: def __init__(self, rbiter, type): self.rbiter = rbiter self.count = 0 self.type = type def __iter__(self): return self def next(self): item = self.rbiter.next() item = item.cast(self.type).dereference()['_M_value_field'] # FIXME: this is weird ... what to do? # Maybe a 'set' display hint? result = ('[%d]' % self.count, item) self.count = self.count + 1 return result def __init__ (self, typename, val): self.typename = typename self.val = val self.iter = RbtreeIterator (val) def to_string (self): return '%s with %d elements' % (self.typename, len (self.iter)) def children (self): keytype = self.val.type().template_argument(0) nodetype = gdb.Type('std::_Rb_tree_node< %s >' % keytype).pointer() return self._iter (self.iter, nodetype) class StdBitsetPrinter: "Print a std::bitset" def __init__(self, val): self.val = val def to_string (self): # If template_argument handled values, we could print the # size. Or we could use a regexp on the type. return 'std::bitset' def children (self): words = self.val['_M_w'] wtype = words.type() tsize = wtype.target().sizeof() nwords = wtype.sizeof() / tsize result = [] byte = 0 while byte < nwords: w = words[byte] bit = 0 while w != 0: if (w & 1) != 0: # Another spot where we could use 'set'? result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) bit = bit + 1 w = w >> 1 byte = byte + 1 return result class StdDequePrinter: "Print a std::deque" class _iter: def __init__(self, start, end): self.p = start self.end = end self.count = 0 def __iter__(self): return self def next(self): if self.p == self.end: raise StopIteration result = (self.count, self.p.dereference()) self.count = self.count + 1 self.p = self.p + 1 return result def __init__(self, val): self.val = val def to_string(self): s = self.val['_M_impl']['_M_start']['_M_cur'] e = self.val['_M_impl']['_M_finish']['_M_cur'] return 'std::deque with %d elements' % long (e - s) def children(self): s = self.val['_M_impl']['_M_start']['_M_cur'] e = self.val['_M_impl']['_M_finish']['_M_cur'] return self._iter(s, e) class StdStringPrinter: "Print a std::string" def __init__(self, val): self.val = val def to_string(self): return self.val['_M_dataplus']['_M_p'] def register_libstdcxx_printers(obj): "Register libstdc++ pretty-printers with objfile Obj." if obj == None: obj = gdb obj.pretty_printers['^std::basic_string$'] = StdStringPrinter obj.pretty_printers['^std::bitset<.*>$'] = StdBitsetPrinter obj.pretty_printers['^std::deque<.*>$'] = StdDequePrinter obj.pretty_printers['^std::list<.*>$'] = StdListPrinter obj.pretty_printers['^std::map<.*>$'] = lambda val: StdMapPrinter("std::map", val) obj.pretty_printers['^std::multimap<.*>$'] = lambda val: StdMapPrinter("std::multimap", val) obj.pretty_printers['^std::multiset<.*>$'] = lambda val: StdSetPrinter("std::multiset", val) obj.pretty_printers['^std::priority_queue<.*>$'] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val) obj.pretty_printers['^std::queue<.*>$'] = lambda val: StdStackOrQueuePrinter("std::queue", val) obj.pretty_printers['^std::set<.*>$'] = lambda val: StdSetPrinter("std::set", val) obj.pretty_printers['^std::stack<.*>$'] = lambda val: StdStackOrQueuePrinter("std::stack", val) obj.pretty_printers['^std::vector<.*>$'] = StdVectorPrinter # vector? register_libstdcxx_printers (gdb.get_current_objfile())