gcc (13.2.0)

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