source: Daodan/MSYS2/mingw32/share/gcc-11.2.0/python/libstdcxx/v6/printers.py

Last change on this file was 1166, checked in by rossy, 3 years ago

Daodan: Replace MinGW build env with an up-to-date MSYS2 env

File size: 75.2 KB
Line 
1# Pretty-printers for libstdc++.
2
3# Copyright (C) 2008-2021 Free Software Foundation, Inc.
4
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18import gdb
19import itertools
20import re
21import sys
22
23### Python 2 + Python 3 compatibility code
24
25# Resources about compatibility:
26#
27# * <http://pythonhosted.org/six/>: Documentation of the "six" module
28
29# FIXME: The handling of e.g. std::basic_string (at least on char)
30# probably needs updating to work with Python 3's new string rules.
31#
32# In particular, Python 3 has a separate type (called byte) for
33# bytestrings, and a special b"" syntax for the byte literals; the old
34# str() type has been redefined to always store Unicode text.
35#
36# We probably can't do much about this until this GDB PR is addressed:
37# <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>
38
39if sys.version_info[0] > 2:
40 ### Python 3 stuff
41 Iterator = object
42 # Python 3 folds these into the normal functions.
43 imap = map
44 izip = zip
45 # Also, int subsumes long
46 long = int
47else:
48 ### Python 2 stuff
49 class Iterator:
50 """Compatibility mixin for iterators
51
52 Instead of writing next() methods for iterators, write
53 __next__() methods and use this mixin to make them work in
54 Python 2 as well as Python 3.
55
56 Idea stolen from the "six" documentation:
57 <http://pythonhosted.org/six/#six.Iterator>
58 """
59
60 def next(self):
61 return self.__next__()
62
63 # In Python 2, we still need these from itertools
64 from itertools import imap, izip
65
66# Try to use the new-style pretty-printing if available.
67_use_gdb_pp = True
68try:
69 import gdb.printing
70except ImportError:
71 _use_gdb_pp = False
72
73# Try to install type-printers.
74_use_type_printing = False
75try:
76 import gdb.types
77 if hasattr(gdb.types, 'TypePrinter'):
78 _use_type_printing = True
79except ImportError:
80 pass
81
82# Starting with the type ORIG, search for the member type NAME. This
83# handles searching upward through superclasses. This is needed to
84# work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
85def find_type(orig, name):
86 typ = orig.strip_typedefs()
87 while True:
88 # Use Type.tag to ignore cv-qualifiers. PR 67440.
89 search = '%s::%s' % (typ.tag, name)
90 try:
91 return gdb.lookup_type(search)
92 except RuntimeError:
93 pass
94 # The type was not found, so try the superclass. We only need
95 # to check the first superclass, so we don't bother with
96 # anything fancier here.
97 fields = typ.fields()
98 if len(fields) and fields[0].is_base_class:
99 typ = fields[0].type
100 else:
101 raise ValueError("Cannot find type %s::%s" % (str(orig), name))
102
103_versioned_namespace = '__8::'
104
105def lookup_templ_spec(templ, *args):
106 """
107 Lookup template specialization templ<args...>
108 """
109 t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args]))
110 try:
111 return gdb.lookup_type(t)
112 except gdb.error as e:
113 # Type not found, try again in versioned namespace.
114 global _versioned_namespace
115 if _versioned_namespace and _versioned_namespace not in templ:
116 t = t.replace('::', '::' + _versioned_namespace, 1)
117 try:
118 return gdb.lookup_type(t)
119 except gdb.error:
120 # If that also fails, rethrow the original exception
121 pass
122 raise e
123
124# Use this to find container node types instead of find_type,
125# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details.
126def lookup_node_type(nodename, containertype):
127 """
128 Lookup specialization of template NODENAME corresponding to CONTAINERTYPE.
129 e.g. if NODENAME is '_List_node' and CONTAINERTYPE is std::list<int>
130 then return the type std::_List_node<int>.
131 Returns None if not found.
132 """
133 # If nodename is unqualified, assume it's in namespace std.
134 if '::' not in nodename:
135 nodename = 'std::' + nodename
136 try:
137 valtype = find_type(containertype, 'value_type')
138 except:
139 valtype = containertype.template_argument(0)
140 valtype = valtype.strip_typedefs()
141 try:
142 return lookup_templ_spec(nodename, valtype)
143 except gdb.error as e:
144 # For debug mode containers the node is in std::__cxx1998.
145 if is_member_of_namespace(nodename, 'std'):
146 if is_member_of_namespace(containertype, 'std::__cxx1998',
147 'std::__debug', '__gnu_debug'):
148 nodename = nodename.replace('::', '::__cxx1998::', 1)
149 try:
150 return lookup_templ_spec(nodename, valtype)
151 except gdb.error:
152 pass
153 return None
154
155def is_member_of_namespace(typ, *namespaces):
156 """
157 Test whether a type is a member of one of the specified namespaces.
158 The type can be specified as a string or a gdb.Type object.
159 """
160 if type(typ) is gdb.Type:
161 typ = str(typ)
162 typ = strip_versioned_namespace(typ)
163 for namespace in namespaces:
164 if typ.startswith(namespace + '::'):
165 return True
166 return False
167
168def is_specialization_of(x, template_name):
169 "Test if a type is a given template instantiation."
170 global _versioned_namespace
171 if type(x) is gdb.Type:
172 x = x.tag
173 if _versioned_namespace:
174 return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None
175 return re.match('^std::%s<.*>$' % template_name, x) is not None
176
177def strip_versioned_namespace(typename):
178 global _versioned_namespace
179 if _versioned_namespace:
180 return typename.replace(_versioned_namespace, '')
181 return typename
182
183def strip_inline_namespaces(type_str):
184 "Remove known inline namespaces from the canonical name of a type."
185 type_str = strip_versioned_namespace(type_str)
186 type_str = type_str.replace('std::__cxx11::', 'std::')
187 expt_ns = 'std::experimental::'
188 for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'):
189 type_str = type_str.replace(expt_ns+lfts_ns+'::', expt_ns)
190 fs_ns = expt_ns + 'filesystem::'
191 type_str = type_str.replace(fs_ns+'v1::', fs_ns)
192 return type_str
193
194def get_template_arg_list(type_obj):
195 "Return a type's template arguments as a list"
196 n = 0
197 template_args = []
198 while True:
199 try:
200 template_args.append(type_obj.template_argument(n))
201 except:
202 return template_args
203 n += 1
204
205class SmartPtrIterator(Iterator):
206 "An iterator for smart pointer types with a single 'child' value"
207
208 def __init__(self, val):
209 self.val = val
210
211 def __iter__(self):
212 return self
213
214 def __next__(self):
215 if self.val is None:
216 raise StopIteration
217 self.val, val = None, self.val
218 return ('get()', val)
219
220class SharedPointerPrinter:
221 "Print a shared_ptr or weak_ptr"
222
223 def __init__ (self, typename, val):
224 self.typename = strip_versioned_namespace(typename)
225 self.val = val
226 self.pointer = val['_M_ptr']
227
228 def children (self):
229 return SmartPtrIterator(self.pointer)
230
231 def to_string (self):
232 state = 'empty'
233 refcounts = self.val['_M_refcount']['_M_pi']
234 if refcounts != 0:
235 usecount = refcounts['_M_use_count']
236 weakcount = refcounts['_M_weak_count']
237 if usecount == 0:
238 state = 'expired, weak count %d' % weakcount
239 else:
240 state = 'use count %d, weak count %d' % (usecount, weakcount - 1)
241 return '%s<%s> (%s)' % (self.typename, str(self.val.type.template_argument(0)), state)
242
243class UniquePointerPrinter:
244 "Print a unique_ptr"
245
246 def __init__ (self, typename, val):
247 self.val = val
248 impl_type = val.type.fields()[0].type.strip_typedefs()
249 # Check for new implementations first:
250 if is_specialization_of(impl_type, '__uniq_ptr_data') \
251 or is_specialization_of(impl_type, '__uniq_ptr_impl'):
252 tuple_member = val['_M_t']['_M_t']
253 elif is_specialization_of(impl_type, 'tuple'):
254 tuple_member = val['_M_t']
255 else:
256 raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type))
257 tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
258 tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base
259 head_field = tuple_head_type.fields()[0]
260 if head_field.name == '_M_head_impl':
261 self.pointer = tuple_member['_M_head_impl']
262 elif head_field.is_base_class:
263 self.pointer = tuple_member.cast(head_field.type)
264 else:
265 raise ValueError("Unsupported implementation for tuple in unique_ptr: %s" % str(impl_type))
266
267 def children (self):
268 return SmartPtrIterator(self.pointer)
269
270 def to_string (self):
271 return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0))))
272
273def get_value_from_aligned_membuf(buf, valtype):
274 """Returns the value held in a __gnu_cxx::__aligned_membuf."""
275 return buf['_M_storage'].address.cast(valtype.pointer()).dereference()
276
277def get_value_from_list_node(node):
278 """Returns the value held in an _List_node<_Val>"""
279 try:
280 member = node.type.fields()[1].name
281 if member == '_M_data':
282 # C++03 implementation, node contains the value as a member
283 return node['_M_data']
284 elif member == '_M_storage':
285 # C++11 implementation, node stores value in __aligned_membuf
286 valtype = node.type.template_argument(0)
287 return get_value_from_aligned_membuf(node['_M_storage'], valtype)
288 except:
289 pass
290 raise ValueError("Unsupported implementation for %s" % str(node.type))
291
292class StdListPrinter:
293 "Print a std::list"
294
295 class _iterator(Iterator):
296 def __init__(self, nodetype, head):
297 self.nodetype = nodetype
298 self.base = head['_M_next']
299 self.head = head.address
300 self.count = 0
301
302 def __iter__(self):
303 return self
304
305 def __next__(self):
306 if self.base == self.head:
307 raise StopIteration
308 elt = self.base.cast(self.nodetype).dereference()
309 self.base = elt['_M_next']
310 count = self.count
311 self.count = self.count + 1
312 val = get_value_from_list_node(elt)
313 return ('[%d]' % count, val)
314
315 def __init__(self, typename, val):
316 self.typename = strip_versioned_namespace(typename)
317 self.val = val
318
319 def children(self):
320 nodetype = lookup_node_type('_List_node', self.val.type).pointer()
321 return self._iterator(nodetype, self.val['_M_impl']['_M_node'])
322
323 def to_string(self):
324 headnode = self.val['_M_impl']['_M_node']
325 if headnode['_M_next'] == headnode.address:
326 return 'empty %s' % (self.typename)
327 return '%s' % (self.typename)
328
329class NodeIteratorPrinter:
330 def __init__(self, typename, val, contname, nodename):
331 self.val = val
332 self.typename = typename
333 self.contname = contname
334 self.nodetype = lookup_node_type(nodename, val.type)
335
336 def to_string(self):
337 if not self.val['_M_node']:
338 return 'non-dereferenceable iterator for std::%s' % (self.contname)
339 node = self.val['_M_node'].cast(self.nodetype.pointer()).dereference()
340 return str(get_value_from_list_node(node))
341
342class StdListIteratorPrinter(NodeIteratorPrinter):
343 "Print std::list::iterator"
344
345 def __init__(self, typename, val):
346 NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node')
347
348class StdFwdListIteratorPrinter(NodeIteratorPrinter):
349 "Print std::forward_list::iterator"
350
351 def __init__(self, typename, val):
352 NodeIteratorPrinter.__init__(self, typename, val, 'forward_list',
353 '_Fwd_list_node')
354
355class StdSlistPrinter:
356 "Print a __gnu_cxx::slist"
357
358 class _iterator(Iterator):
359 def __init__(self, nodetype, head):
360 self.nodetype = nodetype
361 self.base = head['_M_head']['_M_next']
362 self.count = 0
363
364 def __iter__(self):
365 return self
366
367 def __next__(self):
368 if self.base == 0:
369 raise StopIteration
370 elt = self.base.cast(self.nodetype).dereference()
371 self.base = elt['_M_next']
372 count = self.count
373 self.count = self.count + 1
374 return ('[%d]' % count, elt['_M_data'])
375
376 def __init__(self, typename, val):
377 self.val = val
378
379 def children(self):
380 nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self.val.type)
381 return self._iterator(nodetype.pointer(), self.val)
382
383 def to_string(self):
384 if self.val['_M_head']['_M_next'] == 0:
385 return 'empty __gnu_cxx::slist'
386 return '__gnu_cxx::slist'
387
388class StdSlistIteratorPrinter:
389 "Print __gnu_cxx::slist::iterator"
390
391 def __init__(self, typename, val):
392 self.val = val
393
394 def to_string(self):
395 if not self.val['_M_node']:
396 return 'non-dereferenceable iterator for __gnu_cxx::slist'
397 nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self.val.type).pointer()
398 return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data'])
399
400class StdVectorPrinter:
401 "Print a std::vector"
402
403 class _iterator(Iterator):
404 def __init__ (self, start, finish, bitvec):
405 self.bitvec = bitvec
406 if bitvec:
407 self.item = start['_M_p']
408 self.so = 0
409 self.finish = finish['_M_p']
410 self.fo = finish['_M_offset']
411 itype = self.item.dereference().type
412 self.isize = 8 * itype.sizeof
413 else:
414 self.item = start
415 self.finish = finish
416 self.count = 0
417
418 def __iter__(self):
419 return self
420
421 def __next__(self):
422 count = self.count
423 self.count = self.count + 1
424 if self.bitvec:
425 if self.item == self.finish and self.so >= self.fo:
426 raise StopIteration
427 elt = bool(self.item.dereference() & (1 << self.so))
428 self.so = self.so + 1
429 if self.so >= self.isize:
430 self.item = self.item + 1
431 self.so = 0
432 return ('[%d]' % count, elt)
433 else:
434 if self.item == self.finish:
435 raise StopIteration
436 elt = self.item.dereference()
437 self.item = self.item + 1
438 return ('[%d]' % count, elt)
439
440 def __init__(self, typename, val):
441 self.typename = strip_versioned_namespace(typename)
442 self.val = val
443 self.is_bool = val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL
444
445 def children(self):
446 return self._iterator(self.val['_M_impl']['_M_start'],
447 self.val['_M_impl']['_M_finish'],
448 self.is_bool)
449
450 def to_string(self):
451 start = self.val['_M_impl']['_M_start']
452 finish = self.val['_M_impl']['_M_finish']
453 end = self.val['_M_impl']['_M_end_of_storage']
454 if self.is_bool:
455 start = self.val['_M_impl']['_M_start']['_M_p']
456 finish = self.val['_M_impl']['_M_finish']['_M_p']
457 fo = self.val['_M_impl']['_M_finish']['_M_offset']
458 itype = start.dereference().type
459 bl = 8 * itype.sizeof
460 length = bl * (finish - start) + fo
461 capacity = bl * (end - start)
462 return ('%s<bool> of length %d, capacity %d'
463 % (self.typename, int (length), int (capacity)))
464 else:
465 return ('%s of length %d, capacity %d'
466 % (self.typename, int (finish - start), int (end - start)))
467
468 def display_hint(self):
469 return 'array'
470
471class StdVectorIteratorPrinter:
472 "Print std::vector::iterator"
473
474 def __init__(self, typename, val):
475 self.val = val
476
477 def to_string(self):
478 if not self.val['_M_current']:
479 return 'non-dereferenceable iterator for std::vector'
480 return str(self.val['_M_current'].dereference())
481
482class StdBitIteratorPrinter:
483 "Print std::vector<bool>'s _Bit_iterator and _Bit_const_iterator"
484
485 def __init__(self, typename, val):
486 self.val = val
487
488 def to_string(self):
489 if not self.val['_M_p']:
490 return 'non-dereferenceable iterator for std::vector<bool>'
491 return bool(self.val['_M_p'].dereference() & (1 << self.val['_M_offset']))
492
493class StdBitReferencePrinter:
494 "Print std::_Bit_reference"
495
496 def __init__(self, typename, val):
497 self.val = val
498
499 def to_string(self):
500 if not self.val['_M_p']:
501 return 'invalid std::_Bit_reference'
502 return bool(self.val['_M_p'].dereference() & (self.val['_M_mask']))
503
504class StdTuplePrinter:
505 "Print a std::tuple"
506
507 class _iterator(Iterator):
508 @staticmethod
509 def _is_nonempty_tuple (nodes):
510 if len (nodes) == 2:
511 if is_specialization_of (nodes[1].type, '__tuple_base'):
512 return True
513 elif len (nodes) == 1:
514 return True
515 elif len (nodes) == 0:
516 return False
517 raise ValueError("Top of tuple tree does not consist of a single node.")
518
519 def __init__ (self, head):
520 self.head = head
521
522 # Set the base class as the initial head of the
523 # tuple.
524 nodes = self.head.type.fields ()
525 if self._is_nonempty_tuple (nodes):
526 # Set the actual head to the first pair.
527 self.head = self.head.cast (nodes[0].type)
528 self.count = 0
529
530 def __iter__ (self):
531 return self
532
533 def __next__ (self):
534 # Check for further recursions in the inheritance tree.
535 # For a GCC 5+ tuple self.head is None after visiting all nodes:
536 if not self.head:
537 raise StopIteration
538 nodes = self.head.type.fields ()
539 # For a GCC 4.x tuple there is a final node with no fields:
540 if len (nodes) == 0:
541 raise StopIteration
542 # Check that this iteration has an expected structure.
543 if len (nodes) > 2:
544 raise ValueError("Cannot parse more than 2 nodes in a tuple tree.")
545
546 if len (nodes) == 1:
547 # This is the last node of a GCC 5+ std::tuple.
548 impl = self.head.cast (nodes[0].type)
549 self.head = None
550 else:
551 # Either a node before the last node, or the last node of
552 # a GCC 4.x tuple (which has an empty parent).
553
554 # - Left node is the next recursion parent.
555 # - Right node is the actual class contained in the tuple.
556
557 # Process right node.
558 impl = self.head.cast (nodes[1].type)
559
560 # Process left node and set it as head.
561 self.head = self.head.cast (nodes[0].type)
562
563 self.count = self.count + 1
564
565 # Finally, check the implementation. If it is
566 # wrapped in _M_head_impl return that, otherwise return
567 # the value "as is".
568 fields = impl.type.fields ()
569 if len (fields) < 1 or fields[0].name != "_M_head_impl":
570 return ('[%d]' % self.count, impl)
571 else:
572 return ('[%d]' % self.count, impl['_M_head_impl'])
573
574 def __init__ (self, typename, val):
575 self.typename = strip_versioned_namespace(typename)
576 self.val = val;
577
578 def children (self):
579 return self._iterator (self.val)
580
581 def to_string (self):
582 if len (self.val.type.fields ()) == 0:
583 return 'empty %s' % (self.typename)
584 return '%s containing' % (self.typename)
585
586class StdStackOrQueuePrinter:
587 "Print a std::stack or std::queue"
588
589 def __init__ (self, typename, val):
590 self.typename = strip_versioned_namespace(typename)
591 self.visualizer = gdb.default_visualizer(val['c'])
592
593 def children (self):
594 return self.visualizer.children()
595
596 def to_string (self):
597 return '%s wrapping: %s' % (self.typename,
598 self.visualizer.to_string())
599
600 def display_hint (self):
601 if hasattr (self.visualizer, 'display_hint'):
602 return self.visualizer.display_hint ()
603 return None
604
605class RbtreeIterator(Iterator):
606 """
607 Turn an RB-tree-based container (std::map, std::set etc.) into
608 a Python iterable object.
609 """
610
611 def __init__(self, rbtree):
612 self.size = rbtree['_M_t']['_M_impl']['_M_node_count']
613 self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
614 self.count = 0
615
616 def __iter__(self):
617 return self
618
619 def __len__(self):
620 return int (self.size)
621
622 def __next__(self):
623 if self.count == self.size:
624 raise StopIteration
625 result = self.node
626 self.count = self.count + 1
627 if self.count < self.size:
628 # Compute the next node.
629 node = self.node
630 if node.dereference()['_M_right']:
631 node = node.dereference()['_M_right']
632 while node.dereference()['_M_left']:
633 node = node.dereference()['_M_left']
634 else:
635 parent = node.dereference()['_M_parent']
636 while node == parent.dereference()['_M_right']:
637 node = parent
638 parent = parent.dereference()['_M_parent']
639 if node.dereference()['_M_right'] != parent:
640 node = parent
641 self.node = node
642 return result
643
644def get_value_from_Rb_tree_node(node):
645 """Returns the value held in an _Rb_tree_node<_Val>"""
646 try:
647 member = node.type.fields()[1].name
648 if member == '_M_value_field':
649 # C++03 implementation, node contains the value as a member
650 return node['_M_value_field']
651 elif member == '_M_storage':
652 # C++11 implementation, node stores value in __aligned_membuf
653 valtype = node.type.template_argument(0)
654 return get_value_from_aligned_membuf(node['_M_storage'], valtype)
655 except:
656 pass
657 raise ValueError("Unsupported implementation for %s" % str(node.type))
658
659# This is a pretty printer for std::_Rb_tree_iterator (which is
660# std::map::iterator), and has nothing to do with the RbtreeIterator
661# class above.
662class StdRbtreeIteratorPrinter:
663 "Print std::map::iterator, std::set::iterator, etc."
664
665 def __init__ (self, typename, val):
666 self.val = val
667 nodetype = lookup_node_type('_Rb_tree_node', self.val.type)
668 self.link_type = nodetype.pointer()
669
670 def to_string (self):
671 if not self.val['_M_node']:
672 return 'non-dereferenceable iterator for associative container'
673 node = self.val['_M_node'].cast(self.link_type).dereference()
674 return str(get_value_from_Rb_tree_node(node))
675
676class StdDebugIteratorPrinter:
677 "Print a debug enabled version of an iterator"
678
679 def __init__ (self, typename, val):
680 self.val = val
681
682 # Just strip away the encapsulating __gnu_debug::_Safe_iterator
683 # and return the wrapped iterator value.
684 def to_string (self):
685 base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base')
686 itype = self.val.type.template_argument(0)
687 safe_seq = self.val.cast(base_type)['_M_sequence']
688 if not safe_seq:
689 return str(self.val.cast(itype))
690 if self.val['_M_version'] != safe_seq['_M_version']:
691 return "invalid iterator"
692 return str(self.val.cast(itype))
693
694def num_elements(num):
695 """Return either "1 element" or "N elements" depending on the argument."""
696 return '1 element' if num == 1 else '%d elements' % num
697
698class StdMapPrinter:
699 "Print a std::map or std::multimap"
700
701 # Turn an RbtreeIterator into a pretty-print iterator.
702 class _iter(Iterator):
703 def __init__(self, rbiter, type):
704 self.rbiter = rbiter
705 self.count = 0
706 self.type = type
707
708 def __iter__(self):
709 return self
710
711 def __next__(self):
712 if self.count % 2 == 0:
713 n = next(self.rbiter)
714 n = n.cast(self.type).dereference()
715 n = get_value_from_Rb_tree_node(n)
716 self.pair = n
717 item = n['first']
718 else:
719 item = self.pair['second']
720 result = ('[%d]' % self.count, item)
721 self.count = self.count + 1
722 return result
723
724 def __init__ (self, typename, val):
725 self.typename = strip_versioned_namespace(typename)
726 self.val = val
727
728 def to_string (self):
729 return '%s with %s' % (self.typename,
730 num_elements(len(RbtreeIterator (self.val))))
731
732 def children (self):
733 node = lookup_node_type('_Rb_tree_node', self.val.type).pointer()
734 return self._iter (RbtreeIterator (self.val), node)
735
736 def display_hint (self):
737 return 'map'
738
739class StdSetPrinter:
740 "Print a std::set or std::multiset"
741
742 # Turn an RbtreeIterator into a pretty-print iterator.
743 class _iter(Iterator):
744 def __init__(self, rbiter, type):
745 self.rbiter = rbiter
746 self.count = 0
747 self.type = type
748
749 def __iter__(self):
750 return self
751
752 def __next__(self):
753 item = next(self.rbiter)
754 item = item.cast(self.type).dereference()
755 item = get_value_from_Rb_tree_node(item)
756 # FIXME: this is weird ... what to do?
757 # Maybe a 'set' display hint?
758 result = ('[%d]' % self.count, item)
759 self.count = self.count + 1
760 return result
761
762 def __init__ (self, typename, val):
763 self.typename = strip_versioned_namespace(typename)
764 self.val = val
765
766 def to_string (self):
767 return '%s with %s' % (self.typename,
768 num_elements(len(RbtreeIterator (self.val))))
769
770 def children (self):
771 node = lookup_node_type('_Rb_tree_node', self.val.type).pointer()
772 return self._iter (RbtreeIterator (self.val), node)
773
774class StdBitsetPrinter:
775 "Print a std::bitset"
776
777 def __init__(self, typename, val):
778 self.typename = strip_versioned_namespace(typename)
779 self.val = val
780
781 def to_string (self):
782 # If template_argument handled values, we could print the
783 # size. Or we could use a regexp on the type.
784 return '%s' % (self.typename)
785
786 def children (self):
787 try:
788 # An empty bitset may not have any members which will
789 # result in an exception being thrown.
790 words = self.val['_M_w']
791 except:
792 return []
793
794 wtype = words.type
795
796 # The _M_w member can be either an unsigned long, or an
797 # array. This depends on the template specialization used.
798 # If it is a single long, convert to a single element list.
799 if wtype.code == gdb.TYPE_CODE_ARRAY:
800 tsize = wtype.target ().sizeof
801 else:
802 words = [words]
803 tsize = wtype.sizeof
804
805 nwords = wtype.sizeof / tsize
806 result = []
807 byte = 0
808 while byte < nwords:
809 w = words[byte]
810 bit = 0
811 while w != 0:
812 if (w & 1) != 0:
813 # Another spot where we could use 'set'?
814 result.append(('[%d]' % (byte * tsize * 8 + bit), 1))
815 bit = bit + 1
816 w = w >> 1
817 byte = byte + 1
818 return result
819
820class StdDequePrinter:
821 "Print a std::deque"
822
823 class _iter(Iterator):
824 def __init__(self, node, start, end, last, buffer_size):
825 self.node = node
826 self.p = start
827 self.end = end
828 self.last = last
829 self.buffer_size = buffer_size
830 self.count = 0
831
832 def __iter__(self):
833 return self
834
835 def __next__(self):
836 if self.p == self.last:
837 raise StopIteration
838
839 result = ('[%d]' % self.count, self.p.dereference())
840 self.count = self.count + 1
841
842 # Advance the 'cur' pointer.
843 self.p = self.p + 1
844 if self.p == self.end:
845 # If we got to the end of this bucket, move to the
846 # next bucket.
847 self.node = self.node + 1
848 self.p = self.node[0]
849 self.end = self.p + self.buffer_size
850
851 return result
852
853 def __init__(self, typename, val):
854 self.typename = strip_versioned_namespace(typename)
855 self.val = val
856 self.elttype = val.type.template_argument(0)
857 size = self.elttype.sizeof
858 if size < 512:
859 self.buffer_size = int (512 / size)
860 else:
861 self.buffer_size = 1
862
863 def to_string(self):
864 start = self.val['_M_impl']['_M_start']
865 end = self.val['_M_impl']['_M_finish']
866
867 delta_n = end['_M_node'] - start['_M_node'] - 1
868 delta_s = start['_M_last'] - start['_M_cur']
869 delta_e = end['_M_cur'] - end['_M_first']
870
871 size = self.buffer_size * delta_n + delta_s + delta_e
872
873 return '%s with %s' % (self.typename, num_elements(long(size)))
874
875 def children(self):
876 start = self.val['_M_impl']['_M_start']
877 end = self.val['_M_impl']['_M_finish']
878 return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
879 end['_M_cur'], self.buffer_size)
880
881 def display_hint (self):
882 return 'array'
883
884class StdDequeIteratorPrinter:
885 "Print std::deque::iterator"
886
887 def __init__(self, typename, val):
888 self.val = val
889
890 def to_string(self):
891 if not self.val['_M_cur']:
892 return 'non-dereferenceable iterator for std::deque'
893 return str(self.val['_M_cur'].dereference())
894
895class StdStringPrinter:
896 "Print a std::basic_string of some kind"
897
898 def __init__(self, typename, val):
899 self.val = val
900 self.new_string = typename.find("::__cxx11::basic_string") != -1
901
902 def to_string(self):
903 # Make sure &string works, too.
904 type = self.val.type
905 if type.code == gdb.TYPE_CODE_REF:
906 type = type.target ()
907
908 # Calculate the length of the string so that to_string returns
909 # the string according to length, not according to first null
910 # encountered.
911 ptr = self.val ['_M_dataplus']['_M_p']
912 if self.new_string:
913 length = self.val['_M_string_length']
914 # https://sourceware.org/bugzilla/show_bug.cgi?id=17728
915 ptr = ptr.cast(ptr.type.strip_typedefs())
916 else:
917 realtype = type.unqualified ().strip_typedefs ()
918 reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
919 header = ptr.cast(reptype) - 1
920 length = header.dereference ()['_M_length']
921 if hasattr(ptr, "lazy_string"):
922 return ptr.lazy_string (length = length)
923 return ptr.string (length = length)
924
925 def display_hint (self):
926 return 'string'
927
928class Tr1HashtableIterator(Iterator):
929 def __init__ (self, hashtable):
930 self.buckets = hashtable['_M_buckets']
931 self.bucket = 0
932 self.bucket_count = hashtable['_M_bucket_count']
933 self.node_type = find_type(hashtable.type, '_Node').pointer()
934 self.node = 0
935 while self.bucket != self.bucket_count:
936 self.node = self.buckets[self.bucket]
937 if self.node:
938 break
939 self.bucket = self.bucket + 1
940
941 def __iter__ (self):
942 return self
943
944 def __next__ (self):
945 if self.node == 0:
946 raise StopIteration
947 node = self.node.cast(self.node_type)
948 result = node.dereference()['_M_v']
949 self.node = node.dereference()['_M_next'];
950 if self.node == 0:
951 self.bucket = self.bucket + 1
952 while self.bucket != self.bucket_count:
953 self.node = self.buckets[self.bucket]
954 if self.node:
955 break
956 self.bucket = self.bucket + 1
957 return result
958
959class StdHashtableIterator(Iterator):
960 def __init__(self, hashtable):
961 self.node = hashtable['_M_before_begin']['_M_nxt']
962 valtype = hashtable.type.template_argument(1)
963 cached = hashtable.type.template_argument(9).template_argument(0)
964 node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype),
965 'true' if cached else 'false')
966 self.node_type = node_type.pointer()
967
968 def __iter__(self):
969 return self
970
971 def __next__(self):
972 if self.node == 0:
973 raise StopIteration
974 elt = self.node.cast(self.node_type).dereference()
975 self.node = elt['_M_nxt']
976 valptr = elt['_M_storage'].address
977 valptr = valptr.cast(elt.type.template_argument(0).pointer())
978 return valptr.dereference()
979
980class Tr1UnorderedSetPrinter:
981 "Print a std::unordered_set or tr1::unordered_set"
982
983 def __init__ (self, typename, val):
984 self.typename = strip_versioned_namespace(typename)
985 self.val = val
986
987 def hashtable (self):
988 if self.typename.startswith('std::tr1'):
989 return self.val
990 return self.val['_M_h']
991
992 def to_string (self):
993 count = self.hashtable()['_M_element_count']
994 return '%s with %s' % (self.typename, num_elements(count))
995
996 @staticmethod
997 def format_count (i):
998 return '[%d]' % i
999
1000 def children (self):
1001 counter = imap (self.format_count, itertools.count())
1002 if self.typename.startswith('std::tr1'):
1003 return izip (counter, Tr1HashtableIterator (self.hashtable()))
1004 return izip (counter, StdHashtableIterator (self.hashtable()))
1005
1006class Tr1UnorderedMapPrinter:
1007 "Print a std::unordered_map or tr1::unordered_map"
1008
1009 def __init__ (self, typename, val):
1010 self.typename = strip_versioned_namespace(typename)
1011 self.val = val
1012
1013 def hashtable (self):
1014 if self.typename.startswith('std::tr1'):
1015 return self.val
1016 return self.val['_M_h']
1017
1018 def to_string (self):
1019 count = self.hashtable()['_M_element_count']
1020 return '%s with %s' % (self.typename, num_elements(count))
1021
1022 @staticmethod
1023 def flatten (list):
1024 for elt in list:
1025 for i in elt:
1026 yield i
1027
1028 @staticmethod
1029 def format_one (elt):
1030 return (elt['first'], elt['second'])
1031
1032 @staticmethod
1033 def format_count (i):
1034 return '[%d]' % i
1035
1036 def children (self):
1037 counter = imap (self.format_count, itertools.count())
1038 # Map over the hash table and flatten the result.
1039 if self.typename.startswith('std::tr1'):
1040 data = self.flatten (imap (self.format_one, Tr1HashtableIterator (self.hashtable())))
1041 # Zip the two iterators together.
1042 return izip (counter, data)
1043 data = self.flatten (imap (self.format_one, StdHashtableIterator (self.hashtable())))
1044 # Zip the two iterators together.
1045 return izip (counter, data)
1046
1047 def display_hint (self):
1048 return 'map'
1049
1050class StdForwardListPrinter:
1051 "Print a std::forward_list"
1052
1053 class _iterator(Iterator):
1054 def __init__(self, nodetype, head):
1055 self.nodetype = nodetype
1056 self.base = head['_M_next']
1057 self.count = 0
1058
1059 def __iter__(self):
1060 return self
1061
1062 def __next__(self):
1063 if self.base == 0:
1064 raise StopIteration
1065 elt = self.base.cast(self.nodetype).dereference()
1066 self.base = elt['_M_next']
1067 count = self.count
1068 self.count = self.count + 1
1069 valptr = elt['_M_storage'].address
1070 valptr = valptr.cast(elt.type.template_argument(0).pointer())
1071 return ('[%d]' % count, valptr.dereference())
1072
1073 def __init__(self, typename, val):
1074 self.val = val
1075 self.typename = strip_versioned_namespace(typename)
1076
1077 def children(self):
1078 nodetype = lookup_node_type('_Fwd_list_node', self.val.type).pointer()
1079 return self._iterator(nodetype, self.val['_M_impl']['_M_head'])
1080
1081 def to_string(self):
1082 if self.val['_M_impl']['_M_head']['_M_next'] == 0:
1083 return 'empty %s' % self.typename
1084 return '%s' % self.typename
1085
1086class SingleObjContainerPrinter(object):
1087 "Base class for printers of containers of single objects"
1088
1089 def __init__ (self, val, viz, hint = None):
1090 self.contained_value = val
1091 self.visualizer = viz
1092 self.hint = hint
1093
1094 def _recognize(self, type):
1095 """Return TYPE as a string after applying type printers"""
1096 global _use_type_printing
1097 if not _use_type_printing:
1098 return str(type)
1099 return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(),
1100 type) or str(type)
1101
1102 class _contained(Iterator):
1103 def __init__ (self, val):
1104 self.val = val
1105
1106 def __iter__ (self):
1107 return self
1108
1109 def __next__(self):
1110 if self.val is None:
1111 raise StopIteration
1112 retval = self.val
1113 self.val = None
1114 return ('[contained value]', retval)
1115
1116 def children (self):
1117 if self.contained_value is None:
1118 return self._contained (None)
1119 if hasattr (self.visualizer, 'children'):
1120 return self.visualizer.children ()
1121 return self._contained (self.contained_value)
1122
1123 def display_hint (self):
1124 # if contained value is a map we want to display in the same way
1125 if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'):
1126 return self.visualizer.display_hint ()
1127 return self.hint
1128
1129def function_pointer_to_name(f):
1130 "Find the name of the function referred to by the gdb.Value f, "
1131 " which should contain a function pointer from the program."
1132
1133 # Turn the function pointer into an actual address.
1134 # This is needed to unpack ppc64 function descriptors.
1135 f = f.dereference().address
1136
1137 if sys.version_info[0] == 2:
1138 # Older versions of GDB need to use long for Python 2,
1139 # because int(f) on 64-bit big-endian values raises a
1140 # gdb.error saying "Cannot convert value to int."
1141 f = long(f)
1142 else:
1143 f = int(f)
1144
1145 try:
1146 # If the function can't be found older versions of GDB raise a
1147 # RuntimeError saying "Cannot locate object file for block."
1148 return gdb.block_for_pc(f).function.name
1149 except:
1150 return None
1151
1152class StdExpAnyPrinter(SingleObjContainerPrinter):
1153 "Print a std::any or std::experimental::any"
1154
1155 def __init__ (self, typename, val):
1156 self.typename = strip_versioned_namespace(typename)
1157 self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', self.typename, 1)
1158 self.val = val
1159 self.contained_type = None
1160 contained_value = None
1161 visualizer = None
1162 mgr = self.val['_M_manager']
1163 if mgr != 0:
1164 func = function_pointer_to_name(mgr)
1165 if not func:
1166 raise ValueError("Invalid function pointer in %s" % (self.typename))
1167 rx = r"""({0}::_Manager_\w+<.*>)::_S_manage\((enum )?{0}::_Op, (const {0}|{0} const) ?\*, (union )?{0}::_Arg ?\*\)""".format(typename)
1168 m = re.match(rx, func)
1169 if not m:
1170 raise ValueError("Unknown manager function in %s" % self.typename)
1171
1172 mgrname = m.group(1)
1173 # FIXME need to expand 'std::string' so that gdb.lookup_type works
1174 if 'std::string' in mgrname:
1175 mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1))
1176
1177 mgrtype = gdb.lookup_type(mgrname)
1178 self.contained_type = mgrtype.template_argument(0)
1179 valptr = None
1180 if '::_Manager_internal' in mgrname:
1181 valptr = self.val['_M_storage']['_M_buffer'].address
1182 elif '::_Manager_external' in mgrname:
1183 valptr = self.val['_M_storage']['_M_ptr']
1184 else:
1185 raise ValueError("Unknown manager function in %s" % self.typename)
1186 contained_value = valptr.cast(self.contained_type.pointer()).dereference()
1187 visualizer = gdb.default_visualizer(contained_value)
1188 super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer)
1189
1190 def to_string (self):
1191 if self.contained_type is None:
1192 return '%s [no contained value]' % self.typename
1193 desc = "%s containing " % self.typename
1194 if hasattr (self.visualizer, 'children'):
1195 return desc + self.visualizer.to_string ()
1196 valtype = self._recognize (self.contained_type)
1197 return desc + strip_versioned_namespace(str(valtype))
1198
1199class StdExpOptionalPrinter(SingleObjContainerPrinter):
1200 "Print a std::optional or std::experimental::optional"
1201
1202 def __init__ (self, typename, val):
1203 valtype = self._recognize (val.type.template_argument(0))
1204 typename = strip_versioned_namespace(typename)
1205 self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, typename, 1)
1206 payload = val['_M_payload']
1207 if self.typename.startswith('std::experimental'):
1208 engaged = val['_M_engaged']
1209 contained_value = payload
1210 else:
1211 engaged = payload['_M_engaged']
1212 contained_value = payload['_M_payload']
1213 try:
1214 # Since GCC 9
1215 contained_value = contained_value['_M_value']
1216 except:
1217 pass
1218 visualizer = gdb.default_visualizer (contained_value)
1219 if not engaged:
1220 contained_value = None
1221 super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer)
1222
1223 def to_string (self):
1224 if self.contained_value is None:
1225 return "%s [no contained value]" % self.typename
1226 if hasattr (self.visualizer, 'children'):
1227 return "%s containing %s" % (self.typename,
1228 self.visualizer.to_string())
1229 return self.typename
1230
1231class StdVariantPrinter(SingleObjContainerPrinter):
1232 "Print a std::variant"
1233
1234 def __init__(self, typename, val):
1235 alternatives = get_template_arg_list(val.type)
1236 self.typename = strip_versioned_namespace(typename)
1237 self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives]))
1238 self.index = val['_M_index']
1239 if self.index >= len(alternatives):
1240 self.contained_type = None
1241 contained_value = None
1242 visualizer = None
1243 else:
1244 self.contained_type = alternatives[int(self.index)]
1245 addr = val['_M_u']['_M_first']['_M_storage'].address
1246 contained_value = addr.cast(self.contained_type.pointer()).dereference()
1247 visualizer = gdb.default_visualizer(contained_value)
1248 super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array')
1249
1250 def to_string(self):
1251 if self.contained_value is None:
1252 return "%s [no contained value]" % self.typename
1253 if hasattr(self.visualizer, 'children'):
1254 return "%s [index %d] containing %s" % (self.typename, self.index,
1255 self.visualizer.to_string())
1256 return "%s [index %d]" % (self.typename, self.index)
1257
1258class StdNodeHandlePrinter(SingleObjContainerPrinter):
1259 "Print a container node handle"
1260
1261 def __init__(self, typename, val):
1262 self.value_type = val.type.template_argument(1)
1263 nodetype = val.type.template_argument(2).template_argument(0)
1264 self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node')
1265 self.is_map_node = val.type.template_argument(0) != self.value_type
1266 nodeptr = val['_M_ptr']
1267 if nodeptr:
1268 if self.is_rb_tree_node:
1269 contained_value = get_value_from_Rb_tree_node(nodeptr.dereference())
1270 else:
1271 contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'],
1272 self.value_type)
1273 visualizer = gdb.default_visualizer(contained_value)
1274 else:
1275 contained_value = None
1276 visualizer = None
1277 optalloc = val['_M_alloc']
1278 self.alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None
1279 super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer,
1280 'array')
1281
1282 def to_string(self):
1283 desc = 'node handle for '
1284 if not self.is_rb_tree_node:
1285 desc += 'unordered '
1286 if self.is_map_node:
1287 desc += 'map';
1288 else:
1289 desc += 'set';
1290
1291 if self.contained_value:
1292 desc += ' with element'
1293 if hasattr(self.visualizer, 'children'):
1294 return "%s = %s" % (desc, self.visualizer.to_string())
1295 return desc
1296 else:
1297 return 'empty %s' % desc
1298
1299class StdExpStringViewPrinter:
1300 "Print a std::basic_string_view or std::experimental::basic_string_view"
1301
1302 def __init__ (self, typename, val):
1303 self.val = val
1304
1305 def to_string (self):
1306 ptr = self.val['_M_str']
1307 len = self.val['_M_len']
1308 if hasattr (ptr, "lazy_string"):
1309 return ptr.lazy_string (length = len)
1310 return ptr.string (length = len)
1311
1312 def display_hint (self):
1313 return 'string'
1314
1315class StdExpPathPrinter:
1316 "Print a std::experimental::filesystem::path"
1317
1318 def __init__ (self, typename, val):
1319 self.val = val
1320 self.typename = typename
1321 start = self.val['_M_cmpts']['_M_impl']['_M_start']
1322 finish = self.val['_M_cmpts']['_M_impl']['_M_finish']
1323 self.num_cmpts = int (finish - start)
1324
1325 def _path_type(self):
1326 t = str(self.val['_M_type'])
1327 if t[-9:] == '_Root_dir':
1328 return "root-directory"
1329 if t[-10:] == '_Root_name':
1330 return "root-name"
1331 return None
1332
1333 def to_string (self):
1334 path = "%s" % self.val ['_M_pathname']
1335 if self.num_cmpts == 0:
1336 t = self._path_type()
1337 if t:
1338 path = '%s [%s]' % (path, t)
1339 return "experimental::filesystem::path %s" % path
1340
1341 class _iterator(Iterator):
1342 def __init__(self, cmpts, pathtype):
1343 self.pathtype = pathtype
1344 self.item = cmpts['_M_impl']['_M_start']
1345 self.finish = cmpts['_M_impl']['_M_finish']
1346 self.count = 0
1347
1348 def __iter__(self):
1349 return self
1350
1351 def __next__(self):
1352 if self.item == self.finish:
1353 raise StopIteration
1354 item = self.item.dereference()
1355 count = self.count
1356 self.count = self.count + 1
1357 self.item = self.item + 1
1358 path = item['_M_pathname']
1359 t = StdExpPathPrinter(self.pathtype, item)._path_type()
1360 if not t:
1361 t = count
1362 return ('[%s]' % t, path)
1363
1364 def children(self):
1365 return self._iterator(self.val['_M_cmpts'], self.typename)
1366
1367class StdPathPrinter:
1368 "Print a std::filesystem::path"
1369
1370 def __init__ (self, typename, val):
1371 self.val = val
1372 self.typename = typename
1373 impl = self.val['_M_cmpts']['_M_impl']['_M_t']['_M_t']['_M_head_impl']
1374 self.type = impl.cast(gdb.lookup_type('uintptr_t')) & 3
1375 if self.type == 0:
1376 self.impl = impl
1377 else:
1378 self.impl = None
1379
1380 def _path_type(self):
1381 t = str(self.type.cast(gdb.lookup_type(self.typename + '::_Type')))
1382 if t[-9:] == '_Root_dir':
1383 return "root-directory"
1384 if t[-10:] == '_Root_name':
1385 return "root-name"
1386 return None
1387
1388 def to_string (self):
1389 path = "%s" % self.val ['_M_pathname']
1390 if self.type != 0:
1391 t = self._path_type()
1392 if t:
1393 path = '%s [%s]' % (path, t)
1394 return "filesystem::path %s" % path
1395
1396 class _iterator(Iterator):
1397 def __init__(self, impl, pathtype):
1398 self.pathtype = pathtype
1399 if impl:
1400 # We can't access _Impl::_M_size because _Impl is incomplete
1401 # so cast to int* to access the _M_size member at offset zero,
1402 int_type = gdb.lookup_type('int')
1403 cmpt_type = gdb.lookup_type(pathtype+'::_Cmpt')
1404 char_type = gdb.lookup_type('char')
1405 impl = impl.cast(int_type.pointer())
1406 size = impl.dereference()
1407 #self.capacity = (impl + 1).dereference()
1408 if hasattr(gdb.Type, 'alignof'):
1409 sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof)
1410 else:
1411 sizeof_Impl = 2 * int_type.sizeof
1412 begin = impl.cast(char_type.pointer()) + sizeof_Impl
1413 self.item = begin.cast(cmpt_type.pointer())
1414 self.finish = self.item + size
1415 self.count = 0
1416 else:
1417 self.item = None
1418 self.finish = None
1419
1420 def __iter__(self):
1421 return self
1422
1423 def __next__(self):
1424 if self.item == self.finish:
1425 raise StopIteration
1426 item = self.item.dereference()
1427 count = self.count
1428 self.count = self.count + 1
1429 self.item = self.item + 1
1430 path = item['_M_pathname']
1431 t = StdPathPrinter(self.pathtype, item)._path_type()
1432 if not t:
1433 t = count
1434 return ('[%s]' % t, path)
1435
1436 def children(self):
1437 return self._iterator(self.impl, self.typename)
1438
1439
1440class StdPairPrinter:
1441 "Print a std::pair object, with 'first' and 'second' as children"
1442
1443 def __init__(self, typename, val):
1444 self.val = val
1445
1446 class _iter(Iterator):
1447 "An iterator for std::pair types. Returns 'first' then 'second'."
1448
1449 def __init__(self, val):
1450 self.val = val
1451 self.which = 'first'
1452
1453 def __iter__(self):
1454 return self
1455
1456 def __next__(self):
1457 if self.which is None:
1458 raise StopIteration
1459 which = self.which
1460 if which == 'first':
1461 self.which = 'second'
1462 else:
1463 self.which = None
1464 return (which, self.val[which])
1465
1466 def children(self):
1467 return self._iter(self.val)
1468
1469 def to_string(self):
1470 return None
1471
1472class StdCmpCatPrinter:
1473 "Print a comparison category object"
1474
1475 def __init__ (self, typename, val):
1476 self.typename = typename[typename.rfind(':')+1:]
1477 self.val = val['_M_value']
1478
1479 def to_string (self):
1480 if self.typename == 'strong_ordering' and self.val == 0:
1481 name = 'equal'
1482 else:
1483 names = {2:'unordered', -1:'less', 0:'equivalent', 1:'greater'}
1484 name = names[int(self.val)]
1485 return 'std::{}::{}'.format(self.typename, name)
1486
1487# A "regular expression" printer which conforms to the
1488# "SubPrettyPrinter" protocol from gdb.printing.
1489class RxPrinter(object):
1490 def __init__(self, name, function):
1491 super(RxPrinter, self).__init__()
1492 self.name = name
1493 self.function = function
1494 self.enabled = True
1495
1496 def invoke(self, value):
1497 if not self.enabled:
1498 return None
1499
1500 if value.type.code == gdb.TYPE_CODE_REF:
1501 if hasattr(gdb.Value,"referenced_value"):
1502 value = value.referenced_value()
1503
1504 return self.function(self.name, value)
1505
1506# A pretty-printer that conforms to the "PrettyPrinter" protocol from
1507# gdb.printing. It can also be used directly as an old-style printer.
1508class Printer(object):
1509 def __init__(self, name):
1510 super(Printer, self).__init__()
1511 self.name = name
1512 self.subprinters = []
1513 self.lookup = {}
1514 self.enabled = True
1515 self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
1516
1517 def add(self, name, function):
1518 # A small sanity check.
1519 # FIXME
1520 if not self.compiled_rx.match(name):
1521 raise ValueError('libstdc++ programming error: "%s" does not match' % name)
1522 printer = RxPrinter(name, function)
1523 self.subprinters.append(printer)
1524 self.lookup[name] = printer
1525
1526 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
1527 def add_version(self, base, name, function):
1528 self.add(base + name, function)
1529 if _versioned_namespace:
1530 vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % _versioned_namespace, base)
1531 self.add(vbase + name, function)
1532
1533 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
1534 def add_container(self, base, name, function):
1535 self.add_version(base, name, function)
1536 self.add_version(base + '__cxx1998::', name, function)
1537
1538 @staticmethod
1539 def get_basic_type(type):
1540 # If it points to a reference, get the reference.
1541 if type.code == gdb.TYPE_CODE_REF:
1542 type = type.target ()
1543
1544 # Get the unqualified type, stripped of typedefs.
1545 type = type.unqualified ().strip_typedefs ()
1546
1547 return type.tag
1548
1549 def __call__(self, val):
1550 typename = self.get_basic_type(val.type)
1551 if not typename:
1552 return None
1553
1554 # All the types we match are template types, so we can use a
1555 # dictionary.
1556 match = self.compiled_rx.match(typename)
1557 if not match:
1558 return None
1559
1560 basename = match.group(1)
1561
1562 if val.type.code == gdb.TYPE_CODE_REF:
1563 if hasattr(gdb.Value,"referenced_value"):
1564 val = val.referenced_value()
1565
1566 if basename in self.lookup:
1567 return self.lookup[basename].invoke(val)
1568
1569 # Cannot find a pretty printer. Return None.
1570 return None
1571
1572libstdcxx_printer = None
1573
1574class TemplateTypePrinter(object):
1575 r"""
1576 A type printer for class templates with default template arguments.
1577
1578 Recognizes specializations of class templates and prints them without
1579 any template arguments that use a default template argument.
1580 Type printers are recursively applied to the template arguments.
1581
1582 e.g. replace "std::vector<T, std::allocator<T> >" with "std::vector<T>".
1583 """
1584
1585 def __init__(self, name, defargs):
1586 self.name = name
1587 self.defargs = defargs
1588 self.enabled = True
1589
1590 class _recognizer(object):
1591 "The recognizer class for TemplateTypePrinter."
1592
1593 def __init__(self, name, defargs):
1594 self.name = name
1595 self.defargs = defargs
1596 # self.type_obj = None
1597
1598 def recognize(self, type_obj):
1599 """
1600 If type_obj is a specialization of self.name that uses all the
1601 default template arguments for the class template, then return
1602 a string representation of the type without default arguments.
1603 Otherwise, return None.
1604 """
1605
1606 if type_obj.tag is None:
1607 return None
1608
1609 if not type_obj.tag.startswith(self.name):
1610 return None
1611
1612 template_args = get_template_arg_list(type_obj)
1613 displayed_args = []
1614 require_defaulted = False
1615 for n in range(len(template_args)):
1616 # The actual template argument in the type:
1617 targ = template_args[n]
1618 # The default template argument for the class template:
1619 defarg = self.defargs.get(n)
1620 if defarg is not None:
1621 # Substitute other template arguments into the default:
1622 defarg = defarg.format(*template_args)
1623 # Fail to recognize the type (by returning None)
1624 # unless the actual argument is the same as the default.
1625 try:
1626 if targ != gdb.lookup_type(defarg):
1627 return None
1628 except gdb.error:
1629 # Type lookup failed, just use string comparison:
1630 if targ.tag != defarg:
1631 return None
1632 # All subsequent args must have defaults:
1633 require_defaulted = True
1634 elif require_defaulted:
1635 return None
1636 else:
1637 # Recursively apply recognizers to the template argument
1638 # and add it to the arguments that will be displayed:
1639 displayed_args.append(self._recognize_subtype(targ))
1640
1641 # This assumes no class templates in the nested-name-specifier:
1642 template_name = type_obj.tag[0:type_obj.tag.find('<')]
1643 template_name = strip_inline_namespaces(template_name)
1644
1645 return template_name + '<' + ', '.join(displayed_args) + '>'
1646
1647 def _recognize_subtype(self, type_obj):
1648 """Convert a gdb.Type to a string by applying recognizers,
1649 or if that fails then simply converting to a string."""
1650
1651 if type_obj.code == gdb.TYPE_CODE_PTR:
1652 return self._recognize_subtype(type_obj.target()) + '*'
1653 if type_obj.code == gdb.TYPE_CODE_ARRAY:
1654 type_str = self._recognize_subtype(type_obj.target())
1655 if str(type_obj.strip_typedefs()).endswith('[]'):
1656 return type_str + '[]' # array of unknown bound
1657 return "%s[%d]" % (type_str, type_obj.range()[1] + 1)
1658 if type_obj.code == gdb.TYPE_CODE_REF:
1659 return self._recognize_subtype(type_obj.target()) + '&'
1660 if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'):
1661 if type_obj.code == gdb.TYPE_CODE_RVALUE_REF:
1662 return self._recognize_subtype(type_obj.target()) + '&&'
1663
1664 type_str = gdb.types.apply_type_recognizers(
1665 gdb.types.get_type_recognizers(), type_obj)
1666 if type_str:
1667 return type_str
1668 return str(type_obj)
1669
1670 def instantiate(self):
1671 "Return a recognizer object for this type printer."
1672 return self._recognizer(self.name, self.defargs)
1673
1674def add_one_template_type_printer(obj, name, defargs):
1675 r"""
1676 Add a type printer for a class template with default template arguments.
1677
1678 Args:
1679 name (str): The template-name of the class template.
1680 defargs (dict int:string) The default template arguments.
1681
1682 Types in defargs can refer to the Nth template-argument using {N}
1683 (with zero-based indices).
1684
1685 e.g. 'unordered_map' has these defargs:
1686 { 2: 'std::hash<{0}>',
1687 3: 'std::equal_to<{0}>',
1688 4: 'std::allocator<std::pair<const {0}, {1}> >' }
1689
1690 """
1691 printer = TemplateTypePrinter('std::'+name, defargs)
1692 gdb.types.register_type_printer(obj, printer)
1693
1694 # Add type printer for same type in debug namespace:
1695 printer = TemplateTypePrinter('std::__debug::'+name, defargs)
1696 gdb.types.register_type_printer(obj, printer)
1697
1698 if _versioned_namespace:
1699 # Add second type printer for same type in versioned namespace:
1700 ns = 'std::' + _versioned_namespace
1701 # PR 86112 Cannot use dict comprehension here:
1702 defargs = dict((n, d.replace('std::', ns)) for (n,d) in defargs.items())
1703 printer = TemplateTypePrinter(ns+name, defargs)
1704 gdb.types.register_type_printer(obj, printer)
1705
1706class FilteringTypePrinter(object):
1707 r"""
1708 A type printer that uses typedef names for common template specializations.
1709
1710 Args:
1711 match (str): The class template to recognize.
1712 name (str): The typedef-name that will be used instead.
1713
1714 Checks if a specialization of the class template 'match' is the same type
1715 as the typedef 'name', and prints it as 'name' instead.
1716
1717 e.g. if an instantiation of std::basic_istream<C, T> is the same type as
1718 std::istream then print it as std::istream.
1719 """
1720
1721 def __init__(self, match, name):
1722 self.match = match
1723 self.name = name
1724 self.enabled = True
1725
1726 class _recognizer(object):
1727 "The recognizer class for TemplateTypePrinter."
1728
1729 def __init__(self, match, name):
1730 self.match = match
1731 self.name = name
1732 self.type_obj = None
1733
1734 def recognize(self, type_obj):
1735 """
1736 If type_obj starts with self.match and is the same type as
1737 self.name then return self.name, otherwise None.
1738 """
1739 if type_obj.tag is None:
1740 return None
1741
1742 if self.type_obj is None:
1743 if not type_obj.tag.startswith(self.match):
1744 # Filter didn't match.
1745 return None
1746 try:
1747 self.type_obj = gdb.lookup_type(self.name).strip_typedefs()
1748 except:
1749 pass
1750 if self.type_obj == type_obj:
1751 return strip_inline_namespaces(self.name)
1752 return None
1753
1754 def instantiate(self):
1755 "Return a recognizer object for this type printer."
1756 return self._recognizer(self.match, self.name)
1757
1758def add_one_type_printer(obj, match, name):
1759 printer = FilteringTypePrinter('std::' + match, 'std::' + name)
1760 gdb.types.register_type_printer(obj, printer)
1761 if _versioned_namespace:
1762 ns = 'std::' + _versioned_namespace
1763 printer = FilteringTypePrinter(ns + match, ns + name)
1764 gdb.types.register_type_printer(obj, printer)
1765
1766def register_type_printers(obj):
1767 global _use_type_printing
1768
1769 if not _use_type_printing:
1770 return
1771
1772 # Add type printers for typedefs std::string, std::wstring etc.
1773 for ch in ('', 'w', 'u8', 'u16', 'u32'):
1774 add_one_type_printer(obj, 'basic_string', ch + 'string')
1775 add_one_type_printer(obj, '__cxx11::basic_string', ch + 'string')
1776 # Typedefs for __cxx11::basic_string used to be in namespace __cxx11:
1777 add_one_type_printer(obj, '__cxx11::basic_string',
1778 '__cxx11::' + ch + 'string')
1779 add_one_type_printer(obj, 'basic_string_view', ch + 'string_view')
1780
1781 # Add type printers for typedefs std::istream, std::wistream etc.
1782 for ch in ('', 'w'):
1783 for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream',
1784 'filebuf', 'ifstream', 'ofstream', 'fstream'):
1785 add_one_type_printer(obj, 'basic_' + x, ch + x)
1786 for x in ('stringbuf', 'istringstream', 'ostringstream',
1787 'stringstream'):
1788 add_one_type_printer(obj, 'basic_' + x, ch + x)
1789 # <sstream> types are in __cxx11 namespace, but typedefs aren't:
1790 add_one_type_printer(obj, '__cxx11::basic_' + x, ch + x)
1791
1792 # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc.
1793 for abi in ('', '__cxx11::'):
1794 for ch in ('', 'w'):
1795 add_one_type_printer(obj, abi + 'basic_regex', abi + ch + 'regex')
1796 for ch in ('c', 's', 'wc', 'ws'):
1797 add_one_type_printer(obj, abi + 'match_results', abi + ch + 'match')
1798 for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'):
1799 add_one_type_printer(obj, abi + x, abi + ch + x)
1800
1801 # Note that we can't have a printer for std::wstreampos, because
1802 # it is the same type as std::streampos.
1803 add_one_type_printer(obj, 'fpos', 'streampos')
1804
1805 # Add type printers for <chrono> typedefs.
1806 for dur in ('nanoseconds', 'microseconds', 'milliseconds',
1807 'seconds', 'minutes', 'hours'):
1808 add_one_type_printer(obj, 'duration', dur)
1809
1810 # Add type printers for <random> typedefs.
1811 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
1812 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand')
1813 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937')
1814 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64')
1815 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base')
1816 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base')
1817 add_one_type_printer(obj, 'discard_block_engine', 'ranlux24')
1818 add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
1819 add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
1820
1821 # Add type printers for experimental::basic_string_view typedefs.
1822 ns = 'experimental::fundamentals_v1::'
1823 for ch in ('', 'w', 'u8', 'u16', 'u32'):
1824 add_one_type_printer(obj, ns + 'basic_string_view',
1825 ns + ch + 'string_view')
1826
1827 # Do not show defaulted template arguments in class templates.
1828 add_one_template_type_printer(obj, 'unique_ptr',
1829 { 1: 'std::default_delete<{0}>' })
1830 add_one_template_type_printer(obj, 'deque', { 1: 'std::allocator<{0}>'})
1831 add_one_template_type_printer(obj, 'forward_list', { 1: 'std::allocator<{0}>'})
1832 add_one_template_type_printer(obj, 'list', { 1: 'std::allocator<{0}>'})
1833 add_one_template_type_printer(obj, '__cxx11::list', { 1: 'std::allocator<{0}>'})
1834 add_one_template_type_printer(obj, 'vector', { 1: 'std::allocator<{0}>'})
1835 add_one_template_type_printer(obj, 'map',
1836 { 2: 'std::less<{0}>',
1837 3: 'std::allocator<std::pair<{0} const, {1}>>' })
1838 add_one_template_type_printer(obj, 'multimap',
1839 { 2: 'std::less<{0}>',
1840 3: 'std::allocator<std::pair<{0} const, {1}>>' })
1841 add_one_template_type_printer(obj, 'set',
1842 { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
1843 add_one_template_type_printer(obj, 'multiset',
1844 { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
1845 add_one_template_type_printer(obj, 'unordered_map',
1846 { 2: 'std::hash<{0}>',
1847 3: 'std::equal_to<{0}>',
1848 4: 'std::allocator<std::pair<{0} const, {1}>>'})
1849 add_one_template_type_printer(obj, 'unordered_multimap',
1850 { 2: 'std::hash<{0}>',
1851 3: 'std::equal_to<{0}>',
1852 4: 'std::allocator<std::pair<{0} const, {1}>>'})
1853 add_one_template_type_printer(obj, 'unordered_set',
1854 { 1: 'std::hash<{0}>',
1855 2: 'std::equal_to<{0}>',
1856 3: 'std::allocator<{0}>'})
1857 add_one_template_type_printer(obj, 'unordered_multiset',
1858 { 1: 'std::hash<{0}>',
1859 2: 'std::equal_to<{0}>',
1860 3: 'std::allocator<{0}>'})
1861
1862def register_libstdcxx_printers (obj):
1863 "Register libstdc++ pretty-printers with objfile Obj."
1864
1865 global _use_gdb_pp
1866 global libstdcxx_printer
1867
1868 if _use_gdb_pp:
1869 gdb.printing.register_pretty_printer(obj, libstdcxx_printer)
1870 else:
1871 if obj is None:
1872 obj = gdb
1873 obj.pretty_printers.append(libstdcxx_printer)
1874
1875 register_type_printers(obj)
1876
1877def build_libstdcxx_dictionary ():
1878 global libstdcxx_printer
1879
1880 libstdcxx_printer = Printer("libstdc++-v6")
1881
1882 # libstdc++ objects requiring pretty-printing.
1883 # In order from:
1884 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
1885 libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter)
1886 libstdcxx_printer.add_version('std::__cxx11::', 'basic_string', StdStringPrinter)
1887 libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter)
1888 libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter)
1889 libstdcxx_printer.add_container('std::', 'list', StdListPrinter)
1890 libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter)
1891 libstdcxx_printer.add_container('std::', 'map', StdMapPrinter)
1892 libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter)
1893 libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter)
1894 libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter)
1895 libstdcxx_printer.add_version('std::', 'priority_queue',
1896 StdStackOrQueuePrinter)
1897 libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter)
1898 libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter)
1899 libstdcxx_printer.add_container('std::', 'set', StdSetPrinter)
1900 libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter)
1901 libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter)
1902 libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter)
1903 # vector<bool>
1904
1905 # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
1906 libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter)
1907 libstdcxx_printer.add('std::__debug::deque', StdDequePrinter)
1908 libstdcxx_printer.add('std::__debug::list', StdListPrinter)
1909 libstdcxx_printer.add('std::__debug::map', StdMapPrinter)
1910 libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter)
1911 libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter)
1912 libstdcxx_printer.add('std::__debug::priority_queue',
1913 StdStackOrQueuePrinter)
1914 libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter)
1915 libstdcxx_printer.add('std::__debug::set', StdSetPrinter)
1916 libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter)
1917 libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter)
1918 libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter)
1919
1920 # These are the TR1 and C++11 printers.
1921 # For array - the default GDB pretty-printer seems reasonable.
1922 libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter)
1923 libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter)
1924 libstdcxx_printer.add_container('std::', 'unordered_map',
1925 Tr1UnorderedMapPrinter)
1926 libstdcxx_printer.add_container('std::', 'unordered_set',
1927 Tr1UnorderedSetPrinter)
1928 libstdcxx_printer.add_container('std::', 'unordered_multimap',
1929 Tr1UnorderedMapPrinter)
1930 libstdcxx_printer.add_container('std::', 'unordered_multiset',
1931 Tr1UnorderedSetPrinter)
1932 libstdcxx_printer.add_container('std::', 'forward_list',
1933 StdForwardListPrinter)
1934
1935 libstdcxx_printer.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter)
1936 libstdcxx_printer.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter)
1937 libstdcxx_printer.add_version('std::tr1::', 'unordered_map',
1938 Tr1UnorderedMapPrinter)
1939 libstdcxx_printer.add_version('std::tr1::', 'unordered_set',
1940 Tr1UnorderedSetPrinter)
1941 libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap',
1942 Tr1UnorderedMapPrinter)
1943 libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset',
1944 Tr1UnorderedSetPrinter)
1945
1946 # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases.
1947 # The tr1 namespace containers do not have any debug equivalents,
1948 # so do not register printers for them.
1949 libstdcxx_printer.add('std::__debug::unordered_map',
1950 Tr1UnorderedMapPrinter)
1951 libstdcxx_printer.add('std::__debug::unordered_set',
1952 Tr1UnorderedSetPrinter)
1953 libstdcxx_printer.add('std::__debug::unordered_multimap',
1954 Tr1UnorderedMapPrinter)
1955 libstdcxx_printer.add('std::__debug::unordered_multiset',
1956 Tr1UnorderedSetPrinter)
1957 libstdcxx_printer.add('std::__debug::forward_list',
1958 StdForwardListPrinter)
1959
1960 # Library Fundamentals TS components
1961 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
1962 'any', StdExpAnyPrinter)
1963 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
1964 'optional', StdExpOptionalPrinter)
1965 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
1966 'basic_string_view', StdExpStringViewPrinter)
1967 # Filesystem TS components
1968 libstdcxx_printer.add_version('std::experimental::filesystem::v1::',
1969 'path', StdExpPathPrinter)
1970 libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
1971 'path', StdExpPathPrinter)
1972 libstdcxx_printer.add_version('std::filesystem::',
1973 'path', StdPathPrinter)
1974 libstdcxx_printer.add_version('std::filesystem::__cxx11::',
1975 'path', StdPathPrinter)
1976
1977 # C++17 components
1978 libstdcxx_printer.add_version('std::',
1979 'any', StdExpAnyPrinter)
1980 libstdcxx_printer.add_version('std::',
1981 'optional', StdExpOptionalPrinter)
1982 libstdcxx_printer.add_version('std::',
1983 'basic_string_view', StdExpStringViewPrinter)
1984 libstdcxx_printer.add_version('std::',
1985 'variant', StdVariantPrinter)
1986 libstdcxx_printer.add_version('std::',
1987 '_Node_handle', StdNodeHandlePrinter)
1988
1989 # C++20 components
1990 libstdcxx_printer.add_version('std::', 'partial_ordering', StdCmpCatPrinter)
1991 libstdcxx_printer.add_version('std::', 'weak_ordering', StdCmpCatPrinter)
1992 libstdcxx_printer.add_version('std::', 'strong_ordering', StdCmpCatPrinter)
1993
1994 # Extensions.
1995 libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter)
1996
1997 if True:
1998 # These shouldn't be necessary, if GDB "print *i" worked.
1999 # But it often doesn't, so here they are.
2000 libstdcxx_printer.add_container('std::', '_List_iterator',
2001 StdListIteratorPrinter)
2002 libstdcxx_printer.add_container('std::', '_List_const_iterator',
2003 StdListIteratorPrinter)
2004 libstdcxx_printer.add_version('std::', '_Rb_tree_iterator',
2005 StdRbtreeIteratorPrinter)
2006 libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator',
2007 StdRbtreeIteratorPrinter)
2008 libstdcxx_printer.add_container('std::', '_Deque_iterator',
2009 StdDequeIteratorPrinter)
2010 libstdcxx_printer.add_container('std::', '_Deque_const_iterator',
2011 StdDequeIteratorPrinter)
2012 libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator',
2013 StdVectorIteratorPrinter)
2014 libstdcxx_printer.add_version('std::', '_Bit_iterator',
2015 StdBitIteratorPrinter)
2016 libstdcxx_printer.add_version('std::', '_Bit_const_iterator',
2017 StdBitIteratorPrinter)
2018 libstdcxx_printer.add_version('std::', '_Bit_reference',
2019 StdBitReferencePrinter)
2020 libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator',
2021 StdSlistIteratorPrinter)
2022 libstdcxx_printer.add_container('std::', '_Fwd_list_iterator',
2023 StdFwdListIteratorPrinter)
2024 libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator',
2025 StdFwdListIteratorPrinter)
2026
2027 # Debug (compiled with -D_GLIBCXX_DEBUG) printer
2028 # registrations.
2029 libstdcxx_printer.add('__gnu_debug::_Safe_iterator',
2030 StdDebugIteratorPrinter)
2031
2032build_libstdcxx_dictionary ()
Note: See TracBrowser for help on using the repository browser.