Home | History | Annotate | Line # | Download | only in v6
      1 # Pretty-printers for libstdc++.
      2 
      3 # Copyright (C) 2008-2024 Free Software Foundation, Inc.
      4 
      5 # This program is free software; you can redistribute it and/or modify
      6 # it under the terms of the GNU General Public License as published by
      7 # the Free Software Foundation; either version 3 of the License, or
      8 # (at your option) any later version.
      9 #
     10 # This program is distributed in the hope that it will be useful,
     11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 # GNU General Public License for more details.
     14 #
     15 # You should have received a copy of the GNU General Public License
     16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 import gdb
     19 import itertools
     20 import re
     21 import sys
     22 import errno
     23 import datetime
     24 
     25 # Python 2 + Python 3 compatibility code
     26 
     27 # Resources about compatibility:
     28 #
     29 #  * <http://pythonhosted.org/six/>: Documentation of the "six" module
     30 
     31 # FIXME: The handling of e.g. std::basic_string (at least on char)
     32 # probably needs updating to work with Python 3's new string rules.
     33 #
     34 # In particular, Python 3 has a separate type (called byte) for
     35 # bytestrings, and a special b"" syntax for the byte literals; the old
     36 # str() type has been redefined to always store Unicode text.
     37 #
     38 # We probably can't do much about this until this GDB PR is addressed:
     39 # <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>
     40 
     41 if sys.version_info[0] > 2:
     42     # Python 3 stuff
     43     Iterator = object
     44     # Python 3 folds these into the normal functions.
     45     imap = map
     46     izip = zip
     47     # Also, int subsumes long
     48     long = int
     49     _utc_timezone = datetime.timezone.utc
     50 else:
     51     # Python 2 stuff
     52     class Iterator:
     53         """Compatibility mixin for iterators
     54 
     55         Instead of writing next() methods for iterators, write
     56         __next__() methods and use this mixin to make them work in
     57         Python 2 as well as Python 3.
     58 
     59         Idea stolen from the "six" documentation:
     60         <http://pythonhosted.org/six/#six.Iterator>
     61         """
     62 
     63         def next(self):
     64             return self.__next__()
     65 
     66     # In Python 2, we still need these from itertools
     67     from itertools import imap, izip
     68 
     69     # Python 2 does not provide the datetime.UTC singleton.
     70     class UTC(datetime.tzinfo):
     71         """Concrete tzinfo class representing the UTC time zone."""
     72 
     73         def utcoffset(self, dt):
     74             return datetime.timedelta(0)
     75 
     76         def tzname(self, dt):
     77             return "UTC"
     78 
     79         def dst(self, dt):
     80             return datetime.timedelta(0)
     81     _utc_timezone = UTC()
     82 
     83 # Try to use the new-style pretty-printing if available.
     84 _use_gdb_pp = True
     85 try:
     86     import gdb.printing
     87 except ImportError:
     88     _use_gdb_pp = False
     89 
     90 # Try to install type-printers.
     91 _use_type_printing = False
     92 try:
     93     import gdb.types
     94     if hasattr(gdb.types, 'TypePrinter'):
     95         _use_type_printing = True
     96 except ImportError:
     97     pass
     98 
     99 # Use the base class if available.
    100 if hasattr(gdb, 'ValuePrinter'):
    101     printer_base = gdb.ValuePrinter
    102 else:
    103     printer_base = object
    104 
    105 # Starting with the type ORIG, search for the member type NAME.  This
    106 # handles searching upward through superclasses.  This is needed to
    107 # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
    108 
    109 
    110 def find_type(orig, name):
    111     typ = orig.strip_typedefs()
    112     while True:
    113         # Use Type.tag to ignore cv-qualifiers.  PR 67440.
    114         search = '%s::%s' % (typ.tag, name)
    115         try:
    116             return gdb.lookup_type(search)
    117         except RuntimeError:
    118             pass
    119         # The type was not found, so try the superclass.  We only need
    120         # to check the first superclass, so we don't bother with
    121         # anything fancier here.
    122         fields = typ.fields()
    123         if len(fields) and fields[0].is_base_class:
    124             typ = fields[0].type
    125         else:
    126             raise ValueError("Cannot find type %s::%s" % (str(orig), name))
    127 
    128 
    129 _versioned_namespace = '__8::'
    130 
    131 
    132 def lookup_templ_spec(templ, *args):
    133     """
    134     Lookup template specialization templ<args...>.
    135     """
    136     t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args]))
    137     try:
    138         return gdb.lookup_type(t)
    139     except gdb.error as e:
    140         # Type not found, try again in versioned namespace.
    141         global _versioned_namespace
    142         if _versioned_namespace not in templ:
    143             t = t.replace('::', '::' + _versioned_namespace, 1)
    144             try:
    145                 return gdb.lookup_type(t)
    146             except gdb.error:
    147                 # If that also fails, rethrow the original exception
    148                 pass
    149         raise e
    150 
    151 # Use this to find container node types instead of find_type,
    152 # see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details.
    153 def lookup_node_type(nodename, containertype):
    154     """
    155     Lookup specialization of template nodename corresponding to containertype.
    156 
    157     nodename - The name of a class template, as a String
    158     containertype - The container, as a gdb.Type
    159 
    160     Return a gdb.Type for the corresponding specialization of nodename,
    161     or None if the type cannot be found.
    162 
    163     e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list<int>'))
    164     will return a gdb.Type for the type std::_List_node<int>.
    165     """
    166     # If nodename is unqualified, assume it's in namespace std.
    167     if '::' not in nodename:
    168         nodename = 'std::' + nodename
    169     # Use either containertype's value_type or its first template argument.
    170     try:
    171         valtype = find_type(containertype, 'value_type')
    172     except:
    173         valtype = containertype.template_argument(0)
    174     valtype = valtype.strip_typedefs()
    175     try:
    176         return lookup_templ_spec(nodename, valtype)
    177     except gdb.error:
    178         # For debug mode containers the node is in std::__cxx1998.
    179         if is_member_of_namespace(nodename, 'std'):
    180             if is_member_of_namespace(containertype, 'std::__cxx1998',
    181                                       'std::__debug', '__gnu_debug'):
    182                 nodename = nodename.replace('::', '::__cxx1998::', 1)
    183                 try:
    184                     return lookup_templ_spec(nodename, valtype)
    185                 except gdb.error:
    186                     pass
    187         return None
    188 
    189 
    190 def is_member_of_namespace(typ, *namespaces):
    191     """
    192     Test whether a type is a member of one of the specified namespaces.
    193     The type can be specified as a string or a gdb.Type object.
    194     """
    195     if isinstance(typ, gdb.Type):
    196         typ = str(typ)
    197     typ = strip_versioned_namespace(typ)
    198     for namespace in namespaces:
    199         if typ.startswith(namespace + '::'):
    200             return True
    201     return False
    202 
    203 
    204 def is_specialization_of(x, template_name):
    205     """
    206     Test whether a type is a specialization of the named class template.
    207     The type can be specified as a string or a gdb.Type object.
    208     The template should be the name of a class template as a string,
    209     without any 'std' qualification.
    210     """
    211     global _versioned_namespace
    212     if isinstance(x, gdb.Type):
    213         x = x.tag
    214     template_name = '(%s)?%s' % (_versioned_namespace, template_name)
    215     return re.match('^std::%s<.*>$' % template_name, x) is not None
    216 
    217 
    218 def strip_versioned_namespace(typename):
    219     global _versioned_namespace
    220     return typename.replace(_versioned_namespace, '')
    221 
    222 
    223 def strip_fundts_namespace(typ):
    224     """Remove "fundamentals_vN" inline namespace from qualified type name."""
    225     pattern = r'^std::experimental::fundamentals_v\d::'
    226     repl = 'std::experimental::'
    227     if sys.version_info[0] == 2:
    228         return re.sub(pattern, repl, typ, 1)
    229     else: # Technically this needs Python 3.1 but nobody should be using 3.0
    230         return re.sub(pattern, repl, typ, count=1)
    231 
    232 
    233 def strip_inline_namespaces(type_str):
    234     """Remove known inline namespaces from the canonical name of a type."""
    235     type_str = strip_versioned_namespace(type_str)
    236     type_str = type_str.replace('std::__cxx11::', 'std::')
    237     expt_ns = 'std::experimental::'
    238     for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'):
    239         type_str = type_str.replace(expt_ns + lfts_ns + '::', expt_ns)
    240     fs_ns = expt_ns + 'filesystem::'
    241     type_str = type_str.replace(fs_ns + 'v1::', fs_ns)
    242     return type_str
    243 
    244 
    245 def get_template_arg_list(type_obj):
    246     """Return a type's template arguments as a list."""
    247     n = 0
    248     template_args = []
    249     while True:
    250         try:
    251             template_args.append(type_obj.template_argument(n))
    252         except:
    253             return template_args
    254         n += 1
    255 
    256 
    257 class SmartPtrIterator(Iterator):
    258     """An iterator for smart pointer types with a single 'child' value."""
    259 
    260     def __init__(self, val):
    261         self._val = val
    262 
    263     def __iter__(self):
    264         return self
    265 
    266     def __next__(self):
    267         if self._val is None:
    268             raise StopIteration
    269         self._val, val = None, self._val
    270         return ('get()', val)
    271 
    272 
    273 class SharedPointerPrinter(printer_base):
    274     """
    275     Print a shared_ptr, weak_ptr, atomic<shared_ptr>, or atomic<weak_ptr>.
    276     """
    277 
    278     def __init__(self, typename, val):
    279         self._typename = strip_versioned_namespace(typename)
    280         self._val = val
    281         self._pointer = val['_M_ptr']
    282 
    283     def children(self):
    284         return SmartPtrIterator(self._pointer)
    285 
    286     # Return the _Sp_counted_base<>* that holds the refcounts.
    287     def _get_refcounts(self):
    288         if self._typename == 'std::atomic':
    289             # A tagged pointer is stored as uintptr_t.
    290             ptr_val = self._val['_M_refcount']['_M_val']['_M_i']
    291             ptr_val = ptr_val - (ptr_val % 2)  # clear lock bit
    292             ptr_type = find_type(self._val['_M_refcount'].type, 'pointer')
    293             return ptr_val.cast(ptr_type)
    294         return self._val['_M_refcount']['_M_pi']
    295 
    296     def to_string(self):
    297         state = 'empty'
    298         refcounts = self._get_refcounts()
    299         targ = self._val.type.template_argument(0)
    300         targ = strip_versioned_namespace(str(targ))
    301 
    302         if refcounts != 0:
    303             usecount = refcounts['_M_use_count']
    304             weakcount = refcounts['_M_weak_count']
    305             if usecount == 0:
    306                 state = 'expired, weak count %d' % weakcount
    307             else:
    308                 state = 'use count %d, weak count %d' % (
    309                     usecount, weakcount - 1)
    310         return '%s<%s> (%s)' % (self._typename, targ, state)
    311 
    312 
    313 def _tuple_impl_get(val):
    314     """Return the tuple element stored in a _Tuple_impl<N, T> base class."""
    315     bases = val.type.fields()
    316     if not bases[-1].is_base_class:
    317         raise ValueError(
    318             "Unsupported implementation for std::tuple: %s" % str(val.type))
    319     # Get the _Head_base<N, T> base class:
    320     head_base = val.cast(bases[-1].type)
    321     fields = head_base.type.fields()
    322     if len(fields) == 0:
    323         raise ValueError(
    324             "Unsupported implementation for std::tuple: %s" % str(val.type))
    325     if fields[0].name == '_M_head_impl':
    326         # The tuple element is the _Head_base::_M_head_impl data member.
    327         return head_base['_M_head_impl']
    328     elif fields[0].is_base_class:
    329         # The tuple element is an empty base class of _Head_base.
    330         # Cast to that empty base class.
    331         return head_base.cast(fields[0].type)
    332     else:
    333         raise ValueError(
    334             "Unsupported implementation for std::tuple: %s" % str(val.type))
    335 
    336 
    337 def tuple_get(n, val):
    338     """Return the result of std::get<n>(val) on a std::tuple."""
    339     tuple_size = len(get_template_arg_list(val.type))
    340     if n > tuple_size:
    341         raise ValueError("Out of range index for std::get<N> on std::tuple")
    342     # Get the first _Tuple_impl<0, T...> base class:
    343     node = val.cast(val.type.fields()[0].type)
    344     while n > 0:
    345         # Descend through the base classes until the Nth one.
    346         node = node.cast(node.type.fields()[0].type)
    347         n -= 1
    348     return _tuple_impl_get(node)
    349 
    350 
    351 def unique_ptr_get(val):
    352     """Return the result of val.get() on a std::unique_ptr."""
    353     # std::unique_ptr<T, D> contains a std::tuple<D::pointer, D>,
    354     # either as a direct data member _M_t (the old implementation)
    355     # or within a data member of type __uniq_ptr_data.
    356     impl_type = val.type.fields()[0].type.strip_typedefs()
    357     # Check for new implementations first:
    358     if is_specialization_of(impl_type, '__uniq_ptr_data') \
    359             or is_specialization_of(impl_type, '__uniq_ptr_impl'):
    360         tuple_member = val['_M_t']['_M_t']
    361     elif is_specialization_of(impl_type, 'tuple'):
    362         tuple_member = val['_M_t']
    363     else:
    364         raise ValueError(
    365             "Unsupported implementation for unique_ptr: %s" % str(impl_type))
    366     return tuple_get(0, tuple_member)
    367 
    368 
    369 class UniquePointerPrinter(printer_base):
    370     """Print a unique_ptr."""
    371 
    372     def __init__(self, typename, val):
    373         self._val = val
    374 
    375     def children(self):
    376         return SmartPtrIterator(unique_ptr_get(self._val))
    377 
    378     def to_string(self):
    379         t = self._val.type.template_argument(0)
    380         return 'std::unique_ptr<{}>'.format(str(t))
    381 
    382 
    383 def get_value_from_aligned_membuf(buf, valtype):
    384     """Return the value held in a __gnu_cxx::__aligned_membuf."""
    385     return buf['_M_storage'].address.cast(valtype.pointer()).dereference()
    386 
    387 
    388 def get_value_from_list_node(node):
    389     """Return the value held in an _List_node<_Val>."""
    390     try:
    391         member = node.type.fields()[1].name
    392         if member == '_M_data':
    393             # C++03 implementation, node contains the value as a member
    394             return node['_M_data']
    395         elif member == '_M_storage':
    396             # C++11 implementation, node stores value in __aligned_membuf
    397             valtype = node.type.template_argument(0)
    398             return get_value_from_aligned_membuf(node['_M_storage'], valtype)
    399     except:
    400         pass
    401     raise ValueError("Unsupported implementation for %s" % str(node.type))
    402 
    403 
    404 class StdListPrinter(printer_base):
    405     """Print a std::list."""
    406 
    407     class _iterator(Iterator):
    408         def __init__(self, nodetype, head):
    409             self._nodetype = nodetype
    410             self._base = head['_M_next']
    411             self._head = head.address
    412             self._count = 0
    413 
    414         def __iter__(self):
    415             return self
    416 
    417         def __next__(self):
    418             if self._base == self._head:
    419                 raise StopIteration
    420             elt = self._base.cast(self._nodetype).dereference()
    421             self._base = elt['_M_next']
    422             count = self._count
    423             self._count = self._count + 1
    424             val = get_value_from_list_node(elt)
    425             return ('[%d]' % count, val)
    426 
    427     def __init__(self, typename, val):
    428         self._typename = strip_versioned_namespace(typename)
    429         self._val = val
    430 
    431     def children(self):
    432         nodetype = lookup_node_type('_List_node', self._val.type).pointer()
    433         return self._iterator(nodetype, self._val['_M_impl']['_M_node'])
    434 
    435     def to_string(self):
    436         headnode = self._val['_M_impl']['_M_node']
    437         if headnode['_M_next'] == headnode.address:
    438             return 'empty %s' % (self._typename)
    439         return '%s' % (self._typename)
    440 
    441 
    442 class NodeIteratorPrinter(printer_base):
    443     def __init__(self, typename, val, contname, nodename):
    444         self._val = val
    445         self._typename = typename
    446         self._contname = contname
    447         self._nodetype = lookup_node_type(nodename, val.type)
    448 
    449     def to_string(self):
    450         if not self._val['_M_node']:
    451             return 'non-dereferenceable iterator for std::%s' % (self._contname)
    452         node = self._val['_M_node'].cast(
    453             self._nodetype.pointer()).dereference()
    454         return str(get_value_from_list_node(node))
    455 
    456 
    457 class StdListIteratorPrinter(NodeIteratorPrinter):
    458     """Print std::list::iterator."""
    459 
    460     def __init__(self, typename, val):
    461         NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node')
    462 
    463 
    464 class StdFwdListIteratorPrinter(NodeIteratorPrinter):
    465     """Print std::forward_list::iterator."""
    466 
    467     def __init__(self, typename, val):
    468         NodeIteratorPrinter.__init__(self, typename, val, 'forward_list',
    469                                      '_Fwd_list_node')
    470 
    471 
    472 class StdSlistPrinter(printer_base):
    473     """Print a __gnu_cxx::slist."""
    474 
    475     class _iterator(Iterator):
    476         def __init__(self, nodetype, head):
    477             self._nodetype = nodetype
    478             self._base = head['_M_head']['_M_next']
    479             self._count = 0
    480 
    481         def __iter__(self):
    482             return self
    483 
    484         def __next__(self):
    485             if self._base == 0:
    486                 raise StopIteration
    487             elt = self._base.cast(self._nodetype).dereference()
    488             self._base = elt['_M_next']
    489             count = self._count
    490             self._count = self._count + 1
    491             return ('[%d]' % count, elt['_M_data'])
    492 
    493     def __init__(self, typename, val):
    494         self._val = val
    495 
    496     def children(self):
    497         nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self._val.type)
    498         return self._iterator(nodetype.pointer(), self._val)
    499 
    500     def to_string(self):
    501         if self._val['_M_head']['_M_next'] == 0:
    502             return 'empty __gnu_cxx::slist'
    503         return '__gnu_cxx::slist'
    504 
    505 
    506 class StdSlistIteratorPrinter(printer_base):
    507     """Print __gnu_cxx::slist::iterator."""
    508 
    509     def __init__(self, typename, val):
    510         self._val = val
    511 
    512     def to_string(self):
    513         if not self._val['_M_node']:
    514             return 'non-dereferenceable iterator for __gnu_cxx::slist'
    515         nodetype = lookup_node_type(
    516             '__gnu_cxx::_Slist_node', self._val.type).pointer()
    517         return str(self._val['_M_node'].cast(nodetype).dereference()['_M_data'])
    518 
    519 
    520 class StdVectorPrinter(printer_base):
    521     """Print a std::vector."""
    522 
    523     class _iterator(Iterator):
    524         def __init__(self, start, finish, bitvec):
    525             self._bitvec = bitvec
    526             if bitvec:
    527                 self._item = start['_M_p']
    528                 self._so = 0
    529                 self._finish = finish['_M_p']
    530                 self._fo = finish['_M_offset']
    531                 itype = self._item.dereference().type
    532                 self._isize = 8 * itype.sizeof
    533             else:
    534                 self._item = start
    535                 self._finish = finish
    536             self._count = 0
    537 
    538         def __iter__(self):
    539             return self
    540 
    541         def __next__(self):
    542             count = self._count
    543             self._count = self._count + 1
    544             if self._bitvec:
    545                 if self._item == self._finish and self._so >= self._fo:
    546                     raise StopIteration
    547                 elt = bool(self._item.dereference() & (1 << self._so))
    548                 self._so = self._so + 1
    549                 if self._so >= self._isize:
    550                     self._item = self._item + 1
    551                     self._so = 0
    552                 return ('[%d]' % count, elt)
    553             else:
    554                 if self._item == self._finish:
    555                     raise StopIteration
    556                 elt = self._item.dereference()
    557                 self._item = self._item + 1
    558                 return ('[%d]' % count, elt)
    559 
    560     def __init__(self, typename, val):
    561         self._typename = strip_versioned_namespace(typename)
    562         self._val = val
    563         self._is_bool = val.type.template_argument(
    564             0).code == gdb.TYPE_CODE_BOOL
    565 
    566     def children(self):
    567         return self._iterator(self._val['_M_impl']['_M_start'],
    568                               self._val['_M_impl']['_M_finish'],
    569                               self._is_bool)
    570 
    571     def to_string(self):
    572         start = self._val['_M_impl']['_M_start']
    573         finish = self._val['_M_impl']['_M_finish']
    574         end = self._val['_M_impl']['_M_end_of_storage']
    575         if self._is_bool:
    576             start = self._val['_M_impl']['_M_start']['_M_p']
    577             finish = self._val['_M_impl']['_M_finish']['_M_p']
    578             fo = self._val['_M_impl']['_M_finish']['_M_offset']
    579             itype = start.dereference().type
    580             bl = 8 * itype.sizeof
    581             length = bl * (finish - start) + fo
    582             capacity = bl * (end - start)
    583             return ('%s<bool> of length %d, capacity %d'
    584                     % (self._typename, int(length), int(capacity)))
    585         else:
    586             return ('%s of length %d, capacity %d'
    587                     % (self._typename, int(finish - start), int(end - start)))
    588 
    589     def display_hint(self):
    590         return 'array'
    591 
    592 
    593 class StdVectorIteratorPrinter(printer_base):
    594     """Print std::vector::iterator."""
    595 
    596     def __init__(self, typename, val):
    597         self._val = val
    598 
    599     def to_string(self):
    600         if not self._val['_M_current']:
    601             return 'non-dereferenceable iterator for std::vector'
    602         return str(self._val['_M_current'].dereference())
    603 
    604 
    605 class StdBitIteratorPrinter(printer_base):
    606     """Print std::vector<bool>'s _Bit_iterator and _Bit_const_iterator."""
    607 
    608     def __init__(self, typename, val):
    609         self._val = val
    610 
    611     def to_string(self):
    612         if not self._val['_M_p']:
    613             return 'non-dereferenceable iterator for std::vector<bool>'
    614         return bool(self._val['_M_p'].dereference()
    615                     & (1 << self._val['_M_offset']))
    616 
    617 
    618 class StdBitReferencePrinter(printer_base):
    619     """Print std::vector<bool>::reference."""
    620 
    621     def __init__(self, typename, val):
    622         self._val = val
    623 
    624     def to_string(self):
    625         if not self._val['_M_p']:
    626             return 'invalid std::vector<bool>::reference'
    627         return bool(self._val['_M_p'].dereference() & (self._val['_M_mask']))
    628 
    629 
    630 class StdTuplePrinter(printer_base):
    631     """Print a std::tuple."""
    632 
    633     class _iterator(Iterator):
    634         @staticmethod
    635         def _is_nonempty_tuple(nodes):
    636             if len(nodes) == 2:
    637                 if is_specialization_of(nodes[1].type, '__tuple_base'):
    638                     return True
    639             elif len(nodes) == 1:
    640                 return True
    641             elif len(nodes) == 0:
    642                 return False
    643             raise ValueError(
    644                 "Top of tuple tree does not consist of a single node.")
    645 
    646         def __init__(self, head):
    647             self._head = head
    648 
    649             # Set the base class as the initial head of the
    650             # tuple.
    651             nodes = self._head.type.fields()
    652             if self._is_nonempty_tuple(nodes):
    653                 # Set the actual head to the first pair.
    654                 self._head = self._head.cast(nodes[0].type)
    655             self._count = 0
    656 
    657         def __iter__(self):
    658             return self
    659 
    660         def __next__(self):
    661             # Check for further recursions in the inheritance tree.
    662             # For a GCC 5+ tuple self._head is None after visiting all nodes:
    663             if not self._head:
    664                 raise StopIteration
    665             nodes = self._head.type.fields()
    666             # For a GCC 4.x tuple there is a final node with no fields:
    667             if len(nodes) == 0:
    668                 raise StopIteration
    669             # Check that this iteration has an expected structure.
    670             if len(nodes) > 2:
    671                 raise ValueError(
    672                     "Cannot parse more than 2 nodes in a tuple tree.")
    673 
    674             if len(nodes) == 1:
    675                 # This is the last node of a GCC 5+ std::tuple.
    676                 impl = self._head.cast(nodes[0].type)
    677                 self._head = None
    678             else:
    679                 # Either a node before the last node, or the last node of
    680                 # a GCC 4.x tuple (which has an empty parent).
    681 
    682                 # - Left node is the next recursion parent.
    683                 # - Right node is the actual class contained in the tuple.
    684 
    685                 # Process right node.
    686                 impl = self._head.cast(nodes[1].type)
    687 
    688                 # Process left node and set it as head.
    689                 self._head = self._head.cast(nodes[0].type)
    690 
    691             self._count = self._count + 1
    692 
    693             # Finally, check the implementation.  If it is
    694             # wrapped in _M_head_impl return that, otherwise return
    695             # the value "as is".
    696             fields = impl.type.fields()
    697             if len(fields) < 1 or fields[0].name != "_M_head_impl":
    698                 return ('[%d]' % (self._count - 1), impl)
    699             else:
    700                 return ('[%d]' % (self._count - 1), impl['_M_head_impl'])
    701 
    702     def __init__(self, typename, val):
    703         self._typename = strip_versioned_namespace(typename)
    704         self._val = val
    705 
    706     def children(self):
    707         return self._iterator(self._val)
    708 
    709     def to_string(self):
    710         if len(self._val.type.fields()) == 0:
    711             return 'empty %s' % (self._typename)
    712         return '%s containing' % (self._typename)
    713 
    714 
    715 class StdStackOrQueuePrinter(printer_base):
    716     """Print a std::stack or std::queue."""
    717 
    718     def __init__(self, typename, val):
    719         self._typename = strip_versioned_namespace(typename)
    720         self._visualizer = gdb.default_visualizer(val['c'])
    721 
    722     def children(self):
    723         return self._visualizer.children()
    724 
    725     def to_string(self):
    726         return '%s wrapping: %s' % (self._typename,
    727                                     self._visualizer.to_string())
    728 
    729     def display_hint(self):
    730         if hasattr(self._visualizer, 'display_hint'):
    731             return self._visualizer.display_hint()
    732         return None
    733 
    734 
    735 class RbtreeIterator(Iterator):
    736     """
    737     Turn an RB-tree-based container (std::map, std::set etc.) into
    738     a Python iterable object.
    739     """
    740 
    741     def __init__(self, rbtree):
    742         self._size = rbtree['_M_t']['_M_impl']['_M_node_count']
    743         self._node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
    744         self._count = 0
    745 
    746     def __iter__(self):
    747         return self
    748 
    749     def __len__(self):
    750         return int(self._size)
    751 
    752     def __next__(self):
    753         if self._count == self._size:
    754             raise StopIteration
    755         result = self._node
    756         self._count = self._count + 1
    757         if self._count < self._size:
    758             # Compute the next node.
    759             node = self._node
    760             if node.dereference()['_M_right']:
    761                 node = node.dereference()['_M_right']
    762                 while node.dereference()['_M_left']:
    763                     node = node.dereference()['_M_left']
    764             else:
    765                 parent = node.dereference()['_M_parent']
    766                 while node == parent.dereference()['_M_right']:
    767                     node = parent
    768                     parent = parent.dereference()['_M_parent']
    769                 if node.dereference()['_M_right'] != parent:
    770                     node = parent
    771             self._node = node
    772         return result
    773 
    774 
    775 def get_value_from_Rb_tree_node(node):
    776     """Return the value held in an _Rb_tree_node<_Val>."""
    777     try:
    778         member = node.type.fields()[1].name
    779         if member == '_M_value_field':
    780             # C++03 implementation, node contains the value as a member
    781             return node['_M_value_field']
    782         elif member == '_M_storage':
    783             # C++11 implementation, node stores value in __aligned_membuf
    784             valtype = node.type.template_argument(0)
    785             return get_value_from_aligned_membuf(node['_M_storage'], valtype)
    786     except:
    787         pass
    788     raise ValueError("Unsupported implementation for %s" % str(node.type))
    789 
    790 # This is a pretty printer for std::_Rb_tree_iterator (which is
    791 # std::map::iterator), and has nothing to do with the RbtreeIterator
    792 # class above.
    793 
    794 
    795 class StdRbtreeIteratorPrinter(printer_base):
    796     """Print std::map::iterator, std::set::iterator, etc."""
    797 
    798     def __init__(self, typename, val):
    799         self._val = val
    800         nodetype = lookup_node_type('_Rb_tree_node', self._val.type)
    801         self._link_type = nodetype.pointer()
    802 
    803     def to_string(self):
    804         if not self._val['_M_node']:
    805             return 'non-dereferenceable iterator for associative container'
    806         node = self._val['_M_node'].cast(self._link_type).dereference()
    807         return str(get_value_from_Rb_tree_node(node))
    808 
    809 
    810 class StdDebugIteratorPrinter(printer_base):
    811     """Print a debug enabled version of an iterator."""
    812 
    813     def __init__(self, typename, val):
    814         self._val = val
    815 
    816     # Just strip away the encapsulating __gnu_debug::_Safe_iterator
    817     # and return the wrapped iterator value.
    818     def to_string(self):
    819         base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base')
    820         itype = self._val.type.template_argument(0)
    821         safe_seq = self._val.cast(base_type)['_M_sequence']
    822         if not safe_seq:
    823             return str(self._val.cast(itype))
    824         if self._val['_M_version'] != safe_seq['_M_version']:
    825             return "invalid iterator"
    826         return str(self._val.cast(itype))
    827 
    828 
    829 def num_elements(num):
    830     """Return either "1 element" or "N elements" depending on the argument."""
    831     return '1 element' if num == 1 else '%d elements' % num
    832 
    833 
    834 class StdMapPrinter(printer_base):
    835     """Print a std::map or std::multimap."""
    836 
    837     # Turn an RbtreeIterator into a pretty-print iterator.
    838     class _iter(Iterator):
    839         def __init__(self, rbiter, type):
    840             self._rbiter = rbiter
    841             self._count = 0
    842             self._type = type
    843 
    844         def __iter__(self):
    845             return self
    846 
    847         def __next__(self):
    848             if self._count % 2 == 0:
    849                 n = next(self._rbiter)
    850                 n = n.cast(self._type).dereference()
    851                 n = get_value_from_Rb_tree_node(n)
    852                 self._pair = n
    853                 item = n['first']
    854             else:
    855                 item = self._pair['second']
    856             result = ('[%d]' % self._count, item)
    857             self._count = self._count + 1
    858             return result
    859 
    860     def __init__(self, typename, val):
    861         self._typename = strip_versioned_namespace(typename)
    862         self._val = val
    863 
    864     def to_string(self):
    865         return '%s with %s' % (self._typename,
    866                                num_elements(len(RbtreeIterator(self._val))))
    867 
    868     def children(self):
    869         node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
    870         return self._iter(RbtreeIterator(self._val), node)
    871 
    872     def display_hint(self):
    873         return 'map'
    874 
    875 
    876 class StdSetPrinter(printer_base):
    877     """Print a std::set or std::multiset."""
    878 
    879     # Turn an RbtreeIterator into a pretty-print iterator.
    880     class _iter(Iterator):
    881         def __init__(self, rbiter, type):
    882             self._rbiter = rbiter
    883             self._count = 0
    884             self._type = type
    885 
    886         def __iter__(self):
    887             return self
    888 
    889         def __next__(self):
    890             item = next(self._rbiter)
    891             item = item.cast(self._type).dereference()
    892             item = get_value_from_Rb_tree_node(item)
    893             # FIXME: this is weird ... what to do?
    894             # Maybe a 'set' display hint?
    895             result = ('[%d]' % self._count, item)
    896             self._count = self._count + 1
    897             return result
    898 
    899     def __init__(self, typename, val):
    900         self._typename = strip_versioned_namespace(typename)
    901         self._val = val
    902 
    903     def to_string(self):
    904         return '%s with %s' % (self._typename,
    905                                num_elements(len(RbtreeIterator(self._val))))
    906 
    907     def children(self):
    908         node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
    909         return self._iter(RbtreeIterator(self._val), node)
    910 
    911 
    912 class StdBitsetPrinter(printer_base):
    913     """Print a std::bitset."""
    914 
    915     def __init__(self, typename, val):
    916         self._typename = strip_versioned_namespace(typename)
    917         self._val = val
    918 
    919     def to_string(self):
    920         # If template_argument handled values, we could print the
    921         # size.  Or we could use a regexp on the type.
    922         return '%s' % (self._typename)
    923 
    924     def children(self):
    925         try:
    926             # An empty bitset may not have any members which will
    927             # result in an exception being thrown.
    928             words = self._val['_M_w']
    929         except:
    930             return []
    931 
    932         wtype = words.type
    933 
    934         # The _M_w member can be either an unsigned long, or an
    935         # array.  This depends on the template specialization used.
    936         # If it is a single long, convert to a single element list.
    937         if wtype.code == gdb.TYPE_CODE_ARRAY:
    938             tsize = wtype.target().sizeof
    939         else:
    940             words = [words]
    941             tsize = wtype.sizeof
    942 
    943         nwords = wtype.sizeof / tsize
    944         result = []
    945         byte = 0
    946         while byte < nwords:
    947             w = words[byte]
    948             bit = 0
    949             while w != 0:
    950                 if (w & 1) != 0:
    951                     # Another spot where we could use 'set'?
    952                     result.append(('[%d]' % (byte * tsize * 8 + bit), 1))
    953                 bit = bit + 1
    954                 w = w >> 1
    955             byte = byte + 1
    956         return result
    957 
    958 
    959 class StdDequePrinter(printer_base):
    960     """Print a std::deque."""
    961 
    962     class _iter(Iterator):
    963         def __init__(self, node, start, end, last, buffer_size):
    964             self._node = node
    965             self._p = start
    966             self._end = end
    967             self._last = last
    968             self._buffer_size = buffer_size
    969             self._count = 0
    970 
    971         def __iter__(self):
    972             return self
    973 
    974         def __next__(self):
    975             if self._p == self._last:
    976                 raise StopIteration
    977 
    978             result = ('[%d]' % self._count, self._p.dereference())
    979             self._count = self._count + 1
    980 
    981             # Advance the 'cur' pointer.
    982             self._p = self._p + 1
    983             if self._p == self._end:
    984                 # If we got to the end of this bucket, move to the
    985                 # next bucket.
    986                 self._node = self._node + 1
    987                 self._p = self._node[0]
    988                 self._end = self._p + self._buffer_size
    989 
    990             return result
    991 
    992     def __init__(self, typename, val):
    993         self._typename = strip_versioned_namespace(typename)
    994         self._val = val
    995         self._elttype = val.type.template_argument(0)
    996         size = self._elttype.sizeof
    997         if size < 512:
    998             self._buffer_size = int(512 / size)
    999         else:
   1000             self._buffer_size = 1
   1001 
   1002     def to_string(self):
   1003         start = self._val['_M_impl']['_M_start']
   1004         end = self._val['_M_impl']['_M_finish']
   1005 
   1006         delta_n = end['_M_node'] - start['_M_node'] - 1
   1007         delta_s = start['_M_last'] - start['_M_cur']
   1008         delta_e = end['_M_cur'] - end['_M_first']
   1009 
   1010         size = self._buffer_size * delta_n + delta_s + delta_e
   1011 
   1012         return '%s with %s' % (self._typename, num_elements(long(size)))
   1013 
   1014     def children(self):
   1015         start = self._val['_M_impl']['_M_start']
   1016         end = self._val['_M_impl']['_M_finish']
   1017         return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
   1018                           end['_M_cur'], self._buffer_size)
   1019 
   1020     def display_hint(self):
   1021         return 'array'
   1022 
   1023 
   1024 class StdDequeIteratorPrinter(printer_base):
   1025     """Print std::deque::iterator."""
   1026 
   1027     def __init__(self, typename, val):
   1028         self._val = val
   1029 
   1030     def to_string(self):
   1031         if not self._val['_M_cur']:
   1032             return 'non-dereferenceable iterator for std::deque'
   1033         return str(self._val['_M_cur'].dereference())
   1034 
   1035 
   1036 class StdStringPrinter(printer_base):
   1037     """Print a std::basic_string of some kind."""
   1038 
   1039     def __init__(self, typename, val):
   1040         self._val = val
   1041         self._new_string = typename.find("::__cxx11::basic_string") != -1
   1042 
   1043     def to_string(self):
   1044         # Make sure &string works, too.
   1045         type = self._val.type
   1046         if type.code == gdb.TYPE_CODE_REF:
   1047             type = type.target()
   1048 
   1049         # Calculate the length of the string so that to_string returns
   1050         # the string according to length, not according to first null
   1051         # encountered.
   1052         ptr = self._val['_M_dataplus']['_M_p']
   1053         if self._new_string:
   1054             length = self._val['_M_string_length']
   1055             # https://sourceware.org/bugzilla/show_bug.cgi?id=17728
   1056             ptr = ptr.cast(ptr.type.strip_typedefs())
   1057         else:
   1058             realtype = type.unqualified().strip_typedefs()
   1059             reptype = gdb.lookup_type(str(realtype) + '::_Rep').pointer()
   1060             header = ptr.cast(reptype) - 1
   1061             length = header.dereference()['_M_length']
   1062         if hasattr(ptr, "lazy_string"):
   1063             return ptr.lazy_string(length=length)
   1064         return ptr.string(length=length)
   1065 
   1066     def display_hint(self):
   1067         return 'string'
   1068 
   1069 
   1070 def access_streambuf_ptrs(streambuf):
   1071     """Access the streambuf put area pointers."""
   1072     pbase = streambuf['_M_out_beg']
   1073     pptr = streambuf['_M_out_cur']
   1074     egptr = streambuf['_M_in_end']
   1075     return pbase, pptr, egptr
   1076 
   1077 
   1078 class StdStringBufPrinter(printer_base):
   1079     """Print a std::basic_stringbuf."""
   1080 
   1081     def __init__(self, _, val):
   1082         self._val = val
   1083 
   1084     def to_string(self):
   1085         (pbase, pptr, egptr) = access_streambuf_ptrs(self._val)
   1086         # Logic from basic_stringbuf::_M_high_mark()
   1087         if pptr:
   1088             if not egptr or pptr > egptr:
   1089                 return pbase.string(length=pptr - pbase)
   1090             else:
   1091                 return pbase.string(length=egptr - pbase)
   1092         return self._val['_M_string']
   1093 
   1094     def display_hint(self):
   1095         return 'string'
   1096 
   1097 
   1098 class StdStringStreamPrinter(printer_base):
   1099     """Print a std::basic_stringstream."""
   1100 
   1101     def __init__(self, typename, val):
   1102         self._val = val
   1103         self._typename = typename
   1104 
   1105         # Check if the stream was redirected. This is essentially:
   1106         # val['_M_streambuf'] != val['_M_stringbuf'].address
   1107         # However, GDB can't resolve the virtual inheritance, so we do that
   1108         # manually.
   1109         basetype = [f.type for f in val.type.fields() if f.is_base_class][0]
   1110         gdb.set_convenience_variable('__stream', val.cast(basetype).address)
   1111         self._streambuf = gdb.parse_and_eval('$__stream->rdbuf()')
   1112         self._was_redirected = self._streambuf != val['_M_stringbuf'].address
   1113 
   1114     def to_string(self):
   1115         if self._was_redirected:
   1116             return "%s redirected to %s" % (
   1117                 self._typename, self._streambuf.dereference())
   1118         return self._val['_M_stringbuf']
   1119 
   1120     def display_hint(self):
   1121         if self._was_redirected:
   1122             return None
   1123         return 'string'
   1124 
   1125 
   1126 class Tr1HashtableIterator(Iterator):
   1127     def __init__(self, hashtable):
   1128         self._buckets = hashtable['_M_buckets']
   1129         self._bucket = 0
   1130         self._bucket_count = hashtable['_M_bucket_count']
   1131         self._node_type = find_type(hashtable.type, '_Node').pointer()
   1132         self._node = 0
   1133         while self._bucket != self._bucket_count:
   1134             self._node = self._buckets[self._bucket]
   1135             if self._node:
   1136                 break
   1137             self._bucket = self._bucket + 1
   1138 
   1139     def __iter__(self):
   1140         return self
   1141 
   1142     def __next__(self):
   1143         if self._node == 0:
   1144             raise StopIteration
   1145         node = self._node.cast(self._node_type)
   1146         result = node.dereference()['_M_v']
   1147         self._node = node.dereference()['_M_next']
   1148         if self._node == 0:
   1149             self._bucket = self._bucket + 1
   1150             while self._bucket != self._bucket_count:
   1151                 self._node = self._buckets[self._bucket]
   1152                 if self._node:
   1153                     break
   1154                 self._bucket = self._bucket + 1
   1155         return result
   1156 
   1157 
   1158 class StdHashtableIterator(Iterator):
   1159     def __init__(self, hashtable):
   1160         self._node = hashtable['_M_before_begin']['_M_nxt']
   1161         valtype = hashtable.type.template_argument(1)
   1162         cached = hashtable.type.template_argument(9).template_argument(0)
   1163         node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype),
   1164                                       'true' if cached else 'false')
   1165         self._node_type = node_type.pointer()
   1166 
   1167     def __iter__(self):
   1168         return self
   1169 
   1170     def __next__(self):
   1171         if self._node == 0:
   1172             raise StopIteration
   1173         elt = self._node.cast(self._node_type).dereference()
   1174         self._node = elt['_M_nxt']
   1175         valptr = elt['_M_storage'].address
   1176         valptr = valptr.cast(elt.type.template_argument(0).pointer())
   1177         return valptr.dereference()
   1178 
   1179 
   1180 class Tr1UnorderedSetPrinter(printer_base):
   1181     """Print a std::unordered_set or tr1::unordered_set."""
   1182 
   1183     def __init__(self, typename, val):
   1184         self._typename = strip_versioned_namespace(typename)
   1185         self._val = val
   1186 
   1187     def _hashtable(self):
   1188         if self._typename.startswith('std::tr1'):
   1189             return self._val
   1190         return self._val['_M_h']
   1191 
   1192     def to_string(self):
   1193         count = self._hashtable()['_M_element_count']
   1194         return '%s with %s' % (self._typename, num_elements(count))
   1195 
   1196     @staticmethod
   1197     def _format_count(i):
   1198         return '[%d]' % i
   1199 
   1200     def children(self):
   1201         counter = imap(self._format_count, itertools.count())
   1202         if self._typename.startswith('std::tr1'):
   1203             return izip(counter, Tr1HashtableIterator(self._hashtable()))
   1204         return izip(counter, StdHashtableIterator(self._hashtable()))
   1205 
   1206 
   1207 class Tr1UnorderedMapPrinter(printer_base):
   1208     """Print a std::unordered_map or tr1::unordered_map."""
   1209 
   1210     def __init__(self, typename, val):
   1211         self._typename = strip_versioned_namespace(typename)
   1212         self._val = val
   1213 
   1214     def _hashtable(self):
   1215         if self._typename.startswith('std::tr1'):
   1216             return self._val
   1217         return self._val['_M_h']
   1218 
   1219     def to_string(self):
   1220         count = self._hashtable()['_M_element_count']
   1221         return '%s with %s' % (self._typename, num_elements(count))
   1222 
   1223     @staticmethod
   1224     def _flatten(list):
   1225         for elt in list:
   1226             for i in elt:
   1227                 yield i
   1228 
   1229     @staticmethod
   1230     def _format_one(elt):
   1231         return (elt['first'], elt['second'])
   1232 
   1233     @staticmethod
   1234     def _format_count(i):
   1235         return '[%d]' % i
   1236 
   1237     def children(self):
   1238         counter = imap(self._format_count, itertools.count())
   1239         # Map over the hash table and flatten the result.
   1240         if self._typename.startswith('std::tr1'):
   1241             data = self._flatten(
   1242                 imap(self._format_one, Tr1HashtableIterator(self._hashtable())))
   1243             # Zip the two iterators together.
   1244             return izip(counter, data)
   1245         data = self._flatten(
   1246             imap(self._format_one, StdHashtableIterator(self._hashtable())))
   1247         # Zip the two iterators together.
   1248         return izip(counter, data)
   1249 
   1250     def display_hint(self):
   1251         return 'map'
   1252 
   1253 
   1254 class StdForwardListPrinter(printer_base):
   1255     """Print a std::forward_list."""
   1256 
   1257     class _iterator(Iterator):
   1258         def __init__(self, nodetype, head):
   1259             self._nodetype = nodetype
   1260             self._base = head['_M_next']
   1261             self._count = 0
   1262 
   1263         def __iter__(self):
   1264             return self
   1265 
   1266         def __next__(self):
   1267             if self._base == 0:
   1268                 raise StopIteration
   1269             elt = self._base.cast(self._nodetype).dereference()
   1270             self._base = elt['_M_next']
   1271             count = self._count
   1272             self._count = self._count + 1
   1273             valptr = elt['_M_storage'].address
   1274             valptr = valptr.cast(elt.type.template_argument(0).pointer())
   1275             return ('[%d]' % count, valptr.dereference())
   1276 
   1277     def __init__(self, typename, val):
   1278         self._val = val
   1279         self._typename = strip_versioned_namespace(typename)
   1280 
   1281     def children(self):
   1282         nodetype = lookup_node_type('_Fwd_list_node', self._val.type).pointer()
   1283         return self._iterator(nodetype, self._val['_M_impl']['_M_head'])
   1284 
   1285     def to_string(self):
   1286         if self._val['_M_impl']['_M_head']['_M_next'] == 0:
   1287             return 'empty %s' % self._typename
   1288         return '%s' % self._typename
   1289 
   1290 
   1291 class SingleObjContainerPrinter(printer_base):
   1292     """Base class for printers of containers of single objects."""
   1293 
   1294     def __init__(self, val, viz, hint=None):
   1295         self._contained_value = val
   1296         self._visualizer = viz
   1297         self._hint = hint
   1298 
   1299     def _recognize(self, type):
   1300         """Return type as a string after applying type printers."""
   1301         global _use_type_printing
   1302         if not _use_type_printing:
   1303             return str(type)
   1304         return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(),
   1305                                                 type) or str(type)
   1306 
   1307     class _contained(Iterator):
   1308         def __init__(self, val):
   1309             self._val = val
   1310 
   1311         def __iter__(self):
   1312             return self
   1313 
   1314         def __next__(self):
   1315             if self._val is None:
   1316                 raise StopIteration
   1317             retval = self._val
   1318             self._val = None
   1319             return ('[contained value]', retval)
   1320 
   1321     def children(self):
   1322         if self._contained_value is None:
   1323             return self._contained(None)
   1324         if hasattr(self._visualizer, 'children'):
   1325             return self._visualizer.children()
   1326         return self._contained(self._contained_value)
   1327 
   1328     def display_hint(self):
   1329         if (hasattr(self._visualizer, 'children')
   1330                 and hasattr(self._visualizer, 'display_hint')):
   1331             # If contained value is a map we want to display in the same way.
   1332             return self._visualizer.display_hint()
   1333         return self._hint
   1334 
   1335 
   1336 def function_pointer_to_name(f):
   1337     """Find the name of the function referred to by the gdb.Value f,
   1338     which should contain a function pointer from the program."""
   1339 
   1340     # Turn the function pointer into an actual address.
   1341     # This is needed to unpack ppc64 function descriptors.
   1342     f = f.dereference().address
   1343 
   1344     if sys.version_info[0] == 2:
   1345         # Older versions of GDB need to use long for Python 2,
   1346         # because int(f) on 64-bit big-endian values raises a
   1347         # gdb.error saying "Cannot convert value to int."
   1348         f = long(f)
   1349     else:
   1350         f = int(f)
   1351 
   1352     try:
   1353         # If the function can't be found older versions of GDB raise a
   1354         # RuntimeError saying "Cannot locate object file for block."
   1355         return gdb.block_for_pc(f).function.name
   1356     except:
   1357         return None
   1358 
   1359 
   1360 class StdExpAnyPrinter(SingleObjContainerPrinter):
   1361     """Print a std::any or std::experimental::any."""
   1362 
   1363     def __init__(self, typename, val):
   1364         self._typename = strip_versioned_namespace(typename)
   1365         self._typename = strip_fundts_namespace(self._typename)
   1366         self._val = val
   1367         self._contained_type = None
   1368         contained_value = None
   1369         visualizer = None
   1370         mgr = self._val['_M_manager']
   1371         if mgr != 0:
   1372             func = function_pointer_to_name(mgr)
   1373             if not func:
   1374                 raise ValueError(
   1375                     "Invalid function pointer in %s" % (self._typename))
   1376             # We want to use this regular expression:
   1377             # T::_Manager_xxx<.*>::_S_manage\(T::_Op, const T\*, T::_Arg\*\)
   1378             # where T is std::any or std::experimental::any.
   1379             # But we need to account for variances in demangled names
   1380             # between GDB versions, e.g. 'enum T::_Op' instead of 'T::_Op'.
   1381             rx = (
   1382                 r"({0}::_Manager_\w+<.*>)::_S_manage\("
   1383                 r"(enum )?{0}::_Op, (const {0}|{0} const) ?\*, "
   1384                 r"(union )?{0}::_Arg ?\*\)"
   1385             ).format(typename)
   1386             m = re.match(rx, func)
   1387             if not m:
   1388                 raise ValueError(
   1389                     "Unknown manager function in %s" % self._typename)
   1390 
   1391             mgrname = m.group(1)
   1392             # FIXME need to expand 'std::string' so that gdb.lookup_type works
   1393             if 'std::string' in mgrname:
   1394                 mgrtypes = []
   1395                 for s in StdExpAnyPrinter._string_types():
   1396                     try:
   1397                         x = re.sub(r"std::string(?!\w)", s, m.group(1))
   1398                         # The following lookup might raise gdb.error if the
   1399                         # manager function was never instantiated for 's' in
   1400                         # the program, because there will be no such type.
   1401                         mgrtypes.append(gdb.lookup_type(x))
   1402                     except gdb.error:
   1403                         pass
   1404                 if len(mgrtypes) != 1:
   1405                     # FIXME: this is unlikely in practice, but possible for
   1406                     # programs that use both old and new string types with
   1407                     # std::any in a single program. Can we do better?
   1408                     # Maybe find the address of each type's _S_manage and
   1409                     # compare to the address stored in _M_manager?
   1410                     raise ValueError(
   1411                         'Cannot uniquely determine std::string type '
   1412                         'used in std::any'
   1413                     )
   1414                 mgrtype = mgrtypes[0]
   1415             else:
   1416                 mgrtype = gdb.lookup_type(mgrname)
   1417             self._contained_type = mgrtype.template_argument(0)
   1418             valptr = None
   1419             if '::_Manager_internal' in mgrname:
   1420                 valptr = self._val['_M_storage']['_M_buffer'].address
   1421             elif '::_Manager_external' in mgrname:
   1422                 valptr = self._val['_M_storage']['_M_ptr']
   1423             else:
   1424                 raise ValueError(
   1425                     "Unknown manager function in %s" % self._typename)
   1426             contained_value = valptr.cast(
   1427                 self._contained_type.pointer()).dereference()
   1428             visualizer = gdb.default_visualizer(contained_value)
   1429         super(StdExpAnyPrinter, self).__init__(contained_value, visualizer)
   1430 
   1431     def to_string(self):
   1432         if self._contained_type is None:
   1433             return '%s [no contained value]' % self._typename
   1434         desc = "%s containing " % self._typename
   1435         if hasattr(self._visualizer, 'children'):
   1436             return desc + self._visualizer.to_string()
   1437         valtype = self._recognize(self._contained_type)
   1438         return desc + strip_versioned_namespace(str(valtype))
   1439 
   1440     @staticmethod
   1441     def _string_types():
   1442         # This lookup for std::string might return the __cxx11 version,
   1443         # but that's not necessarily the one used by the std::any
   1444         # manager function we're trying to find.
   1445         strings = {str(gdb.lookup_type('std::string').strip_typedefs())}
   1446         # So also consider all the other possible std::string types!
   1447         s = 'basic_string<char, std::char_traits<char>, std::allocator<char> >'
   1448         quals = ['std::', 'std::__cxx11::',
   1449                  'std::' + _versioned_namespace]
   1450         strings |= {q + s for q in quals}  # set of unique strings
   1451         return strings
   1452 
   1453 
   1454 class StdExpOptionalPrinter(SingleObjContainerPrinter):
   1455     """Print a std::optional or std::experimental::optional."""
   1456 
   1457     def __init__(self, typename, val):
   1458         self._typename = strip_versioned_namespace(typename)
   1459         self._typename = strip_fundts_namespace(self._typename)
   1460         payload = val['_M_payload']
   1461         if self._typename.startswith('std::experimental'):
   1462             engaged = val['_M_engaged']
   1463             contained_value = payload
   1464         else:
   1465             engaged = payload['_M_engaged']
   1466             contained_value = payload['_M_payload']
   1467             try:
   1468                 # Since GCC 9
   1469                 contained_value = contained_value['_M_value']
   1470             except:
   1471                 pass
   1472         visualizer = gdb.default_visualizer(contained_value)
   1473         if not engaged:
   1474             contained_value = None
   1475         super(StdExpOptionalPrinter, self).__init__(
   1476             contained_value, visualizer)
   1477 
   1478     def to_string(self):
   1479         if self._contained_value is None:
   1480             return "%s [no contained value]" % self._typename
   1481         if hasattr(self._visualizer, 'children'):
   1482             return "%s containing %s" % (self._typename,
   1483                                          self._visualizer.to_string())
   1484         return self._typename
   1485 
   1486 
   1487 class StdVariantPrinter(SingleObjContainerPrinter):
   1488     """Print a std::variant."""
   1489 
   1490     def __init__(self, typename, val):
   1491         alternatives = get_template_arg_list(val.type)
   1492         self._typename = strip_versioned_namespace(typename)
   1493         self._index = val['_M_index']
   1494         if self._index >= len(alternatives):
   1495             self._contained_type = None
   1496             contained_value = None
   1497             visualizer = None
   1498         else:
   1499             self._contained_type = alternatives[int(self._index)]
   1500             addr = val['_M_u']['_M_first']['_M_storage'].address
   1501             contained_value = addr.cast(
   1502                 self._contained_type.pointer()).dereference()
   1503             visualizer = gdb.default_visualizer(contained_value)
   1504         super(StdVariantPrinter, self).__init__(
   1505             contained_value, visualizer, 'array')
   1506 
   1507     def to_string(self):
   1508         if self._contained_value is None:
   1509             return "%s [no contained value]" % self._typename
   1510         if hasattr(self._visualizer, 'children'):
   1511             return "%s [index %d] containing %s" % (self._typename, self._index,
   1512                                                     self._visualizer.to_string())
   1513         return "%s [index %d]" % (self._typename, self._index)
   1514 
   1515 
   1516 class StdNodeHandlePrinter(SingleObjContainerPrinter):
   1517     """Print a container node handle."""
   1518 
   1519     def __init__(self, typename, val):
   1520         self._value_type = val.type.template_argument(1)
   1521         nodetype = val.type.template_argument(2).template_argument(0)
   1522         self._is_rb_tree_node = is_specialization_of(
   1523             nodetype.name, '_Rb_tree_node')
   1524         self._is_map_node = val.type.template_argument(0) != self._value_type
   1525         nodeptr = val['_M_ptr']
   1526         if nodeptr:
   1527             if self._is_rb_tree_node:
   1528                 contained_value = get_value_from_Rb_tree_node(
   1529                     nodeptr.dereference())
   1530             else:
   1531                 contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'],
   1532                                                                 self._value_type)
   1533             visualizer = gdb.default_visualizer(contained_value)
   1534         else:
   1535             contained_value = None
   1536             visualizer = None
   1537         optalloc = val['_M_alloc']
   1538         self._alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None
   1539         super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer,
   1540                                                    'array')
   1541 
   1542     def to_string(self):
   1543         desc = 'node handle for '
   1544         if not self._is_rb_tree_node:
   1545             desc += 'unordered '
   1546         if self._is_map_node:
   1547             desc += 'map'
   1548         else:
   1549             desc += 'set'
   1550 
   1551         if self._contained_value:
   1552             desc += ' with element'
   1553             if hasattr(self._visualizer, 'children'):
   1554                 return "%s = %s" % (desc, self._visualizer.to_string())
   1555             return desc
   1556         else:
   1557             return 'empty %s' % desc
   1558 
   1559 
   1560 class StdExpStringViewPrinter(printer_base):
   1561     """
   1562     Print a std::basic_string_view or std::experimental::basic_string_view
   1563     """
   1564 
   1565     def __init__(self, typename, val):
   1566         self._val = val
   1567 
   1568     def to_string(self):
   1569         ptr = self._val['_M_str']
   1570         len = self._val['_M_len']
   1571         if hasattr(ptr, "lazy_string"):
   1572             return ptr.lazy_string(length=len)
   1573         return ptr.string(length=len)
   1574 
   1575     def display_hint(self):
   1576         return 'string'
   1577 
   1578 
   1579 class StdExpPathPrinter(printer_base):
   1580     """Print a std::experimental::filesystem::path."""
   1581 
   1582     def __init__(self, typename, val):
   1583         self._val = val
   1584         self._typename = typename
   1585         start = self._val['_M_cmpts']['_M_impl']['_M_start']
   1586         finish = self._val['_M_cmpts']['_M_impl']['_M_finish']
   1587         self._num_cmpts = int(finish - start)
   1588 
   1589     def _path_type(self):
   1590         t = str(self._val['_M_type'])
   1591         if t[-9:] == '_Root_dir':
   1592             return "root-directory"
   1593         if t[-10:] == '_Root_name':
   1594             return "root-name"
   1595         return None
   1596 
   1597     def to_string(self):
   1598         path = "%s" % self._val['_M_pathname']
   1599         if self._num_cmpts == 0:
   1600             t = self._path_type()
   1601             if t:
   1602                 path = '%s [%s]' % (path, t)
   1603         return "experimental::filesystem::path %s" % path
   1604 
   1605     class _iterator(Iterator):
   1606         def __init__(self, cmpts, pathtype):
   1607             self._pathtype = pathtype
   1608             self._item = cmpts['_M_impl']['_M_start']
   1609             self._finish = cmpts['_M_impl']['_M_finish']
   1610             self._count = 0
   1611 
   1612         def __iter__(self):
   1613             return self
   1614 
   1615         def __next__(self):
   1616             if self._item == self._finish:
   1617                 raise StopIteration
   1618             item = self._item.dereference()
   1619             count = self._count
   1620             self._count = self._count + 1
   1621             self._item = self._item + 1
   1622             path = item['_M_pathname']
   1623             t = StdExpPathPrinter(self._pathtype, item)._path_type()
   1624             if not t:
   1625                 t = count
   1626             return ('[%s]' % t, path)
   1627 
   1628     def children(self):
   1629         return self._iterator(self._val['_M_cmpts'], self._typename)
   1630 
   1631 
   1632 class StdPathPrinter(printer_base):
   1633     """Print a std::filesystem::path."""
   1634 
   1635     def __init__(self, typename, val):
   1636         self._val = val
   1637         self._typename = typename
   1638         impl = unique_ptr_get(self._val['_M_cmpts']['_M_impl'])
   1639         self._type = impl.cast(gdb.lookup_type('uintptr_t')) & 3
   1640         if self._type == 0:
   1641             self._impl = impl
   1642         else:
   1643             self._impl = None
   1644 
   1645     def _path_type(self):
   1646         t = str(self._type.cast(gdb.lookup_type(self._typename + '::_Type')))
   1647         if t[-9:] == '_Root_dir':
   1648             return "root-directory"
   1649         if t[-10:] == '_Root_name':
   1650             return "root-name"
   1651         return None
   1652 
   1653     def to_string(self):
   1654         path = "%s" % self._val['_M_pathname']
   1655         if self._type != 0:
   1656             t = self._path_type()
   1657             if t:
   1658                 path = '%s [%s]' % (path, t)
   1659         return "filesystem::path %s" % path
   1660 
   1661     class _iterator(Iterator):
   1662         def __init__(self, impl, pathtype):
   1663             self._pathtype = pathtype
   1664             if impl:
   1665                 # We can't access _Impl::_M_size because _Impl is incomplete
   1666                 # so cast to int* to access the _M_size member at offset zero,
   1667                 int_type = gdb.lookup_type('int')
   1668                 cmpt_type = gdb.lookup_type(pathtype + '::_Cmpt')
   1669                 char_type = gdb.lookup_type('char')
   1670                 impl = impl.cast(int_type.pointer())
   1671                 size = impl.dereference()
   1672                 #self._capacity = (impl + 1).dereference()
   1673                 if hasattr(gdb.Type, 'alignof'):
   1674                     sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof)
   1675                 else:
   1676                     sizeof_Impl = 2 * int_type.sizeof
   1677                 begin = impl.cast(char_type.pointer()) + sizeof_Impl
   1678                 self._item = begin.cast(cmpt_type.pointer())
   1679                 self._finish = self._item + size
   1680                 self._count = 0
   1681             else:
   1682                 self._item = None
   1683                 self._finish = None
   1684 
   1685         def __iter__(self):
   1686             return self
   1687 
   1688         def __next__(self):
   1689             if self._item == self._finish:
   1690                 raise StopIteration
   1691             item = self._item.dereference()
   1692             count = self._count
   1693             self._count = self._count + 1
   1694             self._item = self._item + 1
   1695             path = item['_M_pathname']
   1696             t = StdPathPrinter(self._pathtype, item)._path_type()
   1697             if not t:
   1698                 t = count
   1699             return ('[%s]' % t, path)
   1700 
   1701     def children(self):
   1702         return self._iterator(self._impl, self._typename)
   1703 
   1704 
   1705 class StdPairPrinter(printer_base):
   1706     """Print a std::pair object, with 'first' and 'second' as children."""
   1707 
   1708     def __init__(self, typename, val):
   1709         self._val = val
   1710 
   1711     class _iter(Iterator):
   1712         """An iterator for std::pair types. Returns 'first' then 'second'."""
   1713 
   1714         def __init__(self, val):
   1715             self._val = val
   1716             self._which = 'first'
   1717 
   1718         def __iter__(self):
   1719             return self
   1720 
   1721         def __next__(self):
   1722             if self._which is None:
   1723                 raise StopIteration
   1724             which = self._which
   1725             if which == 'first':
   1726                 self._which = 'second'
   1727             else:
   1728                 self._which = None
   1729             return (which, self._val[which])
   1730 
   1731     def children(self):
   1732         return self._iter(self._val)
   1733 
   1734     def to_string(self):
   1735         return None
   1736 
   1737 
   1738 class StdCmpCatPrinter(printer_base):
   1739     """Print a comparison category object."""
   1740 
   1741     def __init__(self, typename, val):
   1742         self._typename = typename[typename.rfind(':') + 1:]
   1743         self._val = val['_M_value']
   1744 
   1745     def to_string(self):
   1746         if self._typename == 'strong_ordering' and self._val == 0:
   1747             name = 'equal'
   1748         else:
   1749             names = {2: 'unordered', -1: 'less', 0: 'equivalent', 1: 'greater'}
   1750             name = names[int(self._val)]
   1751         return 'std::{}::{}'.format(self._typename, name)
   1752 
   1753 
   1754 class StdErrorCodePrinter(printer_base):
   1755     """Print a std::error_code or std::error_condition."""
   1756 
   1757     _system_is_posix = None  # Whether std::system_category() use errno values.
   1758 
   1759     def __init__(self, typename, val):
   1760         self._val = val
   1761         self._typename = strip_versioned_namespace(typename)
   1762         # Do this only once ...
   1763         if StdErrorCodePrinter._system_is_posix is None:
   1764             try:
   1765                 import posix
   1766                 StdErrorCodePrinter._system_is_posix = True
   1767             except ImportError:
   1768                 StdErrorCodePrinter._system_is_posix = False
   1769 
   1770     @staticmethod
   1771     def _find_errc_enum(name):
   1772         typ = gdb.lookup_type(name)
   1773         if typ is not None and typ.code == gdb.TYPE_CODE_ENUM:
   1774             return typ
   1775         return None
   1776 
   1777     @classmethod
   1778     def _find_standard_errc_enum(cls, name):
   1779         for ns in ['', _versioned_namespace]:
   1780             try:
   1781                 qname = 'std::{}{}'.format(ns, name)
   1782                 return cls._find_errc_enum(qname)
   1783             except RuntimeError:
   1784                 pass
   1785 
   1786     @classmethod
   1787     def _match_net_ts_category(cls, cat):
   1788         net_cats = ['stream', 'socket', 'ip::resolver']
   1789         for c in net_cats:
   1790             func = c + '_category()'
   1791             for ns in ['', _versioned_namespace]:
   1792                 ns = 'std::{}experimental::net::v1'.format(ns)
   1793                 sym = gdb.lookup_symbol('{}::{}::__c'.format(ns, func))[0]
   1794                 if sym is not None:
   1795                     if cat == sym.value().address:
   1796                         name = 'net::' + func
   1797                         enum = cls._find_errc_enum('{}::{}_errc'.format(ns, c))
   1798                         return (name, enum)
   1799         return (None, None)
   1800 
   1801     @classmethod
   1802     def _category_info(cls, cat):
   1803         """Return details of a std::error_category."""
   1804 
   1805         name = None
   1806         enum = None
   1807         is_errno = False
   1808 
   1809         # Try these first, or we get "warning: RTTI symbol not found" when
   1810         # using cat.dynamic_type on the local class types for Net TS
   1811         # categories.
   1812         func, enum = cls._match_net_ts_category(cat)
   1813         if func is not None:
   1814             return (None, func, enum, is_errno)
   1815 
   1816         # This might give a warning for a program-defined category defined as
   1817         # a local class, but there doesn't seem to be any way to avoid that.
   1818         typ = cat.dynamic_type.target()
   1819         # Shortcuts for the known categories defined by libstdc++.
   1820         if typ.tag.endswith('::generic_error_category'):
   1821             name = 'generic'
   1822             is_errno = True
   1823         if typ.tag.endswith('::system_error_category'):
   1824             name = 'system'
   1825             is_errno = cls._system_is_posix
   1826         if typ.tag.endswith('::future_error_category'):
   1827             name = 'future'
   1828             enum = cls._find_standard_errc_enum('future_errc')
   1829         if typ.tag.endswith('::io_error_category'):
   1830             name = 'io'
   1831             enum = cls._find_standard_errc_enum('io_errc')
   1832 
   1833         if name is None:
   1834             try:
   1835                 # Want to call std::error_category::name() override, but it's
   1836                 # unsafe: https://sourceware.org/bugzilla/show_bug.cgi?id=28856
   1837                 # gdb.set_convenience_variable('__cat', cat)
   1838                 # return '"%s"' % gdb.parse_and_eval('$__cat->name()').string()
   1839                 pass
   1840             except:
   1841                 pass
   1842         return (name, typ.tag, enum, is_errno)
   1843 
   1844     @staticmethod
   1845     def _unqualified_name(name):
   1846         """
   1847         Strip any nested-name-specifier from name to give an unqualified name.
   1848         """
   1849         return name.split('::')[-1]
   1850 
   1851     def to_string(self):
   1852         value = self._val['_M_value']
   1853         cat = self._val['_M_cat']
   1854         name, alt_name, enum, is_errno = self._category_info(cat)
   1855         if value == 0:
   1856             default_cats = {'error_code': 'system',
   1857                             'error_condition': 'generic'}
   1858             if name == default_cats[self._unqualified_name(self._typename)]:
   1859                 return self._typename + ' = { }'  # default-constructed value
   1860 
   1861         strval = str(value)
   1862         if is_errno and value != 0:
   1863             try:
   1864                 strval = errno.errorcode[int(value)]
   1865             except:
   1866                 pass
   1867         elif enum is not None:
   1868             strval = self._unqualified_name(str(value.cast(enum)))
   1869 
   1870         if name is not None:
   1871             name = '"%s"' % name
   1872         else:
   1873             name = alt_name
   1874         return '%s = {%s: %s}' % (self._typename, name, strval)
   1875 
   1876 
   1877 class StdRegexStatePrinter(printer_base):
   1878     """Print a state node in the NFA for a std::regex."""
   1879 
   1880     def __init__(self, typename, val):
   1881         self._val = val
   1882         self._typename = typename
   1883 
   1884     def to_string(self):
   1885         opcode = str(self._val['_M_opcode'])
   1886         if opcode:
   1887             opcode = opcode[25:]
   1888         next_id = self._val['_M_next']
   1889 
   1890         variants = {'repeat': 'alt', 'alternative': 'alt',
   1891                     'subexpr_begin': 'subexpr', 'subexpr_end': 'subexpr',
   1892                     'line_begin_assertion': None, 'line_end_assertion': None,
   1893                     'word_boundary': 'neg', 'subexpr_lookahead': 'neg',
   1894                     'backref': 'backref_index',
   1895                     'match': None, 'accept': None,
   1896                     'dummy': None, 'unknown': None
   1897                     }
   1898         v = variants[opcode]
   1899 
   1900         s = "opcode={}, next={}".format(opcode, next_id)
   1901         if v is not None and self._val['_M_' + v] is not None:
   1902             s = "{}, {}={}".format(s, v, self._val['_M_' + v])
   1903         return "{%s}" % (s)
   1904 
   1905 
   1906 class StdSpanPrinter(printer_base):
   1907     """Print a std::span."""
   1908 
   1909     class _iterator(Iterator):
   1910         def __init__(self, begin, size):
   1911             self._count = 0
   1912             self._begin = begin
   1913             self._size = size
   1914 
   1915         def __iter__(self):
   1916             return self
   1917 
   1918         def __next__(self):
   1919             if self._count == self._size:
   1920                 raise StopIteration
   1921 
   1922             count = self._count
   1923             self._count = self._count + 1
   1924             return '[%d]' % count, (self._begin + count).dereference()
   1925 
   1926     def __init__(self, typename, val):
   1927         self._typename = strip_versioned_namespace(typename)
   1928         self._val = val
   1929         size_max = gdb.parse_and_eval('static_cast<std::size_t>(-1)')
   1930         if val.type.template_argument(1) == size_max:
   1931             self._size = val['_M_extent']['_M_extent_value']
   1932         else:
   1933             self._size = val.type.template_argument(1)
   1934 
   1935     def to_string(self):
   1936         return '%s of length %d' % (self._typename, self._size)
   1937 
   1938     def children(self):
   1939         return self._iterator(self._val['_M_ptr'], self._size)
   1940 
   1941     def display_hint(self):
   1942         return 'array'
   1943 
   1944 
   1945 class StdInitializerListPrinter(printer_base):
   1946     """Print a std::initializer_list."""
   1947 
   1948     def __init__(self, typename, val):
   1949         self._typename = typename
   1950         self._val = val
   1951         self._size = val['_M_len']
   1952 
   1953     def to_string(self):
   1954         return '%s of length %d' % (self._typename, self._size)
   1955 
   1956     def children(self):
   1957         return StdSpanPrinter._iterator(self._val['_M_array'], self._size)
   1958 
   1959     def display_hint(self):
   1960         return 'array'
   1961 
   1962 
   1963 class StdAtomicPrinter(printer_base):
   1964     """Print a std:atomic."""
   1965 
   1966     def __init__(self, typename, val):
   1967         self._typename = strip_versioned_namespace(typename)
   1968         self._val = val
   1969         self._shptr_printer = None
   1970         self._value_type = self._val.type.template_argument(0)
   1971         if self._value_type.tag is not None:
   1972             typ = strip_versioned_namespace(self._value_type.tag)
   1973             if (typ.startswith('std::shared_ptr<')
   1974                     or typ.startswith('std::weak_ptr<')):
   1975                 impl = val['_M_impl']
   1976                 self._shptr_printer = SharedPointerPrinter(typename, impl)
   1977                 self.children = self._shptr_children
   1978 
   1979     def _shptr_children(self):
   1980         return SmartPtrIterator(self._shptr_printer._pointer)
   1981 
   1982     def to_string(self):
   1983         if self._shptr_printer is not None:
   1984             return self._shptr_printer.to_string()
   1985 
   1986         if self._value_type.code == gdb.TYPE_CODE_INT:
   1987             val = self._val['_M_i']
   1988         elif self._value_type.code == gdb.TYPE_CODE_FLT:
   1989             val = self._val['_M_fp']
   1990         elif self._value_type.code == gdb.TYPE_CODE_PTR:
   1991             val = self._val['_M_b']['_M_p']
   1992         elif self._value_type.code == gdb.TYPE_CODE_BOOL:
   1993             val = self._val['_M_base']['_M_i']
   1994         else:
   1995             val = self._val['_M_i']
   1996         return '%s<%s> = { %s }' % (self._typename, str(self._value_type), val)
   1997 
   1998 
   1999 class StdFormatArgsPrinter(printer_base):
   2000     """Print a std::basic_format_args."""
   2001     # TODO: add printer for basic_format_arg<Context> and print out children.
   2002     # TODO: add printer for __format::_ArgStore<Context, Args...>.
   2003 
   2004     def __init__(self, typename, val):
   2005         self._typename = strip_versioned_namespace(typename)
   2006         self._val = val
   2007 
   2008     def to_string(self):
   2009         targs = get_template_arg_list(self._val.type)
   2010         char_type = get_template_arg_list(targs[0])[1]
   2011         if char_type == gdb.lookup_type('char'):
   2012             typ = 'std::format_args'
   2013         elif char_type == gdb.lookup_type('wchar_t'):
   2014             typ = 'std::wformat_args'
   2015         else:
   2016             typ = 'std::basic_format_args'
   2017 
   2018         size = self._val['_M_packed_size']
   2019         if size == 1:
   2020             return "%s with 1 argument" % (typ)
   2021         if size == 0:
   2022             size = self._val['_M_unpacked_size']
   2023         return "%s with %d arguments" % (typ, size)
   2024 
   2025 
   2026 class StdChronoDurationPrinter(printer_base):
   2027     """Print a std::chrono::duration."""
   2028 
   2029     def __init__(self, typename, val):
   2030         self._typename = strip_versioned_namespace(typename)
   2031         self._val = val
   2032 
   2033     def _ratio(self):
   2034         # TODO use reduced period i.e. duration::period
   2035         period = self._val.type.template_argument(1)
   2036         num = period.template_argument(0)
   2037         den = period.template_argument(1)
   2038         return (num, den)
   2039 
   2040     def _suffix(self):
   2041         num, den = self._ratio()
   2042         if num == 1:
   2043             if den == 1:
   2044                 return 's'
   2045             if den == 1000:
   2046                 return 'ms'
   2047             if den == 1000000:
   2048                 return 'us'
   2049             if den == 1000000000:
   2050                 return 'ns'
   2051         elif den == 1:
   2052             if num == 60:
   2053                 return 'min'
   2054             if num == 3600:
   2055                 return 'h'
   2056             if num == 86400:
   2057                 return 'd'
   2058             return '[{}]s'.format(num)
   2059         return "[{}/{}]s".format(num, den)
   2060 
   2061     def to_string(self):
   2062         r = self._val['__r']
   2063         if r.type.strip_typedefs().code == gdb.TYPE_CODE_FLT:
   2064             r = "%g" % r
   2065         return "std::chrono::duration = {{ {}{} }}".format(r, self._suffix())
   2066 
   2067 
   2068 class StdChronoTimePointPrinter(printer_base):
   2069     """Print a std::chrono::time_point."""
   2070 
   2071     def __init__(self, typename, val):
   2072         self._typename = strip_versioned_namespace(typename)
   2073         self._val = val
   2074 
   2075     def _clock(self):
   2076         clock = self._val.type.template_argument(0)
   2077         name = strip_versioned_namespace(clock.name)
   2078         if name == 'std::chrono::_V2::system_clock' \
   2079                 or name == 'std::chrono::system_clock':
   2080             return ('std::chrono::sys_time', 0)
   2081         # XXX need to remove leap seconds from utc, gps, and tai
   2082         if name == 'std::chrono::utc_clock':
   2083             return ('std::chrono::utc_time', None)  # XXX
   2084         if name == 'std::chrono::gps_clock':
   2085             return ('std::chrono::gps_time', None)  # XXX 315964809
   2086         if name == 'std::chrono::tai_clock':
   2087             return ('std::chrono::tai_time', None)  # XXX -378691210
   2088         if name == 'std::filesystem::__file_clock':
   2089             return ('std::chrono::file_time', 6437664000)
   2090         if name == 'std::chrono::local_t':
   2091             return ('std::chrono::local_time', 0)
   2092         return ('{} time_point'.format(name), None)
   2093 
   2094     def to_string(self, abbrev=False):
   2095         clock, offset = self._clock()
   2096         d = self._val['__d']
   2097         r = d['__r']
   2098         printer = StdChronoDurationPrinter(d.type.name, d)
   2099         suffix = printer._suffix()
   2100         time = ''
   2101         if offset is not None:
   2102             num, den = printer._ratio()
   2103             secs = (r * num / den) + offset
   2104             try:
   2105                 dt = datetime.datetime.fromtimestamp(secs, _utc_timezone)
   2106                 time = ' [{:%Y-%m-%d %H:%M:%S}]'.format(dt)
   2107             except:
   2108                 pass
   2109         s = '%d%s%s' % (r, suffix, time)
   2110         if abbrev:
   2111             return s
   2112         return '%s = { %s }' % (clock, s)
   2113 
   2114 
   2115 class StdChronoZonedTimePrinter(printer_base):
   2116     """Print a std::chrono::zoned_time."""
   2117 
   2118     def __init__(self, typename, val):
   2119         self._typename = strip_versioned_namespace(typename)
   2120         self._val = val
   2121 
   2122     def to_string(self):
   2123         zone = self._val['_M_zone'].dereference()['_M_name']
   2124         time = self._val['_M_tp']
   2125         printer = StdChronoTimePointPrinter(time.type.name, time)
   2126         time = printer.to_string(True)
   2127         return 'std::chrono::zoned_time = {{ {} {} }}'.format(zone, time)
   2128 
   2129 
   2130 months = [None, 'January', 'February', 'March', 'April', 'May', 'June',
   2131           'July', 'August', 'September', 'October', 'November', 'December']
   2132 
   2133 weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
   2134             'Saturday', 'Sunday']
   2135 
   2136 
   2137 class StdChronoCalendarPrinter(printer_base):
   2138     """Print a std::chrono::day, std::chrono::month, std::chrono::year etc."""
   2139 
   2140     def __init__(self, typename, val):
   2141         self._typename = strip_versioned_namespace(typename)
   2142         self._val = val
   2143 
   2144     def to_string(self):
   2145         val = self._val
   2146         typ = self._typename
   2147         if 'month' in typ and typ != 'std::chrono::year_month_day_last':
   2148             m = val['_M_m']
   2149         if typ.startswith('std::chrono::year'):
   2150             y = val['_M_y']
   2151 
   2152         if typ == 'std::chrono::day':
   2153             return '{}'.format(int(val['_M_d']))
   2154         if typ == 'std::chrono::month':
   2155             if m < 1 or m >= len(months):
   2156                 return "%d is not a valid month" % m
   2157             return months[m]
   2158         if typ == 'std::chrono::year':
   2159             return '{}y'.format(y)
   2160         if typ == 'std::chrono::weekday':
   2161             wd = val['_M_wd']
   2162             if wd < 0 or wd >= len(weekdays):
   2163                 return "%d is not a valid weekday" % wd
   2164             return '{}'.format(weekdays[wd])
   2165         if typ == 'std::chrono::weekday_indexed':
   2166             return '{}[{}]'.format(val['_M_wd'], int(val['_M_index']))
   2167         if typ == 'std::chrono::weekday_last':
   2168             return '{}[last]'.format(val['_M_wd'])
   2169         if typ == 'std::chrono::month_day':
   2170             return '{}/{}'.format(m, val['_M_d'])
   2171         if typ == 'std::chrono::month_day_last':
   2172             return '{}/last'.format(m)
   2173         if typ == 'std::chrono::month_weekday':
   2174             return '{}/{}'.format(m, val['_M_wdi'])
   2175         if typ == 'std::chrono::month_weekday_last':
   2176             return '{}/{}'.format(m, val['_M_wdl'])
   2177         if typ == 'std::chrono::year_month':
   2178             return '{}/{}'.format(y, m)
   2179         if typ == 'std::chrono::year_month_day':
   2180             return '{}/{}/{}'.format(y, m, val['_M_d'])
   2181         if typ == 'std::chrono::year_month_day_last':
   2182             return '{}/{}'.format(y, val['_M_mdl'])
   2183         if typ == 'std::chrono::year_month_weekday':
   2184             return '{}/{}/{}'.format(y, m, val['_M_wdi'])
   2185         if typ == 'std::chrono::year_month_weekday_last':
   2186             return '{}/{}/{}'.format(y, m, val['_M_wdl'])
   2187         if typ.startswith('std::chrono::hh_mm_ss'):
   2188             fract = ''
   2189             if val['fractional_width'] != 0:
   2190                 fract = '.{:0{}d}'.format(int(val['_M_ss']['_M_r']),
   2191                                           int(val['fractional_width']))
   2192             h = int(val['_M_h']['__r'])
   2193             m = int(val['_M_m']['__r'])
   2194             s = int(val['_M_s']['__r'])
   2195             if val['_M_is_neg']:
   2196                 h = -h
   2197             return '{:02}:{:02}:{:02}{}'.format(h, m, s, fract)
   2198 
   2199 
   2200 class StdChronoTimeZonePrinter(printer_base):
   2201     """Print a chrono::time_zone or chrono::time_zone_link."""
   2202 
   2203     def __init__(self, typename, val):
   2204         self._typename = strip_versioned_namespace(typename)
   2205         self._val = val
   2206 
   2207     def to_string(self):
   2208         str = '%s = %s' % (self._typename, self._val['_M_name'])
   2209         if self._typename.endswith("_link"):
   2210             str += ' -> %s' % (self._val['_M_target'])
   2211         return str
   2212 
   2213 
   2214 class StdChronoLeapSecondPrinter(printer_base):
   2215     """Print a chrono::leap_second."""
   2216 
   2217     def __init__(self, typename, val):
   2218         self._typename = strip_versioned_namespace(typename)
   2219         self._val = val
   2220 
   2221     def to_string(self):
   2222         date = self._val['_M_s']['__r']
   2223         neg = '+-'[date < 0]
   2224         return '%s %d (%c)' % (self._typename, abs(date), neg)
   2225 
   2226 
   2227 class StdChronoTzdbPrinter(printer_base):
   2228     """Print a chrono::tzdb."""
   2229 
   2230     def __init__(self, typename, val):
   2231         self._typename = strip_versioned_namespace(typename)
   2232         self._val = val
   2233 
   2234     def to_string(self):
   2235         return '%s %s' % (self._typename, self._val['version'])
   2236 
   2237 
   2238 class StdChronoTimeZoneRulePrinter(printer_base):
   2239     """Print a chrono::time_zone rule."""
   2240 
   2241     def __init__(self, typename, val):
   2242         self._typename = strip_versioned_namespace(typename)
   2243         self._val = val
   2244 
   2245     def to_string(self):
   2246         on = self._val['on']
   2247         kind = on['kind']
   2248         month = months[on['month']]
   2249         suffixes = {1: 'st', 2: 'nd', 3: 'rd',
   2250                     21: 'st', 22: 'nd', 23: 'rd', 31: 'st'}
   2251         day = on['day_of_month']
   2252         ordinal_day = '{}{}'.format(day, suffixes.get(day, 'th'))
   2253         if kind == 0:  # DayOfMonth
   2254             start = '{} {}'.format(month, ordinal_day)
   2255         else:
   2256             weekday = weekdays[on['day_of_week']]
   2257             if kind == 1:  # LastWeekDay
   2258                 start = 'last {} in {}'.format(weekday, month)
   2259             else:
   2260                 if kind == 2:  # LessEq
   2261                     direction = ('last', '<=')
   2262                 else:
   2263                     direction = ('first', '>=')
   2264                 day = on['day_of_month']
   2265                 start = '{} {} {} {} {}'.format(direction[0], weekday,
   2266                                                 direction[1], month,
   2267                                                 ordinal_day)
   2268         return 'time_zone rule {} from {} to {} starting on {}'.format(
   2269             self._val['name'], self._val['from'], self._val['to'], start)
   2270 
   2271 
   2272 class StdLocalePrinter(printer_base):
   2273     """Print a std::locale."""
   2274 
   2275     def __init__(self, typename, val):
   2276         self._val = val
   2277         self._typename = typename
   2278 
   2279     def to_string(self):
   2280         names = self._val['_M_impl']['_M_names']
   2281         mod = ''
   2282         if names[0] == 0:
   2283             name = '*'
   2284         else:
   2285             cats = gdb.parse_and_eval(self._typename + '::_S_categories')
   2286             ncat = gdb.parse_and_eval(self._typename + '::_S_categories_size')
   2287             n = names[0].string()
   2288             cat = cats[0].string()
   2289             name = '{}={}'.format(cat, n)
   2290             cat_names = {cat: n}
   2291             i = 1
   2292             while i < ncat and names[i] != 0:
   2293                 n = names[i].string()
   2294                 cat = cats[i].string()
   2295                 name = '{};{}={}'.format(name, cat, n)
   2296                 cat_names[cat] = n
   2297                 i = i + 1
   2298             uniq_names = set(cat_names.values())
   2299             if len(uniq_names) == 1:
   2300                 name = n
   2301             elif len(uniq_names) == 2:
   2302                 n1, n2 = (uniq_names)
   2303                 name_list = list(cat_names.values())
   2304                 other = None
   2305                 if name_list.count(n1) == 1:
   2306                     name = n2
   2307                     other = n1
   2308                 elif name_list.count(n2) == 1:
   2309                     name = n1
   2310                     other = n2
   2311                 if other is not None:
   2312                     cat = next(c for c, n in cat_names.items() if n == other)
   2313                     mod = ' with "{}={}"'.format(cat, other)
   2314         return 'std::locale = "{}"{}'.format(name, mod)
   2315 
   2316 class StdIntegralConstantPrinter(printer_base):
   2317     """Print a std::true_type or std::false_type."""
   2318 
   2319     def __init__(self, typename, val):
   2320         self._val = val
   2321         self._typename = typename
   2322 
   2323     def to_string(self):
   2324         value_type = self._val.type.template_argument(0)
   2325         value = self._val.type.template_argument(1)
   2326         if value_type.code == gdb.TYPE_CODE_BOOL:
   2327             if value:
   2328                 return "std::true_type"
   2329             else:
   2330                 return "std::false_type"
   2331         typename = strip_versioned_namespace(self._typename)
   2332         return "{}<{}, {}>".format(typename, value_type, value)
   2333 
   2334 class StdTextEncodingPrinter(printer_base):
   2335     """Print a std::text_encoding."""
   2336 
   2337     def __init__(self, typename, val):
   2338         self._val = val
   2339         self._typename = typename
   2340 
   2341     def to_string(self):
   2342         rep = self._val['_M_rep'].dereference()
   2343         if rep['_M_id'] == 1:
   2344             return self._val['_M_name']
   2345         if rep['_M_id'] == 2:
   2346             return 'unknown'
   2347         return rep['_M_name']
   2348 
   2349 # A "regular expression" printer which conforms to the
   2350 # "SubPrettyPrinter" protocol from gdb.printing.
   2351 class RxPrinter(object):
   2352     def __init__(self, name, function):
   2353         super(RxPrinter, self).__init__()
   2354         self.name = name
   2355         self._function = function
   2356         self.enabled = True
   2357 
   2358     def invoke(self, value):
   2359         if not self.enabled:
   2360             return None
   2361 
   2362         if value.type.code == gdb.TYPE_CODE_REF:
   2363             if hasattr(gdb.Value, "referenced_value"):
   2364                 value = value.referenced_value()
   2365 
   2366         return self._function(self.name, value)
   2367 
   2368 # A pretty-printer that conforms to the "PrettyPrinter" protocol from
   2369 # gdb.printing.  It can also be used directly as an old-style printer.
   2370 
   2371 
   2372 class Printer(object):
   2373     def __init__(self, name):
   2374         super(Printer, self).__init__()
   2375         self.name = name
   2376         self._subprinters = []
   2377         self._lookup = {}
   2378         self.enabled = True
   2379         self._compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
   2380 
   2381     def add(self, name, function):
   2382         # A small sanity check.
   2383         # FIXME
   2384         if not self._compiled_rx.match(name):
   2385             raise ValueError(
   2386                 'libstdc++ programming error: "%s" does not match' % name)
   2387         printer = RxPrinter(name, function)
   2388         self._subprinters.append(printer)
   2389         self._lookup[name] = printer
   2390 
   2391     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
   2392     def add_version(self, base, name, function):
   2393         self.add(base + name, function)
   2394         if '__cxx11' not in base:
   2395             vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' %
   2396                            _versioned_namespace, base)
   2397             self.add(vbase + name, function)
   2398 
   2399     # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
   2400     def add_container(self, base, name, function):
   2401         self.add_version(base, name, function)
   2402         self.add_version(base + '__cxx1998::', name, function)
   2403 
   2404     @staticmethod
   2405     def get_basic_type(type):
   2406         # If it points to a reference, get the reference.
   2407         if type.code == gdb.TYPE_CODE_REF:
   2408             type = type.target()
   2409 
   2410         # Get the unqualified type, stripped of typedefs.
   2411         type = type.unqualified().strip_typedefs()
   2412 
   2413         return type.tag
   2414 
   2415     def __call__(self, val):
   2416         typename = self.get_basic_type(val.type)
   2417         if not typename:
   2418             return None
   2419 
   2420         # All the types we match are template types, so we can use a
   2421         # dictionary.
   2422         match = self._compiled_rx.match(typename)
   2423         if not match:
   2424             return None
   2425 
   2426         basename = match.group(1)
   2427 
   2428         if val.type.code == gdb.TYPE_CODE_REF:
   2429             if hasattr(gdb.Value, "referenced_value"):
   2430                 val = val.referenced_value()
   2431 
   2432         if basename in self._lookup:
   2433             return self._lookup[basename].invoke(val)
   2434 
   2435         # Cannot find a pretty printer.  Return None.
   2436         return None
   2437 
   2438 
   2439 libstdcxx_printer = None
   2440 
   2441 
   2442 class TemplateTypePrinter(object):
   2443     """
   2444     A type printer for class templates with default template arguments.
   2445 
   2446     Recognizes specializations of class templates and prints them without
   2447     any template arguments that use a default template argument.
   2448     Type printers are recursively applied to the template arguments.
   2449 
   2450     e.g. replace 'std::vector<T, std::allocator<T> >' with 'std::vector<T>'.
   2451     """
   2452 
   2453     def __init__(self, name, defargs):
   2454         self.name = name
   2455         self._defargs = defargs
   2456         self.enabled = True
   2457 
   2458     class _recognizer(object):
   2459         """The recognizer class for TemplateTypePrinter."""
   2460 
   2461         def __init__(self, name, defargs):
   2462             self.name = name
   2463             self._defargs = defargs
   2464             # self._type_obj = None
   2465 
   2466         def recognize(self, type_obj):
   2467             """
   2468             If type_obj is a specialization of self.name that uses all the
   2469             default template arguments for the class template, then return
   2470             a string representation of the type without default arguments.
   2471             Otherwise, return None.
   2472             """
   2473 
   2474             if type_obj.tag is None:
   2475                 return None
   2476 
   2477             if not type_obj.tag.startswith(self.name):
   2478                 return None
   2479 
   2480             template_args = get_template_arg_list(type_obj)
   2481             displayed_args = []
   2482             require_defaulted = False
   2483             for n in range(len(template_args)):
   2484                 # The actual template argument in the type:
   2485                 targ = template_args[n]
   2486                 # The default template argument for the class template:
   2487                 defarg = self._defargs.get(n)
   2488                 if defarg is not None:
   2489                     # Substitute other template arguments into the default:
   2490                     defarg = defarg.format(*template_args)
   2491                     # Fail to recognize the type (by returning None)
   2492                     # unless the actual argument is the same as the default.
   2493                     try:
   2494                         if targ != gdb.lookup_type(defarg):
   2495                             return None
   2496                     except gdb.error:
   2497                         # Type lookup failed, just use string comparison:
   2498                         if targ.tag != defarg:
   2499                             return None
   2500                     # All subsequent args must have defaults:
   2501                     require_defaulted = True
   2502                 elif require_defaulted:
   2503                     return None
   2504                 else:
   2505                     # Recursively apply recognizers to the template argument
   2506                     # and add it to the arguments that will be displayed:
   2507                     displayed_args.append(self._recognize_subtype(targ))
   2508 
   2509             # This assumes no class templates in the nested-name-specifier:
   2510             template_name = type_obj.tag[0:type_obj.tag.find('<')]
   2511             template_name = strip_inline_namespaces(template_name)
   2512 
   2513             return template_name + '<' + ', '.join(displayed_args) + '>'
   2514 
   2515         def _recognize_subtype(self, type_obj):
   2516             """Convert a gdb.Type to a string by applying recognizers,
   2517             or if that fails then simply converting to a string."""
   2518 
   2519             if type_obj.code == gdb.TYPE_CODE_PTR:
   2520                 return self._recognize_subtype(type_obj.target()) + '*'
   2521             if type_obj.code == gdb.TYPE_CODE_ARRAY:
   2522                 type_str = self._recognize_subtype(type_obj.target())
   2523                 if str(type_obj.strip_typedefs()).endswith('[]'):
   2524                     return type_str + '[]'  # array of unknown bound
   2525                 return "%s[%d]" % (type_str, type_obj.range()[1] + 1)
   2526             if type_obj.code == gdb.TYPE_CODE_REF:
   2527                 return self._recognize_subtype(type_obj.target()) + '&'
   2528             if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'):
   2529                 if type_obj.code == gdb.TYPE_CODE_RVALUE_REF:
   2530                     return self._recognize_subtype(type_obj.target()) + '&&'
   2531 
   2532             type_str = gdb.types.apply_type_recognizers(
   2533                 gdb.types.get_type_recognizers(), type_obj)
   2534             if type_str:
   2535                 return type_str
   2536             return str(type_obj)
   2537 
   2538     def instantiate(self):
   2539         """Return a recognizer object for this type printer."""
   2540         return self._recognizer(self.name, self._defargs)
   2541 
   2542 
   2543 def add_one_template_type_printer(obj, name, defargs):
   2544     """
   2545     Add a type printer for a class template with default template arguments.
   2546 
   2547     Args:
   2548         name (str): The template-name of the class template.
   2549         defargs (dict int:string) The default template arguments.
   2550 
   2551     Types in defargs can refer to the Nth template-argument using {N}
   2552     (with zero-based indices).
   2553 
   2554     e.g. 'unordered_map' has these defargs:
   2555     { 2: 'std::hash<{0}>',
   2556       3: 'std::equal_to<{0}>',
   2557       4: 'std::allocator<std::pair<const {0}, {1}> >' }
   2558     """
   2559     printer = TemplateTypePrinter('std::' + name, defargs)
   2560     gdb.types.register_type_printer(obj, printer)
   2561 
   2562     # Add type printer for same type in debug namespace:
   2563     printer = TemplateTypePrinter('std::__debug::' + name, defargs)
   2564     gdb.types.register_type_printer(obj, printer)
   2565 
   2566     if '__cxx11' not in name:
   2567         # Add second type printer for same type in versioned namespace:
   2568         ns = 'std::' + _versioned_namespace
   2569         # PR 86112 Cannot use dict comprehension here:
   2570         defargs = dict((n, d.replace('std::', ns))
   2571                        for (n, d) in defargs.items())
   2572         printer = TemplateTypePrinter(ns + name, defargs)
   2573         gdb.types.register_type_printer(obj, printer)
   2574 
   2575         # Add type printer for same type in debug namespace:
   2576         printer = TemplateTypePrinter('std::__debug::' + name, defargs)
   2577         gdb.types.register_type_printer(obj, printer)
   2578 
   2579 
   2580 class FilteringTypePrinter(object):
   2581     """
   2582     A type printer that uses typedef names for common template specializations.
   2583 
   2584     Args:
   2585         template (str): The class template to recognize.
   2586         name (str): The typedef-name that will be used instead.
   2587         targ1 (str, optional): The first template argument. Defaults to None.
   2588 
   2589     Checks if a specialization of the class template 'template' is the same type
   2590     as the typedef 'name', and prints it as 'name' instead.
   2591 
   2592     e.g. if an instantiation of std::basic_istream<C, T> is the same type as
   2593     std::istream then print it as std::istream.
   2594 
   2595     If targ1 is provided (not None), match only template specializations with
   2596     this type as the first template argument, e.g. if template='basic_string'
   2597     and targ1='char' then only match 'basic_string<char,...>' and not
   2598     'basic_string<wchar_t,...>'. This rejects non-matching specializations
   2599     more quickly, without needing to do GDB type lookups.
   2600     """
   2601 
   2602     def __init__(self, template, name, targ1=None):
   2603         self._template = template
   2604         self.name = name
   2605         self._targ1 = targ1
   2606         self.enabled = True
   2607 
   2608     class _recognizer(object):
   2609         """The recognizer class for FilteringTypePrinter."""
   2610 
   2611         def __init__(self, template, name, targ1):
   2612             self._template = template
   2613             self.name = name
   2614             self._targ1 = targ1
   2615             self._type_obj = None
   2616 
   2617         def recognize(self, type_obj):
   2618             """
   2619             If type_obj starts with self._template and is the same type as
   2620             self.name then return self.name, otherwise None.
   2621             """
   2622             if type_obj.tag is None:
   2623                 return None
   2624 
   2625             if self._type_obj is None:
   2626                 if self._targ1 is not None:
   2627                     s = '{}<{}'.format(self._template, self._targ1)
   2628                     if not type_obj.tag.startswith(s):
   2629                         # Filter didn't match.
   2630                         return None
   2631                 elif not type_obj.tag.startswith(self._template):
   2632                     # Filter didn't match.
   2633                     return None
   2634 
   2635                 try:
   2636                     self._type_obj = gdb.lookup_type(
   2637                         self.name).strip_typedefs()
   2638                 except:
   2639                     pass
   2640 
   2641             if self._type_obj is None:
   2642                 return None
   2643 
   2644             t1 = gdb.types.get_basic_type(self._type_obj)
   2645             t2 = gdb.types.get_basic_type(type_obj)
   2646             if t1 == t2:
   2647                 return strip_inline_namespaces(self.name)
   2648 
   2649             # Workaround ambiguous typedefs matching both std:: and
   2650             # std::__cxx11:: symbols.
   2651             if self._template.split('::')[-1] == 'basic_string':
   2652                 s1 = self._type_obj.tag.replace('__cxx11::', '')
   2653                 s2 = type_obj.tag.replace('__cxx11::', '')
   2654                 if s1 == s2:
   2655                     return strip_inline_namespaces(self.name)
   2656 
   2657             return None
   2658 
   2659     def instantiate(self):
   2660         """Return a recognizer object for this type printer."""
   2661         return self._recognizer(self._template, self.name, self._targ1)
   2662 
   2663 
   2664 def add_one_type_printer(obj, template, name, targ1=None):
   2665     printer = FilteringTypePrinter('std::' + template, 'std::' + name, targ1)
   2666     gdb.types.register_type_printer(obj, printer)
   2667     if '__cxx11' not in template:
   2668         ns = 'std::' + _versioned_namespace
   2669         printer = FilteringTypePrinter(ns + template, ns + name, targ1)
   2670         gdb.types.register_type_printer(obj, printer)
   2671 
   2672 
   2673 def register_type_printers(obj):
   2674     global _use_type_printing
   2675 
   2676     if not _use_type_printing:
   2677         return
   2678 
   2679     # Add type printers for typedefs std::string, std::wstring etc.
   2680     for ch in (('', 'char'),
   2681                ('w', 'wchar_t'),
   2682                ('u8', 'char8_t'),
   2683                ('u16', 'char16_t'),
   2684                ('u32', 'char32_t')):
   2685         add_one_type_printer(obj, 'basic_string', ch[0] + 'string', ch[1])
   2686         add_one_type_printer(obj, '__cxx11::basic_string',
   2687                              ch[0] + 'string', ch[1])
   2688         # Typedefs for __cxx11::basic_string used to be in namespace __cxx11:
   2689         add_one_type_printer(obj, '__cxx11::basic_string',
   2690                              '__cxx11::' + ch[0] + 'string', ch[1])
   2691         add_one_type_printer(obj, 'basic_string_view',
   2692                              ch[0] + 'string_view', ch[1])
   2693 
   2694     # Add type printers for typedefs std::istream, std::wistream etc.
   2695     for ch in (('', 'char'), ('w', 'wchar_t')):
   2696         for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream',
   2697                   'filebuf', 'ifstream', 'ofstream', 'fstream'):
   2698             add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1])
   2699         for x in ('stringbuf', 'istringstream', 'ostringstream',
   2700                   'stringstream'):
   2701             add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1])
   2702             # <sstream> types are in __cxx11 namespace, but typedefs aren't:
   2703             add_one_type_printer(obj, '__cxx11::basic_' + x, ch[0] + x, ch[1])
   2704 
   2705     # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc.
   2706     for abi in ('', '__cxx11::'):
   2707         for ch in (('', 'char'), ('w', 'wchar_t')):
   2708             add_one_type_printer(obj, abi + 'basic_regex',
   2709                                  abi + ch[0] + 'regex', ch[1])
   2710         for ch in ('c', 's', 'wc', 'ws'):
   2711             add_one_type_printer(
   2712                 obj, abi + 'match_results', abi + ch + 'match')
   2713             for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'):
   2714                 add_one_type_printer(obj, abi + x, abi + ch + x)
   2715 
   2716     # Note that we can't have a printer for std::wstreampos, because
   2717     # it is the same type as std::streampos.
   2718     add_one_type_printer(obj, 'fpos', 'streampos')
   2719 
   2720     # Add type printers for <chrono> typedefs.
   2721     for dur in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds',
   2722                 'minutes', 'hours', 'days', 'weeks', 'years', 'months'):
   2723         add_one_type_printer(obj, 'chrono::duration', 'chrono::' + dur)
   2724 
   2725     # Add type printers for <random> typedefs.
   2726     add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
   2727     add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand')
   2728     add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937')
   2729     add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64')
   2730     add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base')
   2731     add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base')
   2732     add_one_type_printer(obj, 'discard_block_engine', 'ranlux24')
   2733     add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
   2734     add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
   2735 
   2736     # Add type printers for experimental::basic_string_view typedefs.
   2737     ns = 'experimental::fundamentals_v1::'
   2738     for ch in (('', 'char'),
   2739                ('w', 'wchar_t'),
   2740                ('u8', 'char8_t'),
   2741                ('u16', 'char16_t'),
   2742                ('u32', 'char32_t')):
   2743         add_one_type_printer(obj, ns + 'basic_string_view',
   2744                              ns + ch[0] + 'string_view', ch[1])
   2745 
   2746     # Do not show defaulted template arguments in class templates.
   2747     add_one_template_type_printer(obj, 'unique_ptr',
   2748                                   {1: 'std::default_delete<{0}>'})
   2749     add_one_template_type_printer(obj, 'deque', {1: 'std::allocator<{0}>'})
   2750     add_one_template_type_printer(
   2751         obj, 'forward_list', {1: 'std::allocator<{0}>'})
   2752     add_one_template_type_printer(obj, 'list', {1: 'std::allocator<{0}>'})
   2753     add_one_template_type_printer(
   2754         obj, '__cxx11::list', {1: 'std::allocator<{0}>'})
   2755     add_one_template_type_printer(obj, 'vector', {1: 'std::allocator<{0}>'})
   2756     add_one_template_type_printer(obj, 'map',
   2757                                   {2: 'std::less<{0}>',
   2758                                    3: 'std::allocator<std::pair<{0} const, {1}>>'})
   2759     add_one_template_type_printer(obj, 'multimap',
   2760                                   {2: 'std::less<{0}>',
   2761                                    3: 'std::allocator<std::pair<{0} const, {1}>>'})
   2762     add_one_template_type_printer(obj, 'set',
   2763                                   {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'})
   2764     add_one_template_type_printer(obj, 'multiset',
   2765                                   {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'})
   2766     add_one_template_type_printer(obj, 'unordered_map',
   2767                                   {2: 'std::hash<{0}>',
   2768                                    3: 'std::equal_to<{0}>',
   2769                                    4: 'std::allocator<std::pair<{0} const, {1}>>'})
   2770     add_one_template_type_printer(obj, 'unordered_multimap',
   2771                                   {2: 'std::hash<{0}>',
   2772                                    3: 'std::equal_to<{0}>',
   2773                                    4: 'std::allocator<std::pair<{0} const, {1}>>'})
   2774     add_one_template_type_printer(obj, 'unordered_set',
   2775                                   {1: 'std::hash<{0}>',
   2776                                    2: 'std::equal_to<{0}>',
   2777                                    3: 'std::allocator<{0}>'})
   2778     add_one_template_type_printer(obj, 'unordered_multiset',
   2779                                   {1: 'std::hash<{0}>',
   2780                                    2: 'std::equal_to<{0}>',
   2781                                    3: 'std::allocator<{0}>'})
   2782 
   2783 
   2784 def register_libstdcxx_printers(obj):
   2785     """Register libstdc++ pretty-printers with objfile Obj."""
   2786 
   2787     global _use_gdb_pp
   2788     global libstdcxx_printer
   2789 
   2790     if _use_gdb_pp:
   2791         gdb.printing.register_pretty_printer(obj, libstdcxx_printer)
   2792     else:
   2793         if obj is None:
   2794             obj = gdb
   2795         obj.pretty_printers.append(libstdcxx_printer)
   2796 
   2797     register_type_printers(obj)
   2798 
   2799 
   2800 def build_libstdcxx_dictionary():
   2801     global libstdcxx_printer
   2802 
   2803     libstdcxx_printer = Printer("libstdc++-v6")
   2804 
   2805     # libstdc++ objects requiring pretty-printing.
   2806     # In order from:
   2807     # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
   2808     libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter)
   2809     libstdcxx_printer.add_version(
   2810         'std::__cxx11::', 'basic_string', StdStringPrinter)
   2811     libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter)
   2812     libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter)
   2813     libstdcxx_printer.add_container('std::', 'list', StdListPrinter)
   2814     libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter)
   2815     libstdcxx_printer.add_container('std::', 'map', StdMapPrinter)
   2816     libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter)
   2817     libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter)
   2818     libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter)
   2819     libstdcxx_printer.add_version('std::', 'priority_queue',
   2820                                   StdStackOrQueuePrinter)
   2821     libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter)
   2822     libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter)
   2823     libstdcxx_printer.add_container('std::', 'set', StdSetPrinter)
   2824     libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter)
   2825     libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter)
   2826     libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter)
   2827     # vector<bool>
   2828     libstdcxx_printer.add_version('std::', 'locale', StdLocalePrinter)
   2829 
   2830     libstdcxx_printer.add_version('std::', 'integral_constant',
   2831                                   StdIntegralConstantPrinter)
   2832     libstdcxx_printer.add_version('std::', 'text_encoding',
   2833                                   StdTextEncodingPrinter)
   2834 
   2835     if hasattr(gdb.Value, 'dynamic_type'):
   2836         libstdcxx_printer.add_version('std::', 'error_code',
   2837                                       StdErrorCodePrinter)
   2838         libstdcxx_printer.add_version('std::', 'error_condition',
   2839                                       StdErrorCodePrinter)
   2840 
   2841     # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
   2842     libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter)
   2843     libstdcxx_printer.add('std::__debug::deque', StdDequePrinter)
   2844     libstdcxx_printer.add('std::__debug::list', StdListPrinter)
   2845     libstdcxx_printer.add('std::__debug::map', StdMapPrinter)
   2846     libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter)
   2847     libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter)
   2848     libstdcxx_printer.add('std::__debug::set', StdSetPrinter)
   2849     libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter)
   2850 
   2851     # These are the TR1 and C++11 printers.
   2852     # For array - the default GDB pretty-printer seems reasonable.
   2853     libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter)
   2854     libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter)
   2855     libstdcxx_printer.add_container('std::', 'unordered_map',
   2856                                     Tr1UnorderedMapPrinter)
   2857     libstdcxx_printer.add_container('std::', 'unordered_set',
   2858                                     Tr1UnorderedSetPrinter)
   2859     libstdcxx_printer.add_container('std::', 'unordered_multimap',
   2860                                     Tr1UnorderedMapPrinter)
   2861     libstdcxx_printer.add_container('std::', 'unordered_multiset',
   2862                                     Tr1UnorderedSetPrinter)
   2863     libstdcxx_printer.add_container('std::', 'forward_list',
   2864                                     StdForwardListPrinter)
   2865 
   2866     libstdcxx_printer.add_version(
   2867         'std::tr1::', 'shared_ptr', SharedPointerPrinter)
   2868     libstdcxx_printer.add_version(
   2869         'std::tr1::', 'weak_ptr', SharedPointerPrinter)
   2870     libstdcxx_printer.add_version('std::tr1::', 'unordered_map',
   2871                                   Tr1UnorderedMapPrinter)
   2872     libstdcxx_printer.add_version('std::tr1::', 'unordered_set',
   2873                                   Tr1UnorderedSetPrinter)
   2874     libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap',
   2875                                   Tr1UnorderedMapPrinter)
   2876     libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset',
   2877                                   Tr1UnorderedSetPrinter)
   2878 
   2879     libstdcxx_printer.add_version('std::', 'initializer_list',
   2880                                   StdInitializerListPrinter)
   2881     libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter)
   2882     libstdcxx_printer.add_version(
   2883         'std::', 'basic_stringbuf', StdStringBufPrinter)
   2884     libstdcxx_printer.add_version(
   2885         'std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter)
   2886     for sstream in ('istringstream', 'ostringstream', 'stringstream'):
   2887         libstdcxx_printer.add_version(
   2888             'std::', 'basic_' + sstream, StdStringStreamPrinter)
   2889         libstdcxx_printer.add_version(
   2890             'std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter)
   2891 
   2892     libstdcxx_printer.add_version('std::chrono::', 'duration',
   2893                                   StdChronoDurationPrinter)
   2894     libstdcxx_printer.add_version('std::chrono::', 'time_point',
   2895                                   StdChronoTimePointPrinter)
   2896 
   2897     # std::regex components
   2898     libstdcxx_printer.add_version('std::__detail::', '_State',
   2899                                   StdRegexStatePrinter)
   2900 
   2901     # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases.
   2902     # The tr1 namespace containers do not have any debug equivalents,
   2903     # so do not register printers for them.
   2904     libstdcxx_printer.add('std::__debug::unordered_map',
   2905                           Tr1UnorderedMapPrinter)
   2906     libstdcxx_printer.add('std::__debug::unordered_set',
   2907                           Tr1UnorderedSetPrinter)
   2908     libstdcxx_printer.add('std::__debug::unordered_multimap',
   2909                           Tr1UnorderedMapPrinter)
   2910     libstdcxx_printer.add('std::__debug::unordered_multiset',
   2911                           Tr1UnorderedSetPrinter)
   2912     libstdcxx_printer.add('std::__debug::forward_list',
   2913                           StdForwardListPrinter)
   2914 
   2915     # Library Fundamentals TS components
   2916     libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
   2917                                   'any', StdExpAnyPrinter)
   2918     libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
   2919                                   'optional', StdExpOptionalPrinter)
   2920     libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
   2921                                   'basic_string_view', StdExpStringViewPrinter)
   2922     # Filesystem TS components
   2923     libstdcxx_printer.add_version('std::experimental::filesystem::v1::',
   2924                                   'path', StdExpPathPrinter)
   2925     libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
   2926                                   'path', StdExpPathPrinter)
   2927     libstdcxx_printer.add_version('std::filesystem::',
   2928                                   'path', StdPathPrinter)
   2929     libstdcxx_printer.add_version('std::filesystem::__cxx11::',
   2930                                   'path', StdPathPrinter)
   2931 
   2932     # C++17 components
   2933     libstdcxx_printer.add_version('std::',
   2934                                   'any', StdExpAnyPrinter)
   2935     libstdcxx_printer.add_version('std::',
   2936                                   'optional', StdExpOptionalPrinter)
   2937     libstdcxx_printer.add_version('std::',
   2938                                   'basic_string_view', StdExpStringViewPrinter)
   2939     libstdcxx_printer.add_version('std::',
   2940                                   'variant', StdVariantPrinter)
   2941     libstdcxx_printer.add_version('std::',
   2942                                   '_Node_handle', StdNodeHandlePrinter)
   2943 
   2944     # C++20 components
   2945     libstdcxx_printer.add_version(
   2946         'std::', 'partial_ordering', StdCmpCatPrinter)
   2947     libstdcxx_printer.add_version('std::', 'weak_ordering', StdCmpCatPrinter)
   2948     libstdcxx_printer.add_version('std::', 'strong_ordering', StdCmpCatPrinter)
   2949     libstdcxx_printer.add_version('std::', 'span', StdSpanPrinter)
   2950     libstdcxx_printer.add_version('std::', 'basic_format_args',
   2951                                   StdFormatArgsPrinter)
   2952     for c in ['day', 'month', 'year', 'weekday', 'weekday_indexed', 'weekday_last',
   2953               'month_day', 'month_day_last', 'month_weekday', 'month_weekday_last',
   2954               'year_month', 'year_month_day', 'year_month_day_last',
   2955               'year_month_weekday', 'year_month_weekday_last', 'hh_mm_ss']:
   2956         libstdcxx_printer.add_version('std::chrono::', c,
   2957                                       StdChronoCalendarPrinter)
   2958     libstdcxx_printer.add_version('std::chrono::', 'time_zone',
   2959                                   StdChronoTimeZonePrinter)
   2960     libstdcxx_printer.add_version('std::chrono::', 'time_zone_link',
   2961                                   StdChronoTimeZonePrinter)
   2962     libstdcxx_printer.add_version('std::chrono::', 'zoned_time',
   2963                                   StdChronoZonedTimePrinter)
   2964     libstdcxx_printer.add_version('std::chrono::', 'leap_second',
   2965                                   StdChronoLeapSecondPrinter)
   2966     libstdcxx_printer.add_version(
   2967         'std::chrono::', 'tzdb', StdChronoTzdbPrinter)
   2968     # libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule',
   2969     #                              StdChronoTimeZoneRulePrinter)
   2970 
   2971     # Extensions.
   2972     libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter)
   2973 
   2974     if True:
   2975         # These shouldn't be necessary, if GDB "print *i" worked.
   2976         # But it often doesn't, so here they are.
   2977         libstdcxx_printer.add_container('std::', '_List_iterator',
   2978                                         StdListIteratorPrinter)
   2979         libstdcxx_printer.add_container('std::', '_List_const_iterator',
   2980                                         StdListIteratorPrinter)
   2981         libstdcxx_printer.add_version('std::', '_Rb_tree_iterator',
   2982                                       StdRbtreeIteratorPrinter)
   2983         libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator',
   2984                                       StdRbtreeIteratorPrinter)
   2985         libstdcxx_printer.add_container('std::', '_Deque_iterator',
   2986                                         StdDequeIteratorPrinter)
   2987         libstdcxx_printer.add_container('std::', '_Deque_const_iterator',
   2988                                         StdDequeIteratorPrinter)
   2989         libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator',
   2990                                       StdVectorIteratorPrinter)
   2991         libstdcxx_printer.add_container('std::', '_Bit_iterator',
   2992                                         StdBitIteratorPrinter)
   2993         libstdcxx_printer.add_container('std::', '_Bit_const_iterator',
   2994                                         StdBitIteratorPrinter)
   2995         libstdcxx_printer.add_container('std::', '_Bit_reference',
   2996                                         StdBitReferencePrinter)
   2997         libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator',
   2998                                       StdSlistIteratorPrinter)
   2999         libstdcxx_printer.add_container('std::', '_Fwd_list_iterator',
   3000                                         StdFwdListIteratorPrinter)
   3001         libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator',
   3002                                         StdFwdListIteratorPrinter)
   3003 
   3004         # Debug (compiled with -D_GLIBCXX_DEBUG) printer
   3005         # registrations.
   3006         libstdcxx_printer.add('__gnu_debug::_Safe_iterator',
   3007                               StdDebugIteratorPrinter)
   3008 
   3009 
   3010 build_libstdcxx_dictionary()
   3011