1 # Pretty-printers for libstdc++.
3 # Copyright (C) 2008-2024 Free Software Foundation, Inc.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # Python 2 + Python 3 compatibility code
27 # Resources about compatibility:
29 # * <http://pythonhosted.org/six/>: Documentation of the "six" module
31 # FIXME: The handling of e.g. std::basic_string (at least on char)
32 # probably needs updating to work with Python 3's new string rules.
34 # In particular, Python 3 has a separate type (called byte) for
35 # bytestrings, and a special b"" syntax for the byte literals; the old
36 # str() type has been redefined to always store Unicode text.
38 # We probably can't do much about this until this GDB PR is addressed:
39 # <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>
41 if sys
.version_info
[0] > 2:
44 # Python 3 folds these into the normal functions.
47 # Also, int subsumes long
49 _utc_timezone
= datetime
.timezone
.utc
53 """Compatibility mixin for iterators
55 Instead of writing next() methods for iterators, write
56 __next__() methods and use this mixin to make them work in
57 Python 2 as well as Python 3.
59 Idea stolen from the "six" documentation:
60 <http://pythonhosted.org/six/#six.Iterator>
64 return self
.__next
__()
66 # In Python 2, we still need these from itertools
67 from itertools
import imap
, izip
69 # Python 2 does not provide the datetime.UTC singleton.
70 class UTC(datetime
.tzinfo
):
71 """Concrete tzinfo class representing the UTC time zone."""
73 def utcoffset(self
, dt
):
74 return datetime
.timedelta(0)
80 return datetime
.timedelta(0)
83 # Try to use the new-style pretty-printing if available.
90 # Try to install type-printers.
91 _use_type_printing
= False
94 if hasattr(gdb
.types
, 'TypePrinter'):
95 _use_type_printing
= True
99 # Use the base class if available.
100 if hasattr(gdb
, 'ValuePrinter'):
101 printer_base
= gdb
.ValuePrinter
103 printer_base
= object
105 # Starting with the type ORIG, search for the member type NAME. This
106 # handles searching upward through superclasses. This is needed to
107 # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
110 def find_type(orig
, name
):
111 typ
= orig
.strip_typedefs()
113 # Use Type.tag to ignore cv-qualifiers. PR 67440.
114 search
= '%s::%s' % (typ
.tag
, name
)
116 return gdb
.lookup_type(search
)
119 # The type was not found, so try the superclass. We only need
120 # to check the first superclass, so we don't bother with
121 # anything fancier here.
122 fields
= typ
.fields()
123 if len(fields
) and fields
[0].is_base_class
:
126 raise ValueError("Cannot find type %s::%s" % (str(orig
), name
))
129 _versioned_namespace
= '__8::'
132 def lookup_templ_spec(templ
, *args
):
134 Lookup template specialization templ<args...>.
136 t
= '{}<{}>'.format(templ
, ', '.join([str(a
) for a
in args
]))
138 return gdb
.lookup_type(t
)
139 except gdb
.error
as e
:
140 # Type not found, try again in versioned namespace.
141 global _versioned_namespace
142 if _versioned_namespace
not in templ
:
143 t
= t
.replace('::', '::' + _versioned_namespace
, 1)
145 return gdb
.lookup_type(t
)
147 # If that also fails, rethrow the original exception
151 # Use this to find container node types instead of find_type,
152 # see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details.
153 def lookup_node_type(nodename
, containertype
):
155 Lookup specialization of template nodename corresponding to containertype.
157 nodename - The name of a class template, as a String
158 containertype - The container, as a gdb.Type
160 Return a gdb.Type for the corresponding specialization of nodename,
161 or None if the type cannot be found.
163 e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list<int>'))
164 will return a gdb.Type for the type std::_List_node<int>.
166 # If nodename is unqualified, assume it's in namespace std.
167 if '::' not in nodename
:
168 nodename
= 'std::' + nodename
169 # Use either containertype's value_type or its first template argument.
171 valtype
= find_type(containertype
, 'value_type')
173 valtype
= containertype
.template_argument(0)
174 valtype
= valtype
.strip_typedefs()
176 return lookup_templ_spec(nodename
, valtype
)
178 # For debug mode containers the node is in std::__cxx1998.
179 if is_member_of_namespace(nodename
, 'std'):
180 if is_member_of_namespace(containertype
, 'std::__cxx1998',
181 'std::__debug', '__gnu_debug'):
182 nodename
= nodename
.replace('::', '::__cxx1998::', 1)
184 return lookup_templ_spec(nodename
, valtype
)
190 def is_member_of_namespace(typ
, *namespaces
):
192 Test whether a type is a member of one of the specified namespaces.
193 The type can be specified as a string or a gdb.Type object.
195 if isinstance(typ
, gdb
.Type
):
197 typ
= strip_versioned_namespace(typ
)
198 for namespace
in namespaces
:
199 if typ
.startswith(namespace
+ '::'):
204 def is_specialization_of(x
, template_name
):
206 Test whether a type is a specialization of the named class template.
207 The type can be specified as a string or a gdb.Type object.
208 The template should be the name of a class template as a string,
209 without any 'std' qualification.
211 global _versioned_namespace
212 if isinstance(x
, gdb
.Type
):
214 template_name
= '(%s)?%s' % (_versioned_namespace
, template_name
)
215 return re
.match('^std::%s<.*>$' % template_name
, x
) is not None
218 def strip_versioned_namespace(typename
):
219 global _versioned_namespace
220 return typename
.replace(_versioned_namespace
, '')
223 def strip_inline_namespaces(type_str
):
224 """Remove known inline namespaces from the canonical name of a type."""
225 type_str
= strip_versioned_namespace(type_str
)
226 type_str
= type_str
.replace('std::__cxx11::', 'std::')
227 expt_ns
= 'std::experimental::'
228 for lfts_ns
in ('fundamentals_v1', 'fundamentals_v2'):
229 type_str
= type_str
.replace(expt_ns
+ lfts_ns
+ '::', expt_ns
)
230 fs_ns
= expt_ns
+ 'filesystem::'
231 type_str
= type_str
.replace(fs_ns
+ 'v1::', fs_ns
)
235 def get_template_arg_list(type_obj
):
236 """Return a type's template arguments as a list."""
241 template_args
.append(type_obj
.template_argument(n
))
247 class SmartPtrIterator(Iterator
):
248 """An iterator for smart pointer types with a single 'child' value."""
250 def __init__(self
, val
):
257 if self
._val
is None:
259 self
._val
, val
= None, self
._val
260 return ('get()', val
)
263 class SharedPointerPrinter(printer_base
):
265 Print a shared_ptr, weak_ptr, atomic<shared_ptr>, or atomic<weak_ptr>.
268 def __init__(self
, typename
, val
):
269 self
._typename
= strip_versioned_namespace(typename
)
271 self
._pointer
= val
['_M_ptr']
274 return SmartPtrIterator(self
._pointer
)
276 # Return the _Sp_counted_base<>* that holds the refcounts.
277 def _get_refcounts(self
):
278 if self
._typename
== 'std::atomic':
279 # A tagged pointer is stored as uintptr_t.
280 ptr_val
= self
._val
['_M_refcount']['_M_val']['_M_i']
281 ptr_val
= ptr_val
- (ptr_val
% 2) # clear lock bit
282 ptr_type
= find_type(self
._val
['_M_refcount'].type, 'pointer')
283 return ptr_val
.cast(ptr_type
)
284 return self
._val
['_M_refcount']['_M_pi']
288 refcounts
= self
._get
_refcounts
()
289 targ
= self
._val
.type.template_argument(0)
290 targ
= strip_versioned_namespace(str(targ
))
293 usecount
= refcounts
['_M_use_count']
294 weakcount
= refcounts
['_M_weak_count']
296 state
= 'expired, weak count %d' % weakcount
298 state
= 'use count %d, weak count %d' % (
299 usecount
, weakcount
- 1)
300 return '%s<%s> (%s)' % (self
._typename
, targ
, state
)
303 def _tuple_impl_get(val
):
304 """Return the tuple element stored in a _Tuple_impl<N, T> base class."""
305 bases
= val
.type.fields()
306 if not bases
[-1].is_base_class
:
308 "Unsupported implementation for std::tuple: %s" % str(val
.type))
309 # Get the _Head_base<N, T> base class:
310 head_base
= val
.cast(bases
[-1].type)
311 fields
= head_base
.type.fields()
314 "Unsupported implementation for std::tuple: %s" % str(val
.type))
315 if fields
[0].name
== '_M_head_impl':
316 # The tuple element is the _Head_base::_M_head_impl data member.
317 return head_base
['_M_head_impl']
318 elif fields
[0].is_base_class
:
319 # The tuple element is an empty base class of _Head_base.
320 # Cast to that empty base class.
321 return head_base
.cast(fields
[0].type)
324 "Unsupported implementation for std::tuple: %s" % str(val
.type))
327 def tuple_get(n
, val
):
328 """Return the result of std::get<n>(val) on a std::tuple."""
329 tuple_size
= len(get_template_arg_list(val
.type))
331 raise ValueError("Out of range index for std::get<N> on std::tuple")
332 # Get the first _Tuple_impl<0, T...> base class:
333 node
= val
.cast(val
.type.fields()[0].type)
335 # Descend through the base classes until the Nth one.
336 node
= node
.cast(node
.type.fields()[0].type)
338 return _tuple_impl_get(node
)
341 def unique_ptr_get(val
):
342 """Return the result of val.get() on a std::unique_ptr."""
343 # std::unique_ptr<T, D> contains a std::tuple<D::pointer, D>,
344 # either as a direct data member _M_t (the old implementation)
345 # or within a data member of type __uniq_ptr_data.
346 impl_type
= val
.type.fields()[0].type.strip_typedefs()
347 # Check for new implementations first:
348 if is_specialization_of(impl_type
, '__uniq_ptr_data') \
349 or is_specialization_of(impl_type
, '__uniq_ptr_impl'):
350 tuple_member
= val
['_M_t']['_M_t']
351 elif is_specialization_of(impl_type
, 'tuple'):
352 tuple_member
= val
['_M_t']
355 "Unsupported implementation for unique_ptr: %s" % str(impl_type
))
356 return tuple_get(0, tuple_member
)
359 class UniquePointerPrinter(printer_base
):
360 """Print a unique_ptr."""
362 def __init__(self
, typename
, val
):
366 return SmartPtrIterator(unique_ptr_get(self
._val
))
369 t
= self
._val
.type.template_argument(0)
370 return 'std::unique_ptr<{}>'.format(str(t
))
373 def get_value_from_aligned_membuf(buf
, valtype
):
374 """Return the value held in a __gnu_cxx::__aligned_membuf."""
375 return buf
['_M_storage'].address
.cast(valtype
.pointer()).dereference()
378 def get_value_from_list_node(node
):
379 """Return the value held in an _List_node<_Val>."""
381 member
= node
.type.fields()[1].name
382 if member
== '_M_data':
383 # C++03 implementation, node contains the value as a member
384 return node
['_M_data']
385 elif member
== '_M_storage':
386 # C++11 implementation, node stores value in __aligned_membuf
387 valtype
= node
.type.template_argument(0)
388 return get_value_from_aligned_membuf(node
['_M_storage'], valtype
)
391 raise ValueError("Unsupported implementation for %s" % str(node
.type))
394 class StdListPrinter(printer_base
):
395 """Print a std::list."""
397 class _iterator(Iterator
):
398 def __init__(self
, nodetype
, head
):
399 self
._nodetype
= nodetype
400 self
._base
= head
['_M_next']
401 self
._head
= head
.address
408 if self
._base
== self
._head
:
410 elt
= self
._base
.cast(self
._nodetype
).dereference()
411 self
._base
= elt
['_M_next']
413 self
._count
= self
._count
+ 1
414 val
= get_value_from_list_node(elt
)
415 return ('[%d]' % count
, val
)
417 def __init__(self
, typename
, val
):
418 self
._typename
= strip_versioned_namespace(typename
)
422 nodetype
= lookup_node_type('_List_node', self
._val
.type).pointer()
423 return self
._iterator
(nodetype
, self
._val
['_M_impl']['_M_node'])
426 headnode
= self
._val
['_M_impl']['_M_node']
427 if headnode
['_M_next'] == headnode
.address
:
428 return 'empty %s' % (self
._typename
)
429 return '%s' % (self
._typename
)
432 class NodeIteratorPrinter(printer_base
):
433 def __init__(self
, typename
, val
, contname
, nodename
):
435 self
._typename
= typename
436 self
._contname
= contname
437 self
._nodetype
= lookup_node_type(nodename
, val
.type)
440 if not self
._val
['_M_node']:
441 return 'non-dereferenceable iterator for std::%s' % (self
._contname
)
442 node
= self
._val
['_M_node'].cast(
443 self
._nodetype
.pointer()).dereference()
444 return str(get_value_from_list_node(node
))
447 class StdListIteratorPrinter(NodeIteratorPrinter
):
448 """Print std::list::iterator."""
450 def __init__(self
, typename
, val
):
451 NodeIteratorPrinter
.__init
__(self
, typename
, val
, 'list', '_List_node')
454 class StdFwdListIteratorPrinter(NodeIteratorPrinter
):
455 """Print std::forward_list::iterator."""
457 def __init__(self
, typename
, val
):
458 NodeIteratorPrinter
.__init
__(self
, typename
, val
, 'forward_list',
462 class StdSlistPrinter(printer_base
):
463 """Print a __gnu_cxx::slist."""
465 class _iterator(Iterator
):
466 def __init__(self
, nodetype
, head
):
467 self
._nodetype
= nodetype
468 self
._base
= head
['_M_head']['_M_next']
477 elt
= self
._base
.cast(self
._nodetype
).dereference()
478 self
._base
= elt
['_M_next']
480 self
._count
= self
._count
+ 1
481 return ('[%d]' % count
, elt
['_M_data'])
483 def __init__(self
, typename
, val
):
487 nodetype
= lookup_node_type('__gnu_cxx::_Slist_node', self
._val
.type)
488 return self
._iterator
(nodetype
.pointer(), self
._val
)
491 if self
._val
['_M_head']['_M_next'] == 0:
492 return 'empty __gnu_cxx::slist'
493 return '__gnu_cxx::slist'
496 class StdSlistIteratorPrinter(printer_base
):
497 """Print __gnu_cxx::slist::iterator."""
499 def __init__(self
, typename
, val
):
503 if not self
._val
['_M_node']:
504 return 'non-dereferenceable iterator for __gnu_cxx::slist'
505 nodetype
= lookup_node_type(
506 '__gnu_cxx::_Slist_node', self
._val
.type).pointer()
507 return str(self
._val
['_M_node'].cast(nodetype
).dereference()['_M_data'])
510 class StdVectorPrinter(printer_base
):
511 """Print a std::vector."""
513 class _iterator(Iterator
):
514 def __init__(self
, start
, finish
, bitvec
):
515 self
._bitvec
= bitvec
517 self
._item
= start
['_M_p']
519 self
._finish
= finish
['_M_p']
520 self
._fo
= finish
['_M_offset']
521 itype
= self
._item
.dereference().type
522 self
._isize
= 8 * itype
.sizeof
525 self
._finish
= finish
533 self
._count
= self
._count
+ 1
535 if self
._item
== self
._finish
and self
._so
>= self
._fo
:
537 elt
= bool(self
._item
.dereference() & (1 << self
._so
))
538 self
._so
= self
._so
+ 1
539 if self
._so
>= self
._isize
:
540 self
._item
= self
._item
+ 1
542 return ('[%d]' % count
, elt
)
544 if self
._item
== self
._finish
:
546 elt
= self
._item
.dereference()
547 self
._item
= self
._item
+ 1
548 return ('[%d]' % count
, elt
)
550 def __init__(self
, typename
, val
):
551 self
._typename
= strip_versioned_namespace(typename
)
553 self
._is
_bool
= val
.type.template_argument(
554 0).code
== gdb
.TYPE_CODE_BOOL
557 return self
._iterator
(self
._val
['_M_impl']['_M_start'],
558 self
._val
['_M_impl']['_M_finish'],
562 start
= self
._val
['_M_impl']['_M_start']
563 finish
= self
._val
['_M_impl']['_M_finish']
564 end
= self
._val
['_M_impl']['_M_end_of_storage']
566 start
= self
._val
['_M_impl']['_M_start']['_M_p']
567 finish
= self
._val
['_M_impl']['_M_finish']['_M_p']
568 fo
= self
._val
['_M_impl']['_M_finish']['_M_offset']
569 itype
= start
.dereference().type
570 bl
= 8 * itype
.sizeof
571 length
= bl
* (finish
- start
) + fo
572 capacity
= bl
* (end
- start
)
573 return ('%s<bool> of length %d, capacity %d'
574 % (self
._typename
, int(length
), int(capacity
)))
576 return ('%s of length %d, capacity %d'
577 % (self
._typename
, int(finish
- start
), int(end
- start
)))
579 def display_hint(self
):
583 class StdVectorIteratorPrinter(printer_base
):
584 """Print std::vector::iterator."""
586 def __init__(self
, typename
, val
):
590 if not self
._val
['_M_current']:
591 return 'non-dereferenceable iterator for std::vector'
592 return str(self
._val
['_M_current'].dereference())
595 class StdBitIteratorPrinter(printer_base
):
596 """Print std::vector<bool>'s _Bit_iterator and _Bit_const_iterator."""
598 def __init__(self
, typename
, val
):
602 if not self
._val
['_M_p']:
603 return 'non-dereferenceable iterator for std::vector<bool>'
604 return bool(self
._val
['_M_p'].dereference()
605 & (1 << self
._val
['_M_offset']))
608 class StdBitReferencePrinter(printer_base
):
609 """Print std::vector<bool>::reference."""
611 def __init__(self
, typename
, val
):
615 if not self
._val
['_M_p']:
616 # PR libstdc++/115098 removed the reference default constructor
617 # that this case relates to. New code should never need this,
618 # but we still handle it for compatibility with old binaries.
619 return 'invalid std::vector<bool>::reference'
620 return bool(self
._val
['_M_p'].dereference() & (self
._val
['_M_mask']))
623 class StdTuplePrinter(printer_base
):
624 """Print a std::tuple."""
626 class _iterator(Iterator
):
628 def _is_nonempty_tuple(nodes
):
630 if is_specialization_of(nodes
[1].type, '__tuple_base'):
632 elif len(nodes
) == 1:
634 elif len(nodes
) == 0:
637 "Top of tuple tree does not consist of a single node.")
639 def __init__(self
, head
):
642 # Set the base class as the initial head of the
644 nodes
= self
._head
.type.fields()
645 if self
._is
_nonempty
_tuple
(nodes
):
646 # Set the actual head to the first pair.
647 self
._head
= self
._head
.cast(nodes
[0].type)
654 # Check for further recursions in the inheritance tree.
655 # For a GCC 5+ tuple self._head is None after visiting all nodes:
658 nodes
= self
._head
.type.fields()
659 # For a GCC 4.x tuple there is a final node with no fields:
662 # Check that this iteration has an expected structure.
665 "Cannot parse more than 2 nodes in a tuple tree.")
668 # This is the last node of a GCC 5+ std::tuple.
669 impl
= self
._head
.cast(nodes
[0].type)
672 # Either a node before the last node, or the last node of
673 # a GCC 4.x tuple (which has an empty parent).
675 # - Left node is the next recursion parent.
676 # - Right node is the actual class contained in the tuple.
678 # Process right node.
679 impl
= self
._head
.cast(nodes
[1].type)
681 # Process left node and set it as head.
682 self
._head
= self
._head
.cast(nodes
[0].type)
684 self
._count
= self
._count
+ 1
686 # Finally, check the implementation. If it is
687 # wrapped in _M_head_impl return that, otherwise return
689 fields
= impl
.type.fields()
690 if len(fields
) < 1 or fields
[0].name
!= "_M_head_impl":
691 return ('[%d]' % (self
._count
- 1), impl
)
693 return ('[%d]' % (self
._count
- 1), impl
['_M_head_impl'])
695 def __init__(self
, typename
, val
):
696 self
._typename
= strip_versioned_namespace(typename
)
700 return self
._iterator
(self
._val
)
703 if len(self
._val
.type.fields()) == 0:
704 return 'empty %s' % (self
._typename
)
705 return '%s containing' % (self
._typename
)
708 class StdStackOrQueuePrinter(printer_base
):
709 """Print a std::stack or std::queue."""
711 def __init__(self
, typename
, val
):
712 self
._typename
= strip_versioned_namespace(typename
)
713 self
._visualizer
= gdb
.default_visualizer(val
['c'])
716 return self
._visualizer
.children()
719 return '%s wrapping: %s' % (self
._typename
,
720 self
._visualizer
.to_string())
722 def display_hint(self
):
723 if hasattr(self
._visualizer
, 'display_hint'):
724 return self
._visualizer
.display_hint()
728 class RbtreeIterator(Iterator
):
730 Turn an RB-tree-based container (std::map, std::set etc.) into
731 a Python iterable object.
734 def __init__(self
, rbtree
):
735 self
._size
= rbtree
['_M_t']['_M_impl']['_M_node_count']
736 self
._node
= rbtree
['_M_t']['_M_impl']['_M_header']['_M_left']
743 return int(self
._size
)
746 if self
._count
== self
._size
:
749 self
._count
= self
._count
+ 1
750 if self
._count
< self
._size
:
751 # Compute the next node.
753 if node
.dereference()['_M_right']:
754 node
= node
.dereference()['_M_right']
755 while node
.dereference()['_M_left']:
756 node
= node
.dereference()['_M_left']
758 parent
= node
.dereference()['_M_parent']
759 while node
== parent
.dereference()['_M_right']:
761 parent
= parent
.dereference()['_M_parent']
762 if node
.dereference()['_M_right'] != parent
:
768 def get_value_from_Rb_tree_node(node
):
769 """Return the value held in an _Rb_tree_node<_Val>."""
771 member
= node
.type.fields()[1].name
772 if member
== '_M_value_field':
773 # C++03 implementation, node contains the value as a member
774 return node
['_M_value_field']
775 elif member
== '_M_storage':
776 # C++11 implementation, node stores value in __aligned_membuf
777 valtype
= node
.type.template_argument(0)
778 return get_value_from_aligned_membuf(node
['_M_storage'], valtype
)
781 raise ValueError("Unsupported implementation for %s" % str(node
.type))
783 # This is a pretty printer for std::_Rb_tree_iterator (which is
784 # std::map::iterator), and has nothing to do with the RbtreeIterator
788 class StdRbtreeIteratorPrinter(printer_base
):
789 """Print std::map::iterator, std::set::iterator, etc."""
791 def __init__(self
, typename
, val
):
793 nodetype
= lookup_node_type('_Rb_tree_node', self
._val
.type)
794 self
._link
_type
= nodetype
.pointer()
797 if not self
._val
['_M_node']:
798 return 'non-dereferenceable iterator for associative container'
799 node
= self
._val
['_M_node'].cast(self
._link
_type
).dereference()
800 return str(get_value_from_Rb_tree_node(node
))
803 class StdDebugIteratorPrinter(printer_base
):
804 """Print a debug enabled version of an iterator."""
806 def __init__(self
, typename
, val
):
809 # Just strip away the encapsulating __gnu_debug::_Safe_iterator
810 # and return the wrapped iterator value.
812 base_type
= gdb
.lookup_type('__gnu_debug::_Safe_iterator_base')
813 itype
= self
._val
.type.template_argument(0)
814 safe_seq
= self
._val
.cast(base_type
)['_M_sequence']
816 return str(self
._val
.cast(itype
))
817 if self
._val
['_M_version'] != safe_seq
['_M_version']:
818 return "invalid iterator"
819 return str(self
._val
.cast(itype
))
822 def num_elements(num
):
823 """Return either "1 element" or "N elements" depending on the argument."""
824 return '1 element' if num
== 1 else '%d elements' % num
827 class StdMapPrinter(printer_base
):
828 """Print a std::map or std::multimap."""
830 # Turn an RbtreeIterator into a pretty-print iterator.
831 class _iter(Iterator
):
832 def __init__(self
, rbiter
, type):
833 self
._rbiter
= rbiter
841 if self
._count
% 2 == 0:
842 n
= next(self
._rbiter
)
843 n
= n
.cast(self
._type
).dereference()
844 n
= get_value_from_Rb_tree_node(n
)
848 item
= self
._pair
['second']
849 result
= ('[%d]' % self
._count
, item
)
850 self
._count
= self
._count
+ 1
853 def __init__(self
, typename
, val
):
854 self
._typename
= strip_versioned_namespace(typename
)
858 return '%s with %s' % (self
._typename
,
859 num_elements(len(RbtreeIterator(self
._val
))))
862 node
= lookup_node_type('_Rb_tree_node', self
._val
.type).pointer()
863 return self
._iter
(RbtreeIterator(self
._val
), node
)
865 def display_hint(self
):
869 class StdSetPrinter(printer_base
):
870 """Print a std::set or std::multiset."""
872 # Turn an RbtreeIterator into a pretty-print iterator.
873 class _iter(Iterator
):
874 def __init__(self
, rbiter
, type):
875 self
._rbiter
= rbiter
883 item
= next(self
._rbiter
)
884 item
= item
.cast(self
._type
).dereference()
885 item
= get_value_from_Rb_tree_node(item
)
886 # FIXME: this is weird ... what to do?
887 # Maybe a 'set' display hint?
888 result
= ('[%d]' % self
._count
, item
)
889 self
._count
= self
._count
+ 1
892 def __init__(self
, typename
, val
):
893 self
._typename
= strip_versioned_namespace(typename
)
897 return '%s with %s' % (self
._typename
,
898 num_elements(len(RbtreeIterator(self
._val
))))
901 node
= lookup_node_type('_Rb_tree_node', self
._val
.type).pointer()
902 return self
._iter
(RbtreeIterator(self
._val
), node
)
905 class StdBitsetPrinter(printer_base
):
906 """Print a std::bitset."""
908 def __init__(self
, typename
, val
):
909 self
._typename
= strip_versioned_namespace(typename
)
913 # If template_argument handled values, we could print the
914 # size. Or we could use a regexp on the type.
915 return '%s' % (self
._typename
)
919 # An empty bitset may not have any members which will
920 # result in an exception being thrown.
921 words
= self
._val
['_M_w']
927 # The _M_w member can be either an unsigned long, or an
928 # array. This depends on the template specialization used.
929 # If it is a single long, convert to a single element list.
930 if wtype
.code
== gdb
.TYPE_CODE_ARRAY
:
931 tsize
= wtype
.target().sizeof
936 nwords
= wtype
.sizeof
/ tsize
944 # Another spot where we could use 'set'?
945 result
.append(('[%d]' % (byte
* tsize
* 8 + bit
), 1))
952 class StdDequePrinter(printer_base
):
953 """Print a std::deque."""
955 class _iter(Iterator
):
956 def __init__(self
, node
, start
, end
, last
, buffer_size
):
961 self
._buffer
_size
= buffer_size
968 if self
._p
== self
._last
:
971 result
= ('[%d]' % self
._count
, self
._p
.dereference())
972 self
._count
= self
._count
+ 1
974 # Advance the 'cur' pointer.
975 self
._p
= self
._p
+ 1
976 if self
._p
== self
._end
:
977 # If we got to the end of this bucket, move to the
979 self
._node
= self
._node
+ 1
980 self
._p
= self
._node
[0]
981 self
._end
= self
._p
+ self
._buffer
_size
985 def __init__(self
, typename
, val
):
986 self
._typename
= strip_versioned_namespace(typename
)
988 self
._elttype
= val
.type.template_argument(0)
989 size
= self
._elttype
.sizeof
991 self
._buffer
_size
= int(512 / size
)
993 self
._buffer
_size
= 1
996 start
= self
._val
['_M_impl']['_M_start']
997 end
= self
._val
['_M_impl']['_M_finish']
999 delta_n
= end
['_M_node'] - start
['_M_node'] - 1
1000 delta_s
= start
['_M_last'] - start
['_M_cur']
1001 delta_e
= end
['_M_cur'] - end
['_M_first']
1003 size
= self
._buffer
_size
* delta_n
+ delta_s
+ delta_e
1005 return '%s with %s' % (self
._typename
, num_elements(long(size
)))
1008 start
= self
._val
['_M_impl']['_M_start']
1009 end
= self
._val
['_M_impl']['_M_finish']
1010 return self
._iter
(start
['_M_node'], start
['_M_cur'], start
['_M_last'],
1011 end
['_M_cur'], self
._buffer
_size
)
1013 def display_hint(self
):
1017 class StdDequeIteratorPrinter(printer_base
):
1018 """Print std::deque::iterator."""
1020 def __init__(self
, typename
, val
):
1023 def to_string(self
):
1024 if not self
._val
['_M_cur']:
1025 return 'non-dereferenceable iterator for std::deque'
1026 return str(self
._val
['_M_cur'].dereference())
1029 class StdStringPrinter(printer_base
):
1030 """Print a std::basic_string of some kind."""
1032 def __init__(self
, typename
, val
):
1034 self
._new
_string
= typename
.find("::__cxx11::basic_string") != -1
1036 def to_string(self
):
1037 # Make sure &string works, too.
1038 type = self
._val
.type
1039 if type.code
== gdb
.TYPE_CODE_REF
:
1040 type = type.target()
1042 # Calculate the length of the string so that to_string returns
1043 # the string according to length, not according to first null
1045 ptr
= self
._val
['_M_dataplus']['_M_p']
1046 if self
._new
_string
:
1047 length
= self
._val
['_M_string_length']
1048 # https://sourceware.org/bugzilla/show_bug.cgi?id=17728
1049 ptr
= ptr
.cast(ptr
.type.strip_typedefs())
1051 realtype
= type.unqualified().strip_typedefs()
1052 reptype
= gdb
.lookup_type(str(realtype
) + '::_Rep').pointer()
1053 header
= ptr
.cast(reptype
) - 1
1054 length
= header
.dereference()['_M_length']
1055 if hasattr(ptr
, "lazy_string"):
1056 return ptr
.lazy_string(length
=length
)
1057 return ptr
.string(length
=length
)
1059 def display_hint(self
):
1063 def access_streambuf_ptrs(streambuf
):
1064 """Access the streambuf put area pointers."""
1065 pbase
= streambuf
['_M_out_beg']
1066 pptr
= streambuf
['_M_out_cur']
1067 egptr
= streambuf
['_M_in_end']
1068 return pbase
, pptr
, egptr
1071 class StdStringBufPrinter(printer_base
):
1072 """Print a std::basic_stringbuf."""
1074 def __init__(self
, _
, val
):
1077 def to_string(self
):
1078 (pbase
, pptr
, egptr
) = access_streambuf_ptrs(self
._val
)
1079 # Logic from basic_stringbuf::_M_high_mark()
1081 if not egptr
or pptr
> egptr
:
1082 return pbase
.string(length
=pptr
- pbase
)
1084 return pbase
.string(length
=egptr
- pbase
)
1085 return self
._val
['_M_string']
1087 def display_hint(self
):
1091 class StdStringStreamPrinter(printer_base
):
1092 """Print a std::basic_stringstream."""
1094 def __init__(self
, typename
, val
):
1096 self
._typename
= typename
1098 # Check if the stream was redirected. This is essentially:
1099 # val['_M_streambuf'] != val['_M_stringbuf'].address
1100 # However, GDB can't resolve the virtual inheritance, so we do that
1102 basetype
= [f
.type for f
in val
.type.fields() if f
.is_base_class
][0]
1103 gdb
.set_convenience_variable('__stream', val
.cast(basetype
).address
)
1104 self
._streambuf
= gdb
.parse_and_eval('$__stream->rdbuf()')
1105 self
._was
_redirected
= self
._streambuf
!= val
['_M_stringbuf'].address
1107 def to_string(self
):
1108 if self
._was
_redirected
:
1109 return "%s redirected to %s" % (
1110 self
._typename
, self
._streambuf
.dereference())
1111 return self
._val
['_M_stringbuf']
1113 def display_hint(self
):
1114 if self
._was
_redirected
:
1119 class Tr1HashtableIterator(Iterator
):
1120 def __init__(self
, hashtable
):
1121 self
._buckets
= hashtable
['_M_buckets']
1123 self
._bucket
_count
= hashtable
['_M_bucket_count']
1124 self
._node
_type
= find_type(hashtable
.type, '_Node').pointer()
1126 while self
._bucket
!= self
._bucket
_count
:
1127 self
._node
= self
._buckets
[self
._bucket
]
1130 self
._bucket
= self
._bucket
+ 1
1138 node
= self
._node
.cast(self
._node
_type
)
1139 result
= node
.dereference()['_M_v']
1140 self
._node
= node
.dereference()['_M_next']
1142 self
._bucket
= self
._bucket
+ 1
1143 while self
._bucket
!= self
._bucket
_count
:
1144 self
._node
= self
._buckets
[self
._bucket
]
1147 self
._bucket
= self
._bucket
+ 1
1151 class StdHashtableIterator(Iterator
):
1152 def __init__(self
, hashtable
):
1153 self
._node
= hashtable
['_M_before_begin']['_M_nxt']
1154 valtype
= hashtable
.type.template_argument(1)
1155 cached
= hashtable
.type.template_argument(9).template_argument(0)
1156 node_type
= lookup_templ_spec('std::__detail::_Hash_node', str(valtype
),
1157 'true' if cached
else 'false')
1158 self
._node
_type
= node_type
.pointer()
1166 elt
= self
._node
.cast(self
._node
_type
).dereference()
1167 self
._node
= elt
['_M_nxt']
1168 valptr
= elt
['_M_storage'].address
1169 valptr
= valptr
.cast(elt
.type.template_argument(0).pointer())
1170 return valptr
.dereference()
1173 class Tr1UnorderedSetPrinter(printer_base
):
1174 """Print a std::unordered_set or tr1::unordered_set."""
1176 def __init__(self
, typename
, val
):
1177 self
._typename
= strip_versioned_namespace(typename
)
1180 def _hashtable(self
):
1181 if self
._typename
.startswith('std::tr1'):
1183 return self
._val
['_M_h']
1185 def to_string(self
):
1186 count
= self
._hashtable
()['_M_element_count']
1187 return '%s with %s' % (self
._typename
, num_elements(count
))
1190 def _format_count(i
):
1194 counter
= imap(self
._format
_count
, itertools
.count())
1195 if self
._typename
.startswith('std::tr1'):
1196 return izip(counter
, Tr1HashtableIterator(self
._hashtable
()))
1197 return izip(counter
, StdHashtableIterator(self
._hashtable
()))
1200 class Tr1UnorderedMapPrinter(printer_base
):
1201 """Print a std::unordered_map or tr1::unordered_map."""
1203 def __init__(self
, typename
, val
):
1204 self
._typename
= strip_versioned_namespace(typename
)
1207 def _hashtable(self
):
1208 if self
._typename
.startswith('std::tr1'):
1210 return self
._val
['_M_h']
1212 def to_string(self
):
1213 count
= self
._hashtable
()['_M_element_count']
1214 return '%s with %s' % (self
._typename
, num_elements(count
))
1223 def _format_one(elt
):
1224 return (elt
['first'], elt
['second'])
1227 def _format_count(i
):
1231 counter
= imap(self
._format
_count
, itertools
.count())
1232 # Map over the hash table and flatten the result.
1233 if self
._typename
.startswith('std::tr1'):
1234 data
= self
._flatten
(
1235 imap(self
._format
_one
, Tr1HashtableIterator(self
._hashtable
())))
1236 # Zip the two iterators together.
1237 return izip(counter
, data
)
1238 data
= self
._flatten
(
1239 imap(self
._format
_one
, StdHashtableIterator(self
._hashtable
())))
1240 # Zip the two iterators together.
1241 return izip(counter
, data
)
1243 def display_hint(self
):
1247 class StdForwardListPrinter(printer_base
):
1248 """Print a std::forward_list."""
1250 class _iterator(Iterator
):
1251 def __init__(self
, nodetype
, head
):
1252 self
._nodetype
= nodetype
1253 self
._base
= head
['_M_next']
1262 elt
= self
._base
.cast(self
._nodetype
).dereference()
1263 self
._base
= elt
['_M_next']
1265 self
._count
= self
._count
+ 1
1266 valptr
= elt
['_M_storage'].address
1267 valptr
= valptr
.cast(elt
.type.template_argument(0).pointer())
1268 return ('[%d]' % count
, valptr
.dereference())
1270 def __init__(self
, typename
, val
):
1272 self
._typename
= strip_versioned_namespace(typename
)
1275 nodetype
= lookup_node_type('_Fwd_list_node', self
._val
.type).pointer()
1276 return self
._iterator
(nodetype
, self
._val
['_M_impl']['_M_head'])
1278 def to_string(self
):
1279 if self
._val
['_M_impl']['_M_head']['_M_next'] == 0:
1280 return 'empty %s' % self
._typename
1281 return '%s' % self
._typename
1284 class SingleObjContainerPrinter(printer_base
):
1285 """Base class for printers of containers of single objects."""
1287 def __init__(self
, val
, viz
, hint
=None):
1288 self
._contained
_value
= val
1289 self
._visualizer
= viz
1292 def _recognize(self
, type):
1293 """Return type as a string after applying type printers."""
1294 global _use_type_printing
1295 if not _use_type_printing
:
1297 return gdb
.types
.apply_type_recognizers(gdb
.types
.get_type_recognizers(),
1300 class _contained(Iterator
):
1301 def __init__(self
, val
):
1308 if self
._val
is None:
1312 return ('[contained value]', retval
)
1315 if self
._contained
_value
is None:
1316 return self
._contained
(None)
1317 if hasattr(self
._visualizer
, 'children'):
1318 return self
._visualizer
.children()
1319 return self
._contained
(self
._contained
_value
)
1321 def display_hint(self
):
1322 if (hasattr(self
._visualizer
, 'children')
1323 and hasattr(self
._visualizer
, 'display_hint')):
1324 # If contained value is a map we want to display in the same way.
1325 return self
._visualizer
.display_hint()
1329 def function_pointer_to_name(f
):
1330 """Find the name of the function referred to by the gdb.Value f,
1331 which should contain a function pointer from the program."""
1333 # Turn the function pointer into an actual address.
1334 # This is needed to unpack ppc64 function descriptors.
1335 f
= f
.dereference().address
1337 if sys
.version_info
[0] == 2:
1338 # Older versions of GDB need to use long for Python 2,
1339 # because int(f) on 64-bit big-endian values raises a
1340 # gdb.error saying "Cannot convert value to int."
1346 # If the function can't be found older versions of GDB raise a
1347 # RuntimeError saying "Cannot locate object file for block."
1348 return gdb
.block_for_pc(f
).function
.name
1353 class StdExpAnyPrinter(SingleObjContainerPrinter
):
1354 """Print a std::any or std::experimental::any."""
1356 def __init__(self
, typename
, val
):
1357 self
._typename
= strip_versioned_namespace(typename
)
1358 self
._typename
= re
.sub(r
'^std::experimental::fundamentals_v\d::',
1359 'std::experimental::', self
._typename
, 1)
1361 self
._contained
_type
= None
1362 contained_value
= None
1364 mgr
= self
._val
['_M_manager']
1366 func
= function_pointer_to_name(mgr
)
1369 "Invalid function pointer in %s" % (self
._typename
))
1370 # We want to use this regular expression:
1371 # T::_Manager_xxx<.*>::_S_manage\(T::_Op, const T\*, T::_Arg\*\)
1372 # where T is std::any or std::experimental::any.
1373 # But we need to account for variances in demangled names
1374 # between GDB versions, e.g. 'enum T::_Op' instead of 'T::_Op'.
1376 r
"({0}::_Manager_\w+<.*>)::_S_manage\("
1377 r
"(enum )?{0}::_Op, (const {0}|{0} const) ?\*, "
1378 r
"(union )?{0}::_Arg ?\*\)"
1380 m
= re
.match(rx
, func
)
1383 "Unknown manager function in %s" % self
._typename
)
1385 mgrname
= m
.group(1)
1386 # FIXME need to expand 'std::string' so that gdb.lookup_type works
1387 if 'std::string' in mgrname
:
1389 for s
in StdExpAnyPrinter
._string
_types
():
1391 x
= re
.sub(r
"std::string(?!\w)", s
, m
.group(1))
1392 # The following lookup might raise gdb.error if the
1393 # manager function was never instantiated for 's' in
1394 # the program, because there will be no such type.
1395 mgrtypes
.append(gdb
.lookup_type(x
))
1398 if len(mgrtypes
) != 1:
1399 # FIXME: this is unlikely in practice, but possible for
1400 # programs that use both old and new string types with
1401 # std::any in a single program. Can we do better?
1402 # Maybe find the address of each type's _S_manage and
1403 # compare to the address stored in _M_manager?
1405 'Cannot uniquely determine std::string type '
1408 mgrtype
= mgrtypes
[0]
1410 mgrtype
= gdb
.lookup_type(mgrname
)
1411 self
._contained
_type
= mgrtype
.template_argument(0)
1413 if '::_Manager_internal' in mgrname
:
1414 valptr
= self
._val
['_M_storage']['_M_buffer'].address
1415 elif '::_Manager_external' in mgrname
:
1416 valptr
= self
._val
['_M_storage']['_M_ptr']
1419 "Unknown manager function in %s" % self
._typename
)
1420 contained_value
= valptr
.cast(
1421 self
._contained
_type
.pointer()).dereference()
1422 visualizer
= gdb
.default_visualizer(contained_value
)
1423 super(StdExpAnyPrinter
, self
).__init
__(contained_value
, visualizer
)
1425 def to_string(self
):
1426 if self
._contained
_type
is None:
1427 return '%s [no contained value]' % self
._typename
1428 desc
= "%s containing " % self
._typename
1429 if hasattr(self
._visualizer
, 'children'):
1430 return desc
+ self
._visualizer
.to_string()
1431 valtype
= self
._recognize
(self
._contained
_type
)
1432 return desc
+ strip_versioned_namespace(str(valtype
))
1435 def _string_types():
1436 # This lookup for std::string might return the __cxx11 version,
1437 # but that's not necessarily the one used by the std::any
1438 # manager function we're trying to find.
1439 strings
= {str(gdb
.lookup_type('std::string').strip_typedefs())}
1440 # So also consider all the other possible std::string types!
1441 s
= 'basic_string<char, std::char_traits<char>, std::allocator<char> >'
1442 quals
= ['std::', 'std::__cxx11::',
1443 'std::' + _versioned_namespace
]
1444 strings |
= {q
+ s
for q
in quals
} # set of unique strings
1448 class StdExpOptionalPrinter(SingleObjContainerPrinter
):
1449 """Print a std::optional or std::experimental::optional."""
1451 def __init__(self
, typename
, val
):
1452 typename
= strip_versioned_namespace(typename
)
1453 self
._typename
= re
.sub(
1454 r
'^std::(experimental::|)(fundamentals_v\d::|)(.*)',
1455 r
'std::\1\3', typename
, 1)
1456 payload
= val
['_M_payload']
1457 if self
._typename
.startswith('std::experimental'):
1458 engaged
= val
['_M_engaged']
1459 contained_value
= payload
1461 engaged
= payload
['_M_engaged']
1462 contained_value
= payload
['_M_payload']
1465 contained_value
= contained_value
['_M_value']
1468 visualizer
= gdb
.default_visualizer(contained_value
)
1470 contained_value
= None
1471 super(StdExpOptionalPrinter
, self
).__init
__(
1472 contained_value
, visualizer
)
1474 def to_string(self
):
1475 if self
._contained
_value
is None:
1476 return "%s [no contained value]" % self
._typename
1477 if hasattr(self
._visualizer
, 'children'):
1478 return "%s containing %s" % (self
._typename
,
1479 self
._visualizer
.to_string())
1480 return self
._typename
1483 class StdVariantPrinter(SingleObjContainerPrinter
):
1484 """Print a std::variant."""
1486 def __init__(self
, typename
, val
):
1487 alternatives
= get_template_arg_list(val
.type)
1488 self
._typename
= strip_versioned_namespace(typename
)
1489 self
._index
= val
['_M_index']
1490 if self
._index
>= len(alternatives
):
1491 self
._contained
_type
= None
1492 contained_value
= None
1495 self
._contained
_type
= alternatives
[int(self
._index
)]
1496 addr
= val
['_M_u']['_M_first']['_M_storage'].address
1497 contained_value
= addr
.cast(
1498 self
._contained
_type
.pointer()).dereference()
1499 visualizer
= gdb
.default_visualizer(contained_value
)
1500 super(StdVariantPrinter
, self
).__init
__(
1501 contained_value
, visualizer
, 'array')
1503 def to_string(self
):
1504 if self
._contained
_value
is None:
1505 return "%s [no contained value]" % self
._typename
1506 if hasattr(self
._visualizer
, 'children'):
1507 return "%s [index %d] containing %s" % (self
._typename
, self
._index
,
1508 self
._visualizer
.to_string())
1509 return "%s [index %d]" % (self
._typename
, self
._index
)
1512 class StdNodeHandlePrinter(SingleObjContainerPrinter
):
1513 """Print a container node handle."""
1515 def __init__(self
, typename
, val
):
1516 self
._value
_type
= val
.type.template_argument(1)
1517 nodetype
= val
.type.template_argument(2).template_argument(0)
1518 self
._is
_rb
_tree
_node
= is_specialization_of(
1519 nodetype
.name
, '_Rb_tree_node')
1520 self
._is
_map
_node
= val
.type.template_argument(0) != self
._value
_type
1521 nodeptr
= val
['_M_ptr']
1523 if self
._is
_rb
_tree
_node
:
1524 contained_value
= get_value_from_Rb_tree_node(
1525 nodeptr
.dereference())
1527 contained_value
= get_value_from_aligned_membuf(nodeptr
['_M_storage'],
1529 visualizer
= gdb
.default_visualizer(contained_value
)
1531 contained_value
= None
1533 optalloc
= val
['_M_alloc']
1534 self
._alloc
= optalloc
['_M_payload'] if optalloc
['_M_engaged'] else None
1535 super(StdNodeHandlePrinter
, self
).__init
__(contained_value
, visualizer
,
1538 def to_string(self
):
1539 desc
= 'node handle for '
1540 if not self
._is
_rb
_tree
_node
:
1541 desc
+= 'unordered '
1542 if self
._is
_map
_node
:
1547 if self
._contained
_value
:
1548 desc
+= ' with element'
1549 if hasattr(self
._visualizer
, 'children'):
1550 return "%s = %s" % (desc
, self
._visualizer
.to_string())
1553 return 'empty %s' % desc
1556 class StdExpStringViewPrinter(printer_base
):
1558 Print a std::basic_string_view or std::experimental::basic_string_view
1561 def __init__(self
, typename
, val
):
1564 def to_string(self
):
1565 ptr
= self
._val
['_M_str']
1566 len = self
._val
['_M_len']
1567 if hasattr(ptr
, "lazy_string"):
1568 return ptr
.lazy_string(length
=len)
1569 return ptr
.string(length
=len)
1571 def display_hint(self
):
1575 class StdExpPathPrinter(printer_base
):
1576 """Print a std::experimental::filesystem::path."""
1578 def __init__(self
, typename
, val
):
1580 self
._typename
= typename
1581 start
= self
._val
['_M_cmpts']['_M_impl']['_M_start']
1582 finish
= self
._val
['_M_cmpts']['_M_impl']['_M_finish']
1583 self
._num
_cmpts
= int(finish
- start
)
1585 def _path_type(self
):
1586 t
= str(self
._val
['_M_type'])
1587 if t
[-9:] == '_Root_dir':
1588 return "root-directory"
1589 if t
[-10:] == '_Root_name':
1593 def to_string(self
):
1594 path
= "%s" % self
._val
['_M_pathname']
1595 if self
._num
_cmpts
== 0:
1596 t
= self
._path
_type
()
1598 path
= '%s [%s]' % (path
, t
)
1599 return "experimental::filesystem::path %s" % path
1601 class _iterator(Iterator
):
1602 def __init__(self
, cmpts
, pathtype
):
1603 self
._pathtype
= pathtype
1604 self
._item
= cmpts
['_M_impl']['_M_start']
1605 self
._finish
= cmpts
['_M_impl']['_M_finish']
1612 if self
._item
== self
._finish
:
1614 item
= self
._item
.dereference()
1616 self
._count
= self
._count
+ 1
1617 self
._item
= self
._item
+ 1
1618 path
= item
['_M_pathname']
1619 t
= StdExpPathPrinter(self
._pathtype
, item
)._path
_type
()
1622 return ('[%s]' % t
, path
)
1625 return self
._iterator
(self
._val
['_M_cmpts'], self
._typename
)
1628 class StdPathPrinter(printer_base
):
1629 """Print a std::filesystem::path."""
1631 def __init__(self
, typename
, val
):
1633 self
._typename
= typename
1634 impl
= unique_ptr_get(self
._val
['_M_cmpts']['_M_impl'])
1635 self
._type
= impl
.cast(gdb
.lookup_type('uintptr_t')) & 3
1641 def _path_type(self
):
1642 t
= str(self
._type
.cast(gdb
.lookup_type(self
._typename
+ '::_Type')))
1643 if t
[-9:] == '_Root_dir':
1644 return "root-directory"
1645 if t
[-10:] == '_Root_name':
1649 def to_string(self
):
1650 path
= "%s" % self
._val
['_M_pathname']
1652 t
= self
._path
_type
()
1654 path
= '%s [%s]' % (path
, t
)
1655 return "filesystem::path %s" % path
1657 class _iterator(Iterator
):
1658 def __init__(self
, impl
, pathtype
):
1659 self
._pathtype
= pathtype
1661 # We can't access _Impl::_M_size because _Impl is incomplete
1662 # so cast to int* to access the _M_size member at offset zero,
1663 int_type
= gdb
.lookup_type('int')
1664 cmpt_type
= gdb
.lookup_type(pathtype
+ '::_Cmpt')
1665 char_type
= gdb
.lookup_type('char')
1666 impl
= impl
.cast(int_type
.pointer())
1667 size
= impl
.dereference()
1668 #self._capacity = (impl + 1).dereference()
1669 if hasattr(gdb
.Type
, 'alignof'):
1670 sizeof_Impl
= max(2 * int_type
.sizeof
, cmpt_type
.alignof
)
1672 sizeof_Impl
= 2 * int_type
.sizeof
1673 begin
= impl
.cast(char_type
.pointer()) + sizeof_Impl
1674 self
._item
= begin
.cast(cmpt_type
.pointer())
1675 self
._finish
= self
._item
+ size
1685 if self
._item
== self
._finish
:
1687 item
= self
._item
.dereference()
1689 self
._count
= self
._count
+ 1
1690 self
._item
= self
._item
+ 1
1691 path
= item
['_M_pathname']
1692 t
= StdPathPrinter(self
._pathtype
, item
)._path
_type
()
1695 return ('[%s]' % t
, path
)
1698 return self
._iterator
(self
._impl
, self
._typename
)
1701 class StdPairPrinter(printer_base
):
1702 """Print a std::pair object, with 'first' and 'second' as children."""
1704 def __init__(self
, typename
, val
):
1707 class _iter(Iterator
):
1708 """An iterator for std::pair types. Returns 'first' then 'second'."""
1710 def __init__(self
, val
):
1712 self
._which
= 'first'
1718 if self
._which
is None:
1721 if which
== 'first':
1722 self
._which
= 'second'
1725 return (which
, self
._val
[which
])
1728 return self
._iter
(self
._val
)
1730 def to_string(self
):
1734 class StdCmpCatPrinter(printer_base
):
1735 """Print a comparison category object."""
1737 def __init__(self
, typename
, val
):
1738 self
._typename
= typename
[typename
.rfind(':') + 1:]
1739 self
._val
= val
['_M_value']
1741 def to_string(self
):
1742 if self
._typename
== 'strong_ordering' and self
._val
== 0:
1745 names
= {2: 'unordered', -1: 'less', 0: 'equivalent', 1: 'greater'}
1746 name
= names
[int(self
._val
)]
1747 return 'std::{}::{}'.format(self
._typename
, name
)
1750 class StdErrorCodePrinter(printer_base
):
1751 """Print a std::error_code or std::error_condition."""
1753 _system_is_posix
= None # Whether std::system_category() use errno values.
1755 def __init__(self
, typename
, val
):
1757 self
._typename
= strip_versioned_namespace(typename
)
1758 # Do this only once ...
1759 if StdErrorCodePrinter
._system
_is
_posix
is None:
1762 StdErrorCodePrinter
._system
_is
_posix
= True
1764 StdErrorCodePrinter
._system
_is
_posix
= False
1767 def _find_errc_enum(name
):
1768 typ
= gdb
.lookup_type(name
)
1769 if typ
is not None and typ
.code
== gdb
.TYPE_CODE_ENUM
:
1774 def _find_standard_errc_enum(cls
, name
):
1775 for ns
in ['', _versioned_namespace
]:
1777 qname
= 'std::{}{}'.format(ns
, name
)
1778 return cls
._find
_errc
_enum
(qname
)
1779 except RuntimeError:
1783 def _match_net_ts_category(cls
, cat
):
1784 net_cats
= ['stream', 'socket', 'ip::resolver']
1786 func
= c
+ '_category()'
1787 for ns
in ['', _versioned_namespace
]:
1788 ns
= 'std::{}experimental::net::v1'.format(ns
)
1789 sym
= gdb
.lookup_symbol('{}::{}::__c'.format(ns
, func
))[0]
1791 if cat
== sym
.value().address
:
1792 name
= 'net::' + func
1793 enum
= cls
._find
_errc
_enum
('{}::{}_errc'.format(ns
, c
))
1798 def _category_info(cls
, cat
):
1799 """Return details of a std::error_category."""
1805 # Try these first, or we get "warning: RTTI symbol not found" when
1806 # using cat.dynamic_type on the local class types for Net TS
1808 func
, enum
= cls
._match
_net
_ts
_category
(cat
)
1809 if func
is not None:
1810 return (None, func
, enum
, is_errno
)
1812 # This might give a warning for a program-defined category defined as
1813 # a local class, but there doesn't seem to be any way to avoid that.
1814 typ
= cat
.dynamic_type
.target()
1815 # Shortcuts for the known categories defined by libstdc++.
1816 if typ
.tag
.endswith('::generic_error_category'):
1819 if typ
.tag
.endswith('::system_error_category'):
1821 is_errno
= cls
._system
_is
_posix
1822 if typ
.tag
.endswith('::future_error_category'):
1824 enum
= cls
._find
_standard
_errc
_enum
('future_errc')
1825 if typ
.tag
.endswith('::io_error_category'):
1827 enum
= cls
._find
_standard
_errc
_enum
('io_errc')
1831 # Want to call std::error_category::name() override, but it's
1832 # unsafe: https://sourceware.org/bugzilla/show_bug.cgi?id=28856
1833 # gdb.set_convenience_variable('__cat', cat)
1834 # return '"%s"' % gdb.parse_and_eval('$__cat->name()').string()
1838 return (name
, typ
.tag
, enum
, is_errno
)
1841 def _unqualified_name(name
):
1843 Strip any nested-name-specifier from name to give an unqualified name.
1845 return name
.split('::')[-1]
1847 def to_string(self
):
1848 value
= self
._val
['_M_value']
1849 cat
= self
._val
['_M_cat']
1850 name
, alt_name
, enum
, is_errno
= self
._category
_info
(cat
)
1852 default_cats
= {'error_code': 'system',
1853 'error_condition': 'generic'}
1854 if name
== default_cats
[self
._unqualified
_name
(self
._typename
)]:
1855 return self
._typename
+ ' = { }' # default-constructed value
1858 if is_errno
and value
!= 0:
1860 strval
= errno
.errorcode
[int(value
)]
1863 elif enum
is not None:
1864 strval
= self
._unqualified
_name
(str(value
.cast(enum
)))
1866 if name
is not None:
1867 name
= '"%s"' % name
1870 return '%s = {%s: %s}' % (self
._typename
, name
, strval
)
1873 class StdRegexStatePrinter(printer_base
):
1874 """Print a state node in the NFA for a std::regex."""
1876 def __init__(self
, typename
, val
):
1878 self
._typename
= typename
1880 def to_string(self
):
1881 opcode
= str(self
._val
['_M_opcode'])
1883 opcode
= opcode
[25:]
1884 next_id
= self
._val
['_M_next']
1886 variants
= {'repeat': 'alt', 'alternative': 'alt',
1887 'subexpr_begin': 'subexpr', 'subexpr_end': 'subexpr',
1888 'line_begin_assertion': None, 'line_end_assertion': None,
1889 'word_boundary': 'neg', 'subexpr_lookahead': 'neg',
1890 'backref': 'backref_index',
1891 'match': None, 'accept': None,
1892 'dummy': None, 'unknown': None
1894 v
= variants
[opcode
]
1896 s
= "opcode={}, next={}".format(opcode
, next_id
)
1897 if v
is not None and self
._val
['_M_' + v
] is not None:
1898 s
= "{}, {}={}".format(s
, v
, self
._val
['_M_' + v
])
1902 class StdSpanPrinter(printer_base
):
1903 """Print a std::span."""
1905 class _iterator(Iterator
):
1906 def __init__(self
, begin
, size
):
1915 if self
._count
== self
._size
:
1919 self
._count
= self
._count
+ 1
1920 return '[%d]' % count
, (self
._begin
+ count
).dereference()
1922 def __init__(self
, typename
, val
):
1923 self
._typename
= strip_versioned_namespace(typename
)
1925 size_max
= gdb
.parse_and_eval('static_cast<std::size_t>(-1)')
1926 if val
.type.template_argument(1) == size_max
:
1927 self
._size
= val
['_M_extent']['_M_extent_value']
1929 self
._size
= val
.type.template_argument(1)
1931 def to_string(self
):
1932 return '%s of length %d' % (self
._typename
, self
._size
)
1935 return self
._iterator
(self
._val
['_M_ptr'], self
._size
)
1937 def display_hint(self
):
1941 class StdInitializerListPrinter(printer_base
):
1942 """Print a std::initializer_list."""
1944 def __init__(self
, typename
, val
):
1945 self
._typename
= typename
1947 self
._size
= val
['_M_len']
1949 def to_string(self
):
1950 return '%s of length %d' % (self
._typename
, self
._size
)
1953 return StdSpanPrinter
._iterator
(self
._val
['_M_array'], self
._size
)
1955 def display_hint(self
):
1959 class StdAtomicPrinter(printer_base
):
1960 """Print a std:atomic."""
1962 def __init__(self
, typename
, val
):
1963 self
._typename
= strip_versioned_namespace(typename
)
1965 self
._shptr
_printer
= None
1966 self
._value
_type
= self
._val
.type.template_argument(0)
1967 if self
._value
_type
.tag
is not None:
1968 typ
= strip_versioned_namespace(self
._value
_type
.tag
)
1969 if (typ
.startswith('std::shared_ptr<')
1970 or typ
.startswith('std::weak_ptr<')):
1971 impl
= val
['_M_impl']
1972 self
._shptr
_printer
= SharedPointerPrinter(typename
, impl
)
1973 self
.children
= self
._shptr
_children
1975 def _shptr_children(self
):
1976 return SmartPtrIterator(self
._shptr
_printer
._pointer
)
1978 def to_string(self
):
1979 if self
._shptr
_printer
is not None:
1980 return self
._shptr
_printer
.to_string()
1982 if self
._value
_type
.code
== gdb
.TYPE_CODE_INT
:
1983 val
= self
._val
['_M_i']
1984 elif self
._value
_type
.code
== gdb
.TYPE_CODE_FLT
:
1985 val
= self
._val
['_M_fp']
1986 elif self
._value
_type
.code
== gdb
.TYPE_CODE_PTR
:
1987 val
= self
._val
['_M_b']['_M_p']
1988 elif self
._value
_type
.code
== gdb
.TYPE_CODE_BOOL
:
1989 val
= self
._val
['_M_base']['_M_i']
1991 val
= self
._val
['_M_i']
1992 return '%s<%s> = { %s }' % (self
._typename
, str(self
._value
_type
), val
)
1995 class StdFormatArgsPrinter(printer_base
):
1996 """Print a std::basic_format_args."""
1997 # TODO: add printer for basic_format_arg<Context> and print out children.
1998 # TODO: add printer for __format::_ArgStore<Context, Args...>.
2000 def __init__(self
, typename
, val
):
2001 self
._typename
= strip_versioned_namespace(typename
)
2004 def to_string(self
):
2005 targs
= get_template_arg_list(self
._val
.type)
2006 char_type
= get_template_arg_list(targs
[0])[1]
2007 if char_type
== gdb
.lookup_type('char'):
2008 typ
= 'std::format_args'
2009 elif char_type
== gdb
.lookup_type('wchar_t'):
2010 typ
= 'std::wformat_args'
2012 typ
= 'std::basic_format_args'
2014 size
= self
._val
['_M_packed_size']
2016 return "%s with 1 argument" % (typ
)
2018 size
= self
._val
['_M_unpacked_size']
2019 return "%s with %d arguments" % (typ
, size
)
2022 class StdChronoDurationPrinter(printer_base
):
2023 """Print a std::chrono::duration."""
2025 def __init__(self
, typename
, val
):
2026 self
._typename
= strip_versioned_namespace(typename
)
2030 # TODO use reduced period i.e. duration::period
2031 period
= self
._val
.type.template_argument(1)
2032 num
= period
.template_argument(0)
2033 den
= period
.template_argument(1)
2037 num
, den
= self
._ratio
()
2045 if den
== 1000000000:
2054 return '[{}]s'.format(num
)
2055 return "[{}/{}]s".format(num
, den
)
2057 def to_string(self
):
2058 r
= self
._val
['__r']
2059 if r
.type.strip_typedefs().code
== gdb
.TYPE_CODE_FLT
:
2061 return "std::chrono::duration = {{ {}{} }}".format(r
, self
._suffix
())
2064 class StdChronoTimePointPrinter(printer_base
):
2065 """Print a std::chrono::time_point."""
2067 def __init__(self
, typename
, val
):
2068 self
._typename
= strip_versioned_namespace(typename
)
2072 clock
= self
._val
.type.template_argument(0)
2073 name
= strip_versioned_namespace(clock
.name
)
2074 if name
== 'std::chrono::_V2::system_clock' \
2075 or name
== 'std::chrono::system_clock':
2076 return ('std::chrono::sys_time', 0)
2077 # XXX need to remove leap seconds from utc, gps, and tai
2078 if name
== 'std::chrono::utc_clock':
2079 return ('std::chrono::utc_time', None) # XXX
2080 if name
== 'std::chrono::gps_clock':
2081 return ('std::chrono::gps_time', None) # XXX 315964809
2082 if name
== 'std::chrono::tai_clock':
2083 return ('std::chrono::tai_time', None) # XXX -378691210
2084 if name
== 'std::filesystem::__file_clock':
2085 return ('std::chrono::file_time', 6437664000)
2086 if name
== 'std::chrono::local_t':
2087 return ('std::chrono::local_time', 0)
2088 return ('{} time_point'.format(name
), None)
2090 def to_string(self
, abbrev
=False):
2091 clock
, offset
= self
._clock
()
2092 d
= self
._val
['__d']
2094 printer
= StdChronoDurationPrinter(d
.type.name
, d
)
2095 suffix
= printer
._suffix
()
2097 if offset
is not None:
2098 num
, den
= printer
._ratio
()
2099 secs
= (r
* num
/ den
) + offset
2101 dt
= datetime
.datetime
.fromtimestamp(secs
, _utc_timezone
)
2102 time
= ' [{:%Y-%m-%d %H:%M:%S}]'.format(dt
)
2105 s
= '%d%s%s' % (r
, suffix
, time
)
2108 return '%s = { %s }' % (clock
, s
)
2111 class StdChronoZonedTimePrinter(printer_base
):
2112 """Print a std::chrono::zoned_time."""
2114 def __init__(self
, typename
, val
):
2115 self
._typename
= strip_versioned_namespace(typename
)
2118 def to_string(self
):
2119 zone
= self
._val
['_M_zone'].dereference()['_M_name']
2120 time
= self
._val
['_M_tp']
2121 printer
= StdChronoTimePointPrinter(time
.type.name
, time
)
2122 time
= printer
.to_string(True)
2123 return 'std::chrono::zoned_time = {{ {} {} }}'.format(zone
, time
)
2126 months
= [None, 'January', 'February', 'March', 'April', 'May', 'June',
2127 'July', 'August', 'September', 'October', 'November', 'December']
2129 weekdays
= ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
2130 'Saturday', 'Sunday']
2133 class StdChronoCalendarPrinter(printer_base
):
2134 """Print a std::chrono::day, std::chrono::month, std::chrono::year etc."""
2136 def __init__(self
, typename
, val
):
2137 self
._typename
= strip_versioned_namespace(typename
)
2140 def to_string(self
):
2142 typ
= self
._typename
2143 if 'month' in typ
and typ
!= 'std::chrono::year_month_day_last':
2145 if typ
.startswith('std::chrono::year'):
2148 if typ
== 'std::chrono::day':
2149 return '{}'.format(int(val
['_M_d']))
2150 if typ
== 'std::chrono::month':
2151 if m
< 1 or m
>= len(months
):
2152 return "%d is not a valid month" % m
2154 if typ
== 'std::chrono::year':
2155 return '{}y'.format(y
)
2156 if typ
== 'std::chrono::weekday':
2158 if wd
< 0 or wd
>= len(weekdays
):
2159 return "%d is not a valid weekday" % wd
2160 return '{}'.format(weekdays
[wd
])
2161 if typ
== 'std::chrono::weekday_indexed':
2162 return '{}[{}]'.format(val
['_M_wd'], int(val
['_M_index']))
2163 if typ
== 'std::chrono::weekday_last':
2164 return '{}[last]'.format(val
['_M_wd'])
2165 if typ
== 'std::chrono::month_day':
2166 return '{}/{}'.format(m
, val
['_M_d'])
2167 if typ
== 'std::chrono::month_day_last':
2168 return '{}/last'.format(m
)
2169 if typ
== 'std::chrono::month_weekday':
2170 return '{}/{}'.format(m
, val
['_M_wdi'])
2171 if typ
== 'std::chrono::month_weekday_last':
2172 return '{}/{}'.format(m
, val
['_M_wdl'])
2173 if typ
== 'std::chrono::year_month':
2174 return '{}/{}'.format(y
, m
)
2175 if typ
== 'std::chrono::year_month_day':
2176 return '{}/{}/{}'.format(y
, m
, val
['_M_d'])
2177 if typ
== 'std::chrono::year_month_day_last':
2178 return '{}/{}'.format(y
, val
['_M_mdl'])
2179 if typ
== 'std::chrono::year_month_weekday':
2180 return '{}/{}/{}'.format(y
, m
, val
['_M_wdi'])
2181 if typ
== 'std::chrono::year_month_weekday_last':
2182 return '{}/{}/{}'.format(y
, m
, val
['_M_wdl'])
2183 if typ
.startswith('std::chrono::hh_mm_ss'):
2185 if val
['fractional_width'] != 0:
2186 fract
= '.{:0{}d}'.format(int(val
['_M_ss']['_M_r']),
2187 int(val
['fractional_width']))
2188 h
= int(val
['_M_h']['__r'])
2189 m
= int(val
['_M_m']['__r'])
2190 s
= int(val
['_M_s']['__r'])
2191 if val
['_M_is_neg']:
2193 return '{:02}:{:02}:{:02}{}'.format(h
, m
, s
, fract
)
2196 class StdChronoTimeZonePrinter(printer_base
):
2197 """Print a chrono::time_zone or chrono::time_zone_link."""
2199 def __init__(self
, typename
, val
):
2200 self
._typename
= strip_versioned_namespace(typename
)
2203 def to_string(self
):
2204 str = '%s = %s' % (self
._typename
, self
._val
['_M_name'])
2205 if self
._typename
.endswith("_link"):
2206 str += ' -> %s' % (self
._val
['_M_target'])
2210 class StdChronoLeapSecondPrinter(printer_base
):
2211 """Print a chrono::leap_second."""
2213 def __init__(self
, typename
, val
):
2214 self
._typename
= strip_versioned_namespace(typename
)
2217 def to_string(self
):
2218 date
= self
._val
['_M_s']['__r']
2219 neg
= '+-'[date
< 0]
2220 return '%s %d (%c)' % (self
._typename
, abs(date
), neg
)
2223 class StdChronoTzdbPrinter(printer_base
):
2224 """Print a chrono::tzdb."""
2226 def __init__(self
, typename
, val
):
2227 self
._typename
= strip_versioned_namespace(typename
)
2230 def to_string(self
):
2231 return '%s %s' % (self
._typename
, self
._val
['version'])
2234 class StdChronoTimeZoneRulePrinter(printer_base
):
2235 """Print a chrono::time_zone rule."""
2237 def __init__(self
, typename
, val
):
2238 self
._typename
= strip_versioned_namespace(typename
)
2241 def to_string(self
):
2242 on
= self
._val
['on']
2244 month
= months
[on
['month']]
2245 suffixes
= {1: 'st', 2: 'nd', 3: 'rd',
2246 21: 'st', 22: 'nd', 23: 'rd', 31: 'st'}
2247 day
= on
['day_of_month']
2248 ordinal_day
= '{}{}'.format(day
, suffixes
.get(day
, 'th'))
2249 if kind
== 0: # DayOfMonth
2250 start
= '{} {}'.format(month
, ordinal_day
)
2252 weekday
= weekdays
[on
['day_of_week']]
2253 if kind
== 1: # LastWeekDay
2254 start
= 'last {} in {}'.format(weekday
, month
)
2256 if kind
== 2: # LessEq
2257 direction
= ('last', '<=')
2259 direction
= ('first', '>=')
2260 day
= on
['day_of_month']
2261 start
= '{} {} {} {} {}'.format(direction
[0], weekday
,
2262 direction
[1], month
,
2264 return 'time_zone rule {} from {} to {} starting on {}'.format(
2265 self
._val
['name'], self
._val
['from'], self
._val
['to'], start
)
2268 class StdLocalePrinter(printer_base
):
2269 """Print a std::locale."""
2271 def __init__(self
, typename
, val
):
2273 self
._typename
= typename
2275 def to_string(self
):
2276 names
= self
._val
['_M_impl']['_M_names']
2281 cats
= gdb
.parse_and_eval(self
._typename
+ '::_S_categories')
2282 ncat
= gdb
.parse_and_eval(self
._typename
+ '::_S_categories_size')
2283 n
= names
[0].string()
2284 cat
= cats
[0].string()
2285 name
= '{}={}'.format(cat
, n
)
2286 cat_names
= {cat
: n
}
2288 while i
< ncat
and names
[i
] != 0:
2289 n
= names
[i
].string()
2290 cat
= cats
[i
].string()
2291 name
= '{};{}={}'.format(name
, cat
, n
)
2294 uniq_names
= set(cat_names
.values())
2295 if len(uniq_names
) == 1:
2297 elif len(uniq_names
) == 2:
2298 n1
, n2
= (uniq_names
)
2299 name_list
= list(cat_names
.values())
2301 if name_list
.count(n1
) == 1:
2304 elif name_list
.count(n2
) == 1:
2307 if other
is not None:
2308 cat
= next(c
for c
, n
in cat_names
.items() if n
== other
)
2309 mod
= ' with "{}={}"'.format(cat
, other
)
2310 return 'std::locale = "{}"{}'.format(name
, mod
)
2312 class StdIntegralConstantPrinter(printer_base
):
2313 """Print a std::true_type or std::false_type."""
2315 def __init__(self
, typename
, val
):
2317 self
._typename
= typename
2319 def to_string(self
):
2320 value_type
= self
._val
.type.template_argument(0)
2321 value
= self
._val
.type.template_argument(1)
2322 if value_type
.code
== gdb
.TYPE_CODE_BOOL
:
2324 return "std::true_type"
2326 return "std::false_type"
2327 typename
= strip_versioned_namespace(self
._typename
)
2328 return "{}<{}, {}>".format(typename
, value_type
, value
)
2330 class StdTextEncodingPrinter(printer_base
):
2331 """Print a std::text_encoding."""
2333 def __init__(self
, typename
, val
):
2335 self
._typename
= typename
2337 def to_string(self
):
2338 rep
= self
._val
['_M_rep'].dereference()
2339 if rep
['_M_id'] == 1:
2340 return self
._val
['_M_name']
2341 if rep
['_M_id'] == 2:
2343 return rep
['_M_name']
2345 # A "regular expression" printer which conforms to the
2346 # "SubPrettyPrinter" protocol from gdb.printing.
2347 class RxPrinter(object):
2348 def __init__(self
, name
, function
):
2349 super(RxPrinter
, self
).__init
__()
2351 self
._function
= function
2354 def invoke(self
, value
):
2355 if not self
.enabled
:
2358 if value
.type.code
== gdb
.TYPE_CODE_REF
:
2359 if hasattr(gdb
.Value
, "referenced_value"):
2360 value
= value
.referenced_value()
2362 return self
._function
(self
.name
, value
)
2364 # A pretty-printer that conforms to the "PrettyPrinter" protocol from
2365 # gdb.printing. It can also be used directly as an old-style printer.
2368 class Printer(object):
2369 def __init__(self
, name
):
2370 super(Printer
, self
).__init
__()
2372 self
._subprinters
= []
2375 self
._compiled
_rx
= re
.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
2377 def add(self
, name
, function
):
2378 # A small sanity check.
2380 if not self
._compiled
_rx
.match(name
):
2382 'libstdc++ programming error: "%s" does not match' % name
)
2383 printer
= RxPrinter(name
, function
)
2384 self
._subprinters
.append(printer
)
2385 self
._lookup
[name
] = printer
2387 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
2388 def add_version(self
, base
, name
, function
):
2389 self
.add(base
+ name
, function
)
2390 if '__cxx11' not in base
:
2391 vbase
= re
.sub('^(std|__gnu_cxx)::', r
'\g<0>%s' %
2392 _versioned_namespace
, base
)
2393 self
.add(vbase
+ name
, function
)
2395 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
2396 def add_container(self
, base
, name
, function
):
2397 self
.add_version(base
, name
, function
)
2398 self
.add_version(base
+ '__cxx1998::', name
, function
)
2401 def get_basic_type(type):
2402 # If it points to a reference, get the reference.
2403 if type.code
== gdb
.TYPE_CODE_REF
:
2404 type = type.target()
2406 # Get the unqualified type, stripped of typedefs.
2407 type = type.unqualified().strip_typedefs()
2411 def __call__(self
, val
):
2412 typename
= self
.get_basic_type(val
.type)
2416 # All the types we match are template types, so we can use a
2418 match
= self
._compiled
_rx
.match(typename
)
2422 basename
= match
.group(1)
2424 if val
.type.code
== gdb
.TYPE_CODE_REF
:
2425 if hasattr(gdb
.Value
, "referenced_value"):
2426 val
= val
.referenced_value()
2428 if basename
in self
._lookup
:
2429 return self
._lookup
[basename
].invoke(val
)
2431 # Cannot find a pretty printer. Return None.
2435 libstdcxx_printer
= None
2438 class TemplateTypePrinter(object):
2440 A type printer for class templates with default template arguments.
2442 Recognizes specializations of class templates and prints them without
2443 any template arguments that use a default template argument.
2444 Type printers are recursively applied to the template arguments.
2446 e.g. replace 'std::vector<T, std::allocator<T> >' with 'std::vector<T>'.
2449 def __init__(self
, name
, defargs
):
2451 self
._defargs
= defargs
2454 class _recognizer(object):
2455 """The recognizer class for TemplateTypePrinter."""
2457 def __init__(self
, name
, defargs
):
2459 self
._defargs
= defargs
2460 # self._type_obj = None
2462 def recognize(self
, type_obj
):
2464 If type_obj is a specialization of self.name that uses all the
2465 default template arguments for the class template, then return
2466 a string representation of the type without default arguments.
2467 Otherwise, return None.
2470 if type_obj
.tag
is None:
2473 if not type_obj
.tag
.startswith(self
.name
):
2476 template_args
= get_template_arg_list(type_obj
)
2478 require_defaulted
= False
2479 for n
in range(len(template_args
)):
2480 # The actual template argument in the type:
2481 targ
= template_args
[n
]
2482 # The default template argument for the class template:
2483 defarg
= self
._defargs
.get(n
)
2484 if defarg
is not None:
2485 # Substitute other template arguments into the default:
2486 defarg
= defarg
.format(*template_args
)
2487 # Fail to recognize the type (by returning None)
2488 # unless the actual argument is the same as the default.
2490 if targ
!= gdb
.lookup_type(defarg
):
2493 # Type lookup failed, just use string comparison:
2494 if targ
.tag
!= defarg
:
2496 # All subsequent args must have defaults:
2497 require_defaulted
= True
2498 elif require_defaulted
:
2501 # Recursively apply recognizers to the template argument
2502 # and add it to the arguments that will be displayed:
2503 displayed_args
.append(self
._recognize
_subtype
(targ
))
2505 # This assumes no class templates in the nested-name-specifier:
2506 template_name
= type_obj
.tag
[0:type_obj
.tag
.find('<')]
2507 template_name
= strip_inline_namespaces(template_name
)
2509 return template_name
+ '<' + ', '.join(displayed_args
) + '>'
2511 def _recognize_subtype(self
, type_obj
):
2512 """Convert a gdb.Type to a string by applying recognizers,
2513 or if that fails then simply converting to a string."""
2515 if type_obj
.code
== gdb
.TYPE_CODE_PTR
:
2516 return self
._recognize
_subtype
(type_obj
.target()) + '*'
2517 if type_obj
.code
== gdb
.TYPE_CODE_ARRAY
:
2518 type_str
= self
._recognize
_subtype
(type_obj
.target())
2519 if str(type_obj
.strip_typedefs()).endswith('[]'):
2520 return type_str
+ '[]' # array of unknown bound
2521 return "%s[%d]" % (type_str
, type_obj
.range()[1] + 1)
2522 if type_obj
.code
== gdb
.TYPE_CODE_REF
:
2523 return self
._recognize
_subtype
(type_obj
.target()) + '&'
2524 if hasattr(gdb
, 'TYPE_CODE_RVALUE_REF'):
2525 if type_obj
.code
== gdb
.TYPE_CODE_RVALUE_REF
:
2526 return self
._recognize
_subtype
(type_obj
.target()) + '&&'
2528 type_str
= gdb
.types
.apply_type_recognizers(
2529 gdb
.types
.get_type_recognizers(), type_obj
)
2532 return str(type_obj
)
2534 def instantiate(self
):
2535 """Return a recognizer object for this type printer."""
2536 return self
._recognizer
(self
.name
, self
._defargs
)
2539 def add_one_template_type_printer(obj
, name
, defargs
):
2541 Add a type printer for a class template with default template arguments.
2544 name (str): The template-name of the class template.
2545 defargs (dict int:string) The default template arguments.
2547 Types in defargs can refer to the Nth template-argument using {N}
2548 (with zero-based indices).
2550 e.g. 'unordered_map' has these defargs:
2551 { 2: 'std::hash<{0}>',
2552 3: 'std::equal_to<{0}>',
2553 4: 'std::allocator<std::pair<const {0}, {1}> >' }
2555 printer
= TemplateTypePrinter('std::' + name
, defargs
)
2556 gdb
.types
.register_type_printer(obj
, printer
)
2558 # Add type printer for same type in debug namespace:
2559 printer
= TemplateTypePrinter('std::__debug::' + name
, defargs
)
2560 gdb
.types
.register_type_printer(obj
, printer
)
2562 if '__cxx11' not in name
:
2563 # Add second type printer for same type in versioned namespace:
2564 ns
= 'std::' + _versioned_namespace
2565 # PR 86112 Cannot use dict comprehension here:
2566 defargs
= dict((n
, d
.replace('std::', ns
))
2567 for (n
, d
) in defargs
.items())
2568 printer
= TemplateTypePrinter(ns
+ name
, defargs
)
2569 gdb
.types
.register_type_printer(obj
, printer
)
2571 # Add type printer for same type in debug namespace:
2572 printer
= TemplateTypePrinter('std::__debug::' + name
, defargs
)
2573 gdb
.types
.register_type_printer(obj
, printer
)
2576 class FilteringTypePrinter(object):
2578 A type printer that uses typedef names for common template specializations.
2581 template (str): The class template to recognize.
2582 name (str): The typedef-name that will be used instead.
2583 targ1 (str, optional): The first template argument. Defaults to None.
2585 Checks if a specialization of the class template 'template' is the same type
2586 as the typedef 'name', and prints it as 'name' instead.
2588 e.g. if an instantiation of std::basic_istream<C, T> is the same type as
2589 std::istream then print it as std::istream.
2591 If targ1 is provided (not None), match only template specializations with
2592 this type as the first template argument, e.g. if template='basic_string'
2593 and targ1='char' then only match 'basic_string<char,...>' and not
2594 'basic_string<wchar_t,...>'. This rejects non-matching specializations
2595 more quickly, without needing to do GDB type lookups.
2598 def __init__(self
, template
, name
, targ1
=None):
2599 self
._template
= template
2604 class _recognizer(object):
2605 """The recognizer class for FilteringTypePrinter."""
2607 def __init__(self
, template
, name
, targ1
):
2608 self
._template
= template
2611 self
._type
_obj
= None
2613 def recognize(self
, type_obj
):
2615 If type_obj starts with self._template and is the same type as
2616 self.name then return self.name, otherwise None.
2618 if type_obj
.tag
is None:
2621 if self
._type
_obj
is None:
2622 if self
._targ
1 is not None:
2623 s
= '{}<{}'.format(self
._template
, self
._targ
1)
2624 if not type_obj
.tag
.startswith(s
):
2625 # Filter didn't match.
2627 elif not type_obj
.tag
.startswith(self
._template
):
2628 # Filter didn't match.
2632 self
._type
_obj
= gdb
.lookup_type(
2633 self
.name
).strip_typedefs()
2637 if self
._type
_obj
is None:
2640 t1
= gdb
.types
.get_basic_type(self
._type
_obj
)
2641 t2
= gdb
.types
.get_basic_type(type_obj
)
2643 return strip_inline_namespaces(self
.name
)
2645 # Workaround ambiguous typedefs matching both std:: and
2646 # std::__cxx11:: symbols.
2647 if self
._template
.split('::')[-1] == 'basic_string':
2648 s1
= self
._type
_obj
.tag
.replace('__cxx11::', '')
2649 s2
= type_obj
.tag
.replace('__cxx11::', '')
2651 return strip_inline_namespaces(self
.name
)
2655 def instantiate(self
):
2656 """Return a recognizer object for this type printer."""
2657 return self
._recognizer
(self
._template
, self
.name
, self
._targ
1)
2660 def add_one_type_printer(obj
, template
, name
, targ1
=None):
2661 printer
= FilteringTypePrinter('std::' + template
, 'std::' + name
, targ1
)
2662 gdb
.types
.register_type_printer(obj
, printer
)
2663 if '__cxx11' not in template
:
2664 ns
= 'std::' + _versioned_namespace
2665 printer
= FilteringTypePrinter(ns
+ template
, ns
+ name
, targ1
)
2666 gdb
.types
.register_type_printer(obj
, printer
)
2669 def register_type_printers(obj
):
2670 global _use_type_printing
2672 if not _use_type_printing
:
2675 # Add type printers for typedefs std::string, std::wstring etc.
2676 for ch
in (('', 'char'),
2679 ('u16', 'char16_t'),
2680 ('u32', 'char32_t')):
2681 add_one_type_printer(obj
, 'basic_string', ch
[0] + 'string', ch
[1])
2682 add_one_type_printer(obj
, '__cxx11::basic_string',
2683 ch
[0] + 'string', ch
[1])
2684 # Typedefs for __cxx11::basic_string used to be in namespace __cxx11:
2685 add_one_type_printer(obj
, '__cxx11::basic_string',
2686 '__cxx11::' + ch
[0] + 'string', ch
[1])
2687 add_one_type_printer(obj
, 'basic_string_view',
2688 ch
[0] + 'string_view', ch
[1])
2690 # Add type printers for typedefs std::istream, std::wistream etc.
2691 for ch
in (('', 'char'), ('w', 'wchar_t')):
2692 for x
in ('ios', 'streambuf', 'istream', 'ostream', 'iostream',
2693 'filebuf', 'ifstream', 'ofstream', 'fstream'):
2694 add_one_type_printer(obj
, 'basic_' + x
, ch
[0] + x
, ch
[1])
2695 for x
in ('stringbuf', 'istringstream', 'ostringstream',
2697 add_one_type_printer(obj
, 'basic_' + x
, ch
[0] + x
, ch
[1])
2698 # <sstream> types are in __cxx11 namespace, but typedefs aren't:
2699 add_one_type_printer(obj
, '__cxx11::basic_' + x
, ch
[0] + x
, ch
[1])
2701 # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc.
2702 for abi
in ('', '__cxx11::'):
2703 for ch
in (('', 'char'), ('w', 'wchar_t')):
2704 add_one_type_printer(obj
, abi
+ 'basic_regex',
2705 abi
+ ch
[0] + 'regex', ch
[1])
2706 for ch
in ('c', 's', 'wc', 'ws'):
2707 add_one_type_printer(
2708 obj
, abi
+ 'match_results', abi
+ ch
+ 'match')
2709 for x
in ('sub_match', 'regex_iterator', 'regex_token_iterator'):
2710 add_one_type_printer(obj
, abi
+ x
, abi
+ ch
+ x
)
2712 # Note that we can't have a printer for std::wstreampos, because
2713 # it is the same type as std::streampos.
2714 add_one_type_printer(obj
, 'fpos', 'streampos')
2716 # Add type printers for <chrono> typedefs.
2717 for dur
in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds',
2718 'minutes', 'hours', 'days', 'weeks', 'years', 'months'):
2719 add_one_type_printer(obj
, 'chrono::duration', 'chrono::' + dur
)
2721 # Add type printers for <random> typedefs.
2722 add_one_type_printer(obj
, 'linear_congruential_engine', 'minstd_rand0')
2723 add_one_type_printer(obj
, 'linear_congruential_engine', 'minstd_rand')
2724 add_one_type_printer(obj
, 'mersenne_twister_engine', 'mt19937')
2725 add_one_type_printer(obj
, 'mersenne_twister_engine', 'mt19937_64')
2726 add_one_type_printer(obj
, 'subtract_with_carry_engine', 'ranlux24_base')
2727 add_one_type_printer(obj
, 'subtract_with_carry_engine', 'ranlux48_base')
2728 add_one_type_printer(obj
, 'discard_block_engine', 'ranlux24')
2729 add_one_type_printer(obj
, 'discard_block_engine', 'ranlux48')
2730 add_one_type_printer(obj
, 'shuffle_order_engine', 'knuth_b')
2732 # Add type printers for experimental::basic_string_view typedefs.
2733 ns
= 'experimental::fundamentals_v1::'
2734 for ch
in (('', 'char'),
2737 ('u16', 'char16_t'),
2738 ('u32', 'char32_t')):
2739 add_one_type_printer(obj
, ns
+ 'basic_string_view',
2740 ns
+ ch
[0] + 'string_view', ch
[1])
2742 # Do not show defaulted template arguments in class templates.
2743 add_one_template_type_printer(obj
, 'unique_ptr',
2744 {1: 'std::default_delete<{0}>'})
2745 add_one_template_type_printer(obj
, 'deque', {1: 'std::allocator<{0}>'})
2746 add_one_template_type_printer(
2747 obj
, 'forward_list', {1: 'std::allocator<{0}>'})
2748 add_one_template_type_printer(obj
, 'list', {1: 'std::allocator<{0}>'})
2749 add_one_template_type_printer(
2750 obj
, '__cxx11::list', {1: 'std::allocator<{0}>'})
2751 add_one_template_type_printer(obj
, 'vector', {1: 'std::allocator<{0}>'})
2752 add_one_template_type_printer(obj
, 'map',
2753 {2: 'std::less<{0}>',
2754 3: 'std::allocator<std::pair<{0} const, {1}>>'})
2755 add_one_template_type_printer(obj
, 'multimap',
2756 {2: 'std::less<{0}>',
2757 3: 'std::allocator<std::pair<{0} const, {1}>>'})
2758 add_one_template_type_printer(obj
, 'set',
2759 {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'})
2760 add_one_template_type_printer(obj
, 'multiset',
2761 {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'})
2762 add_one_template_type_printer(obj
, 'unordered_map',
2763 {2: 'std::hash<{0}>',
2764 3: 'std::equal_to<{0}>',
2765 4: 'std::allocator<std::pair<{0} const, {1}>>'})
2766 add_one_template_type_printer(obj
, 'unordered_multimap',
2767 {2: 'std::hash<{0}>',
2768 3: 'std::equal_to<{0}>',
2769 4: 'std::allocator<std::pair<{0} const, {1}>>'})
2770 add_one_template_type_printer(obj
, 'unordered_set',
2771 {1: 'std::hash<{0}>',
2772 2: 'std::equal_to<{0}>',
2773 3: 'std::allocator<{0}>'})
2774 add_one_template_type_printer(obj
, 'unordered_multiset',
2775 {1: 'std::hash<{0}>',
2776 2: 'std::equal_to<{0}>',
2777 3: 'std::allocator<{0}>'})
2780 def register_libstdcxx_printers(obj
):
2781 """Register libstdc++ pretty-printers with objfile Obj."""
2784 global libstdcxx_printer
2787 gdb
.printing
.register_pretty_printer(obj
, libstdcxx_printer
)
2791 obj
.pretty_printers
.append(libstdcxx_printer
)
2793 register_type_printers(obj
)
2796 def build_libstdcxx_dictionary():
2797 global libstdcxx_printer
2799 libstdcxx_printer
= Printer("libstdc++-v6")
2801 # libstdc++ objects requiring pretty-printing.
2803 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
2804 libstdcxx_printer
.add_version('std::', 'basic_string', StdStringPrinter
)
2805 libstdcxx_printer
.add_version(
2806 'std::__cxx11::', 'basic_string', StdStringPrinter
)
2807 libstdcxx_printer
.add_container('std::', 'bitset', StdBitsetPrinter
)
2808 libstdcxx_printer
.add_container('std::', 'deque', StdDequePrinter
)
2809 libstdcxx_printer
.add_container('std::', 'list', StdListPrinter
)
2810 libstdcxx_printer
.add_container('std::__cxx11::', 'list', StdListPrinter
)
2811 libstdcxx_printer
.add_container('std::', 'map', StdMapPrinter
)
2812 libstdcxx_printer
.add_container('std::', 'multimap', StdMapPrinter
)
2813 libstdcxx_printer
.add_container('std::', 'multiset', StdSetPrinter
)
2814 libstdcxx_printer
.add_version('std::', 'pair', StdPairPrinter
)
2815 libstdcxx_printer
.add_version('std::', 'priority_queue',
2816 StdStackOrQueuePrinter
)
2817 libstdcxx_printer
.add_version('std::', 'queue', StdStackOrQueuePrinter
)
2818 libstdcxx_printer
.add_version('std::', 'tuple', StdTuplePrinter
)
2819 libstdcxx_printer
.add_container('std::', 'set', StdSetPrinter
)
2820 libstdcxx_printer
.add_version('std::', 'stack', StdStackOrQueuePrinter
)
2821 libstdcxx_printer
.add_version('std::', 'unique_ptr', UniquePointerPrinter
)
2822 libstdcxx_printer
.add_container('std::', 'vector', StdVectorPrinter
)
2824 libstdcxx_printer
.add_version('std::', 'locale', StdLocalePrinter
)
2826 libstdcxx_printer
.add_version('std::', 'integral_constant',
2827 StdIntegralConstantPrinter
)
2828 libstdcxx_printer
.add_version('std::', 'text_encoding',
2829 StdTextEncodingPrinter
)
2831 if hasattr(gdb
.Value
, 'dynamic_type'):
2832 libstdcxx_printer
.add_version('std::', 'error_code',
2833 StdErrorCodePrinter
)
2834 libstdcxx_printer
.add_version('std::', 'error_condition',
2835 StdErrorCodePrinter
)
2837 # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
2838 libstdcxx_printer
.add('std::__debug::bitset', StdBitsetPrinter
)
2839 libstdcxx_printer
.add('std::__debug::deque', StdDequePrinter
)
2840 libstdcxx_printer
.add('std::__debug::list', StdListPrinter
)
2841 libstdcxx_printer
.add('std::__debug::map', StdMapPrinter
)
2842 libstdcxx_printer
.add('std::__debug::multimap', StdMapPrinter
)
2843 libstdcxx_printer
.add('std::__debug::multiset', StdSetPrinter
)
2844 libstdcxx_printer
.add('std::__debug::set', StdSetPrinter
)
2845 libstdcxx_printer
.add('std::__debug::vector', StdVectorPrinter
)
2847 # These are the TR1 and C++11 printers.
2848 # For array - the default GDB pretty-printer seems reasonable.
2849 libstdcxx_printer
.add_version('std::', 'shared_ptr', SharedPointerPrinter
)
2850 libstdcxx_printer
.add_version('std::', 'weak_ptr', SharedPointerPrinter
)
2851 libstdcxx_printer
.add_container('std::', 'unordered_map',
2852 Tr1UnorderedMapPrinter
)
2853 libstdcxx_printer
.add_container('std::', 'unordered_set',
2854 Tr1UnorderedSetPrinter
)
2855 libstdcxx_printer
.add_container('std::', 'unordered_multimap',
2856 Tr1UnorderedMapPrinter
)
2857 libstdcxx_printer
.add_container('std::', 'unordered_multiset',
2858 Tr1UnorderedSetPrinter
)
2859 libstdcxx_printer
.add_container('std::', 'forward_list',
2860 StdForwardListPrinter
)
2862 libstdcxx_printer
.add_version(
2863 'std::tr1::', 'shared_ptr', SharedPointerPrinter
)
2864 libstdcxx_printer
.add_version(
2865 'std::tr1::', 'weak_ptr', SharedPointerPrinter
)
2866 libstdcxx_printer
.add_version('std::tr1::', 'unordered_map',
2867 Tr1UnorderedMapPrinter
)
2868 libstdcxx_printer
.add_version('std::tr1::', 'unordered_set',
2869 Tr1UnorderedSetPrinter
)
2870 libstdcxx_printer
.add_version('std::tr1::', 'unordered_multimap',
2871 Tr1UnorderedMapPrinter
)
2872 libstdcxx_printer
.add_version('std::tr1::', 'unordered_multiset',
2873 Tr1UnorderedSetPrinter
)
2875 libstdcxx_printer
.add_version('std::', 'initializer_list',
2876 StdInitializerListPrinter
)
2877 libstdcxx_printer
.add_version('std::', 'atomic', StdAtomicPrinter
)
2878 libstdcxx_printer
.add_version(
2879 'std::', 'basic_stringbuf', StdStringBufPrinter
)
2880 libstdcxx_printer
.add_version(
2881 'std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter
)
2882 for sstream
in ('istringstream', 'ostringstream', 'stringstream'):
2883 libstdcxx_printer
.add_version(
2884 'std::', 'basic_' + sstream
, StdStringStreamPrinter
)
2885 libstdcxx_printer
.add_version(
2886 'std::__cxx11::', 'basic_' + sstream
, StdStringStreamPrinter
)
2888 libstdcxx_printer
.add_version('std::chrono::', 'duration',
2889 StdChronoDurationPrinter
)
2890 libstdcxx_printer
.add_version('std::chrono::', 'time_point',
2891 StdChronoTimePointPrinter
)
2893 # std::regex components
2894 libstdcxx_printer
.add_version('std::__detail::', '_State',
2895 StdRegexStatePrinter
)
2897 # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases.
2898 # The tr1 namespace containers do not have any debug equivalents,
2899 # so do not register printers for them.
2900 libstdcxx_printer
.add('std::__debug::unordered_map',
2901 Tr1UnorderedMapPrinter
)
2902 libstdcxx_printer
.add('std::__debug::unordered_set',
2903 Tr1UnorderedSetPrinter
)
2904 libstdcxx_printer
.add('std::__debug::unordered_multimap',
2905 Tr1UnorderedMapPrinter
)
2906 libstdcxx_printer
.add('std::__debug::unordered_multiset',
2907 Tr1UnorderedSetPrinter
)
2908 libstdcxx_printer
.add('std::__debug::forward_list',
2909 StdForwardListPrinter
)
2911 # Library Fundamentals TS components
2912 libstdcxx_printer
.add_version('std::experimental::fundamentals_v1::',
2913 'any', StdExpAnyPrinter
)
2914 libstdcxx_printer
.add_version('std::experimental::fundamentals_v1::',
2915 'optional', StdExpOptionalPrinter
)
2916 libstdcxx_printer
.add_version('std::experimental::fundamentals_v1::',
2917 'basic_string_view', StdExpStringViewPrinter
)
2918 # Filesystem TS components
2919 libstdcxx_printer
.add_version('std::experimental::filesystem::v1::',
2920 'path', StdExpPathPrinter
)
2921 libstdcxx_printer
.add_version('std::experimental::filesystem::v1::__cxx11::',
2922 'path', StdExpPathPrinter
)
2923 libstdcxx_printer
.add_version('std::filesystem::',
2924 'path', StdPathPrinter
)
2925 libstdcxx_printer
.add_version('std::filesystem::__cxx11::',
2926 'path', StdPathPrinter
)
2929 libstdcxx_printer
.add_version('std::',
2930 'any', StdExpAnyPrinter
)
2931 libstdcxx_printer
.add_version('std::',
2932 'optional', StdExpOptionalPrinter
)
2933 libstdcxx_printer
.add_version('std::',
2934 'basic_string_view', StdExpStringViewPrinter
)
2935 libstdcxx_printer
.add_version('std::',
2936 'variant', StdVariantPrinter
)
2937 libstdcxx_printer
.add_version('std::',
2938 '_Node_handle', StdNodeHandlePrinter
)
2941 libstdcxx_printer
.add_version(
2942 'std::', 'partial_ordering', StdCmpCatPrinter
)
2943 libstdcxx_printer
.add_version('std::', 'weak_ordering', StdCmpCatPrinter
)
2944 libstdcxx_printer
.add_version('std::', 'strong_ordering', StdCmpCatPrinter
)
2945 libstdcxx_printer
.add_version('std::', 'span', StdSpanPrinter
)
2946 libstdcxx_printer
.add_version('std::', 'basic_format_args',
2947 StdFormatArgsPrinter
)
2948 for c
in ['day', 'month', 'year', 'weekday', 'weekday_indexed', 'weekday_last',
2949 'month_day', 'month_day_last', 'month_weekday', 'month_weekday_last',
2950 'year_month', 'year_month_day', 'year_month_day_last',
2951 'year_month_weekday', 'year_month_weekday_last', 'hh_mm_ss']:
2952 libstdcxx_printer
.add_version('std::chrono::', c
,
2953 StdChronoCalendarPrinter
)
2954 libstdcxx_printer
.add_version('std::chrono::', 'time_zone',
2955 StdChronoTimeZonePrinter
)
2956 libstdcxx_printer
.add_version('std::chrono::', 'time_zone_link',
2957 StdChronoTimeZonePrinter
)
2958 libstdcxx_printer
.add_version('std::chrono::', 'zoned_time',
2959 StdChronoZonedTimePrinter
)
2960 libstdcxx_printer
.add_version('std::chrono::', 'leap_second',
2961 StdChronoLeapSecondPrinter
)
2962 libstdcxx_printer
.add_version(
2963 'std::chrono::', 'tzdb', StdChronoTzdbPrinter
)
2964 # libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule',
2965 # StdChronoTimeZoneRulePrinter)
2968 libstdcxx_printer
.add_version('__gnu_cxx::', 'slist', StdSlistPrinter
)
2971 # These shouldn't be necessary, if GDB "print *i" worked.
2972 # But it often doesn't, so here they are.
2973 libstdcxx_printer
.add_container('std::', '_List_iterator',
2974 StdListIteratorPrinter
)
2975 libstdcxx_printer
.add_container('std::', '_List_const_iterator',
2976 StdListIteratorPrinter
)
2977 libstdcxx_printer
.add_version('std::', '_Rb_tree_iterator',
2978 StdRbtreeIteratorPrinter
)
2979 libstdcxx_printer
.add_version('std::', '_Rb_tree_const_iterator',
2980 StdRbtreeIteratorPrinter
)
2981 libstdcxx_printer
.add_container('std::', '_Deque_iterator',
2982 StdDequeIteratorPrinter
)
2983 libstdcxx_printer
.add_container('std::', '_Deque_const_iterator',
2984 StdDequeIteratorPrinter
)
2985 libstdcxx_printer
.add_version('__gnu_cxx::', '__normal_iterator',
2986 StdVectorIteratorPrinter
)
2987 libstdcxx_printer
.add_container('std::', '_Bit_iterator',
2988 StdBitIteratorPrinter
)
2989 libstdcxx_printer
.add_container('std::', '_Bit_const_iterator',
2990 StdBitIteratorPrinter
)
2991 libstdcxx_printer
.add_container('std::', '_Bit_reference',
2992 StdBitReferencePrinter
)
2993 libstdcxx_printer
.add_version('__gnu_cxx::', '_Slist_iterator',
2994 StdSlistIteratorPrinter
)
2995 libstdcxx_printer
.add_container('std::', '_Fwd_list_iterator',
2996 StdFwdListIteratorPrinter
)
2997 libstdcxx_printer
.add_container('std::', '_Fwd_list_const_iterator',
2998 StdFwdListIteratorPrinter
)
3000 # Debug (compiled with -D_GLIBCXX_DEBUG) printer
3002 libstdcxx_printer
.add('__gnu_debug::_Safe_iterator',
3003 StdDebugIteratorPrinter
)
3006 build_libstdcxx_dictionary()