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