# The type was not found, so try the superclass. We only need
# to check the first superclass, so we don't bother with
# anything fancier here.
- field = typ.fields()[0]
- if not field.is_base_class:
+ fields = typ.fields()
+ if len(fields) and fields[0].is_base_class:
+ typ = fields[0].type
+ else:
raise ValueError("Cannot find type %s::%s" % (str(orig), name))
- typ = field.type
_versioned_namespace = '__8::'
+def lookup_templ_spec(templ, *args):
+ """
+ Lookup template specialization templ<args...>
+ """
+ t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args]))
+ try:
+ return gdb.lookup_type(t)
+ except gdb.error as e:
+ # Type not found, try again in versioned namespace.
+ global _versioned_namespace
+ if _versioned_namespace and _versioned_namespace not in templ:
+ t = t.replace('::', '::' + _versioned_namespace, 1)
+ try:
+ return gdb.lookup_type(t)
+ except gdb.error:
+ # If that also fails, rethrow the original exception
+ pass
+ raise e
+
+# Use this to find container node types instead of find_type,
+# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details.
+def lookup_node_type(nodename, containertype):
+ """
+ Lookup specialization of template NODENAME corresponding to CONTAINERTYPE.
+ e.g. if NODENAME is '_List_node' and CONTAINERTYPE is std::list<int>
+ then return the type std::_List_node<int>.
+ Returns None if not found.
+ """
+ # If nodename is unqualified, assume it's in namespace std.
+ if '::' not in nodename:
+ nodename = 'std::' + nodename
+ try:
+ valtype = find_type(containertype, 'value_type')
+ except:
+ valtype = containertype.template_argument(0)
+ valtype = valtype.strip_typedefs()
+ try:
+ return lookup_templ_spec(nodename, valtype)
+ except gdb.error as e:
+ # For debug mode containers the node is in std::__cxx1998.
+ if is_member_of_namespace(nodename, 'std'):
+ if is_member_of_namespace(containertype, 'std::__cxx1998',
+ 'std::__debug', '__gnu_debug'):
+ nodename = nodename.replace('::', '::__cxx1998::', 1)
+ return lookup_templ_spec(nodename, valtype)
+ try:
+ return lookup_templ_spec(nodename, valtype)
+ except gdb.error:
+ pass
+ return None
+
+def is_member_of_namespace(typ, *namespaces):
+ """
+ Test whether a type is a member of one of the specified namespaces.
+ The type can be specified as a string or a gdb.Type object.
+ """
+ if type(typ) is gdb.Type:
+ typ = str(typ)
+ typ = strip_versioned_namespace(typ)
+ for namespace in namespaces:
+ if typ.startswith(namespace + '::'):
+ return True
+ return False
+
def is_specialization_of(x, template_name):
"Test if a type is a given template instantiation."
global _versioned_namespace
self.val = val
def children(self):
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
+ nodetype = lookup_node_type('_List_node', self.val.type).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']:
+ headnode = self.val['_M_impl']['_M_node']
+ if headnode['_M_next'] == headnode.address:
return 'empty %s' % (self.typename)
return '%s' % (self.typename)
class NodeIteratorPrinter:
- def __init__(self, typename, val, contname):
+ def __init__(self, typename, val, contname, nodename):
self.val = val
self.typename = typename
self.contname = contname
+ self.nodetype = lookup_node_type(nodename, val.type)
def to_string(self):
if not self.val['_M_node']:
return 'non-dereferenceable iterator for std::%s' % (self.contname)
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- node = self.val['_M_node'].cast(nodetype).dereference()
+ node = self.val['_M_node'].cast(self.nodetype.pointer()).dereference()
return str(get_value_from_list_node(node))
class StdListIteratorPrinter(NodeIteratorPrinter):
"Print std::list::iterator"
def __init__(self, typename, val):
- NodeIteratorPrinter.__init__(self, typename, val, 'list')
+ NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node')
class StdFwdListIteratorPrinter(NodeIteratorPrinter):
"Print std::forward_list::iterator"
def __init__(self, typename, val):
- NodeIteratorPrinter.__init__(self, typename, val, 'forward_list')
+ NodeIteratorPrinter.__init__(self, typename, val, 'forward_list',
+ '_Fwd_list_node')
class StdSlistPrinter:
"Print a __gnu_cxx::slist"
self.val = val
def children(self):
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- return self._iterator(nodetype, self.val)
+ nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self.val.type)
+ return self._iterator(nodetype.pointer(), self.val)
def to_string(self):
if self.val['_M_head']['_M_next'] == 0:
def to_string(self):
if not self.val['_M_node']:
return 'non-dereferenceable iterator for __gnu_cxx::slist'
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
+ nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self.val.type).pointer()
return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data'])
class StdVectorPrinter:
def __init__ (self, typename, val):
self.val = val
- valtype = self.val.type.template_argument(0).strip_typedefs()
- nodetype = '_Rb_tree_node<' + str(valtype) + '>'
- if _versioned_namespace and typename.startswith('std::' + _versioned_namespace):
- nodetype = _versioned_namespace + nodetype
- nodetype = gdb.lookup_type('std::' + nodetype)
- self.link_type = nodetype.strip_typedefs().pointer()
+ nodetype = lookup_node_type('_Rb_tree_node', self.val.type)
+ self.link_type = nodetype.pointer()
def to_string (self):
if not self.val['_M_node']:
num_elements(len(RbtreeIterator (self.val))))
def children (self):
- rep_type = find_type(self.val.type, '_Rep_type')
- node = find_type(rep_type, '_Link_type')
- node = node.strip_typedefs()
+ node = lookup_node_type('_Rb_tree_node', self.val.type).pointer()
return self._iter (RbtreeIterator (self.val), node)
def display_hint (self):
num_elements(len(RbtreeIterator (self.val))))
def children (self):
- rep_type = find_type(self.val.type, '_Rep_type')
- node = find_type(rep_type, '_Link_type')
- node = node.strip_typedefs()
+ node = lookup_node_type('_Rb_tree_node', self.val.type).pointer()
return self._iter (RbtreeIterator (self.val), node)
class StdBitsetPrinter:
return 'string'
class Tr1HashtableIterator(Iterator):
- def __init__ (self, hash):
- self.buckets = hash['_M_buckets']
+ def __init__ (self, hashtable):
+ self.buckets = hashtable['_M_buckets']
self.bucket = 0
- self.bucket_count = hash['_M_bucket_count']
- self.node_type = find_type(hash.type, '_Node').pointer()
+ self.bucket_count = hashtable['_M_bucket_count']
+ self.node_type = find_type(hashtable.type, '_Node').pointer()
self.node = 0
while self.bucket != self.bucket_count:
self.node = self.buckets[self.bucket]
return result
class StdHashtableIterator(Iterator):
- def __init__(self, hash):
- self.node = hash['_M_before_begin']['_M_nxt']
- self.node_type = find_type(hash.type, '__node_type').pointer()
+ def __init__(self, hashtable):
+ self.node = hashtable['_M_before_begin']['_M_nxt']
+ valtype = hashtable.type.template_argument(1)
+ cached = hashtable.type.template_argument(9).template_argument(0)
+ node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype),
+ 'true' if cached else 'false')
+ self.node_type = node_type.pointer()
def __iter__(self):
return self
return valptr.dereference()
class Tr1UnorderedSetPrinter:
- "Print a tr1::unordered_set"
+ "Print a std::unordered_set or tr1::unordered_set"
def __init__ (self, typename, val):
self.typename = strip_versioned_namespace(typename)
return izip (counter, StdHashtableIterator (self.hashtable()))
class Tr1UnorderedMapPrinter:
- "Print a tr1::unordered_map"
+ "Print a std::unordered_map or tr1::unordered_map"
def __init__ (self, typename, val):
self.typename = strip_versioned_namespace(typename)
self.typename = strip_versioned_namespace(typename)
def children(self):
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
+ nodetype = lookup_node_type('_Fwd_list_node', self.val.type).pointer()
return self._iterator(nodetype, self.val['_M_impl']['_M_head'])
def to_string(self):