1 # Pretty-printers for libstdc++.
3 # Copyright (C) 2008-2018 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/>.
23 ### Python 2 + Python 3 compatibility code
25 # Resources about compatibility:
27 # * <http://pythonhosted.org/six/>: Documentation of the "six" module
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.
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.
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>
39 if sys
.version_info
[0] > 2:
42 # Python 3 folds these into the normal functions.
45 # Also, int subsumes long
50 """Compatibility mixin for iterators
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.
56 Idea stolen from the "six" documentation:
57 <http://pythonhosted.org/six/#six.Iterator>
61 return self
.__next
__()
63 # In Python 2, we still need these from itertools
64 from itertools
import imap
, izip
66 # Try to use the new-style pretty-printing if available.
73 # Try to install type-printers.
74 _use_type_printing
= False
77 if hasattr(gdb
.types
, 'TypePrinter'):
78 _use_type_printing
= True
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.
85 def find_type(orig
, name
):
86 typ
= orig
.strip_typedefs()
88 # Strip cv-qualifiers. PR 67440.
89 search
= '%s::%s' % (typ
.unqualified(), name
)
91 return gdb
.lookup_type(search
)
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 field
= typ
.fields()[0]
98 if not field
.is_base_class
:
99 raise ValueError("Cannot find type %s::%s" % (str(orig
), name
))
102 _versioned_namespace
= '__8::'
104 # Test if a type is a given template instantiation.
105 def is_specialization_of(type, template_name
):
106 global _versioned_namespace
107 if _versioned_namespace
:
108 return re
.match('^std::(%s)?%s<.*>$' % (_versioned_namespace
, template_name
), type) is not None
109 return re
.match('^std::%s<.*>$' % template_name
, type) is not None
111 def strip_versioned_namespace(typename
):
112 global _versioned_namespace
113 if _versioned_namespace
:
114 return typename
.replace(_versioned_namespace
, '')
117 class SharedPointerPrinter
:
118 "Print a shared_ptr or weak_ptr"
120 def __init__ (self
, typename
, val
):
121 self
.typename
= strip_versioned_namespace(typename
)
124 def to_string (self
):
126 refcounts
= self
.val
['_M_refcount']['_M_pi']
128 usecount
= refcounts
['_M_use_count']
129 weakcount
= refcounts
['_M_weak_count']
131 state
= 'expired, weak %d' % weakcount
133 state
= 'count %d, weak %d' % (usecount
, weakcount
- 1)
134 return '%s (%s) %s' % (self
.typename
, state
, self
.val
['_M_ptr'])
136 class UniquePointerPrinter
:
139 def __init__ (self
, typename
, val
):
142 def to_string (self
):
143 impl_type
= self
.val
.type.fields()[0].type.tag
144 if is_specialization_of(impl_type
, '__uniq_ptr_impl'): # New implementation
145 v
= self
.val
['_M_t']['_M_t']['_M_head_impl']
146 elif is_specialization_of(impl_type
, 'tuple'):
147 v
= self
.val
['_M_t']['_M_head_impl']
149 raise ValueError("Unsupported implementation for unique_ptr: %s" % self
.val
.type.fields()[0].type.tag
)
150 return 'std::unique_ptr<%s> containing %s' % (str(v
.type.target()),
153 def get_value_from_aligned_membuf(buf
, valtype
):
154 """Returns the value held in a __gnu_cxx::__aligned_membuf."""
155 return buf
['_M_storage'].address
.cast(valtype
.pointer()).dereference()
157 def get_value_from_list_node(node
):
158 """Returns the value held in an _List_node<_Val>"""
160 member
= node
.type.fields()[1].name
161 if member
== '_M_data':
162 # C++03 implementation, node contains the value as a member
163 return node
['_M_data']
164 elif member
== '_M_storage':
165 # C++11 implementation, node stores value in __aligned_membuf
166 valtype
= node
.type.template_argument(0)
167 return get_value_from_aligned_membuf(node
['_M_storage'], valtype
)
170 raise ValueError("Unsupported implementation for %s" % str(node
.type))
172 class StdListPrinter
:
175 class _iterator(Iterator
):
176 def __init__(self
, nodetype
, head
):
177 self
.nodetype
= nodetype
178 self
.base
= head
['_M_next']
179 self
.head
= head
.address
186 if self
.base
== self
.head
:
188 elt
= self
.base
.cast(self
.nodetype
).dereference()
189 self
.base
= elt
['_M_next']
191 self
.count
= self
.count
+ 1
192 val
= get_value_from_list_node(elt
)
193 return ('[%d]' % count
, val
)
195 def __init__(self
, typename
, val
):
196 self
.typename
= strip_versioned_namespace(typename
)
200 nodetype
= find_type(self
.val
.type, '_Node')
201 nodetype
= nodetype
.strip_typedefs().pointer()
202 return self
._iterator
(nodetype
, self
.val
['_M_impl']['_M_node'])
205 if self
.val
['_M_impl']['_M_node'].address
== self
.val
['_M_impl']['_M_node']['_M_next']:
206 return 'empty %s' % (self
.typename
)
207 return '%s' % (self
.typename
)
209 class StdListIteratorPrinter
:
210 "Print std::list::iterator"
212 def __init__(self
, typename
, val
):
214 self
.typename
= typename
217 if not self
.val
['_M_node']:
218 return 'non-dereferenceable iterator for std::list'
219 nodetype
= find_type(self
.val
.type, '_Node')
220 nodetype
= nodetype
.strip_typedefs().pointer()
221 node
= self
.val
['_M_node'].cast(nodetype
).dereference()
222 return str(get_value_from_list_node(node
))
224 class StdSlistPrinter
:
225 "Print a __gnu_cxx::slist"
227 class _iterator(Iterator
):
228 def __init__(self
, nodetype
, head
):
229 self
.nodetype
= nodetype
230 self
.base
= head
['_M_head']['_M_next']
239 elt
= self
.base
.cast(self
.nodetype
).dereference()
240 self
.base
= elt
['_M_next']
242 self
.count
= self
.count
+ 1
243 return ('[%d]' % count
, elt
['_M_data'])
245 def __init__(self
, typename
, val
):
249 nodetype
= find_type(self
.val
.type, '_Node')
250 nodetype
= nodetype
.strip_typedefs().pointer()
251 return self
._iterator
(nodetype
, self
.val
)
254 if self
.val
['_M_head']['_M_next'] == 0:
255 return 'empty __gnu_cxx::slist'
256 return '__gnu_cxx::slist'
258 class StdSlistIteratorPrinter
:
259 "Print __gnu_cxx::slist::iterator"
261 def __init__(self
, typename
, val
):
265 if not self
.val
['_M_node']:
266 return 'non-dereferenceable iterator for __gnu_cxx::slist'
267 nodetype
= find_type(self
.val
.type, '_Node')
268 nodetype
= nodetype
.strip_typedefs().pointer()
269 return str(self
.val
['_M_node'].cast(nodetype
).dereference()['_M_data'])
271 class StdVectorPrinter
:
272 "Print a std::vector"
274 class _iterator(Iterator
):
275 def __init__ (self
, start
, finish
, bitvec
):
278 self
.item
= start
['_M_p']
279 self
.so
= start
['_M_offset']
280 self
.finish
= finish
['_M_p']
281 self
.fo
= finish
['_M_offset']
282 itype
= self
.item
.dereference().type
283 self
.isize
= 8 * itype
.sizeof
294 self
.count
= self
.count
+ 1
296 if self
.item
== self
.finish
and self
.so
>= self
.fo
:
298 elt
= self
.item
.dereference()
299 if elt
& (1 << self
.so
):
303 self
.so
= self
.so
+ 1
304 if self
.so
>= self
.isize
:
305 self
.item
= self
.item
+ 1
307 return ('[%d]' % count
, obit
)
309 if self
.item
== self
.finish
:
311 elt
= self
.item
.dereference()
312 self
.item
= self
.item
+ 1
313 return ('[%d]' % count
, elt
)
315 def __init__(self
, typename
, val
):
316 self
.typename
= strip_versioned_namespace(typename
)
318 self
.is_bool
= val
.type.template_argument(0).code
== gdb
.TYPE_CODE_BOOL
321 return self
._iterator
(self
.val
['_M_impl']['_M_start'],
322 self
.val
['_M_impl']['_M_finish'],
326 start
= self
.val
['_M_impl']['_M_start']
327 finish
= self
.val
['_M_impl']['_M_finish']
328 end
= self
.val
['_M_impl']['_M_end_of_storage']
330 start
= self
.val
['_M_impl']['_M_start']['_M_p']
331 so
= self
.val
['_M_impl']['_M_start']['_M_offset']
332 finish
= self
.val
['_M_impl']['_M_finish']['_M_p']
333 fo
= self
.val
['_M_impl']['_M_finish']['_M_offset']
334 itype
= start
.dereference().type
335 bl
= 8 * itype
.sizeof
336 length
= (bl
- so
) + bl
* ((finish
- start
) - 1) + fo
337 capacity
= bl
* (end
- start
)
338 return ('%s<bool> of length %d, capacity %d'
339 % (self
.typename
, int (length
), int (capacity
)))
341 return ('%s of length %d, capacity %d'
342 % (self
.typename
, int (finish
- start
), int (end
- start
)))
344 def display_hint(self
):
347 class StdVectorIteratorPrinter
:
348 "Print std::vector::iterator"
350 def __init__(self
, typename
, val
):
354 if not self
.val
['_M_current']:
355 return 'non-dereferenceable iterator for std::vector'
356 return str(self
.val
['_M_current'].dereference())
358 class StdTuplePrinter
:
361 class _iterator(Iterator
):
362 def __init__ (self
, head
):
365 # Set the base class as the initial head of the
367 nodes
= self
.head
.type.fields ()
369 # Set the actual head to the first pair.
370 self
.head
= self
.head
.cast (nodes
[0].type)
371 elif len (nodes
) != 0:
372 raise ValueError("Top of tuple tree does not consist of a single node.")
379 # Check for further recursions in the inheritance tree.
380 # For a GCC 5+ tuple self.head is None after visiting all nodes:
383 nodes
= self
.head
.type.fields ()
384 # For a GCC 4.x tuple there is a final node with no fields:
387 # Check that this iteration has an expected structure.
389 raise ValueError("Cannot parse more than 2 nodes in a tuple tree.")
392 # This is the last node of a GCC 5+ std::tuple.
393 impl
= self
.head
.cast (nodes
[0].type)
396 # Either a node before the last node, or the last node of
397 # a GCC 4.x tuple (which has an empty parent).
399 # - Left node is the next recursion parent.
400 # - Right node is the actual class contained in the tuple.
402 # Process right node.
403 impl
= self
.head
.cast (nodes
[1].type)
405 # Process left node and set it as head.
406 self
.head
= self
.head
.cast (nodes
[0].type)
408 self
.count
= self
.count
+ 1
410 # Finally, check the implementation. If it is
411 # wrapped in _M_head_impl return that, otherwise return
413 fields
= impl
.type.fields ()
414 if len (fields
) < 1 or fields
[0].name
!= "_M_head_impl":
415 return ('[%d]' % self
.count
, impl
)
417 return ('[%d]' % self
.count
, impl
['_M_head_impl'])
419 def __init__ (self
, typename
, val
):
420 self
.typename
= strip_versioned_namespace(typename
)
424 return self
._iterator
(self
.val
)
426 def to_string (self
):
427 if len (self
.val
.type.fields ()) == 0:
428 return 'empty %s' % (self
.typename
)
429 return '%s containing' % (self
.typename
)
431 class StdStackOrQueuePrinter
:
432 "Print a std::stack or std::queue"
434 def __init__ (self
, typename
, val
):
435 self
.typename
= strip_versioned_namespace(typename
)
436 self
.visualizer
= gdb
.default_visualizer(val
['c'])
439 return self
.visualizer
.children()
441 def to_string (self
):
442 return '%s wrapping: %s' % (self
.typename
,
443 self
.visualizer
.to_string())
445 def display_hint (self
):
446 if hasattr (self
.visualizer
, 'display_hint'):
447 return self
.visualizer
.display_hint ()
450 class RbtreeIterator(Iterator
):
452 Turn an RB-tree-based container (std::map, std::set etc.) into
453 a Python iterable object.
456 def __init__(self
, rbtree
):
457 self
.size
= rbtree
['_M_t']['_M_impl']['_M_node_count']
458 self
.node
= rbtree
['_M_t']['_M_impl']['_M_header']['_M_left']
465 return int (self
.size
)
468 if self
.count
== self
.size
:
471 self
.count
= self
.count
+ 1
472 if self
.count
< self
.size
:
473 # Compute the next node.
475 if node
.dereference()['_M_right']:
476 node
= node
.dereference()['_M_right']
477 while node
.dereference()['_M_left']:
478 node
= node
.dereference()['_M_left']
480 parent
= node
.dereference()['_M_parent']
481 while node
== parent
.dereference()['_M_right']:
483 parent
= parent
.dereference()['_M_parent']
484 if node
.dereference()['_M_right'] != parent
:
489 def get_value_from_Rb_tree_node(node
):
490 """Returns the value held in an _Rb_tree_node<_Val>"""
492 member
= node
.type.fields()[1].name
493 if member
== '_M_value_field':
494 # C++03 implementation, node contains the value as a member
495 return node
['_M_value_field']
496 elif member
== '_M_storage':
497 # C++11 implementation, node stores value in __aligned_membuf
498 valtype
= node
.type.template_argument(0)
499 return get_value_from_aligned_membuf(node
['_M_storage'], valtype
)
502 raise ValueError("Unsupported implementation for %s" % str(node
.type))
504 # This is a pretty printer for std::_Rb_tree_iterator (which is
505 # std::map::iterator), and has nothing to do with the RbtreeIterator
507 class StdRbtreeIteratorPrinter
:
508 "Print std::map::iterator, std::set::iterator, etc."
510 def __init__ (self
, typename
, val
):
512 valtype
= self
.val
.type.template_argument(0).strip_typedefs()
513 nodetype
= '_Rb_tree_node<' + str(valtype
) + '>'
514 if _versioned_namespace
and typename
.startswith('std::' + _versioned_namespace
):
515 nodetype
= _versioned_namespace
+ nodetype
516 nodetype
= gdb
.lookup_type('std::' + nodetype
)
517 self
.link_type
= nodetype
.strip_typedefs().pointer()
519 def to_string (self
):
520 if not self
.val
['_M_node']:
521 return 'non-dereferenceable iterator for associative container'
522 node
= self
.val
['_M_node'].cast(self
.link_type
).dereference()
523 return str(get_value_from_Rb_tree_node(node
))
525 class StdDebugIteratorPrinter
:
526 "Print a debug enabled version of an iterator"
528 def __init__ (self
, typename
, val
):
531 # Just strip away the encapsulating __gnu_debug::_Safe_iterator
532 # and return the wrapped iterator value.
533 def to_string (self
):
534 base_type
= gdb
.lookup_type('__gnu_debug::_Safe_iterator_base')
535 safe_seq
= self
.val
.cast(base_type
)['_M_sequence']
536 if not safe_seq
or self
.val
['_M_version'] != safe_seq
['_M_version']:
537 return "invalid iterator"
538 itype
= self
.val
.type.template_argument(0)
539 return str(self
.val
.cast(itype
))
541 def num_elements(num
):
542 """Return either "1 element" or "N elements" depending on the argument."""
543 return '1 element' if num
== 1 else '%d elements' % num
546 "Print a std::map or std::multimap"
548 # Turn an RbtreeIterator into a pretty-print iterator.
549 class _iter(Iterator
):
550 def __init__(self
, rbiter
, type):
559 if self
.count
% 2 == 0:
560 n
= next(self
.rbiter
)
561 n
= n
.cast(self
.type).dereference()
562 n
= get_value_from_Rb_tree_node(n
)
566 item
= self
.pair
['second']
567 result
= ('[%d]' % self
.count
, item
)
568 self
.count
= self
.count
+ 1
571 def __init__ (self
, typename
, val
):
572 self
.typename
= strip_versioned_namespace(typename
)
575 def to_string (self
):
576 return '%s with %s' % (self
.typename
,
577 num_elements(len(RbtreeIterator (self
.val
))))
580 rep_type
= find_type(self
.val
.type, '_Rep_type')
581 node
= find_type(rep_type
, '_Link_type')
582 node
= node
.strip_typedefs()
583 return self
._iter
(RbtreeIterator (self
.val
), node
)
585 def display_hint (self
):
589 "Print a std::set or std::multiset"
591 # Turn an RbtreeIterator into a pretty-print iterator.
592 class _iter(Iterator
):
593 def __init__(self
, rbiter
, type):
602 item
= next(self
.rbiter
)
603 item
= item
.cast(self
.type).dereference()
604 item
= get_value_from_Rb_tree_node(item
)
605 # FIXME: this is weird ... what to do?
606 # Maybe a 'set' display hint?
607 result
= ('[%d]' % self
.count
, item
)
608 self
.count
= self
.count
+ 1
611 def __init__ (self
, typename
, val
):
612 self
.typename
= strip_versioned_namespace(typename
)
615 def to_string (self
):
616 return '%s with %s' % (self
.typename
,
617 num_elements(len(RbtreeIterator (self
.val
))))
620 rep_type
= find_type(self
.val
.type, '_Rep_type')
621 node
= find_type(rep_type
, '_Link_type')
622 node
= node
.strip_typedefs()
623 return self
._iter
(RbtreeIterator (self
.val
), node
)
625 class StdBitsetPrinter
:
626 "Print a std::bitset"
628 def __init__(self
, typename
, val
):
629 self
.typename
= strip_versioned_namespace(typename
)
632 def to_string (self
):
633 # If template_argument handled values, we could print the
634 # size. Or we could use a regexp on the type.
635 return '%s' % (self
.typename
)
638 words
= self
.val
['_M_w']
641 # The _M_w member can be either an unsigned long, or an
642 # array. This depends on the template specialization used.
643 # If it is a single long, convert to a single element list.
644 if wtype
.code
== gdb
.TYPE_CODE_ARRAY
:
645 tsize
= wtype
.target ().sizeof
650 nwords
= wtype
.sizeof
/ tsize
658 # Another spot where we could use 'set'?
659 result
.append(('[%d]' % (byte
* tsize
* 8 + bit
), 1))
665 class StdDequePrinter
:
668 class _iter(Iterator
):
669 def __init__(self
, node
, start
, end
, last
, buffer_size
):
674 self
.buffer_size
= buffer_size
681 if self
.p
== self
.last
:
684 result
= ('[%d]' % self
.count
, self
.p
.dereference())
685 self
.count
= self
.count
+ 1
687 # Advance the 'cur' pointer.
689 if self
.p
== self
.end
:
690 # If we got to the end of this bucket, move to the
692 self
.node
= self
.node
+ 1
693 self
.p
= self
.node
[0]
694 self
.end
= self
.p
+ self
.buffer_size
698 def __init__(self
, typename
, val
):
699 self
.typename
= strip_versioned_namespace(typename
)
701 self
.elttype
= val
.type.template_argument(0)
702 size
= self
.elttype
.sizeof
704 self
.buffer_size
= int (512 / size
)
709 start
= self
.val
['_M_impl']['_M_start']
710 end
= self
.val
['_M_impl']['_M_finish']
712 delta_n
= end
['_M_node'] - start
['_M_node'] - 1
713 delta_s
= start
['_M_last'] - start
['_M_cur']
714 delta_e
= end
['_M_cur'] - end
['_M_first']
716 size
= self
.buffer_size
* delta_n
+ delta_s
+ delta_e
718 return '%s with %s' % (self
.typename
, num_elements(long(size
)))
721 start
= self
.val
['_M_impl']['_M_start']
722 end
= self
.val
['_M_impl']['_M_finish']
723 return self
._iter
(start
['_M_node'], start
['_M_cur'], start
['_M_last'],
724 end
['_M_cur'], self
.buffer_size
)
726 def display_hint (self
):
729 class StdDequeIteratorPrinter
:
730 "Print std::deque::iterator"
732 def __init__(self
, typename
, val
):
736 if not self
.val
['_M_cur']:
737 return 'non-dereferenceable iterator for std::deque'
738 return str(self
.val
['_M_cur'].dereference())
740 class StdStringPrinter
:
741 "Print a std::basic_string of some kind"
743 def __init__(self
, typename
, val
):
745 self
.new_string
= typename
.find("::__cxx11::basic_string") != -1
748 # Make sure &string works, too.
750 if type.code
== gdb
.TYPE_CODE_REF
:
751 type = type.target ()
753 # Calculate the length of the string so that to_string returns
754 # the string according to length, not according to first null
756 ptr
= self
.val
['_M_dataplus']['_M_p']
758 length
= self
.val
['_M_string_length']
759 # https://sourceware.org/bugzilla/show_bug.cgi?id=17728
760 ptr
= ptr
.cast(ptr
.type.strip_typedefs())
762 realtype
= type.unqualified ().strip_typedefs ()
763 reptype
= gdb
.lookup_type (str (realtype
) + '::_Rep').pointer ()
764 header
= ptr
.cast(reptype
) - 1
765 length
= header
.dereference ()['_M_length']
766 if hasattr(ptr
, "lazy_string"):
767 return ptr
.lazy_string (length
= length
)
768 return ptr
.string (length
= length
)
770 def display_hint (self
):
773 class Tr1HashtableIterator(Iterator
):
774 def __init__ (self
, hash):
775 self
.buckets
= hash['_M_buckets']
777 self
.bucket_count
= hash['_M_bucket_count']
778 self
.node_type
= find_type(hash.type, '_Node').pointer()
780 while self
.bucket
!= self
.bucket_count
:
781 self
.node
= self
.buckets
[self
.bucket
]
784 self
.bucket
= self
.bucket
+ 1
792 node
= self
.node
.cast(self
.node_type
)
793 result
= node
.dereference()['_M_v']
794 self
.node
= node
.dereference()['_M_next'];
796 self
.bucket
= self
.bucket
+ 1
797 while self
.bucket
!= self
.bucket_count
:
798 self
.node
= self
.buckets
[self
.bucket
]
801 self
.bucket
= self
.bucket
+ 1
804 class StdHashtableIterator(Iterator
):
805 def __init__(self
, hash):
806 self
.node
= hash['_M_before_begin']['_M_nxt']
807 self
.node_type
= find_type(hash.type, '__node_type').pointer()
815 elt
= self
.node
.cast(self
.node_type
).dereference()
816 self
.node
= elt
['_M_nxt']
817 valptr
= elt
['_M_storage'].address
818 valptr
= valptr
.cast(elt
.type.template_argument(0).pointer())
819 return valptr
.dereference()
821 class Tr1UnorderedSetPrinter
:
822 "Print a tr1::unordered_set"
824 def __init__ (self
, typename
, val
):
825 self
.typename
= strip_versioned_namespace(typename
)
828 def hashtable (self
):
829 if self
.typename
.startswith('std::tr1'):
831 return self
.val
['_M_h']
833 def to_string (self
):
834 count
= self
.hashtable()['_M_element_count']
835 return '%s with %s' % (self
.typename
, num_elements(count
))
838 def format_count (i
):
842 counter
= imap (self
.format_count
, itertools
.count())
843 if self
.typename
.startswith('std::tr1'):
844 return izip (counter
, Tr1HashtableIterator (self
.hashtable()))
845 return izip (counter
, StdHashtableIterator (self
.hashtable()))
847 class Tr1UnorderedMapPrinter
:
848 "Print a tr1::unordered_map"
850 def __init__ (self
, typename
, val
):
851 self
.typename
= strip_versioned_namespace(typename
)
854 def hashtable (self
):
855 if self
.typename
.startswith('std::tr1'):
857 return self
.val
['_M_h']
859 def to_string (self
):
860 count
= self
.hashtable()['_M_element_count']
861 return '%s with %s' % (self
.typename
, num_elements(count
))
870 def format_one (elt
):
871 return (elt
['first'], elt
['second'])
874 def format_count (i
):
878 counter
= imap (self
.format_count
, itertools
.count())
879 # Map over the hash table and flatten the result.
880 if self
.typename
.startswith('std::tr1'):
881 data
= self
.flatten (imap (self
.format_one
, Tr1HashtableIterator (self
.hashtable())))
882 # Zip the two iterators together.
883 return izip (counter
, data
)
884 data
= self
.flatten (imap (self
.format_one
, StdHashtableIterator (self
.hashtable())))
885 # Zip the two iterators together.
886 return izip (counter
, data
)
889 def display_hint (self
):
892 class StdForwardListPrinter
:
893 "Print a std::forward_list"
895 class _iterator(Iterator
):
896 def __init__(self
, nodetype
, head
):
897 self
.nodetype
= nodetype
898 self
.base
= head
['_M_next']
907 elt
= self
.base
.cast(self
.nodetype
).dereference()
908 self
.base
= elt
['_M_next']
910 self
.count
= self
.count
+ 1
911 valptr
= elt
['_M_storage'].address
912 valptr
= valptr
.cast(elt
.type.template_argument(0).pointer())
913 return ('[%d]' % count
, valptr
.dereference())
915 def __init__(self
, typename
, val
):
917 self
.typename
= strip_versioned_namespace(typename
)
920 nodetype
= find_type(self
.val
.type, '_Node')
921 nodetype
= nodetype
.strip_typedefs().pointer()
922 return self
._iterator
(nodetype
, self
.val
['_M_impl']['_M_head'])
925 if self
.val
['_M_impl']['_M_head']['_M_next'] == 0:
926 return 'empty %s' % self
.typename
927 return '%s' % self
.typename
929 class SingleObjContainerPrinter(object):
930 "Base class for printers of containers of single objects"
932 def __init__ (self
, val
, viz
, hint
= None):
933 self
.contained_value
= val
934 self
.visualizer
= viz
937 def _recognize(self
, type):
938 """Return TYPE as a string after applying type printers"""
939 global _use_type_printing
940 if not _use_type_printing
:
942 return gdb
.types
.apply_type_recognizers(gdb
.types
.get_type_recognizers(),
945 class _contained(Iterator
):
946 def __init__ (self
, val
):
957 return ('[contained value]', retval
)
960 if self
.contained_value
is None:
961 return self
._contained
(None)
962 if hasattr (self
.visualizer
, 'children'):
963 return self
.visualizer
.children ()
964 return self
._contained
(self
.contained_value
)
966 def display_hint (self
):
967 # if contained value is a map we want to display in the same way
968 if hasattr (self
.visualizer
, 'children') and hasattr (self
.visualizer
, 'display_hint'):
969 return self
.visualizer
.display_hint ()
972 class StdExpAnyPrinter(SingleObjContainerPrinter
):
973 "Print a std::any or std::experimental::any"
975 def __init__ (self
, typename
, val
):
976 self
.typename
= strip_versioned_namespace(typename
)
977 self
.typename
= re
.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', self
.typename
, 1)
979 self
.contained_type
= None
980 contained_value
= None
982 mgr
= self
.val
['_M_manager']
984 func
= gdb
.block_for_pc(int(mgr
.cast(gdb
.lookup_type('intptr_t'))))
986 raise ValueError("Invalid function pointer in %s" % self
.typename
)
987 rx
= r
"""({0}::_Manager_\w+<.*>)::_S_manage\({0}::_Op, {0} const\*, {0}::_Arg\*\)""".format(typename
)
988 m
= re
.match(rx
, func
.function
.name
)
990 raise ValueError("Unknown manager function in %s" % self
.typename
)
993 # FIXME need to expand 'std::string' so that gdb.lookup_type works
994 if 'std::string' in mgrname
:
995 mgrname
= re
.sub("std::string(?!\w)", str(gdb
.lookup_type('std::string').strip_typedefs()), m
.group(1))
997 mgrtype
= gdb
.lookup_type(mgrname
)
998 self
.contained_type
= mgrtype
.template_argument(0)
1000 if '::_Manager_internal' in mgrname
:
1001 valptr
= self
.val
['_M_storage']['_M_buffer'].address
1002 elif '::_Manager_external' in mgrname
:
1003 valptr
= self
.val
['_M_storage']['_M_ptr']
1005 raise ValueError("Unknown manager function in %s" % self
.typename
)
1006 contained_value
= valptr
.cast(self
.contained_type
.pointer()).dereference()
1007 visualizer
= gdb
.default_visualizer(contained_value
)
1008 super(StdExpAnyPrinter
, self
).__init
__ (contained_value
, visualizer
)
1010 def to_string (self
):
1011 if self
.contained_type
is None:
1012 return '%s [no contained value]' % self
.typename
1013 desc
= "%s containing " % self
.typename
1014 if hasattr (self
.visualizer
, 'children'):
1015 return desc
+ self
.visualizer
.to_string ()
1016 valtype
= self
._recognize
(self
.contained_type
)
1017 return desc
+ strip_versioned_namespace(str(valtype
))
1019 class StdExpOptionalPrinter(SingleObjContainerPrinter
):
1020 "Print a std::optional or std::experimental::optional"
1022 def __init__ (self
, typename
, val
):
1023 valtype
= self
._recognize
(val
.type.template_argument(0))
1024 self
.typename
= strip_versioned_namespace(typename
)
1025 self
.typename
= re
.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r
'std::\1\3<%s>' % valtype
, self
.typename
, 1)
1026 if not self
.typename
.startswith('std::experimental'):
1027 val
= val
['_M_payload']
1029 contained_value
= val
['_M_payload'] if self
.val
['_M_engaged'] else None
1030 visualizer
= gdb
.default_visualizer (val
['_M_payload'])
1031 super (StdExpOptionalPrinter
, self
).__init
__ (contained_value
, visualizer
)
1033 def to_string (self
):
1034 if self
.contained_value
is None:
1035 return "%s [no contained value]" % self
.typename
1036 if hasattr (self
.visualizer
, 'children'):
1037 return "%s containing %s" % (self
.typename
,
1038 self
.visualizer
.to_string())
1039 return self
.typename
1041 class StdVariantPrinter(SingleObjContainerPrinter
):
1042 "Print a std::variant"
1044 def __init__(self
, typename
, val
):
1045 alternatives
= self
._template
_args
(val
)
1046 self
.typename
= strip_versioned_namespace(typename
)
1047 self
.typename
= "%s<%s>" % (self
.typename
, ', '.join([self
._recognize
(alt
) for alt
in alternatives
]))
1048 self
.index
= val
['_M_index']
1049 if self
.index
>= len(alternatives
):
1050 self
.contained_type
= None
1051 contained_value
= None
1054 self
.contained_type
= alternatives
[int(self
.index
)]
1055 addr
= val
['_M_u']['_M_first']['_M_storage'].address
1056 contained_value
= addr
.cast(self
.contained_type
.pointer()).dereference()
1057 visualizer
= gdb
.default_visualizer(contained_value
)
1058 super (StdVariantPrinter
, self
).__init
__(contained_value
, visualizer
, 'array')
1061 def _template_args(val
):
1066 args
.append(val
.type.template_argument(n
))
1071 def to_string(self
):
1072 if self
.contained_value
is None:
1073 return "%s [no contained value]" % self
.typename
1074 if hasattr(self
.visualizer
, 'children'):
1075 return "%s [index %d] containing %s" % (self
.typename
, self
.index
,
1076 self
.visualizer
.to_string())
1077 return "%s [index %d]" % (self
.typename
, self
.index
)
1079 class StdNodeHandlePrinter(SingleObjContainerPrinter
):
1080 "Print a container node handle"
1082 def __init__(self
, typename
, val
):
1083 self
.value_type
= val
.type.template_argument(1)
1084 nodetype
= val
.type.template_argument(2).template_argument(0)
1085 self
.is_rb_tree_node
= is_specialization_of(nodetype
.name
, '_Rb_tree_node')
1086 self
.is_map_node
= val
.type.template_argument(0) != self
.value_type
1087 nodeptr
= val
['_M_ptr']
1089 if self
.is_rb_tree_node
:
1090 contained_value
= get_value_from_Rb_tree_node(nodeptr
.dereference())
1092 contained_value
= get_value_from_aligned_membuf(nodeptr
['_M_storage'],
1094 visualizer
= gdb
.default_visualizer(contained_value
)
1096 contained_value
= None
1098 optalloc
= val
['_M_alloc']
1099 self
.alloc
= optalloc
['_M_payload'] if optalloc
['_M_engaged'] else None
1100 super(StdNodeHandlePrinter
, self
).__init
__(contained_value
, visualizer
,
1103 def to_string(self
):
1104 desc
= 'node handle for '
1105 if not self
.is_rb_tree_node
:
1106 desc
+= 'unordered '
1107 if self
.is_map_node
:
1112 if self
.contained_value
:
1113 desc
+= ' with element'
1114 if hasattr(self
.visualizer
, 'children'):
1115 return "%s = %s" % (desc
, self
.visualizer
.to_string())
1118 return 'empty %s' % desc
1120 class StdExpStringViewPrinter
:
1121 "Print a std::basic_string_view or std::experimental::basic_string_view"
1123 def __init__ (self
, typename
, val
):
1126 def to_string (self
):
1127 ptr
= self
.val
['_M_str']
1128 len = self
.val
['_M_len']
1129 if hasattr (ptr
, "lazy_string"):
1130 return ptr
.lazy_string (length
= len)
1131 return ptr
.string (length
= len)
1133 def display_hint (self
):
1136 class StdExpPathPrinter
:
1137 "Print a std::experimental::filesystem::path"
1139 def __init__ (self
, typename
, val
):
1141 start
= self
.val
['_M_cmpts']['_M_impl']['_M_start']
1142 finish
= self
.val
['_M_cmpts']['_M_impl']['_M_finish']
1143 self
.num_cmpts
= int (finish
- start
)
1145 def _path_type(self
):
1146 t
= str(self
.val
['_M_type'])
1147 if t
[-9:] == '_Root_dir':
1148 return "root-directory"
1149 if t
[-10:] == '_Root_name':
1153 def to_string (self
):
1154 path
= "%s" % self
.val
['_M_pathname']
1155 if self
.num_cmpts
== 0:
1156 t
= self
._path
_type
()
1158 path
= '%s [%s]' % (path
, t
)
1159 return "filesystem::path %s" % path
1161 class _iterator(Iterator
):
1162 def __init__(self
, cmpts
):
1163 self
.item
= cmpts
['_M_impl']['_M_start']
1164 self
.finish
= cmpts
['_M_impl']['_M_finish']
1171 if self
.item
== self
.finish
:
1173 item
= self
.item
.dereference()
1175 self
.count
= self
.count
+ 1
1176 self
.item
= self
.item
+ 1
1177 path
= item
['_M_pathname']
1178 t
= StdExpPathPrinter(item
.type.name
, item
)._path
_type
()
1181 return ('[%s]' % t
, path
)
1184 return self
._iterator
(self
.val
['_M_cmpts'])
1187 # A "regular expression" printer which conforms to the
1188 # "SubPrettyPrinter" protocol from gdb.printing.
1189 class RxPrinter(object):
1190 def __init__(self
, name
, function
):
1191 super(RxPrinter
, self
).__init
__()
1193 self
.function
= function
1196 def invoke(self
, value
):
1197 if not self
.enabled
:
1200 if value
.type.code
== gdb
.TYPE_CODE_REF
:
1201 if hasattr(gdb
.Value
,"referenced_value"):
1202 value
= value
.referenced_value()
1204 return self
.function(self
.name
, value
)
1206 # A pretty-printer that conforms to the "PrettyPrinter" protocol from
1207 # gdb.printing. It can also be used directly as an old-style printer.
1208 class Printer(object):
1209 def __init__(self
, name
):
1210 super(Printer
, self
).__init
__()
1212 self
.subprinters
= []
1215 self
.compiled_rx
= re
.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
1217 def add(self
, name
, function
):
1218 # A small sanity check.
1220 if not self
.compiled_rx
.match(name
):
1221 raise ValueError('libstdc++ programming error: "%s" does not match' % name
)
1222 printer
= RxPrinter(name
, function
)
1223 self
.subprinters
.append(printer
)
1224 self
.lookup
[name
] = printer
1226 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
1227 def add_version(self
, base
, name
, function
):
1228 self
.add(base
+ name
, function
)
1229 if _versioned_namespace
:
1230 vbase
= re
.sub('^(std|__gnu_cxx)::', r
'\g<0>%s' % _versioned_namespace
, base
)
1231 self
.add(vbase
+ name
, function
)
1233 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
1234 def add_container(self
, base
, name
, function
):
1235 self
.add_version(base
, name
, function
)
1236 self
.add_version(base
+ '__cxx1998::', name
, function
)
1239 def get_basic_type(type):
1240 # If it points to a reference, get the reference.
1241 if type.code
== gdb
.TYPE_CODE_REF
:
1242 type = type.target ()
1244 # Get the unqualified type, stripped of typedefs.
1245 type = type.unqualified ().strip_typedefs ()
1249 def __call__(self
, val
):
1250 typename
= self
.get_basic_type(val
.type)
1254 # All the types we match are template types, so we can use a
1256 match
= self
.compiled_rx
.match(typename
)
1260 basename
= match
.group(1)
1262 if val
.type.code
== gdb
.TYPE_CODE_REF
:
1263 if hasattr(gdb
.Value
,"referenced_value"):
1264 val
= val
.referenced_value()
1266 if basename
in self
.lookup
:
1267 return self
.lookup
[basename
].invoke(val
)
1269 # Cannot find a pretty printer. Return None.
1272 libstdcxx_printer
= None
1274 class TemplateTypePrinter(object):
1276 A type printer for class templates.
1278 Recognizes type names that match a regular expression.
1279 Replaces them with a formatted string which can use replacement field
1280 {N} to refer to the \N subgroup of the regex match.
1281 Type printers are recusively applied to the subgroups.
1283 This allows recognizing e.g. "std::vector<(.*), std::allocator<\\1> >"
1284 and replacing it with "std::vector<{1}>", omitting the template argument
1285 that uses the default type.
1288 def __init__(self
, name
, pattern
, subst
):
1290 self
.pattern
= re
.compile(pattern
)
1294 class _recognizer(object):
1295 def __init__(self
, pattern
, subst
):
1296 self
.pattern
= pattern
1298 self
.type_obj
= None
1300 def recognize(self
, type_obj
):
1301 if type_obj
.tag
is None:
1304 m
= self
.pattern
.match(type_obj
.tag
)
1306 subs
= list(m
.groups())
1307 for i
, sub
in enumerate(subs
):
1308 if ('{%d}' % (i
+1)) in self
.subst
:
1309 # apply recognizers to subgroup
1310 rep
= gdb
.types
.apply_type_recognizers(
1311 gdb
.types
.get_type_recognizers(),
1312 gdb
.lookup_type(sub
))
1315 subs
= [None] + subs
1316 return self
.subst
.format(*subs
)
1319 def instantiate(self
):
1320 return self
._recognizer
(self
.pattern
, self
.subst
)
1322 def add_one_template_type_printer(obj
, name
, match
, subst
):
1323 match
= '^std::' + match
+ '$'
1324 printer
= TemplateTypePrinter(name
, match
, 'std::' + subst
)
1325 gdb
.types
.register_type_printer(obj
, printer
)
1326 if _versioned_namespace
:
1327 # Add second type printer for same type in versioned namespace:
1328 match
= match
.replace('std::', 'std::' + _versioned_namespace
)
1329 printer
= TemplateTypePrinter(name
, match
, 'std::' + subst
)
1330 gdb
.types
.register_type_printer(obj
, printer
)
1332 class FilteringTypePrinter(object):
1333 def __init__(self
, match
, name
):
1338 class _recognizer(object):
1339 def __init__(self
, match
, name
):
1342 self
.type_obj
= None
1344 def recognize(self
, type_obj
):
1345 if type_obj
.tag
is None:
1348 if self
.type_obj
is None:
1349 if not self
.match
in type_obj
.tag
:
1350 # Filter didn't match.
1353 self
.type_obj
= gdb
.lookup_type(self
.name
).strip_typedefs()
1356 if self
.type_obj
== type_obj
:
1357 return strip_versioned_namespace(self
.name
)
1360 def instantiate(self
):
1361 return self
._recognizer
(self
.match
, self
.name
)
1363 def add_one_type_printer(obj
, match
, name
):
1364 printer
= FilteringTypePrinter(match
, 'std::' + name
)
1365 gdb
.types
.register_type_printer(obj
, printer
)
1366 if _versioned_namespace
:
1367 printer
= FilteringTypePrinter(match
, 'std::' + _versioned_namespace
+ name
)
1368 gdb
.types
.register_type_printer(obj
, printer
)
1370 def register_type_printers(obj
):
1371 global _use_type_printing
1373 if not _use_type_printing
:
1376 for pfx
in ('', 'w'):
1377 add_one_type_printer(obj
, 'basic_string', pfx
+ 'string')
1378 add_one_type_printer(obj
, 'basic_string_view', pfx
+ 'string_view')
1379 add_one_type_printer(obj
, 'basic_ios', pfx
+ 'ios')
1380 add_one_type_printer(obj
, 'basic_streambuf', pfx
+ 'streambuf')
1381 add_one_type_printer(obj
, 'basic_istream', pfx
+ 'istream')
1382 add_one_type_printer(obj
, 'basic_ostream', pfx
+ 'ostream')
1383 add_one_type_printer(obj
, 'basic_iostream', pfx
+ 'iostream')
1384 add_one_type_printer(obj
, 'basic_stringbuf', pfx
+ 'stringbuf')
1385 add_one_type_printer(obj
, 'basic_istringstream',
1386 pfx
+ 'istringstream')
1387 add_one_type_printer(obj
, 'basic_ostringstream',
1388 pfx
+ 'ostringstream')
1389 add_one_type_printer(obj
, 'basic_stringstream',
1390 pfx
+ 'stringstream')
1391 add_one_type_printer(obj
, 'basic_filebuf', pfx
+ 'filebuf')
1392 add_one_type_printer(obj
, 'basic_ifstream', pfx
+ 'ifstream')
1393 add_one_type_printer(obj
, 'basic_ofstream', pfx
+ 'ofstream')
1394 add_one_type_printer(obj
, 'basic_fstream', pfx
+ 'fstream')
1395 add_one_type_printer(obj
, 'basic_regex', pfx
+ 'regex')
1396 add_one_type_printer(obj
, 'sub_match', pfx
+ 'csub_match')
1397 add_one_type_printer(obj
, 'sub_match', pfx
+ 'ssub_match')
1398 add_one_type_printer(obj
, 'match_results', pfx
+ 'cmatch')
1399 add_one_type_printer(obj
, 'match_results', pfx
+ 'smatch')
1400 add_one_type_printer(obj
, 'regex_iterator', pfx
+ 'cregex_iterator')
1401 add_one_type_printer(obj
, 'regex_iterator', pfx
+ 'sregex_iterator')
1402 add_one_type_printer(obj
, 'regex_token_iterator',
1403 pfx
+ 'cregex_token_iterator')
1404 add_one_type_printer(obj
, 'regex_token_iterator',
1405 pfx
+ 'sregex_token_iterator')
1407 # Note that we can't have a printer for std::wstreampos, because
1408 # it shares the same underlying type as std::streampos.
1409 add_one_type_printer(obj
, 'fpos', 'streampos')
1411 add_one_type_printer(obj
, 'basic_string', 'u16string')
1412 add_one_type_printer(obj
, 'basic_string', 'u32string')
1413 add_one_type_printer(obj
, 'basic_string_view', 'u16string_view')
1414 add_one_type_printer(obj
, 'basic_string_view', 'u32string_view')
1416 for dur
in ('nanoseconds', 'microseconds', 'milliseconds',
1417 'seconds', 'minutes', 'hours'):
1418 add_one_type_printer(obj
, 'duration', dur
)
1420 add_one_type_printer(obj
, 'linear_congruential_engine', 'minstd_rand0')
1421 add_one_type_printer(obj
, 'linear_congruential_engine', 'minstd_rand')
1422 add_one_type_printer(obj
, 'mersenne_twister_engine', 'mt19937')
1423 add_one_type_printer(obj
, 'mersenne_twister_engine', 'mt19937_64')
1424 add_one_type_printer(obj
, 'subtract_with_carry_engine', 'ranlux24_base')
1425 add_one_type_printer(obj
, 'subtract_with_carry_engine', 'ranlux48_base')
1426 add_one_type_printer(obj
, 'discard_block_engine', 'ranlux24')
1427 add_one_type_printer(obj
, 'discard_block_engine', 'ranlux48')
1428 add_one_type_printer(obj
, 'shuffle_order_engine', 'knuth_b')
1430 # Do not show defaulted template arguments in class templates
1431 add_one_template_type_printer(obj
, 'unique_ptr<T>',
1432 'unique_ptr<(.*), std::default_delete<\\1 ?> >',
1435 add_one_template_type_printer(obj
, 'basic_string<T>',
1436 'basic_string<((un)?signed char), std::char_traits<\\1 ?>, std::allocator<\\1 ?> >',
1437 'basic_string<{1}>')
1439 add_one_template_type_printer(obj
, 'deque<T>',
1440 'deque<(.*), std::allocator<\\1 ?> >',
1442 add_one_template_type_printer(obj
, 'forward_list<T>',
1443 'forward_list<(.*), std::allocator<\\1 ?> >',
1444 'forward_list<{1}>')
1445 add_one_template_type_printer(obj
, 'list<T>',
1446 'list<(.*), std::allocator<\\1 ?> >',
1448 add_one_template_type_printer(obj
, 'vector<T>',
1449 'vector<(.*), std::allocator<\\1 ?> >',
1451 add_one_template_type_printer(obj
, 'map<Key, T>',
1452 'map<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
1454 add_one_template_type_printer(obj
, 'multimap<Key, T>',
1455 'multimap<(.*), (.*), std::less<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
1456 'multimap<{1}, {2}>')
1457 add_one_template_type_printer(obj
, 'set<T>',
1458 'set<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
1460 add_one_template_type_printer(obj
, 'multiset<T>',
1461 'multiset<(.*), std::less<\\1 ?>, std::allocator<\\1 ?> >',
1463 add_one_template_type_printer(obj
, 'unordered_map<Key, T>',
1464 'unordered_map<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
1465 'unordered_map<{1}, {2}>')
1466 add_one_template_type_printer(obj
, 'unordered_multimap<Key, T>',
1467 'unordered_multimap<(.*), (.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<std::pair<\\1 const, \\2 ?> > >',
1468 'unordered_multimap<{1}, {2}>')
1469 add_one_template_type_printer(obj
, 'unordered_set<T>',
1470 'unordered_set<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
1471 'unordered_set<{1}>')
1472 add_one_template_type_printer(obj
, 'unordered_multiset<T>',
1473 'unordered_multiset<(.*), std::hash<\\1 ?>, std::equal_to<\\1 ?>, std::allocator<\\1 ?> >',
1474 'unordered_multiset<{1}>')
1476 # strip the "fundamentals_v1" inline namespace from these types
1477 add_one_template_type_printer(obj
, 'any<T>',
1478 'experimental::fundamentals_v\d::any<(.*)>',
1479 'experimental::any<\\1>')
1480 add_one_template_type_printer(obj
, 'optional<T>',
1481 'experimental::fundamentals_v\d::optional<(.*)>',
1482 'experimental::optional<\\1>')
1483 add_one_template_type_printer(obj
, 'basic_string_view<C>',
1484 'experimental::fundamentals_v\d::basic_string_view<(.*), std::char_traits<\\1> >',
1485 'experimental::basic_string_view<\\1>')
1487 def register_libstdcxx_printers (obj
):
1488 "Register libstdc++ pretty-printers with objfile Obj."
1491 global libstdcxx_printer
1494 gdb
.printing
.register_pretty_printer(obj
, libstdcxx_printer
)
1498 obj
.pretty_printers
.append(libstdcxx_printer
)
1500 register_type_printers(obj
)
1502 def build_libstdcxx_dictionary ():
1503 global libstdcxx_printer
1505 libstdcxx_printer
= Printer("libstdc++-v6")
1507 # libstdc++ objects requiring pretty-printing.
1509 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
1510 libstdcxx_printer
.add_version('std::', 'basic_string', StdStringPrinter
)
1511 libstdcxx_printer
.add_version('std::__cxx11::', 'basic_string', StdStringPrinter
)
1512 libstdcxx_printer
.add_container('std::', 'bitset', StdBitsetPrinter
)
1513 libstdcxx_printer
.add_container('std::', 'deque', StdDequePrinter
)
1514 libstdcxx_printer
.add_container('std::', 'list', StdListPrinter
)
1515 libstdcxx_printer
.add_container('std::__cxx11::', 'list', StdListPrinter
)
1516 libstdcxx_printer
.add_container('std::', 'map', StdMapPrinter
)
1517 libstdcxx_printer
.add_container('std::', 'multimap', StdMapPrinter
)
1518 libstdcxx_printer
.add_container('std::', 'multiset', StdSetPrinter
)
1519 libstdcxx_printer
.add_version('std::', 'priority_queue',
1520 StdStackOrQueuePrinter
)
1521 libstdcxx_printer
.add_version('std::', 'queue', StdStackOrQueuePrinter
)
1522 libstdcxx_printer
.add_version('std::', 'tuple', StdTuplePrinter
)
1523 libstdcxx_printer
.add_container('std::', 'set', StdSetPrinter
)
1524 libstdcxx_printer
.add_version('std::', 'stack', StdStackOrQueuePrinter
)
1525 libstdcxx_printer
.add_version('std::', 'unique_ptr', UniquePointerPrinter
)
1526 libstdcxx_printer
.add_container('std::', 'vector', StdVectorPrinter
)
1529 # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
1530 libstdcxx_printer
.add('std::__debug::bitset', StdBitsetPrinter
)
1531 libstdcxx_printer
.add('std::__debug::deque', StdDequePrinter
)
1532 libstdcxx_printer
.add('std::__debug::list', StdListPrinter
)
1533 libstdcxx_printer
.add('std::__debug::map', StdMapPrinter
)
1534 libstdcxx_printer
.add('std::__debug::multimap', StdMapPrinter
)
1535 libstdcxx_printer
.add('std::__debug::multiset', StdSetPrinter
)
1536 libstdcxx_printer
.add('std::__debug::priority_queue',
1537 StdStackOrQueuePrinter
)
1538 libstdcxx_printer
.add('std::__debug::queue', StdStackOrQueuePrinter
)
1539 libstdcxx_printer
.add('std::__debug::set', StdSetPrinter
)
1540 libstdcxx_printer
.add('std::__debug::stack', StdStackOrQueuePrinter
)
1541 libstdcxx_printer
.add('std::__debug::unique_ptr', UniquePointerPrinter
)
1542 libstdcxx_printer
.add('std::__debug::vector', StdVectorPrinter
)
1544 # These are the TR1 and C++11 printers.
1545 # For array - the default GDB pretty-printer seems reasonable.
1546 libstdcxx_printer
.add_version('std::', 'shared_ptr', SharedPointerPrinter
)
1547 libstdcxx_printer
.add_version('std::', 'weak_ptr', SharedPointerPrinter
)
1548 libstdcxx_printer
.add_container('std::', 'unordered_map',
1549 Tr1UnorderedMapPrinter
)
1550 libstdcxx_printer
.add_container('std::', 'unordered_set',
1551 Tr1UnorderedSetPrinter
)
1552 libstdcxx_printer
.add_container('std::', 'unordered_multimap',
1553 Tr1UnorderedMapPrinter
)
1554 libstdcxx_printer
.add_container('std::', 'unordered_multiset',
1555 Tr1UnorderedSetPrinter
)
1556 libstdcxx_printer
.add_container('std::', 'forward_list',
1557 StdForwardListPrinter
)
1559 libstdcxx_printer
.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter
)
1560 libstdcxx_printer
.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter
)
1561 libstdcxx_printer
.add_version('std::tr1::', 'unordered_map',
1562 Tr1UnorderedMapPrinter
)
1563 libstdcxx_printer
.add_version('std::tr1::', 'unordered_set',
1564 Tr1UnorderedSetPrinter
)
1565 libstdcxx_printer
.add_version('std::tr1::', 'unordered_multimap',
1566 Tr1UnorderedMapPrinter
)
1567 libstdcxx_printer
.add_version('std::tr1::', 'unordered_multiset',
1568 Tr1UnorderedSetPrinter
)
1570 # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases.
1571 # The tr1 namespace containers do not have any debug equivalents,
1572 # so do not register printers for them.
1573 libstdcxx_printer
.add('std::__debug::unordered_map',
1574 Tr1UnorderedMapPrinter
)
1575 libstdcxx_printer
.add('std::__debug::unordered_set',
1576 Tr1UnorderedSetPrinter
)
1577 libstdcxx_printer
.add('std::__debug::unordered_multimap',
1578 Tr1UnorderedMapPrinter
)
1579 libstdcxx_printer
.add('std::__debug::unordered_multiset',
1580 Tr1UnorderedSetPrinter
)
1581 libstdcxx_printer
.add('std::__debug::forward_list',
1582 StdForwardListPrinter
)
1584 # Library Fundamentals TS components
1585 libstdcxx_printer
.add_version('std::experimental::fundamentals_v1::',
1586 'any', StdExpAnyPrinter
)
1587 libstdcxx_printer
.add_version('std::experimental::fundamentals_v1::',
1588 'optional', StdExpOptionalPrinter
)
1589 libstdcxx_printer
.add_version('std::experimental::fundamentals_v1::',
1590 'basic_string_view', StdExpStringViewPrinter
)
1591 # Filesystem TS components
1592 libstdcxx_printer
.add_version('std::experimental::filesystem::v1::',
1593 'path', StdExpPathPrinter
)
1594 libstdcxx_printer
.add_version('std::experimental::filesystem::v1::__cxx11::',
1595 'path', StdExpPathPrinter
)
1596 libstdcxx_printer
.add_version('std::filesystem::',
1597 'path', StdExpPathPrinter
)
1598 libstdcxx_printer
.add_version('std::filesystem::__cxx11::',
1599 'path', StdExpPathPrinter
)
1602 libstdcxx_printer
.add_version('std::',
1603 'any', StdExpAnyPrinter
)
1604 libstdcxx_printer
.add_version('std::',
1605 'optional', StdExpOptionalPrinter
)
1606 libstdcxx_printer
.add_version('std::',
1607 'basic_string_view', StdExpStringViewPrinter
)
1608 libstdcxx_printer
.add_version('std::',
1609 'variant', StdVariantPrinter
)
1610 libstdcxx_printer
.add_version('std::',
1611 '_Node_handle', StdNodeHandlePrinter
)
1614 libstdcxx_printer
.add_version('__gnu_cxx::', 'slist', StdSlistPrinter
)
1617 # These shouldn't be necessary, if GDB "print *i" worked.
1618 # But it often doesn't, so here they are.
1619 libstdcxx_printer
.add_container('std::', '_List_iterator',
1620 StdListIteratorPrinter
)
1621 libstdcxx_printer
.add_container('std::', '_List_const_iterator',
1622 StdListIteratorPrinter
)
1623 libstdcxx_printer
.add_version('std::', '_Rb_tree_iterator',
1624 StdRbtreeIteratorPrinter
)
1625 libstdcxx_printer
.add_version('std::', '_Rb_tree_const_iterator',
1626 StdRbtreeIteratorPrinter
)
1627 libstdcxx_printer
.add_container('std::', '_Deque_iterator',
1628 StdDequeIteratorPrinter
)
1629 libstdcxx_printer
.add_container('std::', '_Deque_const_iterator',
1630 StdDequeIteratorPrinter
)
1631 libstdcxx_printer
.add_version('__gnu_cxx::', '__normal_iterator',
1632 StdVectorIteratorPrinter
)
1633 libstdcxx_printer
.add_version('__gnu_cxx::', '_Slist_iterator',
1634 StdSlistIteratorPrinter
)
1636 # Debug (compiled with -D_GLIBCXX_DEBUG) printer
1637 # registrations. The Rb_tree debug iterator when unwrapped
1638 # from the encapsulating __gnu_debug::_Safe_iterator does not
1639 # have the __norm namespace. Just use the existing printer
1640 # registration for that.
1641 libstdcxx_printer
.add('__gnu_debug::_Safe_iterator',
1642 StdDebugIteratorPrinter
)
1643 libstdcxx_printer
.add('std::__norm::_List_iterator',
1644 StdListIteratorPrinter
)
1645 libstdcxx_printer
.add('std::__norm::_List_const_iterator',
1646 StdListIteratorPrinter
)
1647 libstdcxx_printer
.add('std::__norm::_Deque_const_iterator',
1648 StdDequeIteratorPrinter
)
1649 libstdcxx_printer
.add('std::__norm::_Deque_iterator',
1650 StdDequeIteratorPrinter
)
1652 build_libstdcxx_dictionary ()