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