gcc/gcc8-libstdc++-prettyprinter-update-14.patch
Siddhesh Poyarekar 9ebe2f9de7 Update libstdc++ pretty printer from latest GTS version
Also add a script that makes the update more convenient in future.

Resolves: RHEL-50290
2025-03-04 15:20:28 -05:00

4167 lines
159 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

libstdc++-v3/python/libstdcxx/v6/__init__.py | 4 +-
libstdc++-v3/python/libstdcxx/v6/printers.py | 2593 +++++++++++++++++++-------
libstdc++-v3/python/libstdcxx/v6/xmethods.py | 170 +-
3 files changed, 2017 insertions(+), 750 deletions(-)
diff --git a/libstdc++-v3/python/libstdcxx/v6/__init__.py b/libstdc++-v3/python/libstdcxx/v6/__init__.py
index b001c8520b6..f40acd922af 100644
--- a/libstdc++-v3/python/libstdcxx/v6/__init__.py
+++ b/libstdc++-v3/python/libstdcxx/v6/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2018 Free Software Foundation, Inc.
+# Copyright (C) 2014-2024 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -13,8 +13,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import gdb
-
# Load the xmethods if GDB supports them.
def gdb_has_xmethods():
try:
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index ba9bbc096a0..3026de35bbd 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -1,6 +1,6 @@
# Pretty-printers for libstdc++.
-# Copyright (C) 2008-2018 Free Software Foundation, Inc.
+# Copyright (C) 2008-2024 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,8 +19,10 @@ import gdb
import itertools
import re
import sys
+import errno
+import datetime
-### Python 2 + Python 3 compatibility code
+# Python 2 + Python 3 compatibility code
# Resources about compatibility:
#
@@ -37,15 +39,16 @@ import sys
# <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>
if sys.version_info[0] > 2:
- ### Python 3 stuff
+ # Python 3 stuff
Iterator = object
# Python 3 folds these into the normal functions.
imap = map
izip = zip
# Also, int subsumes long
long = int
+ _utc_timezone = datetime.timezone.utc
else:
- ### Python 2 stuff
+ # Python 2 stuff
class Iterator:
"""Compatibility mixin for iterators
@@ -63,6 +66,20 @@ else:
# In Python 2, we still need these from itertools
from itertools import imap, izip
+ # Python 2 does not provide the datetime.UTC singleton.
+ class UTC(datetime.tzinfo):
+ """Concrete tzinfo class representing the UTC time zone."""
+
+ def utcoffset(self, dt):
+ return datetime.timedelta(0)
+
+ def tzname(self, dt):
+ return "UTC"
+
+ def dst(self, dt):
+ return datetime.timedelta(0)
+ _utc_timezone = UTC()
+
# Try to use the new-style pretty-printing if available.
_use_gdb_pp = True
try:
@@ -79,14 +96,22 @@ try:
except ImportError:
pass
+# Use the base class if available.
+if hasattr(gdb, 'ValuePrinter'):
+ printer_base = gdb.ValuePrinter
+else:
+ printer_base = object
+
# Starting with the type ORIG, search for the member type NAME. This
# handles searching upward through superclasses. This is needed to
# work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
+
+
def find_type(orig, name):
typ = orig.strip_typedefs()
while True:
- # Strip cv-qualifiers. PR 67440.
- search = '%s::%s' % (typ.unqualified(), name)
+ # Use Type.tag to ignore cv-qualifiers. PR 67440.
+ search = '%s::%s' % (typ.tag, name)
try:
return gdb.lookup_type(search)
except RuntimeError:
@@ -94,39 +119,131 @@ def find_type(orig, name):
# The type was not found, so try the superclass. We only need
# to check the first superclass, so we don't bother with
# anything fancier here.
- field = typ.fields()[0]
- if not field.is_base_class:
+ fields = typ.fields()
+ if len(fields) and fields[0].is_base_class:
+ typ = fields[0].type
+ else:
raise ValueError("Cannot find type %s::%s" % (str(orig), name))
- typ = field.type
+
_versioned_namespace = '__8::'
-def is_specialization_of(type, template_name):
- "Test if a type is a given template instantiation."
+
+def lookup_templ_spec(templ, *args):
+ """
+ Lookup template specialization templ<args...>.
+ """
+ t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args]))
+ try:
+ return gdb.lookup_type(t)
+ except gdb.error as e:
+ # Type not found, try again in versioned namespace.
+ global _versioned_namespace
+ if _versioned_namespace not in templ:
+ t = t.replace('::', '::' + _versioned_namespace, 1)
+ try:
+ return gdb.lookup_type(t)
+ except gdb.error:
+ # If that also fails, rethrow the original exception
+ pass
+ raise e
+
+# Use this to find container node types instead of find_type,
+# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details.
+def lookup_node_type(nodename, containertype):
+ """
+ Lookup specialization of template nodename corresponding to containertype.
+
+ nodename - The name of a class template, as a String
+ containertype - The container, as a gdb.Type
+
+ Return a gdb.Type for the corresponding specialization of nodename,
+ or None if the type cannot be found.
+
+ e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list<int>'))
+ will return a gdb.Type for the type std::_List_node<int>.
+ """
+ # If nodename is unqualified, assume it's in namespace std.
+ if '::' not in nodename:
+ nodename = 'std::' + nodename
+ # Use either containertype's value_type or its first template argument.
+ try:
+ valtype = find_type(containertype, 'value_type')
+ except:
+ valtype = containertype.template_argument(0)
+ valtype = valtype.strip_typedefs()
+ try:
+ return lookup_templ_spec(nodename, valtype)
+ except gdb.error:
+ # For debug mode containers the node is in std::__cxx1998.
+ if is_member_of_namespace(nodename, 'std'):
+ if is_member_of_namespace(containertype, 'std::__cxx1998',
+ 'std::__debug', '__gnu_debug'):
+ nodename = nodename.replace('::', '::__cxx1998::', 1)
+ try:
+ return lookup_templ_spec(nodename, valtype)
+ except gdb.error:
+ pass
+ return None
+
+
+def is_member_of_namespace(typ, *namespaces):
+ """
+ Test whether a type is a member of one of the specified namespaces.
+ The type can be specified as a string or a gdb.Type object.
+ """
+ if isinstance(typ, gdb.Type):
+ typ = str(typ)
+ typ = strip_versioned_namespace(typ)
+ for namespace in namespaces:
+ if typ.startswith(namespace + '::'):
+ return True
+ return False
+
+
+def is_specialization_of(x, template_name):
+ """
+ Test whether a type is a specialization of the named class template.
+ The type can be specified as a string or a gdb.Type object.
+ The template should be the name of a class template as a string,
+ without any 'std' qualification.
+ """
global _versioned_namespace
- if _versioned_namespace:
- return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), type) is not None
- return re.match('^std::%s<.*>$' % template_name, type) is not None
+ if isinstance(x, gdb.Type):
+ x = x.tag
+ template_name = '(%s)?%s' % (_versioned_namespace, template_name)
+ return re.match('^std::%s<.*>$' % template_name, x) is not None
+
def strip_versioned_namespace(typename):
global _versioned_namespace
- if _versioned_namespace:
- return typename.replace(_versioned_namespace, '')
- return typename
+ return typename.replace(_versioned_namespace, '')
+
+
+def strip_fundts_namespace(typ):
+ """Remove "fundamentals_vN" inline namespace from qualified type name."""
+ pattern = r'^std::experimental::fundamentals_v\d::'
+ repl = 'std::experimental::'
+ if sys.version_info[0] == 2:
+ return re.sub(pattern, repl, typ, 1)
+ else: # Technically this needs Python 3.1 but nobody should be using 3.0
+ return re.sub(pattern, repl, typ, count=1)
+
def strip_inline_namespaces(type_str):
- "Remove known inline namespaces from the canonical name of a type."
+ """Remove known inline namespaces from the canonical name of a type."""
type_str = strip_versioned_namespace(type_str)
type_str = type_str.replace('std::__cxx11::', 'std::')
expt_ns = 'std::experimental::'
for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'):
- type_str = type_str.replace(expt_ns+lfts_ns+'::', expt_ns)
+ type_str = type_str.replace(expt_ns + lfts_ns + '::', expt_ns)
fs_ns = expt_ns + 'filesystem::'
- type_str = type_str.replace(fs_ns+'v1::', fs_ns)
+ type_str = type_str.replace(fs_ns + 'v1::', fs_ns)
return type_str
+
def get_template_arg_list(type_obj):
- "Return a type's template arguments as a list"
+ """Return a type's template arguments as a list."""
n = 0
template_args = []
while True:
@@ -136,78 +253,140 @@ def get_template_arg_list(type_obj):
return template_args
n += 1
+
class SmartPtrIterator(Iterator):
- "An iterator for smart pointer types with a single 'child' value"
+ """An iterator for smart pointer types with a single 'child' value."""
def __init__(self, val):
- self.val = val
+ self._val = val
def __iter__(self):
return self
def __next__(self):
- if self.val is None:
+ if self._val is None:
raise StopIteration
- self.val, val = None, self.val
+ self._val, val = None, self._val
return ('get()', val)
-class SharedPointerPrinter:
- "Print a shared_ptr or weak_ptr"
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
- self.pointer = val['_M_ptr']
+class SharedPointerPrinter(printer_base):
+ """
+ Print a shared_ptr, weak_ptr, atomic<shared_ptr>, or atomic<weak_ptr>.
+ """
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+ self._pointer = val['_M_ptr']
- def children (self):
- return SmartPtrIterator(self.pointer)
+ def children(self):
+ return SmartPtrIterator(self._pointer)
+
+ # Return the _Sp_counted_base<>* that holds the refcounts.
+ def _get_refcounts(self):
+ if self._typename == 'std::atomic':
+ # A tagged pointer is stored as uintptr_t.
+ ptr_val = self._val['_M_refcount']['_M_val']['_M_i']
+ ptr_val = ptr_val - (ptr_val % 2) # clear lock bit
+ ptr_type = find_type(self._val['_M_refcount'].type, 'pointer')
+ return ptr_val.cast(ptr_type)
+ return self._val['_M_refcount']['_M_pi']
- def to_string (self):
+ def to_string(self):
state = 'empty'
- refcounts = self.val['_M_refcount']['_M_pi']
+ refcounts = self._get_refcounts()
+ targ = self._val.type.template_argument(0)
+ targ = strip_versioned_namespace(str(targ))
+
if refcounts != 0:
usecount = refcounts['_M_use_count']
weakcount = refcounts['_M_weak_count']
if usecount == 0:
state = 'expired, weak count %d' % weakcount
else:
- state = 'use count %d, weak count %d' % (usecount, weakcount - 1)
- return '%s<%s> (%s)' % (self.typename, str(self.val.type.template_argument(0)), state)
-
-class UniquePointerPrinter:
- "Print a unique_ptr"
-
- def __init__ (self, typename, val):
- self.val = val
- impl_type = val.type.fields()[0].type.strip_typedefs()
- if is_specialization_of(str(impl_type), '__uniq_ptr_impl'): # New implementation
- tuple_member = val['_M_t']['_M_t']
- elif is_specialization_of(str(impl_type), 'tuple'):
- tuple_member = val['_M_t']
- else:
- raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type))
- tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
- tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base
- head_field = tuple_head_type.fields()[0]
- if head_field.name == '_M_head_impl':
- self.pointer = tuple_member['_M_head_impl']
- elif head_field.is_base_class:
- self.pointer = tuple_member.cast(head_field.type)
- else:
- raise ValueError("Unsupported implementation for tuple in unique_ptr: %s" % str(impl_type))
+ state = 'use count %d, weak count %d' % (
+ usecount, weakcount - 1)
+ return '%s<%s> (%s)' % (self._typename, targ, state)
+
+
+def _tuple_impl_get(val):
+ """Return the tuple element stored in a _Tuple_impl<N, T> base class."""
+ bases = val.type.fields()
+ if not bases[-1].is_base_class:
+ raise ValueError(
+ "Unsupported implementation for std::tuple: %s" % str(val.type))
+ # Get the _Head_base<N, T> base class:
+ head_base = val.cast(bases[-1].type)
+ fields = head_base.type.fields()
+ if len(fields) == 0:
+ raise ValueError(
+ "Unsupported implementation for std::tuple: %s" % str(val.type))
+ if fields[0].name == '_M_head_impl':
+ # The tuple element is the _Head_base::_M_head_impl data member.
+ return head_base['_M_head_impl']
+ elif fields[0].is_base_class:
+ # The tuple element is an empty base class of _Head_base.
+ # Cast to that empty base class.
+ return head_base.cast(fields[0].type)
+ else:
+ raise ValueError(
+ "Unsupported implementation for std::tuple: %s" % str(val.type))
+
+
+def tuple_get(n, val):
+ """Return the result of std::get<n>(val) on a std::tuple."""
+ tuple_size = len(get_template_arg_list(val.type))
+ if n > tuple_size:
+ raise ValueError("Out of range index for std::get<N> on std::tuple")
+ # Get the first _Tuple_impl<0, T...> base class:
+ node = val.cast(val.type.fields()[0].type)
+ while n > 0:
+ # Descend through the base classes until the Nth one.
+ node = node.cast(node.type.fields()[0].type)
+ n -= 1
+ return _tuple_impl_get(node)
+
+
+def unique_ptr_get(val):
+ """Return the result of val.get() on a std::unique_ptr."""
+ # std::unique_ptr<T, D> contains a std::tuple<D::pointer, D>,
+ # either as a direct data member _M_t (the old implementation)
+ # or within a data member of type __uniq_ptr_data.
+ impl_type = val.type.fields()[0].type.strip_typedefs()
+ # Check for new implementations first:
+ if is_specialization_of(impl_type, '__uniq_ptr_data') \
+ or is_specialization_of(impl_type, '__uniq_ptr_impl'):
+ tuple_member = val['_M_t']['_M_t']
+ elif is_specialization_of(impl_type, 'tuple'):
+ tuple_member = val['_M_t']
+ else:
+ raise ValueError(
+ "Unsupported implementation for unique_ptr: %s" % str(impl_type))
+ return tuple_get(0, tuple_member)
+
- def children (self):
- return SmartPtrIterator(self.pointer)
+class UniquePointerPrinter(printer_base):
+ """Print a unique_ptr."""
+
+ def __init__(self, typename, val):
+ self._val = val
+
+ def children(self):
+ return SmartPtrIterator(unique_ptr_get(self._val))
+
+ def to_string(self):
+ t = self._val.type.template_argument(0)
+ return 'std::unique_ptr<{}>'.format(str(t))
- def to_string (self):
- return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0))))
def get_value_from_aligned_membuf(buf, valtype):
- """Returns the value held in a __gnu_cxx::__aligned_membuf."""
+ """Return the value held in a __gnu_cxx::__aligned_membuf."""
return buf['_M_storage'].address.cast(valtype.pointer()).dereference()
+
def get_value_from_list_node(node):
- """Returns the value held in an _List_node<_Val>"""
+ """Return the value held in an _List_node<_Val>."""
try:
member = node.type.fields()[1].name
if member == '_M_data':
@@ -221,240 +400,281 @@ def get_value_from_list_node(node):
pass
raise ValueError("Unsupported implementation for %s" % str(node.type))
-class StdListPrinter:
- "Print a std::list"
+
+class StdListPrinter(printer_base):
+ """Print a std::list."""
class _iterator(Iterator):
def __init__(self, nodetype, head):
- self.nodetype = nodetype
- self.base = head['_M_next']
- self.head = head.address
- self.count = 0
+ self._nodetype = nodetype
+ self._base = head['_M_next']
+ self._head = head.address
+ self._count = 0
def __iter__(self):
return self
def __next__(self):
- if self.base == self.head:
+ if self._base == self._head:
raise StopIteration
- elt = self.base.cast(self.nodetype).dereference()
- self.base = elt['_M_next']
- count = self.count
- self.count = self.count + 1
+ elt = self._base.cast(self._nodetype).dereference()
+ self._base = elt['_M_next']
+ count = self._count
+ self._count = self._count + 1
val = get_value_from_list_node(elt)
return ('[%d]' % count, val)
def __init__(self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
def children(self):
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- return self._iterator(nodetype, self.val['_M_impl']['_M_node'])
+ nodetype = lookup_node_type('_List_node', self._val.type).pointer()
+ return self._iterator(nodetype, self._val['_M_impl']['_M_node'])
def to_string(self):
- if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']:
- return 'empty %s' % (self.typename)
- return '%s' % (self.typename)
+ headnode = self._val['_M_impl']['_M_node']
+ if headnode['_M_next'] == headnode.address:
+ return 'empty %s' % (self._typename)
+ return '%s' % (self._typename)
-class NodeIteratorPrinter:
- def __init__(self, typename, val, contname):
- self.val = val
- self.typename = typename
- self.contname = contname
+
+class NodeIteratorPrinter(printer_base):
+ def __init__(self, typename, val, contname, nodename):
+ self._val = val
+ self._typename = typename
+ self._contname = contname
+ self._nodetype = lookup_node_type(nodename, val.type)
def to_string(self):
- if not self.val['_M_node']:
- return 'non-dereferenceable iterator for std::%s' % (self.contname)
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- node = self.val['_M_node'].cast(nodetype).dereference()
+ if not self._val['_M_node']:
+ return 'non-dereferenceable iterator for std::%s' % (self._contname)
+ node = self._val['_M_node'].cast(
+ self._nodetype.pointer()).dereference()
return str(get_value_from_list_node(node))
+
class StdListIteratorPrinter(NodeIteratorPrinter):
- "Print std::list::iterator"
+ """Print std::list::iterator."""
def __init__(self, typename, val):
- NodeIteratorPrinter.__init__(self, typename, val, 'list')
+ NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node')
+
class StdFwdListIteratorPrinter(NodeIteratorPrinter):
- "Print std::forward_list::iterator"
+ """Print std::forward_list::iterator."""
def __init__(self, typename, val):
- NodeIteratorPrinter.__init__(self, typename, val, 'forward_list')
+ NodeIteratorPrinter.__init__(self, typename, val, 'forward_list',
+ '_Fwd_list_node')
-class StdSlistPrinter:
- "Print a __gnu_cxx::slist"
+
+class StdSlistPrinter(printer_base):
+ """Print a __gnu_cxx::slist."""
class _iterator(Iterator):
def __init__(self, nodetype, head):
- self.nodetype = nodetype
- self.base = head['_M_head']['_M_next']
- self.count = 0
+ self._nodetype = nodetype
+ self._base = head['_M_head']['_M_next']
+ self._count = 0
def __iter__(self):
return self
def __next__(self):
- if self.base == 0:
+ if self._base == 0:
raise StopIteration
- elt = self.base.cast(self.nodetype).dereference()
- self.base = elt['_M_next']
- count = self.count
- self.count = self.count + 1
+ elt = self._base.cast(self._nodetype).dereference()
+ self._base = elt['_M_next']
+ count = self._count
+ self._count = self._count + 1
return ('[%d]' % count, elt['_M_data'])
def __init__(self, typename, val):
- self.val = val
+ self._val = val
def children(self):
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- return self._iterator(nodetype, self.val)
+ nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self._val.type)
+ return self._iterator(nodetype.pointer(), self._val)
def to_string(self):
- if self.val['_M_head']['_M_next'] == 0:
+ if self._val['_M_head']['_M_next'] == 0:
return 'empty __gnu_cxx::slist'
return '__gnu_cxx::slist'
-class StdSlistIteratorPrinter:
- "Print __gnu_cxx::slist::iterator"
+
+class StdSlistIteratorPrinter(printer_base):
+ """Print __gnu_cxx::slist::iterator."""
def __init__(self, typename, val):
- self.val = val
+ self._val = val
def to_string(self):
- if not self.val['_M_node']:
+ if not self._val['_M_node']:
return 'non-dereferenceable iterator for __gnu_cxx::slist'
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data'])
+ nodetype = lookup_node_type(
+ '__gnu_cxx::_Slist_node', self._val.type).pointer()
+ return str(self._val['_M_node'].cast(nodetype).dereference()['_M_data'])
+
-class StdVectorPrinter:
- "Print a std::vector"
+class StdVectorPrinter(printer_base):
+ """Print a std::vector."""
class _iterator(Iterator):
- def __init__ (self, start, finish, bitvec):
- self.bitvec = bitvec
+ def __init__(self, start, finish, bitvec):
+ self._bitvec = bitvec
if bitvec:
- self.item = start['_M_p']
- self.so = start['_M_offset']
- self.finish = finish['_M_p']
- self.fo = finish['_M_offset']
- itype = self.item.dereference().type
- self.isize = 8 * itype.sizeof
+ self._item = start['_M_p']
+ self._so = 0
+ self._finish = finish['_M_p']
+ self._fo = finish['_M_offset']
+ itype = self._item.dereference().type
+ self._isize = 8 * itype.sizeof
else:
- self.item = start
- self.finish = finish
- self.count = 0
+ self._item = start
+ self._finish = finish
+ self._count = 0
def __iter__(self):
return self
def __next__(self):
- count = self.count
- self.count = self.count + 1
- if self.bitvec:
- if self.item == self.finish and self.so >= self.fo:
+ count = self._count
+ self._count = self._count + 1
+ if self._bitvec:
+ if self._item == self._finish and self._so >= self._fo:
raise StopIteration
- elt = self.item.dereference()
- if elt & (1 << self.so):
- obit = 1
- else:
- obit = 0
- self.so = self.so + 1
- if self.so >= self.isize:
- self.item = self.item + 1
- self.so = 0
- return ('[%d]' % count, obit)
+ elt = bool(self._item.dereference() & (1 << self._so))
+ self._so = self._so + 1
+ if self._so >= self._isize:
+ self._item = self._item + 1
+ self._so = 0
+ return ('[%d]' % count, elt)
else:
- if self.item == self.finish:
+ if self._item == self._finish:
raise StopIteration
- elt = self.item.dereference()
- self.item = self.item + 1
+ elt = self._item.dereference()
+ self._item = self._item + 1
return ('[%d]' % count, elt)
def __init__(self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
- self.is_bool = val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+ self._is_bool = val.type.template_argument(
+ 0).code == gdb.TYPE_CODE_BOOL
def children(self):
- return self._iterator(self.val['_M_impl']['_M_start'],
- self.val['_M_impl']['_M_finish'],
- self.is_bool)
+ return self._iterator(self._val['_M_impl']['_M_start'],
+ self._val['_M_impl']['_M_finish'],
+ self._is_bool)
def to_string(self):
- start = self.val['_M_impl']['_M_start']
- finish = self.val['_M_impl']['_M_finish']
- end = self.val['_M_impl']['_M_end_of_storage']
- if self.is_bool:
- start = self.val['_M_impl']['_M_start']['_M_p']
- so = self.val['_M_impl']['_M_start']['_M_offset']
- finish = self.val['_M_impl']['_M_finish']['_M_p']
- fo = self.val['_M_impl']['_M_finish']['_M_offset']
+ start = self._val['_M_impl']['_M_start']
+ finish = self._val['_M_impl']['_M_finish']
+ end = self._val['_M_impl']['_M_end_of_storage']
+ if self._is_bool:
+ start = self._val['_M_impl']['_M_start']['_M_p']
+ finish = self._val['_M_impl']['_M_finish']['_M_p']
+ fo = self._val['_M_impl']['_M_finish']['_M_offset']
itype = start.dereference().type
bl = 8 * itype.sizeof
- length = (bl - so) + bl * ((finish - start) - 1) + fo
+ length = bl * (finish - start) + fo
capacity = bl * (end - start)
return ('%s<bool> of length %d, capacity %d'
- % (self.typename, int (length), int (capacity)))
+ % (self._typename, int(length), int(capacity)))
else:
return ('%s of length %d, capacity %d'
- % (self.typename, int (finish - start), int (end - start)))
+ % (self._typename, int(finish - start), int(end - start)))
def display_hint(self):
return 'array'
-class StdVectorIteratorPrinter:
- "Print std::vector::iterator"
+
+class StdVectorIteratorPrinter(printer_base):
+ """Print std::vector::iterator."""
def __init__(self, typename, val):
- self.val = val
+ self._val = val
def to_string(self):
- if not self.val['_M_current']:
+ if not self._val['_M_current']:
return 'non-dereferenceable iterator for std::vector'
- return str(self.val['_M_current'].dereference())
+ return str(self._val['_M_current'].dereference())
+
+
+class StdBitIteratorPrinter(printer_base):
+ """Print std::vector<bool>'s _Bit_iterator and _Bit_const_iterator."""
+
+ def __init__(self, typename, val):
+ self._val = val
+
+ def to_string(self):
+ if not self._val['_M_p']:
+ return 'non-dereferenceable iterator for std::vector<bool>'
+ return bool(self._val['_M_p'].dereference()
+ & (1 << self._val['_M_offset']))
-class StdTuplePrinter:
- "Print a std::tuple"
+
+class StdBitReferencePrinter(printer_base):
+ """Print std::vector<bool>::reference."""
+
+ def __init__(self, typename, val):
+ self._val = val
+
+ def to_string(self):
+ if not self._val['_M_p']:
+ return 'invalid std::vector<bool>::reference'
+ return bool(self._val['_M_p'].dereference() & (self._val['_M_mask']))
+
+
+class StdTuplePrinter(printer_base):
+ """Print a std::tuple."""
class _iterator(Iterator):
- def __init__ (self, head):
- self.head = head
+ @staticmethod
+ def _is_nonempty_tuple(nodes):
+ if len(nodes) == 2:
+ if is_specialization_of(nodes[1].type, '__tuple_base'):
+ return True
+ elif len(nodes) == 1:
+ return True
+ elif len(nodes) == 0:
+ return False
+ raise ValueError(
+ "Top of tuple tree does not consist of a single node.")
+
+ def __init__(self, head):
+ self._head = head
# Set the base class as the initial head of the
# tuple.
- nodes = self.head.type.fields ()
- if len (nodes) == 1:
+ nodes = self._head.type.fields()
+ if self._is_nonempty_tuple(nodes):
# Set the actual head to the first pair.
- self.head = self.head.cast (nodes[0].type)
- elif len (nodes) != 0:
- raise ValueError("Top of tuple tree does not consist of a single node.")
- self.count = 0
+ self._head = self._head.cast(nodes[0].type)
+ self._count = 0
- def __iter__ (self):
+ def __iter__(self):
return self
- def __next__ (self):
+ def __next__(self):
# Check for further recursions in the inheritance tree.
- # For a GCC 5+ tuple self.head is None after visiting all nodes:
- if not self.head:
+ # For a GCC 5+ tuple self._head is None after visiting all nodes:
+ if not self._head:
raise StopIteration
- nodes = self.head.type.fields ()
+ nodes = self._head.type.fields()
# For a GCC 4.x tuple there is a final node with no fields:
- if len (nodes) == 0:
+ if len(nodes) == 0:
raise StopIteration
# Check that this iteration has an expected structure.
- if len (nodes) > 2:
- raise ValueError("Cannot parse more than 2 nodes in a tuple tree.")
+ if len(nodes) > 2:
+ raise ValueError(
+ "Cannot parse more than 2 nodes in a tuple tree.")
- if len (nodes) == 1:
+ if len(nodes) == 1:
# This is the last node of a GCC 5+ std::tuple.
- impl = self.head.cast (nodes[0].type)
- self.head = None
+ impl = self._head.cast(nodes[0].type)
+ self._head = None
else:
# Either a node before the last node, or the last node of
# a GCC 4.x tuple (which has an empty parent).
@@ -463,53 +683,55 @@ class StdTuplePrinter:
# - Right node is the actual class contained in the tuple.
# Process right node.
- impl = self.head.cast (nodes[1].type)
+ impl = self._head.cast(nodes[1].type)
# Process left node and set it as head.
- self.head = self.head.cast (nodes[0].type)
+ self._head = self._head.cast(nodes[0].type)
- self.count = self.count + 1
+ self._count = self._count + 1
# Finally, check the implementation. If it is
# wrapped in _M_head_impl return that, otherwise return
# the value "as is".
- fields = impl.type.fields ()
- if len (fields) < 1 or fields[0].name != "_M_head_impl":
- return ('[%d]' % self.count, impl)
+ fields = impl.type.fields()
+ if len(fields) < 1 or fields[0].name != "_M_head_impl":
+ return ('[%d]' % (self._count - 1), impl)
else:
- return ('[%d]' % self.count, impl['_M_head_impl'])
+ return ('[%d]' % (self._count - 1), impl['_M_head_impl'])
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val;
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
- def children (self):
- return self._iterator (self.val)
+ def children(self):
+ return self._iterator(self._val)
- def to_string (self):
- if len (self.val.type.fields ()) == 0:
- return 'empty %s' % (self.typename)
- return '%s containing' % (self.typename)
+ def to_string(self):
+ if len(self._val.type.fields()) == 0:
+ return 'empty %s' % (self._typename)
+ return '%s containing' % (self._typename)
-class StdStackOrQueuePrinter:
- "Print a std::stack or std::queue"
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.visualizer = gdb.default_visualizer(val['c'])
+class StdStackOrQueuePrinter(printer_base):
+ """Print a std::stack or std::queue."""
- def children (self):
- return self.visualizer.children()
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._visualizer = gdb.default_visualizer(val['c'])
- def to_string (self):
- return '%s wrapping: %s' % (self.typename,
- self.visualizer.to_string())
+ def children(self):
+ return self._visualizer.children()
+
+ def to_string(self):
+ return '%s wrapping: %s' % (self._typename,
+ self._visualizer.to_string())
- def display_hint (self):
- if hasattr (self.visualizer, 'display_hint'):
- return self.visualizer.display_hint ()
+ def display_hint(self):
+ if hasattr(self._visualizer, 'display_hint'):
+ return self._visualizer.display_hint()
return None
+
class RbtreeIterator(Iterator):
"""
Turn an RB-tree-based container (std::map, std::set etc.) into
@@ -517,24 +739,24 @@ class RbtreeIterator(Iterator):
"""
def __init__(self, rbtree):
- self.size = rbtree['_M_t']['_M_impl']['_M_node_count']
- self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
- self.count = 0
+ self._size = rbtree['_M_t']['_M_impl']['_M_node_count']
+ self._node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
+ self._count = 0
def __iter__(self):
return self
def __len__(self):
- return int (self.size)
+ return int(self._size)
def __next__(self):
- if self.count == self.size:
+ if self._count == self._size:
raise StopIteration
- result = self.node
- self.count = self.count + 1
- if self.count < self.size:
+ result = self._node
+ self._count = self._count + 1
+ if self._count < self._size:
# Compute the next node.
- node = self.node
+ node = self._node
if node.dereference()['_M_right']:
node = node.dereference()['_M_right']
while node.dereference()['_M_left']:
@@ -546,11 +768,12 @@ class RbtreeIterator(Iterator):
parent = parent.dereference()['_M_parent']
if node.dereference()['_M_right'] != parent:
node = parent
- self.node = node
+ self._node = node
return result
+
def get_value_from_Rb_tree_node(node):
- """Returns the value held in an _Rb_tree_node<_Val>"""
+ """Return the value held in an _Rb_tree_node<_Val>."""
try:
member = node.type.fields()[1].name
if member == '_M_value_field':
@@ -567,143 +790,142 @@ def get_value_from_Rb_tree_node(node):
# This is a pretty printer for std::_Rb_tree_iterator (which is
# std::map::iterator), and has nothing to do with the RbtreeIterator
# class above.
-class StdRbtreeIteratorPrinter:
- "Print std::map::iterator, std::set::iterator, etc."
-
- def __init__ (self, typename, val):
- self.val = val
- valtype = self.val.type.template_argument(0).strip_typedefs()
- nodetype = '_Rb_tree_node<' + str(valtype) + '>'
- if _versioned_namespace and typename.startswith('std::' + _versioned_namespace):
- nodetype = _versioned_namespace + nodetype
- nodetype = gdb.lookup_type('std::' + nodetype)
- self.link_type = nodetype.strip_typedefs().pointer()
-
- def to_string (self):
- if not self.val['_M_node']:
+
+
+class StdRbtreeIteratorPrinter(printer_base):
+ """Print std::map::iterator, std::set::iterator, etc."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ nodetype = lookup_node_type('_Rb_tree_node', self._val.type)
+ self._link_type = nodetype.pointer()
+
+ def to_string(self):
+ if not self._val['_M_node']:
return 'non-dereferenceable iterator for associative container'
- node = self.val['_M_node'].cast(self.link_type).dereference()
+ node = self._val['_M_node'].cast(self._link_type).dereference()
return str(get_value_from_Rb_tree_node(node))
-class StdDebugIteratorPrinter:
- "Print a debug enabled version of an iterator"
- def __init__ (self, typename, val):
- self.val = val
+class StdDebugIteratorPrinter(printer_base):
+ """Print a debug enabled version of an iterator."""
+
+ def __init__(self, typename, val):
+ self._val = val
# Just strip away the encapsulating __gnu_debug::_Safe_iterator
# and return the wrapped iterator value.
- def to_string (self):
+ def to_string(self):
base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base')
- itype = self.val.type.template_argument(0)
- safe_seq = self.val.cast(base_type)['_M_sequence']
+ itype = self._val.type.template_argument(0)
+ safe_seq = self._val.cast(base_type)['_M_sequence']
if not safe_seq:
- return str(self.val.cast(itype))
- if self.val['_M_version'] != safe_seq['_M_version']:
+ return str(self._val.cast(itype))
+ if self._val['_M_version'] != safe_seq['_M_version']:
return "invalid iterator"
- return str(self.val.cast(itype))
+ return str(self._val.cast(itype))
+
def num_elements(num):
"""Return either "1 element" or "N elements" depending on the argument."""
return '1 element' if num == 1 else '%d elements' % num
-class StdMapPrinter:
- "Print a std::map or std::multimap"
+
+class StdMapPrinter(printer_base):
+ """Print a std::map or std::multimap."""
# Turn an RbtreeIterator into a pretty-print iterator.
class _iter(Iterator):
def __init__(self, rbiter, type):
- self.rbiter = rbiter
- self.count = 0
- self.type = type
+ self._rbiter = rbiter
+ self._count = 0
+ self._type = type
def __iter__(self):
return self
def __next__(self):
- if self.count % 2 == 0:
- n = next(self.rbiter)
- n = n.cast(self.type).dereference()
+ if self._count % 2 == 0:
+ n = next(self._rbiter)
+ n = n.cast(self._type).dereference()
n = get_value_from_Rb_tree_node(n)
- self.pair = n
+ self._pair = n
item = n['first']
else:
- item = self.pair['second']
- result = ('[%d]' % self.count, item)
- self.count = self.count + 1
+ item = self._pair['second']
+ result = ('[%d]' % self._count, item)
+ self._count = self._count + 1
return result
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
- def to_string (self):
- return '%s with %s' % (self.typename,
- num_elements(len(RbtreeIterator (self.val))))
+ def to_string(self):
+ return '%s with %s' % (self._typename,
+ num_elements(len(RbtreeIterator(self._val))))
- def children (self):
- rep_type = find_type(self.val.type, '_Rep_type')
- node = find_type(rep_type, '_Link_type')
- node = node.strip_typedefs()
- return self._iter (RbtreeIterator (self.val), node)
+ def children(self):
+ node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
+ return self._iter(RbtreeIterator(self._val), node)
- def display_hint (self):
+ def display_hint(self):
return 'map'
-class StdSetPrinter:
- "Print a std::set or std::multiset"
+
+class StdSetPrinter(printer_base):
+ """Print a std::set or std::multiset."""
# Turn an RbtreeIterator into a pretty-print iterator.
class _iter(Iterator):
def __init__(self, rbiter, type):
- self.rbiter = rbiter
- self.count = 0
- self.type = type
+ self._rbiter = rbiter
+ self._count = 0
+ self._type = type
def __iter__(self):
return self
def __next__(self):
- item = next(self.rbiter)
- item = item.cast(self.type).dereference()
+ item = next(self._rbiter)
+ item = item.cast(self._type).dereference()
item = get_value_from_Rb_tree_node(item)
# FIXME: this is weird ... what to do?
# Maybe a 'set' display hint?
- result = ('[%d]' % self.count, item)
- self.count = self.count + 1
+ result = ('[%d]' % self._count, item)
+ self._count = self._count + 1
return result
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
- def to_string (self):
- return '%s with %s' % (self.typename,
- num_elements(len(RbtreeIterator (self.val))))
+ def to_string(self):
+ return '%s with %s' % (self._typename,
+ num_elements(len(RbtreeIterator(self._val))))
- def children (self):
- rep_type = find_type(self.val.type, '_Rep_type')
- node = find_type(rep_type, '_Link_type')
- node = node.strip_typedefs()
- return self._iter (RbtreeIterator (self.val), node)
+ def children(self):
+ node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
+ return self._iter(RbtreeIterator(self._val), node)
-class StdBitsetPrinter:
- "Print a std::bitset"
+
+class StdBitsetPrinter(printer_base):
+ """Print a std::bitset."""
def __init__(self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
- def to_string (self):
+ def to_string(self):
# If template_argument handled values, we could print the
# size. Or we could use a regexp on the type.
- return '%s' % (self.typename)
+ return '%s' % (self._typename)
- def children (self):
+ def children(self):
try:
# An empty bitset may not have any members which will
# result in an exception being thrown.
- words = self.val['_M_w']
+ words = self._val['_M_w']
except:
return []
@@ -713,7 +935,7 @@ class StdBitsetPrinter:
# array. This depends on the template specialization used.
# If it is a single long, convert to a single element list.
if wtype.code == gdb.TYPE_CODE_ARRAY:
- tsize = wtype.target ().sizeof
+ tsize = wtype.target().sizeof
else:
words = [words]
tsize = wtype.sizeof
@@ -733,279 +955,349 @@ class StdBitsetPrinter:
byte = byte + 1
return result
-class StdDequePrinter:
- "Print a std::deque"
+
+class StdDequePrinter(printer_base):
+ """Print a std::deque."""
class _iter(Iterator):
def __init__(self, node, start, end, last, buffer_size):
- self.node = node
- self.p = start
- self.end = end
- self.last = last
- self.buffer_size = buffer_size
- self.count = 0
+ self._node = node
+ self._p = start
+ self._end = end
+ self._last = last
+ self._buffer_size = buffer_size
+ self._count = 0
def __iter__(self):
return self
def __next__(self):
- if self.p == self.last:
+ if self._p == self._last:
raise StopIteration
- result = ('[%d]' % self.count, self.p.dereference())
- self.count = self.count + 1
+ result = ('[%d]' % self._count, self._p.dereference())
+ self._count = self._count + 1
# Advance the 'cur' pointer.
- self.p = self.p + 1
- if self.p == self.end:
+ self._p = self._p + 1
+ if self._p == self._end:
# If we got to the end of this bucket, move to the
# next bucket.
- self.node = self.node + 1
- self.p = self.node[0]
- self.end = self.p + self.buffer_size
+ self._node = self._node + 1
+ self._p = self._node[0]
+ self._end = self._p + self._buffer_size
return result
def __init__(self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
- self.elttype = val.type.template_argument(0)
- size = self.elttype.sizeof
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+ self._elttype = val.type.template_argument(0)
+ size = self._elttype.sizeof
if size < 512:
- self.buffer_size = int (512 / size)
+ self._buffer_size = int(512 / size)
else:
- self.buffer_size = 1
+ self._buffer_size = 1
def to_string(self):
- start = self.val['_M_impl']['_M_start']
- end = self.val['_M_impl']['_M_finish']
+ start = self._val['_M_impl']['_M_start']
+ end = self._val['_M_impl']['_M_finish']
delta_n = end['_M_node'] - start['_M_node'] - 1
delta_s = start['_M_last'] - start['_M_cur']
delta_e = end['_M_cur'] - end['_M_first']
- size = self.buffer_size * delta_n + delta_s + delta_e
+ size = self._buffer_size * delta_n + delta_s + delta_e
- return '%s with %s' % (self.typename, num_elements(long(size)))
+ return '%s with %s' % (self._typename, num_elements(long(size)))
def children(self):
- start = self.val['_M_impl']['_M_start']
- end = self.val['_M_impl']['_M_finish']
+ start = self._val['_M_impl']['_M_start']
+ end = self._val['_M_impl']['_M_finish']
return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
- end['_M_cur'], self.buffer_size)
+ end['_M_cur'], self._buffer_size)
- def display_hint (self):
+ def display_hint(self):
return 'array'
-class StdDequeIteratorPrinter:
- "Print std::deque::iterator"
+
+class StdDequeIteratorPrinter(printer_base):
+ """Print std::deque::iterator."""
def __init__(self, typename, val):
- self.val = val
+ self._val = val
def to_string(self):
- if not self.val['_M_cur']:
+ if not self._val['_M_cur']:
return 'non-dereferenceable iterator for std::deque'
- return str(self.val['_M_cur'].dereference())
+ return str(self._val['_M_cur'].dereference())
-class StdStringPrinter:
- "Print a std::basic_string of some kind"
+
+class StdStringPrinter(printer_base):
+ """Print a std::basic_string of some kind."""
def __init__(self, typename, val):
- self.val = val
- self.new_string = typename.find("::__cxx11::basic_string") != -1
+ self._val = val
+ self._new_string = typename.find("::__cxx11::basic_string") != -1
def to_string(self):
# Make sure &string works, too.
- type = self.val.type
+ type = self._val.type
if type.code == gdb.TYPE_CODE_REF:
- type = type.target ()
+ type = type.target()
# Calculate the length of the string so that to_string returns
# the string according to length, not according to first null
# encountered.
- ptr = self.val ['_M_dataplus']['_M_p']
- if self.new_string:
- length = self.val['_M_string_length']
+ ptr = self._val['_M_dataplus']['_M_p']
+ if self._new_string:
+ length = self._val['_M_string_length']
# https://sourceware.org/bugzilla/show_bug.cgi?id=17728
ptr = ptr.cast(ptr.type.strip_typedefs())
else:
- realtype = type.unqualified ().strip_typedefs ()
- reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
+ realtype = type.unqualified().strip_typedefs()
+ reptype = gdb.lookup_type(str(realtype) + '::_Rep').pointer()
header = ptr.cast(reptype) - 1
- length = header.dereference ()['_M_length']
+ length = header.dereference()['_M_length']
if hasattr(ptr, "lazy_string"):
- return ptr.lazy_string (length = length)
- return ptr.string (length = length)
+ return ptr.lazy_string(length=length)
+ return ptr.string(length=length)
+
+ def display_hint(self):
+ return 'string'
+
+
+def access_streambuf_ptrs(streambuf):
+ """Access the streambuf put area pointers."""
+ pbase = streambuf['_M_out_beg']
+ pptr = streambuf['_M_out_cur']
+ egptr = streambuf['_M_in_end']
+ return pbase, pptr, egptr
- def display_hint (self):
+
+class StdStringBufPrinter(printer_base):
+ """Print a std::basic_stringbuf."""
+
+ def __init__(self, _, val):
+ self._val = val
+
+ def to_string(self):
+ (pbase, pptr, egptr) = access_streambuf_ptrs(self._val)
+ # Logic from basic_stringbuf::_M_high_mark()
+ if pptr:
+ if not egptr or pptr > egptr:
+ return pbase.string(length=pptr - pbase)
+ else:
+ return pbase.string(length=egptr - pbase)
+ return self._val['_M_string']
+
+ def display_hint(self):
return 'string'
+
+class StdStringStreamPrinter(printer_base):
+ """Print a std::basic_stringstream."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+
+ # Check if the stream was redirected. This is essentially:
+ # val['_M_streambuf'] != val['_M_stringbuf'].address
+ # However, GDB can't resolve the virtual inheritance, so we do that
+ # manually.
+ basetype = [f.type for f in val.type.fields() if f.is_base_class][0]
+ gdb.set_convenience_variable('__stream', val.cast(basetype).address)
+ self._streambuf = gdb.parse_and_eval('$__stream->rdbuf()')
+ self._was_redirected = self._streambuf != val['_M_stringbuf'].address
+
+ def to_string(self):
+ if self._was_redirected:
+ return "%s redirected to %s" % (
+ self._typename, self._streambuf.dereference())
+ return self._val['_M_stringbuf']
+
+ def display_hint(self):
+ if self._was_redirected:
+ return None
+ return 'string'
+
+
class Tr1HashtableIterator(Iterator):
- def __init__ (self, hash):
- self.buckets = hash['_M_buckets']
- self.bucket = 0
- self.bucket_count = hash['_M_bucket_count']
- self.node_type = find_type(hash.type, '_Node').pointer()
- self.node = 0
- while self.bucket != self.bucket_count:
- self.node = self.buckets[self.bucket]
- if self.node:
+ def __init__(self, hashtable):
+ self._buckets = hashtable['_M_buckets']
+ self._bucket = 0
+ self._bucket_count = hashtable['_M_bucket_count']
+ self._node_type = find_type(hashtable.type, '_Node').pointer()
+ self._node = 0
+ while self._bucket != self._bucket_count:
+ self._node = self._buckets[self._bucket]
+ if self._node:
break
- self.bucket = self.bucket + 1
+ self._bucket = self._bucket + 1
- def __iter__ (self):
+ def __iter__(self):
return self
- def __next__ (self):
- if self.node == 0:
+ def __next__(self):
+ if self._node == 0:
raise StopIteration
- node = self.node.cast(self.node_type)
+ node = self._node.cast(self._node_type)
result = node.dereference()['_M_v']
- self.node = node.dereference()['_M_next'];
- if self.node == 0:
- self.bucket = self.bucket + 1
- while self.bucket != self.bucket_count:
- self.node = self.buckets[self.bucket]
- if self.node:
+ self._node = node.dereference()['_M_next']
+ if self._node == 0:
+ self._bucket = self._bucket + 1
+ while self._bucket != self._bucket_count:
+ self._node = self._buckets[self._bucket]
+ if self._node:
break
- self.bucket = self.bucket + 1
+ self._bucket = self._bucket + 1
return result
+
class StdHashtableIterator(Iterator):
- def __init__(self, hash):
- self.node = hash['_M_before_begin']['_M_nxt']
- self.node_type = find_type(hash.type, '__node_type').pointer()
+ def __init__(self, hashtable):
+ self._node = hashtable['_M_before_begin']['_M_nxt']
+ valtype = hashtable.type.template_argument(1)
+ cached = hashtable.type.template_argument(9).template_argument(0)
+ node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype),
+ 'true' if cached else 'false')
+ self._node_type = node_type.pointer()
def __iter__(self):
return self
def __next__(self):
- if self.node == 0:
+ if self._node == 0:
raise StopIteration
- elt = self.node.cast(self.node_type).dereference()
- self.node = elt['_M_nxt']
+ elt = self._node.cast(self._node_type).dereference()
+ self._node = elt['_M_nxt']
valptr = elt['_M_storage'].address
valptr = valptr.cast(elt.type.template_argument(0).pointer())
return valptr.dereference()
-class Tr1UnorderedSetPrinter:
- "Print a tr1::unordered_set"
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
+class Tr1UnorderedSetPrinter(printer_base):
+ """Print a std::unordered_set or tr1::unordered_set."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
- def hashtable (self):
- if self.typename.startswith('std::tr1'):
- return self.val
- return self.val['_M_h']
+ def _hashtable(self):
+ if self._typename.startswith('std::tr1'):
+ return self._val
+ return self._val['_M_h']
- def to_string (self):
- count = self.hashtable()['_M_element_count']
- return '%s with %s' % (self.typename, num_elements(count))
+ def to_string(self):
+ count = self._hashtable()['_M_element_count']
+ return '%s with %s' % (self._typename, num_elements(count))
@staticmethod
- def format_count (i):
+ def _format_count(i):
return '[%d]' % i
- def children (self):
- counter = imap (self.format_count, itertools.count())
- if self.typename.startswith('std::tr1'):
- return izip (counter, Tr1HashtableIterator (self.hashtable()))
- return izip (counter, StdHashtableIterator (self.hashtable()))
+ def children(self):
+ counter = imap(self._format_count, itertools.count())
+ if self._typename.startswith('std::tr1'):
+ return izip(counter, Tr1HashtableIterator(self._hashtable()))
+ return izip(counter, StdHashtableIterator(self._hashtable()))
-class Tr1UnorderedMapPrinter:
- "Print a tr1::unordered_map"
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.val = val
+class Tr1UnorderedMapPrinter(printer_base):
+ """Print a std::unordered_map or tr1::unordered_map."""
- def hashtable (self):
- if self.typename.startswith('std::tr1'):
- return self.val
- return self.val['_M_h']
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def _hashtable(self):
+ if self._typename.startswith('std::tr1'):
+ return self._val
+ return self._val['_M_h']
- def to_string (self):
- count = self.hashtable()['_M_element_count']
- return '%s with %s' % (self.typename, num_elements(count))
+ def to_string(self):
+ count = self._hashtable()['_M_element_count']
+ return '%s with %s' % (self._typename, num_elements(count))
@staticmethod
- def flatten (list):
+ def _flatten(list):
for elt in list:
for i in elt:
yield i
@staticmethod
- def format_one (elt):
+ def _format_one(elt):
return (elt['first'], elt['second'])
@staticmethod
- def format_count (i):
+ def _format_count(i):
return '[%d]' % i
- def children (self):
- counter = imap (self.format_count, itertools.count())
+ def children(self):
+ counter = imap(self._format_count, itertools.count())
# Map over the hash table and flatten the result.
- if self.typename.startswith('std::tr1'):
- data = self.flatten (imap (self.format_one, Tr1HashtableIterator (self.hashtable())))
+ if self._typename.startswith('std::tr1'):
+ data = self._flatten(
+ imap(self._format_one, Tr1HashtableIterator(self._hashtable())))
# Zip the two iterators together.
- return izip (counter, data)
- data = self.flatten (imap (self.format_one, StdHashtableIterator (self.hashtable())))
+ return izip(counter, data)
+ data = self._flatten(
+ imap(self._format_one, StdHashtableIterator(self._hashtable())))
# Zip the two iterators together.
- return izip (counter, data)
+ return izip(counter, data)
- def display_hint (self):
+ def display_hint(self):
return 'map'
-class StdForwardListPrinter:
- "Print a std::forward_list"
+
+class StdForwardListPrinter(printer_base):
+ """Print a std::forward_list."""
class _iterator(Iterator):
def __init__(self, nodetype, head):
- self.nodetype = nodetype
- self.base = head['_M_next']
- self.count = 0
+ self._nodetype = nodetype
+ self._base = head['_M_next']
+ self._count = 0
def __iter__(self):
return self
def __next__(self):
- if self.base == 0:
+ if self._base == 0:
raise StopIteration
- elt = self.base.cast(self.nodetype).dereference()
- self.base = elt['_M_next']
- count = self.count
- self.count = self.count + 1
+ elt = self._base.cast(self._nodetype).dereference()
+ self._base = elt['_M_next']
+ count = self._count
+ self._count = self._count + 1
valptr = elt['_M_storage'].address
valptr = valptr.cast(elt.type.template_argument(0).pointer())
return ('[%d]' % count, valptr.dereference())
def __init__(self, typename, val):
- self.val = val
- self.typename = strip_versioned_namespace(typename)
+ self._val = val
+ self._typename = strip_versioned_namespace(typename)
def children(self):
- nodetype = find_type(self.val.type, '_Node')
- nodetype = nodetype.strip_typedefs().pointer()
- return self._iterator(nodetype, self.val['_M_impl']['_M_head'])
+ nodetype = lookup_node_type('_Fwd_list_node', self._val.type).pointer()
+ return self._iterator(nodetype, self._val['_M_impl']['_M_head'])
def to_string(self):
- if self.val['_M_impl']['_M_head']['_M_next'] == 0:
- return 'empty %s' % self.typename
- return '%s' % self.typename
+ if self._val['_M_impl']['_M_head']['_M_next'] == 0:
+ return 'empty %s' % self._typename
+ return '%s' % self._typename
+
-class SingleObjContainerPrinter(object):
- "Base class for printers of containers of single objects"
+class SingleObjContainerPrinter(printer_base):
+ """Base class for printers of containers of single objects."""
- def __init__ (self, val, viz, hint = None):
- self.contained_value = val
- self.visualizer = viz
- self.hint = hint
+ def __init__(self, val, viz, hint=None):
+ self._contained_value = val
+ self._visualizer = viz
+ self._hint = hint
def _recognize(self, type):
- """Return TYPE as a string after applying type printers"""
+ """Return type as a string after applying type printers."""
global _use_type_printing
if not _use_type_printing:
return str(type)
@@ -1013,35 +1305,37 @@ class SingleObjContainerPrinter(object):
type) or str(type)
class _contained(Iterator):
- def __init__ (self, val):
- self.val = val
+ def __init__(self, val):
+ self._val = val
- def __iter__ (self):
+ def __iter__(self):
return self
def __next__(self):
- if self.val is None:
+ if self._val is None:
raise StopIteration
- retval = self.val
- self.val = None
+ retval = self._val
+ self._val = None
return ('[contained value]', retval)
- def children (self):
- if self.contained_value is None:
- return self._contained (None)
- if hasattr (self.visualizer, 'children'):
- return self.visualizer.children ()
- return self._contained (self.contained_value)
+ def children(self):
+ if self._contained_value is None:
+ return self._contained(None)
+ if hasattr(self._visualizer, 'children'):
+ return self._visualizer.children()
+ return self._contained(self._contained_value)
+
+ def display_hint(self):
+ if (hasattr(self._visualizer, 'children')
+ and hasattr(self._visualizer, 'display_hint')):
+ # If contained value is a map we want to display in the same way.
+ return self._visualizer.display_hint()
+ return self._hint
- def display_hint (self):
- # if contained value is a map we want to display in the same way
- if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'):
- return self.visualizer.display_hint ()
- return self.hint
def function_pointer_to_name(f):
- "Find the name of the function referred to by the gdb.Value f, "
- " which should contain a function pointer from the program."
+ """Find the name of the function referred to by the gdb.Value f,
+ which should contain a function pointer from the program."""
# Turn the function pointer into an actual address.
# This is needed to unpack ppc64 function descriptors.
@@ -1062,252 +1356,1003 @@ def function_pointer_to_name(f):
except:
return None
+
class StdExpAnyPrinter(SingleObjContainerPrinter):
- "Print a std::any or std::experimental::any"
+ """Print a std::any or std::experimental::any."""
- def __init__ (self, typename, val):
- self.typename = strip_versioned_namespace(typename)
- self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', self.typename, 1)
- self.val = val
- self.contained_type = None
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._typename = strip_fundts_namespace(self._typename)
+ self._val = val
+ self._contained_type = None
contained_value = None
visualizer = None
- mgr = self.val['_M_manager']
+ mgr = self._val['_M_manager']
if mgr != 0:
func = function_pointer_to_name(mgr)
if not func:
- raise ValueError("Invalid function pointer in %s" % (self.typename))
- rx = r"""({0}::_Manager_\w+<.*>)::_S_manage""".format(typename)
+ raise ValueError(
+ "Invalid function pointer in %s" % (self._typename))
+ # We want to use this regular expression:
+ # T::_Manager_xxx<.*>::_S_manage\(T::_Op, const T\*, T::_Arg\*\)
+ # where T is std::any or std::experimental::any.
+ # But we need to account for variances in demangled names
+ # between GDB versions, e.g. 'enum T::_Op' instead of 'T::_Op'.
+ rx = (
+ r"({0}::_Manager_\w+<.*>)::_S_manage\("
+ r"(enum )?{0}::_Op, (const {0}|{0} const) ?\*, "
+ r"(union )?{0}::_Arg ?\*\)"
+ ).format(typename)
m = re.match(rx, func)
if not m:
- raise ValueError("Unknown manager function in %s" % self.typename)
+ raise ValueError(
+ "Unknown manager function in %s" % self._typename)
mgrname = m.group(1)
# FIXME need to expand 'std::string' so that gdb.lookup_type works
if 'std::string' in mgrname:
- mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
-
- mgrtype = gdb.lookup_type(mgrname)
- self.contained_type = mgrtype.template_argument(0)
+ mgrtypes = []
+ for s in StdExpAnyPrinter._string_types():
+ try:
+ x = re.sub(r"std::string(?!\w)", s, m.group(1))
+ # The following lookup might raise gdb.error if the
+ # manager function was never instantiated for 's' in
+ # the program, because there will be no such type.
+ mgrtypes.append(gdb.lookup_type(x))
+ except gdb.error:
+ pass
+ if len(mgrtypes) != 1:
+ # FIXME: this is unlikely in practice, but possible for
+ # programs that use both old and new string types with
+ # std::any in a single program. Can we do better?
+ # Maybe find the address of each type's _S_manage and
+ # compare to the address stored in _M_manager?
+ raise ValueError(
+ 'Cannot uniquely determine std::string type '
+ 'used in std::any'
+ )
+ mgrtype = mgrtypes[0]
+ else:
+ mgrtype = gdb.lookup_type(mgrname)
+ self._contained_type = mgrtype.template_argument(0)
valptr = None
if '::_Manager_internal' in mgrname:
- valptr = self.val['_M_storage']['_M_buffer'].address
+ valptr = self._val['_M_storage']['_M_buffer'].address
elif '::_Manager_external' in mgrname:
- valptr = self.val['_M_storage']['_M_ptr']
+ valptr = self._val['_M_storage']['_M_ptr']
else:
- raise ValueError("Unknown manager function in %s" % self.typename)
- contained_value = valptr.cast(self.contained_type.pointer()).dereference()
+ raise ValueError(
+ "Unknown manager function in %s" % self._typename)
+ contained_value = valptr.cast(
+ self._contained_type.pointer()).dereference()
visualizer = gdb.default_visualizer(contained_value)
- super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer)
-
- def to_string (self):
- if self.contained_type is None:
- return '%s [no contained value]' % self.typename
- desc = "%s containing " % self.typename
- if hasattr (self.visualizer, 'children'):
- return desc + self.visualizer.to_string ()
- valtype = self._recognize (self.contained_type)
+ super(StdExpAnyPrinter, self).__init__(contained_value, visualizer)
+
+ def to_string(self):
+ if self._contained_type is None:
+ return '%s [no contained value]' % self._typename
+ desc = "%s containing " % self._typename
+ if hasattr(self._visualizer, 'children'):
+ return desc + self._visualizer.to_string()
+ valtype = self._recognize(self._contained_type)
return desc + strip_versioned_namespace(str(valtype))
+ @staticmethod
+ def _string_types():
+ # This lookup for std::string might return the __cxx11 version,
+ # but that's not necessarily the one used by the std::any
+ # manager function we're trying to find.
+ strings = {str(gdb.lookup_type('std::string').strip_typedefs())}
+ # So also consider all the other possible std::string types!
+ s = 'basic_string<char, std::char_traits<char>, std::allocator<char> >'
+ quals = ['std::', 'std::__cxx11::',
+ 'std::' + _versioned_namespace]
+ strings |= {q + s for q in quals} # set of unique strings
+ return strings
+
+
class StdExpOptionalPrinter(SingleObjContainerPrinter):
- "Print a std::optional or std::experimental::optional"
-
- def __init__ (self, typename, val):
- valtype = self._recognize (val.type.template_argument(0))
- self.typename = strip_versioned_namespace(typename)
- self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, self.typename, 1)
- if not self.typename.startswith('std::experimental'):
- val = val['_M_payload']
- self.val = val
- contained_value = val['_M_payload'] if self.val['_M_engaged'] else None
- visualizer = gdb.default_visualizer (val['_M_payload'])
- super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer)
-
- def to_string (self):
- if self.contained_value is None:
- return "%s [no contained value]" % self.typename
- if hasattr (self.visualizer, 'children'):
- return "%s containing %s" % (self.typename,
- self.visualizer.to_string())
- return self.typename
+ """Print a std::optional or std::experimental::optional."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._typename = strip_fundts_namespace(self._typename)
+ payload = val['_M_payload']
+ if self._typename.startswith('std::experimental'):
+ engaged = val['_M_engaged']
+ contained_value = payload
+ else:
+ engaged = payload['_M_engaged']
+ contained_value = payload['_M_payload']
+ try:
+ # Since GCC 9
+ contained_value = contained_value['_M_value']
+ except:
+ pass
+ visualizer = gdb.default_visualizer(contained_value)
+ if not engaged:
+ contained_value = None
+ super(StdExpOptionalPrinter, self).__init__(
+ contained_value, visualizer)
+
+ def to_string(self):
+ if self._contained_value is None:
+ return "%s [no contained value]" % self._typename
+ if hasattr(self._visualizer, 'children'):
+ return "%s containing %s" % (self._typename,
+ self._visualizer.to_string())
+ return self._typename
+
class StdVariantPrinter(SingleObjContainerPrinter):
- "Print a std::variant"
+ """Print a std::variant."""
def __init__(self, typename, val):
alternatives = get_template_arg_list(val.type)
- self.typename = strip_versioned_namespace(typename)
- self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives]))
- self.index = val['_M_index']
- if self.index >= len(alternatives):
- self.contained_type = None
+ self._typename = strip_versioned_namespace(typename)
+ self._index = val['_M_index']
+ if self._index >= len(alternatives):
+ self._contained_type = None
contained_value = None
visualizer = None
else:
- self.contained_type = alternatives[int(self.index)]
+ self._contained_type = alternatives[int(self._index)]
addr = val['_M_u']['_M_first']['_M_storage'].address
- contained_value = addr.cast(self.contained_type.pointer()).dereference()
+ contained_value = addr.cast(
+ self._contained_type.pointer()).dereference()
visualizer = gdb.default_visualizer(contained_value)
- super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array')
+ super(StdVariantPrinter, self).__init__(
+ contained_value, visualizer, 'array')
def to_string(self):
- if self.contained_value is None:
- return "%s [no contained value]" % self.typename
- if hasattr(self.visualizer, 'children'):
- return "%s [index %d] containing %s" % (self.typename, self.index,
- self.visualizer.to_string())
- return "%s [index %d]" % (self.typename, self.index)
+ if self._contained_value is None:
+ return "%s [no contained value]" % self._typename
+ if hasattr(self._visualizer, 'children'):
+ return "%s [index %d] containing %s" % (self._typename, self._index,
+ self._visualizer.to_string())
+ return "%s [index %d]" % (self._typename, self._index)
+
class StdNodeHandlePrinter(SingleObjContainerPrinter):
- "Print a container node handle"
+ """Print a container node handle."""
def __init__(self, typename, val):
- self.value_type = val.type.template_argument(1)
+ self._value_type = val.type.template_argument(1)
nodetype = val.type.template_argument(2).template_argument(0)
- self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node')
- self.is_map_node = val.type.template_argument(0) != self.value_type
+ self._is_rb_tree_node = is_specialization_of(
+ nodetype.name, '_Rb_tree_node')
+ self._is_map_node = val.type.template_argument(0) != self._value_type
nodeptr = val['_M_ptr']
if nodeptr:
- if self.is_rb_tree_node:
- contained_value = get_value_from_Rb_tree_node(nodeptr.dereference())
+ if self._is_rb_tree_node:
+ contained_value = get_value_from_Rb_tree_node(
+ nodeptr.dereference())
else:
contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'],
- self.value_type)
+ self._value_type)
visualizer = gdb.default_visualizer(contained_value)
else:
contained_value = None
visualizer = None
optalloc = val['_M_alloc']
- self.alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None
+ self._alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None
super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer,
'array')
def to_string(self):
desc = 'node handle for '
- if not self.is_rb_tree_node:
+ if not self._is_rb_tree_node:
desc += 'unordered '
- if self.is_map_node:
- desc += 'map';
+ if self._is_map_node:
+ desc += 'map'
else:
- desc += 'set';
+ desc += 'set'
- if self.contained_value:
+ if self._contained_value:
desc += ' with element'
- if hasattr(self.visualizer, 'children'):
- return "%s = %s" % (desc, self.visualizer.to_string())
+ if hasattr(self._visualizer, 'children'):
+ return "%s = %s" % (desc, self._visualizer.to_string())
return desc
else:
return 'empty %s' % desc
-class StdExpStringViewPrinter:
- "Print a std::basic_string_view or std::experimental::basic_string_view"
- def __init__ (self, typename, val):
- self.val = val
+class StdExpStringViewPrinter(printer_base):
+ """
+ Print a std::basic_string_view or std::experimental::basic_string_view
+ """
+
+ def __init__(self, typename, val):
+ self._val = val
- def to_string (self):
- ptr = self.val['_M_str']
- len = self.val['_M_len']
- if hasattr (ptr, "lazy_string"):
- return ptr.lazy_string (length = len)
- return ptr.string (length = len)
+ def to_string(self):
+ ptr = self._val['_M_str']
+ len = self._val['_M_len']
+ if hasattr(ptr, "lazy_string"):
+ return ptr.lazy_string(length=len)
+ return ptr.string(length=len)
- def display_hint (self):
+ def display_hint(self):
return 'string'
-class StdExpPathPrinter:
- "Print a std::experimental::filesystem::path or std::filesystem::path"
- def __init__ (self, typename, val):
- self.val = val
- self.typename = typename
- start = self.val['_M_cmpts']['_M_impl']['_M_start']
- finish = self.val['_M_cmpts']['_M_impl']['_M_finish']
- self.num_cmpts = int (finish - start)
+class StdExpPathPrinter(printer_base):
+ """Print a std::experimental::filesystem::path."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+ start = self._val['_M_cmpts']['_M_impl']['_M_start']
+ finish = self._val['_M_cmpts']['_M_impl']['_M_finish']
+ self._num_cmpts = int(finish - start)
def _path_type(self):
- t = str(self.val['_M_type'])
+ t = str(self._val['_M_type'])
if t[-9:] == '_Root_dir':
return "root-directory"
if t[-10:] == '_Root_name':
return "root-name"
return None
- def to_string (self):
- path = "%s" % self.val ['_M_pathname']
- if self.num_cmpts == 0:
+ def to_string(self):
+ path = "%s" % self._val['_M_pathname']
+ if self._num_cmpts == 0:
t = self._path_type()
if t:
path = '%s [%s]' % (path, t)
- return "filesystem::path %s" % path
+ return "experimental::filesystem::path %s" % path
class _iterator(Iterator):
def __init__(self, cmpts, pathtype):
- self.pathtype = pathtype
- self.item = cmpts['_M_impl']['_M_start']
- self.finish = cmpts['_M_impl']['_M_finish']
- self.count = 0
+ self._pathtype = pathtype
+ self._item = cmpts['_M_impl']['_M_start']
+ self._finish = cmpts['_M_impl']['_M_finish']
+ self._count = 0
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ if self._item == self._finish:
+ raise StopIteration
+ item = self._item.dereference()
+ count = self._count
+ self._count = self._count + 1
+ self._item = self._item + 1
+ path = item['_M_pathname']
+ t = StdExpPathPrinter(self._pathtype, item)._path_type()
+ if not t:
+ t = count
+ return ('[%s]' % t, path)
+
+ def children(self):
+ return self._iterator(self._val['_M_cmpts'], self._typename)
+
+
+class StdPathPrinter(printer_base):
+ """Print a std::filesystem::path."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+ impl = unique_ptr_get(self._val['_M_cmpts']['_M_impl'])
+ self._type = impl.cast(gdb.lookup_type('uintptr_t')) & 3
+ if self._type == 0:
+ self._impl = impl
+ else:
+ self._impl = None
+
+ def _path_type(self):
+ t = str(self._type.cast(gdb.lookup_type(self._typename + '::_Type')))
+ if t[-9:] == '_Root_dir':
+ return "root-directory"
+ if t[-10:] == '_Root_name':
+ return "root-name"
+ return None
+
+ def to_string(self):
+ path = "%s" % self._val['_M_pathname']
+ if self._type != 0:
+ t = self._path_type()
+ if t:
+ path = '%s [%s]' % (path, t)
+ return "filesystem::path %s" % path
+
+ class _iterator(Iterator):
+ def __init__(self, impl, pathtype):
+ self._pathtype = pathtype
+ if impl:
+ # We can't access _Impl::_M_size because _Impl is incomplete
+ # so cast to int* to access the _M_size member at offset zero,
+ int_type = gdb.lookup_type('int')
+ cmpt_type = gdb.lookup_type(pathtype + '::_Cmpt')
+ char_type = gdb.lookup_type('char')
+ impl = impl.cast(int_type.pointer())
+ size = impl.dereference()
+ #self._capacity = (impl + 1).dereference()
+ if hasattr(gdb.Type, 'alignof'):
+ sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof)
+ else:
+ sizeof_Impl = 2 * int_type.sizeof
+ begin = impl.cast(char_type.pointer()) + sizeof_Impl
+ self._item = begin.cast(cmpt_type.pointer())
+ self._finish = self._item + size
+ self._count = 0
+ else:
+ self._item = None
+ self._finish = None
def __iter__(self):
return self
def __next__(self):
- if self.item == self.finish:
+ if self._item == self._finish:
raise StopIteration
- item = self.item.dereference()
- count = self.count
- self.count = self.count + 1
- self.item = self.item + 1
+ item = self._item.dereference()
+ count = self._count
+ self._count = self._count + 1
+ self._item = self._item + 1
path = item['_M_pathname']
- t = StdExpPathPrinter(self.pathtype, item)._path_type()
+ t = StdPathPrinter(self._pathtype, item)._path_type()
if not t:
t = count
return ('[%s]' % t, path)
def children(self):
- return self._iterator(self.val['_M_cmpts'], self.typename)
+ return self._iterator(self._impl, self._typename)
-class StdPairPrinter:
- "Print a std::pair object, with 'first' and 'second' as children"
+class StdPairPrinter(printer_base):
+ """Print a std::pair object, with 'first' and 'second' as children."""
def __init__(self, typename, val):
- self.val = val
+ self._val = val
class _iter(Iterator):
- "An iterator for std::pair types. Returns 'first' then 'second'."
+ """An iterator for std::pair types. Returns 'first' then 'second'."""
def __init__(self, val):
- self.val = val
- self.which = 'first'
+ self._val = val
+ self._which = 'first'
def __iter__(self):
return self
def __next__(self):
- if self.which is None:
+ if self._which is None:
raise StopIteration
- which = self.which
+ which = self._which
if which == 'first':
- self.which = 'second'
+ self._which = 'second'
else:
- self.which = None
- return (which, self.val[which])
+ self._which = None
+ return (which, self._val[which])
def children(self):
- return self._iter(self.val)
+ return self._iter(self._val)
def to_string(self):
return None
+class StdCmpCatPrinter(printer_base):
+ """Print a comparison category object."""
+
+ def __init__(self, typename, val):
+ self._typename = typename[typename.rfind(':') + 1:]
+ self._val = val['_M_value']
+
+ def to_string(self):
+ if self._typename == 'strong_ordering' and self._val == 0:
+ name = 'equal'
+ else:
+ names = {2: 'unordered', -1: 'less', 0: 'equivalent', 1: 'greater'}
+ name = names[int(self._val)]
+ return 'std::{}::{}'.format(self._typename, name)
+
+
+class StdErrorCodePrinter(printer_base):
+ """Print a std::error_code or std::error_condition."""
+
+ _system_is_posix = None # Whether std::system_category() use errno values.
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = strip_versioned_namespace(typename)
+ # Do this only once ...
+ if StdErrorCodePrinter._system_is_posix is None:
+ try:
+ import posix
+ StdErrorCodePrinter._system_is_posix = True
+ except ImportError:
+ StdErrorCodePrinter._system_is_posix = False
+
+ @staticmethod
+ def _find_errc_enum(name):
+ typ = gdb.lookup_type(name)
+ if typ is not None and typ.code == gdb.TYPE_CODE_ENUM:
+ return typ
+ return None
+
+ @classmethod
+ def _find_standard_errc_enum(cls, name):
+ for ns in ['', _versioned_namespace]:
+ try:
+ qname = 'std::{}{}'.format(ns, name)
+ return cls._find_errc_enum(qname)
+ except RuntimeError:
+ pass
+
+ @classmethod
+ def _match_net_ts_category(cls, cat):
+ net_cats = ['stream', 'socket', 'ip::resolver']
+ for c in net_cats:
+ func = c + '_category()'
+ for ns in ['', _versioned_namespace]:
+ ns = 'std::{}experimental::net::v1'.format(ns)
+ sym = gdb.lookup_symbol('{}::{}::__c'.format(ns, func))[0]
+ if sym is not None:
+ if cat == sym.value().address:
+ name = 'net::' + func
+ enum = cls._find_errc_enum('{}::{}_errc'.format(ns, c))
+ return (name, enum)
+ return (None, None)
+
+ @classmethod
+ def _category_info(cls, cat):
+ """Return details of a std::error_category."""
+
+ name = None
+ enum = None
+ is_errno = False
+
+ # Try these first, or we get "warning: RTTI symbol not found" when
+ # using cat.dynamic_type on the local class types for Net TS
+ # categories.
+ func, enum = cls._match_net_ts_category(cat)
+ if func is not None:
+ return (None, func, enum, is_errno)
+
+ # This might give a warning for a program-defined category defined as
+ # a local class, but there doesn't seem to be any way to avoid that.
+ typ = cat.dynamic_type.target()
+ # Shortcuts for the known categories defined by libstdc++.
+ if typ.tag.endswith('::generic_error_category'):
+ name = 'generic'
+ is_errno = True
+ if typ.tag.endswith('::system_error_category'):
+ name = 'system'
+ is_errno = cls._system_is_posix
+ if typ.tag.endswith('::future_error_category'):
+ name = 'future'
+ enum = cls._find_standard_errc_enum('future_errc')
+ if typ.tag.endswith('::io_error_category'):
+ name = 'io'
+ enum = cls._find_standard_errc_enum('io_errc')
+
+ if name is None:
+ try:
+ # Want to call std::error_category::name() override, but it's
+ # unsafe: https://sourceware.org/bugzilla/show_bug.cgi?id=28856
+ # gdb.set_convenience_variable('__cat', cat)
+ # return '"%s"' % gdb.parse_and_eval('$__cat->name()').string()
+ pass
+ except:
+ pass
+ return (name, typ.tag, enum, is_errno)
+
+ @staticmethod
+ def _unqualified_name(name):
+ """
+ Strip any nested-name-specifier from name to give an unqualified name.
+ """
+ return name.split('::')[-1]
+
+ def to_string(self):
+ value = self._val['_M_value']
+ cat = self._val['_M_cat']
+ name, alt_name, enum, is_errno = self._category_info(cat)
+ if value == 0:
+ default_cats = {'error_code': 'system',
+ 'error_condition': 'generic'}
+ if name == default_cats[self._unqualified_name(self._typename)]:
+ return self._typename + ' = { }' # default-constructed value
+
+ strval = str(value)
+ if is_errno and value != 0:
+ try:
+ strval = errno.errorcode[int(value)]
+ except:
+ pass
+ elif enum is not None:
+ strval = self._unqualified_name(str(value.cast(enum)))
+
+ if name is not None:
+ name = '"%s"' % name
+ else:
+ name = alt_name
+ return '%s = {%s: %s}' % (self._typename, name, strval)
+
+
+class StdRegexStatePrinter(printer_base):
+ """Print a state node in the NFA for a std::regex."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+
+ def to_string(self):
+ opcode = str(self._val['_M_opcode'])
+ if opcode:
+ opcode = opcode[25:]
+ next_id = self._val['_M_next']
+
+ variants = {'repeat': 'alt', 'alternative': 'alt',
+ 'subexpr_begin': 'subexpr', 'subexpr_end': 'subexpr',
+ 'line_begin_assertion': None, 'line_end_assertion': None,
+ 'word_boundary': 'neg', 'subexpr_lookahead': 'neg',
+ 'backref': 'backref_index',
+ 'match': None, 'accept': None,
+ 'dummy': None, 'unknown': None
+ }
+ v = variants[opcode]
+
+ s = "opcode={}, next={}".format(opcode, next_id)
+ if v is not None and self._val['_M_' + v] is not None:
+ s = "{}, {}={}".format(s, v, self._val['_M_' + v])
+ return "{%s}" % (s)
+
+
+class StdSpanPrinter(printer_base):
+ """Print a std::span."""
+
+ class _iterator(Iterator):
+ def __init__(self, begin, size):
+ self._count = 0
+ self._begin = begin
+ self._size = size
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ if self._count == self._size:
+ raise StopIteration
+
+ count = self._count
+ self._count = self._count + 1
+ return '[%d]' % count, (self._begin + count).dereference()
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+ size_max = gdb.parse_and_eval('static_cast<std::size_t>(-1)')
+ if val.type.template_argument(1) == size_max:
+ self._size = val['_M_extent']['_M_extent_value']
+ else:
+ self._size = val.type.template_argument(1)
+
+ def to_string(self):
+ return '%s of length %d' % (self._typename, self._size)
+
+ def children(self):
+ return self._iterator(self._val['_M_ptr'], self._size)
+
+ def display_hint(self):
+ return 'array'
+
+
+class StdInitializerListPrinter(printer_base):
+ """Print a std::initializer_list."""
+
+ def __init__(self, typename, val):
+ self._typename = typename
+ self._val = val
+ self._size = val['_M_len']
+
+ def to_string(self):
+ return '%s of length %d' % (self._typename, self._size)
+
+ def children(self):
+ return StdSpanPrinter._iterator(self._val['_M_array'], self._size)
+
+ def display_hint(self):
+ return 'array'
+
+
+class StdAtomicPrinter(printer_base):
+ """Print a std:atomic."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+ self._shptr_printer = None
+ self._value_type = self._val.type.template_argument(0)
+ if self._value_type.tag is not None:
+ typ = strip_versioned_namespace(self._value_type.tag)
+ if (typ.startswith('std::shared_ptr<')
+ or typ.startswith('std::weak_ptr<')):
+ impl = val['_M_impl']
+ self._shptr_printer = SharedPointerPrinter(typename, impl)
+ self.children = self._shptr_children
+
+ def _shptr_children(self):
+ return SmartPtrIterator(self._shptr_printer._pointer)
+
+ def to_string(self):
+ if self._shptr_printer is not None:
+ return self._shptr_printer.to_string()
+
+ if self._value_type.code == gdb.TYPE_CODE_INT:
+ val = self._val['_M_i']
+ elif self._value_type.code == gdb.TYPE_CODE_FLT:
+ val = self._val['_M_fp']
+ elif self._value_type.code == gdb.TYPE_CODE_PTR:
+ val = self._val['_M_b']['_M_p']
+ elif self._value_type.code == gdb.TYPE_CODE_BOOL:
+ val = self._val['_M_base']['_M_i']
+ else:
+ val = self._val['_M_i']
+ return '%s<%s> = { %s }' % (self._typename, str(self._value_type), val)
+
+
+class StdFormatArgsPrinter(printer_base):
+ """Print a std::basic_format_args."""
+ # TODO: add printer for basic_format_arg<Context> and print out children.
+ # TODO: add printer for __format::_ArgStore<Context, Args...>.
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ targs = get_template_arg_list(self._val.type)
+ char_type = get_template_arg_list(targs[0])[1]
+ if char_type == gdb.lookup_type('char'):
+ typ = 'std::format_args'
+ elif char_type == gdb.lookup_type('wchar_t'):
+ typ = 'std::wformat_args'
+ else:
+ typ = 'std::basic_format_args'
+
+ size = self._val['_M_packed_size']
+ if size == 1:
+ return "%s with 1 argument" % (typ)
+ if size == 0:
+ size = self._val['_M_unpacked_size']
+ return "%s with %d arguments" % (typ, size)
+
+
+class StdChronoDurationPrinter(printer_base):
+ """Print a std::chrono::duration."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def _ratio(self):
+ # TODO use reduced period i.e. duration::period
+ period = self._val.type.template_argument(1)
+ num = period.template_argument(0)
+ den = period.template_argument(1)
+ return (num, den)
+
+ def _suffix(self):
+ num, den = self._ratio()
+ if num == 1:
+ if den == 1:
+ return 's'
+ if den == 1000:
+ return 'ms'
+ if den == 1000000:
+ return 'us'
+ if den == 1000000000:
+ return 'ns'
+ elif den == 1:
+ if num == 60:
+ return 'min'
+ if num == 3600:
+ return 'h'
+ if num == 86400:
+ return 'd'
+ return '[{}]s'.format(num)
+ return "[{}/{}]s".format(num, den)
+
+ def to_string(self):
+ r = self._val['__r']
+ if r.type.strip_typedefs().code == gdb.TYPE_CODE_FLT:
+ r = "%g" % r
+ return "std::chrono::duration = {{ {}{} }}".format(r, self._suffix())
+
+
+class StdChronoTimePointPrinter(printer_base):
+ """Print a std::chrono::time_point."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def _clock(self):
+ clock = self._val.type.template_argument(0)
+ name = strip_versioned_namespace(clock.name)
+ if name == 'std::chrono::_V2::system_clock' \
+ or name == 'std::chrono::system_clock':
+ return ('std::chrono::sys_time', 0)
+ # XXX need to remove leap seconds from utc, gps, and tai
+ if name == 'std::chrono::utc_clock':
+ return ('std::chrono::utc_time', None) # XXX
+ if name == 'std::chrono::gps_clock':
+ return ('std::chrono::gps_time', None) # XXX 315964809
+ if name == 'std::chrono::tai_clock':
+ return ('std::chrono::tai_time', None) # XXX -378691210
+ if name == 'std::filesystem::__file_clock':
+ return ('std::chrono::file_time', 6437664000)
+ if name == 'std::chrono::local_t':
+ return ('std::chrono::local_time', 0)
+ return ('{} time_point'.format(name), None)
+
+ def to_string(self, abbrev=False):
+ clock, offset = self._clock()
+ d = self._val['__d']
+ r = d['__r']
+ printer = StdChronoDurationPrinter(d.type.name, d)
+ suffix = printer._suffix()
+ time = ''
+ if offset is not None:
+ num, den = printer._ratio()
+ secs = (r * num / den) + offset
+ try:
+ dt = datetime.datetime.fromtimestamp(secs, _utc_timezone)
+ time = ' [{:%Y-%m-%d %H:%M:%S}]'.format(dt)
+ except:
+ pass
+ s = '%d%s%s' % (r, suffix, time)
+ if abbrev:
+ return s
+ return '%s = { %s }' % (clock, s)
+
+
+class StdChronoZonedTimePrinter(printer_base):
+ """Print a std::chrono::zoned_time."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ zone = self._val['_M_zone'].dereference()['_M_name']
+ time = self._val['_M_tp']
+ printer = StdChronoTimePointPrinter(time.type.name, time)
+ time = printer.to_string(True)
+ return 'std::chrono::zoned_time = {{ {} {} }}'.format(zone, time)
+
+
+months = [None, 'January', 'February', 'March', 'April', 'May', 'June',
+ 'July', 'August', 'September', 'October', 'November', 'December']
+
+weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
+ 'Saturday', 'Sunday']
+
+
+class StdChronoCalendarPrinter(printer_base):
+ """Print a std::chrono::day, std::chrono::month, std::chrono::year etc."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ val = self._val
+ typ = self._typename
+ if 'month' in typ and typ != 'std::chrono::year_month_day_last':
+ m = val['_M_m']
+ if typ.startswith('std::chrono::year'):
+ y = val['_M_y']
+
+ if typ == 'std::chrono::day':
+ return '{}'.format(int(val['_M_d']))
+ if typ == 'std::chrono::month':
+ if m < 1 or m >= len(months):
+ return "%d is not a valid month" % m
+ return months[m]
+ if typ == 'std::chrono::year':
+ return '{}y'.format(y)
+ if typ == 'std::chrono::weekday':
+ wd = val['_M_wd']
+ if wd < 0 or wd >= len(weekdays):
+ return "%d is not a valid weekday" % wd
+ return '{}'.format(weekdays[wd])
+ if typ == 'std::chrono::weekday_indexed':
+ return '{}[{}]'.format(val['_M_wd'], int(val['_M_index']))
+ if typ == 'std::chrono::weekday_last':
+ return '{}[last]'.format(val['_M_wd'])
+ if typ == 'std::chrono::month_day':
+ return '{}/{}'.format(m, val['_M_d'])
+ if typ == 'std::chrono::month_day_last':
+ return '{}/last'.format(m)
+ if typ == 'std::chrono::month_weekday':
+ return '{}/{}'.format(m, val['_M_wdi'])
+ if typ == 'std::chrono::month_weekday_last':
+ return '{}/{}'.format(m, val['_M_wdl'])
+ if typ == 'std::chrono::year_month':
+ return '{}/{}'.format(y, m)
+ if typ == 'std::chrono::year_month_day':
+ return '{}/{}/{}'.format(y, m, val['_M_d'])
+ if typ == 'std::chrono::year_month_day_last':
+ return '{}/{}'.format(y, val['_M_mdl'])
+ if typ == 'std::chrono::year_month_weekday':
+ return '{}/{}/{}'.format(y, m, val['_M_wdi'])
+ if typ == 'std::chrono::year_month_weekday_last':
+ return '{}/{}/{}'.format(y, m, val['_M_wdl'])
+ if typ.startswith('std::chrono::hh_mm_ss'):
+ fract = ''
+ if val['fractional_width'] != 0:
+ fract = '.{:0{}d}'.format(int(val['_M_ss']['_M_r']),
+ int(val['fractional_width']))
+ h = int(val['_M_h']['__r'])
+ m = int(val['_M_m']['__r'])
+ s = int(val['_M_s']['__r'])
+ if val['_M_is_neg']:
+ h = -h
+ return '{:02}:{:02}:{:02}{}'.format(h, m, s, fract)
+
+
+class StdChronoTimeZonePrinter(printer_base):
+ """Print a chrono::time_zone or chrono::time_zone_link."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ str = '%s = %s' % (self._typename, self._val['_M_name'])
+ if self._typename.endswith("_link"):
+ str += ' -> %s' % (self._val['_M_target'])
+ return str
+
+
+class StdChronoLeapSecondPrinter(printer_base):
+ """Print a chrono::leap_second."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ date = self._val['_M_s']['__r']
+ neg = '+-'[date < 0]
+ return '%s %d (%c)' % (self._typename, abs(date), neg)
+
+
+class StdChronoTzdbPrinter(printer_base):
+ """Print a chrono::tzdb."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ return '%s %s' % (self._typename, self._val['version'])
+
+
+class StdChronoTimeZoneRulePrinter(printer_base):
+ """Print a chrono::time_zone rule."""
+
+ def __init__(self, typename, val):
+ self._typename = strip_versioned_namespace(typename)
+ self._val = val
+
+ def to_string(self):
+ on = self._val['on']
+ kind = on['kind']
+ month = months[on['month']]
+ suffixes = {1: 'st', 2: 'nd', 3: 'rd',
+ 21: 'st', 22: 'nd', 23: 'rd', 31: 'st'}
+ day = on['day_of_month']
+ ordinal_day = '{}{}'.format(day, suffixes.get(day, 'th'))
+ if kind == 0: # DayOfMonth
+ start = '{} {}'.format(month, ordinal_day)
+ else:
+ weekday = weekdays[on['day_of_week']]
+ if kind == 1: # LastWeekDay
+ start = 'last {} in {}'.format(weekday, month)
+ else:
+ if kind == 2: # LessEq
+ direction = ('last', '<=')
+ else:
+ direction = ('first', '>=')
+ day = on['day_of_month']
+ start = '{} {} {} {} {}'.format(direction[0], weekday,
+ direction[1], month,
+ ordinal_day)
+ return 'time_zone rule {} from {} to {} starting on {}'.format(
+ self._val['name'], self._val['from'], self._val['to'], start)
+
+
+class StdLocalePrinter(printer_base):
+ """Print a std::locale."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+
+ def to_string(self):
+ names = self._val['_M_impl']['_M_names']
+ mod = ''
+ if names[0] == 0:
+ name = '*'
+ else:
+ cats = gdb.parse_and_eval(self._typename + '::_S_categories')
+ ncat = gdb.parse_and_eval(self._typename + '::_S_categories_size')
+ n = names[0].string()
+ cat = cats[0].string()
+ name = '{}={}'.format(cat, n)
+ cat_names = {cat: n}
+ i = 1
+ while i < ncat and names[i] != 0:
+ n = names[i].string()
+ cat = cats[i].string()
+ name = '{};{}={}'.format(name, cat, n)
+ cat_names[cat] = n
+ i = i + 1
+ uniq_names = set(cat_names.values())
+ if len(uniq_names) == 1:
+ name = n
+ elif len(uniq_names) == 2:
+ n1, n2 = (uniq_names)
+ name_list = list(cat_names.values())
+ other = None
+ if name_list.count(n1) == 1:
+ name = n2
+ other = n1
+ elif name_list.count(n2) == 1:
+ name = n1
+ other = n2
+ if other is not None:
+ cat = next(c for c, n in cat_names.items() if n == other)
+ mod = ' with "{}={}"'.format(cat, other)
+ return 'std::locale = "{}"{}'.format(name, mod)
+
+class StdIntegralConstantPrinter(printer_base):
+ """Print a std::true_type or std::false_type."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+
+ def to_string(self):
+ value_type = self._val.type.template_argument(0)
+ value = self._val.type.template_argument(1)
+ if value_type.code == gdb.TYPE_CODE_BOOL:
+ if value:
+ return "std::true_type"
+ else:
+ return "std::false_type"
+ typename = strip_versioned_namespace(self._typename)
+ return "{}<{}, {}>".format(typename, value_type, value)
+
+class StdTextEncodingPrinter(printer_base):
+ """Print a std::text_encoding."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+
+ def to_string(self):
+ rep = self._val['_M_rep'].dereference()
+ if rep['_M_id'] == 1:
+ return self._val['_M_name']
+ if rep['_M_id'] == 2:
+ return 'unknown'
+ return rep['_M_name']
+
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
class RxPrinter(object):
def __init__(self, name, function):
super(RxPrinter, self).__init__()
self.name = name
- self.function = function
+ self._function = function
self.enabled = True
def invoke(self, value):
@@ -1315,36 +2360,40 @@ class RxPrinter(object):
return None
if value.type.code == gdb.TYPE_CODE_REF:
- if hasattr(gdb.Value,"referenced_value"):
+ if hasattr(gdb.Value, "referenced_value"):
value = value.referenced_value()
- return self.function(self.name, value)
+ return self._function(self.name, value)
# A pretty-printer that conforms to the "PrettyPrinter" protocol from
# gdb.printing. It can also be used directly as an old-style printer.
+
+
class Printer(object):
def __init__(self, name):
super(Printer, self).__init__()
self.name = name
- self.subprinters = []
- self.lookup = {}
+ self._subprinters = []
+ self._lookup = {}
self.enabled = True
- self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
+ self._compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
def add(self, name, function):
# A small sanity check.
# FIXME
- if not self.compiled_rx.match(name):
- raise ValueError('libstdc++ programming error: "%s" does not match' % name)
+ if not self._compiled_rx.match(name):
+ raise ValueError(
+ 'libstdc++ programming error: "%s" does not match' % name)
printer = RxPrinter(name, function)
- self.subprinters.append(printer)
- self.lookup[name] = printer
+ self._subprinters.append(printer)
+ self._lookup[name] = printer
# Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
def add_version(self, base, name, function):
self.add(base + name, function)
- if _versioned_namespace:
- vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % _versioned_namespace, base)
+ if '__cxx11' not in base:
+ vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' %
+ _versioned_namespace, base)
self.add(vbase + name, function)
# Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
@@ -1356,10 +2405,10 @@ class Printer(object):
def get_basic_type(type):
# If it points to a reference, get the reference.
if type.code == gdb.TYPE_CODE_REF:
- type = type.target ()
+ type = type.target()
# Get the unqualified type, stripped of typedefs.
- type = type.unqualified ().strip_typedefs ()
+ type = type.unqualified().strip_typedefs()
return type.tag
@@ -1370,47 +2419,49 @@ class Printer(object):
# All the types we match are template types, so we can use a
# dictionary.
- match = self.compiled_rx.match(typename)
+ match = self._compiled_rx.match(typename)
if not match:
return None
basename = match.group(1)
if val.type.code == gdb.TYPE_CODE_REF:
- if hasattr(gdb.Value,"referenced_value"):
+ if hasattr(gdb.Value, "referenced_value"):
val = val.referenced_value()
- if basename in self.lookup:
- return self.lookup[basename].invoke(val)
+ if basename in self._lookup:
+ return self._lookup[basename].invoke(val)
# Cannot find a pretty printer. Return None.
return None
+
libstdcxx_printer = None
+
class TemplateTypePrinter(object):
- r"""
+ """
A type printer for class templates with default template arguments.
Recognizes specializations of class templates and prints them without
any template arguments that use a default template argument.
Type printers are recursively applied to the template arguments.
- e.g. replace "std::vector<T, std::allocator<T> >" with "std::vector<T>".
+ e.g. replace 'std::vector<T, std::allocator<T> >' with 'std::vector<T>'.
"""
def __init__(self, name, defargs):
self.name = name
- self.defargs = defargs
+ self._defargs = defargs
self.enabled = True
class _recognizer(object):
- "The recognizer class for TemplateTypePrinter."
+ """The recognizer class for TemplateTypePrinter."""
def __init__(self, name, defargs):
self.name = name
- self.defargs = defargs
- # self.type_obj = None
+ self._defargs = defargs
+ # self._type_obj = None
def recognize(self, type_obj):
"""
@@ -1433,7 +2484,7 @@ class TemplateTypePrinter(object):
# The actual template argument in the type:
targ = template_args[n]
# The default template argument for the class template:
- defarg = self.defargs.get(n)
+ defarg = self._defargs.get(n)
if defarg is not None:
# Substitute other template arguments into the default:
defarg = defarg.format(*template_args)
@@ -1470,7 +2521,7 @@ class TemplateTypePrinter(object):
if type_obj.code == gdb.TYPE_CODE_ARRAY:
type_str = self._recognize_subtype(type_obj.target())
if str(type_obj.strip_typedefs()).endswith('[]'):
- return type_str + '[]' # array of unknown bound
+ return type_str + '[]' # array of unknown bound
return "%s[%d]" % (type_str, type_obj.range()[1] + 1)
if type_obj.code == gdb.TYPE_CODE_REF:
return self._recognize_subtype(type_obj.target()) + '&'
@@ -1479,17 +2530,18 @@ class TemplateTypePrinter(object):
return self._recognize_subtype(type_obj.target()) + '&&'
type_str = gdb.types.apply_type_recognizers(
- gdb.types.get_type_recognizers(), type_obj)
+ gdb.types.get_type_recognizers(), type_obj)
if type_str:
return type_str
return str(type_obj)
def instantiate(self):
- "Return a recognizer object for this type printer."
- return self._recognizer(self.name, self.defargs)
+ """Return a recognizer object for this type printer."""
+ return self._recognizer(self.name, self._defargs)
+
def add_one_template_type_printer(obj, name, defargs):
- r"""
+ """
Add a type printer for a class template with default template arguments.
Args:
@@ -1503,78 +2555,121 @@ def add_one_template_type_printer(obj, name, defargs):
{ 2: 'std::hash<{0}>',
3: 'std::equal_to<{0}>',
4: 'std::allocator<std::pair<const {0}, {1}> >' }
-
"""
- printer = TemplateTypePrinter('std::'+name, defargs)
+ printer = TemplateTypePrinter('std::' + name, defargs)
+ gdb.types.register_type_printer(obj, printer)
+
+ # Add type printer for same type in debug namespace:
+ printer = TemplateTypePrinter('std::__debug::' + name, defargs)
gdb.types.register_type_printer(obj, printer)
- if _versioned_namespace:
+
+ if '__cxx11' not in name:
# Add second type printer for same type in versioned namespace:
ns = 'std::' + _versioned_namespace
# PR 86112 Cannot use dict comprehension here:
- defargs = dict((n, d.replace('std::', ns)) for (n,d) in defargs.items())
- printer = TemplateTypePrinter(ns+name, defargs)
+ defargs = dict((n, d.replace('std::', ns))
+ for (n, d) in defargs.items())
+ printer = TemplateTypePrinter(ns + name, defargs)
+ gdb.types.register_type_printer(obj, printer)
+
+ # Add type printer for same type in debug namespace:
+ printer = TemplateTypePrinter('std::__debug::' + name, defargs)
gdb.types.register_type_printer(obj, printer)
+
class FilteringTypePrinter(object):
- r"""
+ """
A type printer that uses typedef names for common template specializations.
Args:
- match (str): The class template to recognize.
+ template (str): The class template to recognize.
name (str): The typedef-name that will be used instead.
+ targ1 (str, optional): The first template argument. Defaults to None.
- Checks if a specialization of the class template 'match' is the same type
+ Checks if a specialization of the class template 'template' is the same type
as the typedef 'name', and prints it as 'name' instead.
e.g. if an instantiation of std::basic_istream<C, T> is the same type as
std::istream then print it as std::istream.
+
+ If targ1 is provided (not None), match only template specializations with
+ this type as the first template argument, e.g. if template='basic_string'
+ and targ1='char' then only match 'basic_string<char,...>' and not
+ 'basic_string<wchar_t,...>'. This rejects non-matching specializations
+ more quickly, without needing to do GDB type lookups.
"""
- def __init__(self, match, name):
- self.match = match
+ def __init__(self, template, name, targ1=None):
+ self._template = template
self.name = name
+ self._targ1 = targ1
self.enabled = True
class _recognizer(object):
- "The recognizer class for TemplateTypePrinter."
+ """The recognizer class for FilteringTypePrinter."""
- def __init__(self, match, name):
- self.match = match
+ def __init__(self, template, name, targ1):
+ self._template = template
self.name = name
- self.type_obj = None
+ self._targ1 = targ1
+ self._type_obj = None
def recognize(self, type_obj):
"""
- If type_obj starts with self.match and is the same type as
+ If type_obj starts with self._template and is the same type as
self.name then return self.name, otherwise None.
"""
if type_obj.tag is None:
return None
- if self.type_obj is None:
- if not type_obj.tag.startswith(self.match):
+ if self._type_obj is None:
+ if self._targ1 is not None:
+ s = '{}<{}'.format(self._template, self._targ1)
+ if not type_obj.tag.startswith(s):
+ # Filter didn't match.
+ return None
+ elif not type_obj.tag.startswith(self._template):
# Filter didn't match.
return None
+
try:
- self.type_obj = gdb.lookup_type(self.name).strip_typedefs()
+ self._type_obj = gdb.lookup_type(
+ self.name).strip_typedefs()
except:
pass
- if self.type_obj == type_obj:
+
+ if self._type_obj is None:
+ return None
+
+ t1 = gdb.types.get_basic_type(self._type_obj)
+ t2 = gdb.types.get_basic_type(type_obj)
+ if t1 == t2:
return strip_inline_namespaces(self.name)
+
+ # Workaround ambiguous typedefs matching both std:: and
+ # std::__cxx11:: symbols.
+ if self._template.split('::')[-1] == 'basic_string':
+ s1 = self._type_obj.tag.replace('__cxx11::', '')
+ s2 = type_obj.tag.replace('__cxx11::', '')
+ if s1 == s2:
+ return strip_inline_namespaces(self.name)
+
return None
def instantiate(self):
- "Return a recognizer object for this type printer."
- return self._recognizer(self.match, self.name)
+ """Return a recognizer object for this type printer."""
+ return self._recognizer(self._template, self.name, self._targ1)
-def add_one_type_printer(obj, match, name):
- printer = FilteringTypePrinter('std::' + match, 'std::' + name)
+
+def add_one_type_printer(obj, template, name, targ1=None):
+ printer = FilteringTypePrinter('std::' + template, 'std::' + name, targ1)
gdb.types.register_type_printer(obj, printer)
- if _versioned_namespace:
+ if '__cxx11' not in template:
ns = 'std::' + _versioned_namespace
- printer = FilteringTypePrinter(ns + match, ns + name)
+ printer = FilteringTypePrinter(ns + template, ns + name, targ1)
gdb.types.register_type_printer(obj, printer)
+
def register_type_printers(obj):
global _use_type_printing
@@ -1582,29 +2677,39 @@ def register_type_printers(obj):
return
# Add type printers for typedefs std::string, std::wstring etc.
- for ch in ('', 'w', 'u16', 'u32'):
- add_one_type_printer(obj, 'basic_string', ch + 'string')
+ for ch in (('', 'char'),
+ ('w', 'wchar_t'),
+ ('u8', 'char8_t'),
+ ('u16', 'char16_t'),
+ ('u32', 'char32_t')):
+ add_one_type_printer(obj, 'basic_string', ch[0] + 'string', ch[1])
+ add_one_type_printer(obj, '__cxx11::basic_string',
+ ch[0] + 'string', ch[1])
+ # Typedefs for __cxx11::basic_string used to be in namespace __cxx11:
add_one_type_printer(obj, '__cxx11::basic_string',
- '__cxx11::' + ch + 'string')
- add_one_type_printer(obj, 'basic_string_view', ch + 'string_view')
+ '__cxx11::' + ch[0] + 'string', ch[1])
+ add_one_type_printer(obj, 'basic_string_view',
+ ch[0] + 'string_view', ch[1])
# Add type printers for typedefs std::istream, std::wistream etc.
- for ch in ('', 'w'):
+ for ch in (('', 'char'), ('w', 'wchar_t')):
for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream',
'filebuf', 'ifstream', 'ofstream', 'fstream'):
- add_one_type_printer(obj, 'basic_' + x, ch + x)
+ add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1])
for x in ('stringbuf', 'istringstream', 'ostringstream',
'stringstream'):
- add_one_type_printer(obj, 'basic_' + x, ch + x)
- # <sstream> types are in __cxx11 namespace, but typedefs aren'x:
- add_one_type_printer(obj, '__cxx11::basic_' + x, ch + x)
+ add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1])
+ # <sstream> types are in __cxx11 namespace, but typedefs aren't:
+ add_one_type_printer(obj, '__cxx11::basic_' + x, ch[0] + x, ch[1])
# Add type printers for typedefs regex, wregex, cmatch, wcmatch etc.
for abi in ('', '__cxx11::'):
- for ch in ('', 'w'):
- add_one_type_printer(obj, abi + 'basic_regex', abi + ch + 'regex')
+ for ch in (('', 'char'), ('w', 'wchar_t')):
+ add_one_type_printer(obj, abi + 'basic_regex',
+ abi + ch[0] + 'regex', ch[1])
for ch in ('c', 's', 'wc', 'ws'):
- add_one_type_printer(obj, abi + 'match_results', abi + ch + 'match')
+ add_one_type_printer(
+ obj, abi + 'match_results', abi + ch + 'match')
for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'):
add_one_type_printer(obj, abi + x, abi + ch + x)
@@ -1613,9 +2718,9 @@ def register_type_printers(obj):
add_one_type_printer(obj, 'fpos', 'streampos')
# Add type printers for <chrono> typedefs.
- for dur in ('nanoseconds', 'microseconds', 'milliseconds',
- 'seconds', 'minutes', 'hours'):
- add_one_type_printer(obj, 'duration', dur)
+ for dur in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds',
+ 'minutes', 'hours', 'days', 'weeks', 'years', 'months'):
+ add_one_type_printer(obj, 'chrono::duration', 'chrono::' + dur)
# Add type printers for <random> typedefs.
add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
@@ -1630,47 +2735,54 @@ def register_type_printers(obj):
# Add type printers for experimental::basic_string_view typedefs.
ns = 'experimental::fundamentals_v1::'
- for ch in ('', 'w', 'u16', 'u32'):
+ for ch in (('', 'char'),
+ ('w', 'wchar_t'),
+ ('u8', 'char8_t'),
+ ('u16', 'char16_t'),
+ ('u32', 'char32_t')):
add_one_type_printer(obj, ns + 'basic_string_view',
- ns + ch + 'string_view')
+ ns + ch[0] + 'string_view', ch[1])
# Do not show defaulted template arguments in class templates.
add_one_template_type_printer(obj, 'unique_ptr',
- { 1: 'std::default_delete<{0}>' })
- add_one_template_type_printer(obj, 'deque', { 1: 'std::allocator<{0}>'})
- add_one_template_type_printer(obj, 'forward_list', { 1: 'std::allocator<{0}>'})
- add_one_template_type_printer(obj, 'list', { 1: 'std::allocator<{0}>'})
- add_one_template_type_printer(obj, '__cxx11::list', { 1: 'std::allocator<{0}>'})
- add_one_template_type_printer(obj, 'vector', { 1: 'std::allocator<{0}>'})
+ {1: 'std::default_delete<{0}>'})
+ add_one_template_type_printer(obj, 'deque', {1: 'std::allocator<{0}>'})
+ add_one_template_type_printer(
+ obj, 'forward_list', {1: 'std::allocator<{0}>'})
+ add_one_template_type_printer(obj, 'list', {1: 'std::allocator<{0}>'})
+ add_one_template_type_printer(
+ obj, '__cxx11::list', {1: 'std::allocator<{0}>'})
+ add_one_template_type_printer(obj, 'vector', {1: 'std::allocator<{0}>'})
add_one_template_type_printer(obj, 'map',
- { 2: 'std::less<{0}>',
- 3: 'std::allocator<std::pair<{0} const, {1}>>' })
+ {2: 'std::less<{0}>',
+ 3: 'std::allocator<std::pair<{0} const, {1}>>'})
add_one_template_type_printer(obj, 'multimap',
- { 2: 'std::less<{0}>',
- 3: 'std::allocator<std::pair<{0} const, {1}>>' })
+ {2: 'std::less<{0}>',
+ 3: 'std::allocator<std::pair<{0} const, {1}>>'})
add_one_template_type_printer(obj, 'set',
- { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
+ {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'})
add_one_template_type_printer(obj, 'multiset',
- { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
+ {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'})
add_one_template_type_printer(obj, 'unordered_map',
- { 2: 'std::hash<{0}>',
- 3: 'std::equal_to<{0}>',
- 4: 'std::allocator<std::pair<{0} const, {1}>>'})
+ {2: 'std::hash<{0}>',
+ 3: 'std::equal_to<{0}>',
+ 4: 'std::allocator<std::pair<{0} const, {1}>>'})
add_one_template_type_printer(obj, 'unordered_multimap',
- { 2: 'std::hash<{0}>',
- 3: 'std::equal_to<{0}>',
- 4: 'std::allocator<std::pair<{0} const, {1}>>'})
+ {2: 'std::hash<{0}>',
+ 3: 'std::equal_to<{0}>',
+ 4: 'std::allocator<std::pair<{0} const, {1}>>'})
add_one_template_type_printer(obj, 'unordered_set',
- { 1: 'std::hash<{0}>',
- 2: 'std::equal_to<{0}>',
- 3: 'std::allocator<{0}>'})
+ {1: 'std::hash<{0}>',
+ 2: 'std::equal_to<{0}>',
+ 3: 'std::allocator<{0}>'})
add_one_template_type_printer(obj, 'unordered_multiset',
- { 1: 'std::hash<{0}>',
- 2: 'std::equal_to<{0}>',
- 3: 'std::allocator<{0}>'})
+ {1: 'std::hash<{0}>',
+ 2: 'std::equal_to<{0}>',
+ 3: 'std::allocator<{0}>'})
-def register_libstdcxx_printers (obj):
- "Register libstdc++ pretty-printers with objfile Obj."
+
+def register_libstdcxx_printers(obj):
+ """Register libstdc++ pretty-printers with objfile Obj."""
global _use_gdb_pp
global libstdcxx_printer
@@ -1684,7 +2796,8 @@ def register_libstdcxx_printers (obj):
register_type_printers(obj)
-def build_libstdcxx_dictionary ():
+
+def build_libstdcxx_dictionary():
global libstdcxx_printer
libstdcxx_printer = Printer("libstdc++-v6")
@@ -1693,7 +2806,8 @@ def build_libstdcxx_dictionary ():
# In order from:
# http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter)
- libstdcxx_printer.add_version('std::__cxx11::', 'basic_string', StdStringPrinter)
+ libstdcxx_printer.add_version(
+ 'std::__cxx11::', 'basic_string', StdStringPrinter)
libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter)
libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter)
libstdcxx_printer.add_container('std::', 'list', StdListPrinter)
@@ -1711,6 +2825,18 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter)
libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter)
# vector<bool>
+ libstdcxx_printer.add_version('std::', 'locale', StdLocalePrinter)
+
+ libstdcxx_printer.add_version('std::', 'integral_constant',
+ StdIntegralConstantPrinter)
+ libstdcxx_printer.add_version('std::', 'text_encoding',
+ StdTextEncodingPrinter)
+
+ if hasattr(gdb.Value, 'dynamic_type'):
+ libstdcxx_printer.add_version('std::', 'error_code',
+ StdErrorCodePrinter)
+ libstdcxx_printer.add_version('std::', 'error_condition',
+ StdErrorCodePrinter)
# Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter)
@@ -1719,12 +2845,7 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add('std::__debug::map', StdMapPrinter)
libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter)
libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter)
- libstdcxx_printer.add('std::__debug::priority_queue',
- StdStackOrQueuePrinter)
- libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter)
libstdcxx_printer.add('std::__debug::set', StdSetPrinter)
- libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter)
- libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter)
libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter)
# These are the TR1 and C++11 printers.
@@ -1742,8 +2863,10 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_container('std::', 'forward_list',
StdForwardListPrinter)
- libstdcxx_printer.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter)
- libstdcxx_printer.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter)
+ libstdcxx_printer.add_version(
+ 'std::tr1::', 'shared_ptr', SharedPointerPrinter)
+ libstdcxx_printer.add_version(
+ 'std::tr1::', 'weak_ptr', SharedPointerPrinter)
libstdcxx_printer.add_version('std::tr1::', 'unordered_map',
Tr1UnorderedMapPrinter)
libstdcxx_printer.add_version('std::tr1::', 'unordered_set',
@@ -1753,6 +2876,28 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset',
Tr1UnorderedSetPrinter)
+ libstdcxx_printer.add_version('std::', 'initializer_list',
+ StdInitializerListPrinter)
+ libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter)
+ libstdcxx_printer.add_version(
+ 'std::', 'basic_stringbuf', StdStringBufPrinter)
+ libstdcxx_printer.add_version(
+ 'std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter)
+ for sstream in ('istringstream', 'ostringstream', 'stringstream'):
+ libstdcxx_printer.add_version(
+ 'std::', 'basic_' + sstream, StdStringStreamPrinter)
+ libstdcxx_printer.add_version(
+ 'std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter)
+
+ libstdcxx_printer.add_version('std::chrono::', 'duration',
+ StdChronoDurationPrinter)
+ libstdcxx_printer.add_version('std::chrono::', 'time_point',
+ StdChronoTimePointPrinter)
+
+ # std::regex components
+ libstdcxx_printer.add_version('std::__detail::', '_State',
+ StdRegexStatePrinter)
+
# These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases.
# The tr1 namespace containers do not have any debug equivalents,
# so do not register printers for them.
@@ -1780,9 +2925,9 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
'path', StdExpPathPrinter)
libstdcxx_printer.add_version('std::filesystem::',
- 'path', StdExpPathPrinter)
+ 'path', StdPathPrinter)
libstdcxx_printer.add_version('std::filesystem::__cxx11::',
- 'path', StdExpPathPrinter)
+ 'path', StdPathPrinter)
# C++17 components
libstdcxx_printer.add_version('std::',
@@ -1796,6 +2941,33 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add_version('std::',
'_Node_handle', StdNodeHandlePrinter)
+ # C++20 components
+ libstdcxx_printer.add_version(
+ 'std::', 'partial_ordering', StdCmpCatPrinter)
+ libstdcxx_printer.add_version('std::', 'weak_ordering', StdCmpCatPrinter)
+ libstdcxx_printer.add_version('std::', 'strong_ordering', StdCmpCatPrinter)
+ libstdcxx_printer.add_version('std::', 'span', StdSpanPrinter)
+ libstdcxx_printer.add_version('std::', 'basic_format_args',
+ StdFormatArgsPrinter)
+ for c in ['day', 'month', 'year', 'weekday', 'weekday_indexed', 'weekday_last',
+ 'month_day', 'month_day_last', 'month_weekday', 'month_weekday_last',
+ 'year_month', 'year_month_day', 'year_month_day_last',
+ 'year_month_weekday', 'year_month_weekday_last', 'hh_mm_ss']:
+ libstdcxx_printer.add_version('std::chrono::', c,
+ StdChronoCalendarPrinter)
+ libstdcxx_printer.add_version('std::chrono::', 'time_zone',
+ StdChronoTimeZonePrinter)
+ libstdcxx_printer.add_version('std::chrono::', 'time_zone_link',
+ StdChronoTimeZonePrinter)
+ libstdcxx_printer.add_version('std::chrono::', 'zoned_time',
+ StdChronoZonedTimePrinter)
+ libstdcxx_printer.add_version('std::chrono::', 'leap_second',
+ StdChronoLeapSecondPrinter)
+ libstdcxx_printer.add_version(
+ 'std::chrono::', 'tzdb', StdChronoTzdbPrinter)
+ # libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule',
+ # StdChronoTimeZoneRulePrinter)
+
# Extensions.
libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter)
@@ -1816,6 +2988,12 @@ def build_libstdcxx_dictionary ():
StdDequeIteratorPrinter)
libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator',
StdVectorIteratorPrinter)
+ libstdcxx_printer.add_container('std::', '_Bit_iterator',
+ StdBitIteratorPrinter)
+ libstdcxx_printer.add_container('std::', '_Bit_const_iterator',
+ StdBitIteratorPrinter)
+ libstdcxx_printer.add_container('std::', '_Bit_reference',
+ StdBitReferencePrinter)
libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator',
StdSlistIteratorPrinter)
libstdcxx_printer.add_container('std::', '_Fwd_list_iterator',
@@ -1828,4 +3006,5 @@ def build_libstdcxx_dictionary ():
libstdcxx_printer.add('__gnu_debug::_Safe_iterator',
StdDebugIteratorPrinter)
-build_libstdcxx_dictionary ()
+
+build_libstdcxx_dictionary()
diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
index 12fefdb041c..436c866e001 100644
--- a/libstdc++-v3/python/libstdcxx/v6/xmethods.py
+++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
@@ -1,6 +1,6 @@
# Xmethods for libstdc++.
-# Copyright (C) 2014-2018 Free Software Foundation, Inc.
+# Copyright (C) 2014-2024 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,12 +21,27 @@ import re
matcher_name_prefix = 'libstdc++::'
+
def get_bool_type():
return gdb.lookup_type('bool')
def get_std_size_type():
return gdb.lookup_type('std::size_t')
+_versioned_namespace = '__8::'
+
+def is_specialization_of(x, template_name):
+ """
+ Test whether a type is a specialization of the named class template.
+ The type can be specified as a string or a gdb.Type object.
+ The template should be the name of a class template as a string,
+ without any 'std' qualification.
+ """
+ if isinstance(x, gdb.Type):
+ x = x.tag
+ template_name = '(%s)?%s' % (_versioned_namespace, template_name)
+ return re.match(r'^std::(__\d::)?%s<.*>$' % template_name, x) is not None
+
class LibStdCxxXMethod(gdb.xmethod.XMethod):
def __init__(self, name, worker_class):
gdb.xmethod.XMethod.__init__(self, name)
@@ -34,6 +49,7 @@ class LibStdCxxXMethod(gdb.xmethod.XMethod):
# Xmethods for std::array
+
class ArrayWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type, size):
self._val_type = val_type
@@ -43,6 +59,7 @@ class ArrayWorkerBase(gdb.xmethod.XMethodWorker):
nullptr = gdb.parse_and_eval('(void *) 0')
return nullptr.cast(self._val_type.pointer()).dereference()
+
class ArraySizeWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
@@ -56,6 +73,7 @@ class ArraySizeWorker(ArrayWorkerBase):
def __call__(self, obj):
return self._size
+
class ArrayEmptyWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
@@ -69,6 +87,7 @@ class ArrayEmptyWorker(ArrayWorkerBase):
def __call__(self, obj):
return (int(self._size) == 0)
+
class ArrayFrontWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
@@ -85,6 +104,7 @@ class ArrayFrontWorker(ArrayWorkerBase):
else:
return self.null_value()
+
class ArrayBackWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
@@ -101,6 +121,7 @@ class ArrayBackWorker(ArrayWorkerBase):
else:
return self.null_value()
+
class ArrayAtWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
@@ -117,6 +138,7 @@ class ArrayAtWorker(ArrayWorkerBase):
((int(index), self._size)))
return obj['_M_elems'][index]
+
class ArraySubscriptWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
@@ -133,6 +155,7 @@ class ArraySubscriptWorker(ArrayWorkerBase):
else:
return self.null_value()
+
class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
@@ -148,7 +171,7 @@ class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?array<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, 'array'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -160,24 +183,34 @@ class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
return None
return method.worker_class(value_type, size)
+
# Xmethods for std::deque
+
class DequeWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type):
self._val_type = val_type
self._bufsize = 512 // val_type.sizeof or 1
def size(self, obj):
- first_node = obj['_M_impl']['_M_start']['_M_node']
- last_node = obj['_M_impl']['_M_finish']['_M_node']
- cur = obj['_M_impl']['_M_finish']['_M_cur']
- first = obj['_M_impl']['_M_finish']['_M_first']
- return (last_node - first_node) * self._bufsize + (cur - first)
+ start = obj['_M_impl']['_M_start']
+ finish = obj['_M_impl']['_M_finish']
+ if start['_M_cur'] == finish['_M_cur']:
+ return 0
+ return (self._bufsize
+ * (finish['_M_node'] - start['_M_node'] - 1)
+ + (finish['_M_cur'] - finish['_M_first'])
+ + (start['_M_last'] - start['_M_cur']))
def index(self, obj, idx):
- first_node = obj['_M_impl']['_M_start']['_M_node']
- index_node = first_node + int(idx) // self._bufsize
- return index_node[0][idx % self._bufsize]
+ start = obj['_M_impl']['_M_start']
+ first_node_size = start['_M_last'] - start['_M_cur']
+ if idx < first_node_size:
+ return start['_M_cur'][idx]
+ idx = idx - first_node_size
+ index_node = start['_M_node'][1 + int(idx) // self._bufsize]
+ return index_node[idx % self._bufsize]
+
class DequeEmptyWorker(DequeWorkerBase):
def get_arg_types(self):
@@ -190,6 +223,7 @@ class DequeEmptyWorker(DequeWorkerBase):
return (obj['_M_impl']['_M_start']['_M_cur'] ==
obj['_M_impl']['_M_finish']['_M_cur'])
+
class DequeSizeWorker(DequeWorkerBase):
def get_arg_types(self):
return None
@@ -200,6 +234,7 @@ class DequeSizeWorker(DequeWorkerBase):
def __call__(self, obj):
return self.size(obj)
+
class DequeFrontWorker(DequeWorkerBase):
def get_arg_types(self):
return None
@@ -210,6 +245,7 @@ class DequeFrontWorker(DequeWorkerBase):
def __call__(self, obj):
return obj['_M_impl']['_M_start']['_M_cur'][0]
+
class DequeBackWorker(DequeWorkerBase):
def get_arg_types(self):
return None
@@ -219,12 +255,13 @@ class DequeBackWorker(DequeWorkerBase):
def __call__(self, obj):
if (obj['_M_impl']['_M_finish']['_M_cur'] ==
- obj['_M_impl']['_M_finish']['_M_first']):
+ obj['_M_impl']['_M_finish']['_M_first']):
prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1
return prev_node[0][self._bufsize - 1]
else:
return obj['_M_impl']['_M_finish']['_M_cur'][-1]
+
class DequeSubscriptWorker(DequeWorkerBase):
def get_arg_types(self):
return get_std_size_type()
@@ -235,6 +272,7 @@ class DequeSubscriptWorker(DequeWorkerBase):
def __call__(self, obj, subscript):
return self.index(obj, subscript)
+
class DequeAtWorker(DequeWorkerBase):
def get_arg_types(self):
return get_std_size_type()
@@ -248,7 +286,8 @@ class DequeAtWorker(DequeWorkerBase):
raise IndexError('Deque index "%d" should not be >= %d.' %
(int(index), deque_size))
else:
- return self.index(obj, index)
+ return self.index(obj, index)
+
class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
@@ -265,7 +304,7 @@ class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?deque<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, 'deque'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -274,6 +313,7 @@ class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
# Xmethods for std::forward_list
+
class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher):
def __init__(self, val_type, node_type):
self._val_type = val_type
@@ -282,6 +322,7 @@ class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher):
def get_arg_types(self):
return None
+
class ForwardListEmptyWorker(ForwardListWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
@@ -289,6 +330,7 @@ class ForwardListEmptyWorker(ForwardListWorkerBase):
def __call__(self, obj):
return obj['_M_impl']['_M_head']['_M_next'] == 0
+
class ForwardListFrontWorker(ForwardListWorkerBase):
def get_result_type(self, obj):
return self._val_type
@@ -298,6 +340,7 @@ class ForwardListFrontWorker(ForwardListWorkerBase):
val_address = node['_M_storage']['_M_storage'].address
return val_address.cast(self._val_type.pointer()).dereference()
+
class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
matcher_name = matcher_name_prefix + 'forward_list'
@@ -309,7 +352,7 @@ class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?forward_list<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, 'forward_list'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -320,6 +363,7 @@ class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
# Xmethods for std::list
+
class ListWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type, node_type):
self._val_type = val_type
@@ -337,6 +381,7 @@ class ListWorkerBase(gdb.xmethod.XMethodWorker):
addr = node['_M_storage'].address
return addr.cast(self._val_type.pointer()).dereference()
+
class ListEmptyWorker(ListWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
@@ -348,6 +393,7 @@ class ListEmptyWorker(ListWorkerBase):
else:
return False
+
class ListSizeWorker(ListWorkerBase):
def get_result_type(self, obj):
return get_std_size_type()
@@ -361,6 +407,7 @@ class ListSizeWorker(ListWorkerBase):
size += 1
return size
+
class ListFrontWorker(ListWorkerBase):
def get_result_type(self, obj):
return self._val_type
@@ -369,6 +416,7 @@ class ListFrontWorker(ListWorkerBase):
node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
return self.get_value_from_node(node)
+
class ListBackWorker(ListWorkerBase):
def get_result_type(self, obj):
return self._val_type
@@ -377,6 +425,7 @@ class ListBackWorker(ListWorkerBase):
prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
return self.get_value_from_node(prev_node)
+
class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
@@ -390,7 +439,7 @@ class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, '(__cxx11::)?list'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -401,6 +450,7 @@ class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
# Xmethods for std::vector
+
class VectorWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type):
self._val_type = val_type
@@ -425,6 +475,7 @@ class VectorWorkerBase(gdb.xmethod.XMethodWorker):
else:
return obj['_M_impl']['_M_start'][index]
+
class VectorEmptyWorker(VectorWorkerBase):
def get_arg_types(self):
return None
@@ -435,6 +486,7 @@ class VectorEmptyWorker(VectorWorkerBase):
def __call__(self, obj):
return int(self.size(obj)) == 0
+
class VectorSizeWorker(VectorWorkerBase):
def get_arg_types(self):
return None
@@ -445,6 +497,7 @@ class VectorSizeWorker(VectorWorkerBase):
def __call__(self, obj):
return self.size(obj)
+
class VectorFrontWorker(VectorWorkerBase):
def get_arg_types(self):
return None
@@ -455,6 +508,7 @@ class VectorFrontWorker(VectorWorkerBase):
def __call__(self, obj):
return self.get(obj, 0)
+
class VectorBackWorker(VectorWorkerBase):
def get_arg_types(self):
return None
@@ -465,6 +519,7 @@ class VectorBackWorker(VectorWorkerBase):
def __call__(self, obj):
return self.get(obj, int(self.size(obj)) - 1)
+
class VectorAtWorker(VectorWorkerBase):
def get_arg_types(self):
return get_std_size_type()
@@ -479,6 +534,7 @@ class VectorAtWorker(VectorWorkerBase):
((int(index), size)))
return self.get(obj, int(index))
+
class VectorSubscriptWorker(VectorWorkerBase):
def get_arg_types(self):
return get_std_size_type()
@@ -489,6 +545,7 @@ class VectorSubscriptWorker(VectorWorkerBase):
def __call__(self, obj, subscript):
return self.get(obj, int(subscript))
+
class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
@@ -505,7 +562,7 @@ class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?vector<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, 'vector'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -514,6 +571,7 @@ class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
# Xmethods for associative containers
+
class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, unordered):
self._unordered = unordered
@@ -527,6 +585,7 @@ class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
def get_arg_types(self):
return None
+
class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
@@ -534,6 +593,7 @@ class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
def __call__(self, obj):
return int(self.node_count(obj)) == 0
+
class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
def get_result_type(self, obj):
return get_std_size_type()
@@ -541,6 +601,7 @@ class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
def __call__(self, obj):
return self.node_count(obj)
+
class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self, name):
gdb.xmethod.XMethodMatcher.__init__(self,
@@ -554,7 +615,7 @@ class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?%s<.*>$' % self._name, class_type.tag):
+ if not is_specialization_of(class_type, self._name):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -564,8 +625,11 @@ class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
# Xmethods for std::unique_ptr
+
class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
- "Implements std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->()"
+ """
+ Implement std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->().
+ """
def __init__(self, elem_type):
self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
@@ -581,19 +645,31 @@ class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
return self._elem_type.pointer()
def _supports(self, method_name):
- "operator-> is not supported for unique_ptr<T[]>"
+ # operator-> is not supported for unique_ptr<T[]>
return method_name == 'get' or not self._is_array
def __call__(self, obj):
impl_type = obj.dereference().type.fields()[0].type.tag
- if re.match('^std::(__\d+::)?__uniq_ptr_impl<.*>$', impl_type): # New implementation
- return obj['_M_t']['_M_t']['_M_head_impl']
- elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type):
- return obj['_M_t']['_M_head_impl']
- return None
+ # Check for new implementations first:
+ if is_specialization_of(impl_type, '__uniq_ptr_(data|impl)'):
+ tuple_member = obj['_M_t']['_M_t']
+ elif is_specialization_of(impl_type, 'tuple'):
+ tuple_member = obj['_M_t']
+ else:
+ return None
+ tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
+ tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base
+ head_field = tuple_head_type.fields()[0]
+ if head_field.name == '_M_head_impl':
+ return tuple_member.cast(tuple_head_type)['_M_head_impl']
+ elif head_field.is_base_class:
+ return tuple_member.cast(head_field.type)
+ else:
+ return None
+
class UniquePtrDerefWorker(UniquePtrGetWorker):
- "Implements std::unique_ptr<T>::operator*()"
+ """Implement std::unique_ptr<T>::operator*()."""
def __init__(self, elem_type):
UniquePtrGetWorker.__init__(self, elem_type)
@@ -602,14 +678,15 @@ class UniquePtrDerefWorker(UniquePtrGetWorker):
return self._elem_type
def _supports(self, method_name):
- "operator* is not supported for unique_ptr<T[]>"
+ # operator* is not supported for unique_ptr<T[]>
return not self._is_array
def __call__(self, obj):
return UniquePtrGetWorker.__call__(self, obj).dereference()
+
class UniquePtrSubscriptWorker(UniquePtrGetWorker):
- "Implements std::unique_ptr<T>::operator[](size_t)"
+ """Implement std::unique_ptr<T>::operator[](size_t)."""
def __init__(self, elem_type):
UniquePtrGetWorker.__init__(self, elem_type)
@@ -621,12 +698,13 @@ class UniquePtrSubscriptWorker(UniquePtrGetWorker):
return self._elem_type
def _supports(self, method_name):
- "operator[] is only supported for unique_ptr<T[]>"
+ # operator[] is only supported for unique_ptr<T[]>
return self._is_array
def __call__(self, obj, index):
return UniquePtrGetWorker.__call__(self, obj)[index]
+
class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
@@ -640,7 +718,7 @@ class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, 'unique_ptr'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -652,8 +730,11 @@ class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
# Xmethods for std::shared_ptr
+
class SharedPtrGetWorker(gdb.xmethod.XMethodWorker):
- "Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()"
+ """
+ Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->().
+ """
def __init__(self, elem_type):
self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
@@ -669,14 +750,15 @@ class SharedPtrGetWorker(gdb.xmethod.XMethodWorker):
return self._elem_type.pointer()
def _supports(self, method_name):
- "operator-> is not supported for shared_ptr<T[]>"
+ # operator-> is not supported for shared_ptr<T[]>
return method_name == 'get' or not self._is_array
def __call__(self, obj):
return obj['_M_ptr']
+
class SharedPtrDerefWorker(SharedPtrGetWorker):
- "Implements std::shared_ptr<T>::operator*()"
+ """Implement std::shared_ptr<T>::operator*()."""
def __init__(self, elem_type):
SharedPtrGetWorker.__init__(self, elem_type)
@@ -685,14 +767,15 @@ class SharedPtrDerefWorker(SharedPtrGetWorker):
return self._elem_type
def _supports(self, method_name):
- "operator* is not supported for shared_ptr<T[]>"
+ # operator* is not supported for shared_ptr<T[]>
return not self._is_array
def __call__(self, obj):
return SharedPtrGetWorker.__call__(self, obj).dereference()
+
class SharedPtrSubscriptWorker(SharedPtrGetWorker):
- "Implements std::shared_ptr<T>::operator[](size_t)"
+ """Implement std::shared_ptr<T>::operator[](size_t)."""
def __init__(self, elem_type):
SharedPtrGetWorker.__init__(self, elem_type)
@@ -704,22 +787,23 @@ class SharedPtrSubscriptWorker(SharedPtrGetWorker):
return self._elem_type
def _supports(self, method_name):
- "operator[] is only supported for shared_ptr<T[]>"
+ # operator[] is only supported for shared_ptr<T[]>
return self._is_array
def __call__(self, obj, index):
# Check bounds if _elem_type is an array of known bound
- m = re.match('.*\[(\d+)]$', str(self._elem_type))
+ m = re.match(r'.*\[(\d+)]$', str(self._elem_type))
if m and index >= int(m.group(1)):
raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
(self._elem_type, int(index), int(m.group(1))))
return SharedPtrGetWorker.__call__(self, obj)[index]
+
class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker):
- "Implements std::shared_ptr<T>::use_count()"
+ """Implement std::shared_ptr<T>::use_count()."""
def __init__(self, elem_type):
- SharedPtrUseCountWorker.__init__(self, elem_type)
+ pass
def get_arg_types(self):
return None
@@ -727,12 +811,16 @@ class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker):
def get_result_type(self, obj):
return gdb.lookup_type('long')
+ def _supports(self, method_name):
+ return True
+
def __call__(self, obj):
refcounts = obj['_M_refcount']['_M_pi']
return refcounts['_M_use_count'] if refcounts else 0
+
class SharedPtrUniqueWorker(SharedPtrUseCountWorker):
- "Implements std::shared_ptr<T>::unique()"
+ """Implement std::shared_ptr<T>::unique()."""
def __init__(self, elem_type):
SharedPtrUseCountWorker.__init__(self, elem_type)
@@ -743,6 +831,7 @@ class SharedPtrUniqueWorker(SharedPtrUseCountWorker):
def __call__(self, obj):
return SharedPtrUseCountWorker.__call__(self, obj) == 1
+
class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
@@ -758,7 +847,7 @@ class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
- if not re.match('^std::(__\d+::)?shared_ptr<.*>$', class_type.tag):
+ if not is_specialization_of(class_type, 'shared_ptr'):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
@@ -768,6 +857,7 @@ class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
return worker
return None
+
def register_libstdcxx_xmethods(locus):
gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())