xref: /openbsd-src/gnu/llvm/libcxx/utils/gdb/libcxx/printers.py (revision d0fc3bb68efd6c434b4053cd7adb29023cbec341)
1#===----------------------------------------------------------------------===##
2#
3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4# See https://llvm.org/LICENSE.txt for license information.
5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6#
7#===----------------------------------------------------------------------===##
8"""GDB pretty-printers for libc++.
9
10These should work for objects compiled when _LIBCPP_ABI_UNSTABLE is defined
11and when it is undefined.
12"""
13
14from __future__ import print_function
15
16import re
17import gdb
18
19# One under-documented feature of the gdb pretty-printer API
20# is that clients can call any other member of the API
21# before they call to_string.
22# Therefore all self.FIELDs must be set in the pretty-printer's
23# __init__ function.
24
25_void_pointer_type = gdb.lookup_type("void").pointer()
26
27
28_long_int_type = gdb.lookup_type("unsigned long long")
29
30_libcpp_big_endian = False
31
32def addr_as_long(addr):
33    return int(addr.cast(_long_int_type))
34
35
36# The size of a pointer in bytes.
37_pointer_size = _void_pointer_type.sizeof
38
39
40def _remove_cxx_namespace(typename):
41    """Removed libc++ specific namespace from the type.
42
43    Arguments:
44      typename(string): A type, such as std::__u::something.
45
46    Returns:
47      A string without the libc++ specific part, such as std::something.
48    """
49
50    return re.sub("std::__.*?::", "std::", typename)
51
52
53def _remove_generics(typename):
54    """Remove generics part of the type. Assumes typename is not empty.
55
56    Arguments:
57      typename(string): A type such as std::my_collection<element>.
58
59    Returns:
60      The prefix up to the generic part, such as std::my_collection.
61    """
62
63    match = re.match("^([^<]+)", typename)
64    return match.group(1)
65
66
67# Some common substitutions on the types to reduce visual clutter (A user who
68# wants to see the actual details can always use print/r).
69_common_substitutions = [
70    ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
71     "std::string"),
72    ("std::basic_string_view<char, std::char_traits<char> >",
73     "std::string_view"),
74]
75
76
77def _prettify_typename(gdb_type):
78    """Returns a pretty name for the type, or None if no name can be found.
79
80    Arguments:
81      gdb_type(gdb.Type): A type object.
82
83    Returns:
84      A string, without type_defs, libc++ namespaces, and common substitutions
85      applied.
86    """
87
88    type_without_typedefs = gdb_type.strip_typedefs()
89    typename = type_without_typedefs.name or type_without_typedefs.tag or \
90        str(type_without_typedefs)
91    result = _remove_cxx_namespace(typename)
92    for find_str, subst_str in _common_substitutions:
93        result = re.sub(find_str, subst_str, result)
94    return result
95
96
97def _typename_for_nth_generic_argument(gdb_type, n):
98    """Returns a pretty string for the nth argument of the given type.
99
100    Arguments:
101      gdb_type(gdb.Type): A type object, such as the one for std::map<int, int>
102      n: The (zero indexed) index of the argument to return.
103
104    Returns:
105      A string for the nth argument, such a "std::string"
106    """
107    element_type = gdb_type.template_argument(n)
108    return _prettify_typename(element_type)
109
110
111def _typename_with_n_generic_arguments(gdb_type, n):
112    """Return a string for the type with the first n (1, ...) generic args."""
113
114    base_type = _remove_generics(_prettify_typename(gdb_type))
115    arg_list = [base_type]
116    template = "%s<"
117    for i in range(n):
118        arg_list.append(_typename_for_nth_generic_argument(gdb_type, i))
119        template += "%s, "
120    result = (template[:-2] + ">") % tuple(arg_list)
121    return result
122
123
124def _typename_with_first_generic_argument(gdb_type):
125    return _typename_with_n_generic_arguments(gdb_type, 1)
126
127
128class StdTuplePrinter(object):
129    """Print a std::tuple."""
130
131    class _Children(object):
132        """Class to iterate over the tuple's children."""
133
134        def __init__(self, val):
135            self.val = val
136            self.child_iter = iter(self.val["__base_"].type.fields())
137            self.count = 0
138
139        def __iter__(self):
140            return self
141
142        def __next__(self):
143            # child_iter raises StopIteration when appropriate.
144            field_name = self.child_iter.next()
145            child = self.val["__base_"][field_name]["__value_"]
146            self.count += 1
147            return ("[%d]" % self.count, child)
148
149        # TODO Delete when we drop Python 2.
150        def next(self):
151            return self.__next__()
152
153    def __init__(self, val):
154        self.val = val
155
156    def to_string(self):
157        typename = _remove_generics(_prettify_typename(self.val.type))
158        if not self.val.type.fields():
159            return "empty %s" % typename
160        return "%s containing" % typename
161
162    def children(self):
163        if not self.val.type.fields():
164            return iter(())
165        return self._Children(self.val)
166
167
168def _get_base_subobject(child_class_value, index=0):
169    """Returns the object's value in the form of the parent class at index.
170
171    This function effectively casts the child_class_value to the base_class's
172    type, but the type-to-cast to is stored in the field at index, and once
173    we know the field, we can just return the data.
174
175    Args:
176      child_class_value: the value to cast
177      index: the parent class index
178
179    Raises:
180      Exception: field at index was not a base-class field.
181    """
182
183    field = child_class_value.type.fields()[index]
184    if not field.is_base_class:
185        raise Exception("Not a base-class field.")
186    return child_class_value[field]
187
188
189def _value_of_pair_first(value):
190    """Convenience for _get_base_subobject, for the common case."""
191    return _get_base_subobject(value, 0)["__value_"]
192
193
194class StdStringPrinter(object):
195    """Print a std::string."""
196
197    def _get_short_size(self, short_field, short_size):
198        """Short size depends on both endianness and a compile-time define."""
199
200        # If the padding field is present after all this indirection, then string
201        # was compiled with _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT defined.
202        field = short_field.type.fields()[1].type.fields()[0]
203        libcpp_abi_alternate_string_layout = field.name and "__padding" in field.name
204
205        # This logical structure closely follows the original code (which is clearer
206        # in C++).  Keep them parallel to make them easier to compare.
207        if libcpp_abi_alternate_string_layout:
208            if _libcpp_big_endian:
209                return short_size >> 1
210            else:
211                return short_size
212        elif _libcpp_big_endian:
213            return short_size
214        else:
215            return short_size >> 1
216
217    def __init__(self, val):
218        self.val = val
219
220    def to_string(self):
221        """Build a python string from the data whether stored inline or separately."""
222
223        value_field = _value_of_pair_first(self.val["__r_"])
224        short_field = value_field["__s"]
225        short_size = short_field["__size_"]
226        if short_size == 0:
227            return ""
228        short_mask = self.val["__short_mask"]
229        # Counter intuitive to compare the size and short_mask to see if the string
230        # is long, but that's the way the implementation does it. Note that
231        # __is_long() doesn't use get_short_size in C++.
232        is_long = short_size & short_mask
233        if is_long:
234            long_field = value_field["__l"]
235            data = long_field["__data_"]
236            size = long_field["__size_"]
237        else:
238            data = short_field["__data_"]
239            size = self._get_short_size(short_field, short_size)
240        if hasattr(data, "lazy_string"):
241            return data.lazy_string(length=size)
242        return data.string(length=size)
243
244    def display_hint(self):
245        return "string"
246
247
248class StdStringViewPrinter(object):
249    """Print a std::string_view."""
250
251    def __init__(self, val):
252      self.val = val
253
254    def to_string(self):  # pylint: disable=g-bad-name
255      """GDB calls this to compute the pretty-printed form."""
256
257      ptr = self.val["__data"]
258      length = self.val["__size"]
259      print_length = length
260      # We print more than just a simple string (i.e. we also print
261      # "of length %d").  Thus we can't use the "string" display_hint,
262      # and thus we have to handle "print elements" ourselves.
263      # For reference sake, gdb ensures limit == None or limit > 0.
264      limit = gdb.parameter("print elements")
265      if limit is not None:
266        print_length = min(print_length, limit)
267      # FIXME: Passing ISO-8859-1 here isn't always correct.
268      string = ptr.string("ISO-8859-1", "ignore", print_length)
269      if length > print_length:
270        string += "..."
271      return "std::string_view of length %d: \"%s\"" % (length, string)
272
273
274class StdUniquePtrPrinter(object):
275    """Print a std::unique_ptr."""
276
277    def __init__(self, val):
278        self.val = val
279        self.addr = _value_of_pair_first(self.val["__ptr_"])
280        self.pointee_type = self.val.type.template_argument(0)
281
282    def to_string(self):
283        typename = _remove_generics(_prettify_typename(self.val.type))
284        if not self.addr:
285            return "%s is nullptr" % typename
286        return ("%s<%s> containing" %
287                (typename,
288                 _remove_generics(_prettify_typename(self.pointee_type))))
289
290    def __iter__(self):
291        if self.addr:
292            yield "__ptr_", self.addr.cast(self.pointee_type.pointer())
293
294    def children(self):
295        return self
296
297
298class StdSharedPointerPrinter(object):
299    """Print a std::shared_ptr."""
300
301    def __init__(self, val):
302        self.val = val
303        self.addr = self.val["__ptr_"]
304
305    def to_string(self):
306        """Returns self as a string."""
307        typename = _remove_generics(_prettify_typename(self.val.type))
308        pointee_type = _remove_generics(
309            _prettify_typename(self.val.type.template_argument(0)))
310        if not self.addr:
311            return "%s is nullptr" % typename
312        refcount = self.val["__cntrl_"]
313        if refcount != 0:
314            usecount = refcount["__shared_owners_"] + 1
315            weakcount = refcount["__shared_weak_owners_"]
316            if usecount == 0:
317                state = "expired, weak %d" % weakcount
318            else:
319                state = "count %d, weak %d" % (usecount, weakcount)
320        return "%s<%s> %s containing" % (typename, pointee_type, state)
321
322    def __iter__(self):
323        if self.addr:
324            yield "__ptr_", self.addr
325
326    def children(self):
327        return self
328
329
330class StdVectorPrinter(object):
331    """Print a std::vector."""
332
333    class _VectorBoolIterator(object):
334        """Class to iterate over the bool vector's children."""
335
336        def __init__(self, begin, size, bits_per_word):
337            self.item = begin
338            self.size = size
339            self.bits_per_word = bits_per_word
340            self.count = 0
341            self.offset = 0
342
343        def __iter__(self):
344            return self
345
346        def __next__(self):
347            """Retrieve the next element."""
348
349            self.count += 1
350            if self.count > self.size:
351                raise StopIteration
352            entry = self.item.dereference()
353            if entry & (1 << self.offset):
354                outbit = 1
355            else:
356                outbit = 0
357            self.offset += 1
358            if self.offset >= self.bits_per_word:
359                self.item += 1
360                self.offset = 0
361            return ("[%d]" % self.count, outbit)
362
363        # TODO Delete when we drop Python 2.
364        def next(self):
365            return self.__next__()
366
367    class _VectorIterator(object):
368        """Class to iterate over the non-bool vector's children."""
369
370        def __init__(self, begin, end):
371            self.item = begin
372            self.end = end
373            self.count = 0
374
375        def __iter__(self):
376            return self
377
378        def __next__(self):
379            self.count += 1
380            if self.item == self.end:
381                raise StopIteration
382            entry = self.item.dereference()
383            self.item += 1
384            return ("[%d]" % self.count, entry)
385
386        # TODO Delete when we drop Python 2.
387        def next(self):
388            return self.__next__()
389
390    def __init__(self, val):
391        """Set val, length, capacity, and iterator for bool and normal vectors."""
392        self.val = val
393        self.typename = _remove_generics(_prettify_typename(val.type))
394        begin = self.val["__begin_"]
395        if self.val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL:
396            self.typename += "<bool>"
397            self.length = self.val["__size_"]
398            bits_per_word = self.val["__bits_per_word"]
399            self.capacity = _value_of_pair_first(
400                self.val["__cap_alloc_"]) * bits_per_word
401            self.iterator = self._VectorBoolIterator(
402                begin, self.length, bits_per_word)
403        else:
404            end = self.val["__end_"]
405            self.length = end - begin
406            self.capacity = _get_base_subobject(
407                self.val["__end_cap_"])["__value_"] - begin
408            self.iterator = self._VectorIterator(begin, end)
409
410    def to_string(self):
411        return ("%s of length %d, capacity %d" %
412                (self.typename, self.length, self.capacity))
413
414    def children(self):
415        return self.iterator
416
417    def display_hint(self):
418        return "array"
419
420
421class StdBitsetPrinter(object):
422    """Print a std::bitset."""
423
424    def __init__(self, val):
425        self.val = val
426        self.n_words = int(self.val["__n_words"])
427        self.bits_per_word = int(self.val["__bits_per_word"])
428        if self.n_words == 1:
429            self.values = [int(self.val["__first_"])]
430        else:
431            self.values = [int(self.val["__first_"][index])
432                           for index in range(self.n_words)]
433
434    def to_string(self):
435        typename = _prettify_typename(self.val.type)
436        return "%s" % typename
437
438    def _byte_it(self, value):
439        index = -1
440        while value:
441            index += 1
442            will_yield = value % 2
443            value /= 2
444            if will_yield:
445                yield index
446
447    def _list_it(self):
448        for word_index in range(self.n_words):
449            current = self.values[word_index]
450            if current:
451                for n in self._byte_it(current):
452                    yield ("[%d]" % (word_index * self.bits_per_word + n), 1)
453
454    def __iter__(self):
455        return self._list_it()
456
457    def children(self):
458        return self
459
460
461class StdDequePrinter(object):
462    """Print a std::deque."""
463
464    def __init__(self, val):
465        self.val = val
466        self.size = int(_value_of_pair_first(val["__size_"]))
467        self.start_ptr = self.val["__map_"]["__begin_"]
468        self.first_block_start_index = int(self.val["__start_"])
469        self.node_type = self.start_ptr.type
470        self.block_size = self._calculate_block_size(
471            val.type.template_argument(0))
472
473    def _calculate_block_size(self, element_type):
474        """Calculates the number of elements in a full block."""
475        size = element_type.sizeof
476        # Copied from struct __deque_block_size implementation of libcxx.
477        return 4096 / size if size < 256 else 16
478
479    def _bucket_it(self, start_addr, start_index, end_index):
480        for i in range(start_index, end_index):
481            yield i, (start_addr.dereference() + i).dereference()
482
483    def _list_it(self):
484        """Primary iteration worker."""
485        num_emitted = 0
486        current_addr = self.start_ptr
487        start_index = self.first_block_start_index
488        while num_emitted < self.size:
489            end_index = min(start_index + self.size -
490                            num_emitted, self.block_size)
491            for _, elem in self._bucket_it(current_addr, start_index, end_index):
492                yield "", elem
493            num_emitted += end_index - start_index
494            current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size) \
495                              .cast(self.node_type)
496            start_index = 0
497
498    def to_string(self):
499        typename = _remove_generics(_prettify_typename(self.val.type))
500        if self.size:
501            return "%s with %d elements" % (typename, self.size)
502        return "%s is empty" % typename
503
504    def __iter__(self):
505        return self._list_it()
506
507    def children(self):
508        return self
509
510    def display_hint(self):
511        return "array"
512
513
514class StdListPrinter(object):
515    """Print a std::list."""
516
517    def __init__(self, val):
518        self.val = val
519        size_alloc_field = self.val["__size_alloc_"]
520        self.size = int(_value_of_pair_first(size_alloc_field))
521        dummy_node = self.val["__end_"]
522        self.nodetype = gdb.lookup_type(
523            re.sub("__list_node_base", "__list_node",
524                   str(dummy_node.type.strip_typedefs()))).pointer()
525        self.first_node = dummy_node["__next_"]
526
527    def to_string(self):
528        typename = _remove_generics(_prettify_typename(self.val.type))
529        if self.size:
530            return "%s with %d elements" % (typename, self.size)
531        return "%s is empty" % typename
532
533    def _list_iter(self):
534        current_node = self.first_node
535        for _ in range(self.size):
536            yield "", current_node.cast(self.nodetype).dereference()["__value_"]
537            current_node = current_node.dereference()["__next_"]
538
539    def __iter__(self):
540        return self._list_iter()
541
542    def children(self):
543        return self if self.nodetype else iter(())
544
545    def display_hint(self):
546        return "array"
547
548
549class StdQueueOrStackPrinter(object):
550    """Print a std::queue or std::stack."""
551
552    def __init__(self, val):
553        self.val = val
554        self.underlying = val["c"]
555
556    def to_string(self):
557        typename = _remove_generics(_prettify_typename(self.val.type))
558        return "%s wrapping" % typename
559
560    def children(self):
561        return iter([("", self.underlying)])
562
563    def display_hint(self):
564        return "array"
565
566
567class StdPriorityQueuePrinter(object):
568    """Print a std::priority_queue."""
569
570    def __init__(self, val):
571        self.val = val
572        self.underlying = val["c"]
573
574    def to_string(self):
575        # TODO(tamur): It would be nice to print the top element. The technical
576        # difficulty is that, the implementation refers to the underlying
577        # container, which is a generic class. libstdcxx pretty printers do not
578        # print the top element.
579        typename = _remove_generics(_prettify_typename(self.val.type))
580        return "%s wrapping" % typename
581
582    def children(self):
583        return iter([("", self.underlying)])
584
585    def display_hint(self):
586        return "array"
587
588
589class RBTreeUtils(object):
590    """Utility class for std::(multi)map, and std::(multi)set and iterators."""
591
592    def __init__(self, cast_type, root):
593        self.cast_type = cast_type
594        self.root = root
595
596    def left_child(self, node):
597        result = node.cast(self.cast_type).dereference()["__left_"]
598        return result
599
600    def right_child(self, node):
601        result = node.cast(self.cast_type).dereference()["__right_"]
602        return result
603
604    def parent(self, node):
605        """Return the parent of node, if it exists."""
606        # If this is the root, then from the algorithm's point of view, it has no
607        # parent.
608        if node == self.root:
609            return None
610
611        # We don't have enough information to tell if this is the end_node (which
612        # doesn't have a __parent_ field), or the root (which doesn't have a parent
613        # from the algorithm's point of view), so cast_type may not be correct for
614        # this particular node. Use heuristics.
615
616        # The end_node's left child is the root. Note that when printing interators
617        # in isolation, the root is unknown.
618        if self.left_child(node) == self.root:
619            return None
620
621        parent = node.cast(self.cast_type).dereference()["__parent_"]
622        # If the value at the offset of __parent_ doesn't look like a valid pointer,
623        # then assume that node is the end_node (and therefore has no parent).
624        # End_node type has a pointer embedded, so should have pointer alignment.
625        if addr_as_long(parent) % _void_pointer_type.alignof:
626            return None
627        # This is ugly, but the only other option is to dereference an invalid
628        # pointer.  0x8000 is fairly arbitrary, but has had good results in
629        # practice.  If there was a way to tell if a pointer is invalid without
630        # actually dereferencing it and spewing error messages, that would be ideal.
631        if parent < 0x8000:
632            return None
633        return parent
634
635    def is_left_child(self, node):
636        parent = self.parent(node)
637        return parent is not None and self.left_child(parent) == node
638
639    def is_right_child(self, node):
640        parent = self.parent(node)
641        return parent is not None and self.right_child(parent) == node
642
643
644class AbstractRBTreePrinter(object):
645    """Abstract super class for std::(multi)map, and std::(multi)set."""
646
647    def __init__(self, val):
648        self.val = val
649        tree = self.val["__tree_"]
650        self.size = int(_value_of_pair_first(tree["__pair3_"]))
651        dummy_root = tree["__pair1_"]
652        root = _value_of_pair_first(dummy_root)["__left_"]
653        cast_type = self._init_cast_type(val.type)
654        self.util = RBTreeUtils(cast_type, root)
655
656    def _get_key_value(self, node):
657        """Subclasses should override to return a list of values to yield."""
658        raise NotImplementedError
659
660    def _traverse(self):
661        """Traverses the binary search tree in order."""
662        current = self.util.root
663        skip_left_child = False
664        while True:
665            if not skip_left_child and self.util.left_child(current):
666                current = self.util.left_child(current)
667                continue
668            skip_left_child = False
669            for key_value in self._get_key_value(current):
670                yield "", key_value
671            right_child = self.util.right_child(current)
672            if right_child:
673                current = right_child
674                continue
675            while self.util.is_right_child(current):
676                current = self.util.parent(current)
677            if self.util.is_left_child(current):
678                current = self.util.parent(current)
679                skip_left_child = True
680                continue
681            break
682
683    def __iter__(self):
684        return self._traverse()
685
686    def children(self):
687        return self if self.util.cast_type and self.size > 0 else iter(())
688
689    def to_string(self):
690        typename = _remove_generics(_prettify_typename(self.val.type))
691        if self.size:
692            return "%s with %d elements" % (typename, self.size)
693        return "%s is empty" % typename
694
695
696class StdMapPrinter(AbstractRBTreePrinter):
697    """Print a std::map or std::multimap."""
698
699    def _init_cast_type(self, val_type):
700        map_it_type = gdb.lookup_type(
701            str(val_type.strip_typedefs()) + "::iterator").strip_typedefs()
702        tree_it_type = map_it_type.template_argument(0)
703        node_ptr_type = tree_it_type.template_argument(1)
704        return node_ptr_type
705
706    def display_hint(self):
707        return "map"
708
709    def _get_key_value(self, node):
710        key_value = node.cast(self.util.cast_type).dereference()[
711            "__value_"]["__cc"]
712        return [key_value["first"], key_value["second"]]
713
714
715class StdSetPrinter(AbstractRBTreePrinter):
716    """Print a std::set."""
717
718    def _init_cast_type(self, val_type):
719        set_it_type = gdb.lookup_type(
720            str(val_type.strip_typedefs()) + "::iterator").strip_typedefs()
721        node_ptr_type = set_it_type.template_argument(1)
722        return node_ptr_type
723
724    def display_hint(self):
725        return "array"
726
727    def _get_key_value(self, node):
728        key_value = node.cast(self.util.cast_type).dereference()["__value_"]
729        return [key_value]
730
731
732class AbstractRBTreeIteratorPrinter(object):
733    """Abstract super class for std::(multi)map, and std::(multi)set iterator."""
734
735    def _initialize(self, val, typename):
736        self.typename = typename
737        self.val = val
738        self.addr = self.val["__ptr_"]
739        cast_type = self.val.type.template_argument(1)
740        self.util = RBTreeUtils(cast_type, None)
741        if self.addr:
742            self.node = self.addr.cast(cast_type).dereference()
743
744    def _is_valid_node(self):
745        if not self.util.parent(self.addr):
746            return False
747        return self.util.is_left_child(self.addr) or \
748            self.util.is_right_child(self.addr)
749
750    def to_string(self):
751        if not self.addr:
752            return "%s is nullptr" % self.typename
753        return "%s " % self.typename
754
755    def _get_node_value(self, node):
756        raise NotImplementedError
757
758    def __iter__(self):
759        addr_str = "[%s]" % str(self.addr)
760        if not self._is_valid_node():
761            yield addr_str, " end()"
762        else:
763            yield addr_str, self._get_node_value(self.node)
764
765    def children(self):
766        return self if self.addr else iter(())
767
768
769class MapIteratorPrinter(AbstractRBTreeIteratorPrinter):
770    """Print a std::(multi)map iterator."""
771
772    def __init__(self, val):
773        self._initialize(val["__i_"],
774                         _remove_generics(_prettify_typename(val.type)))
775
776    def _get_node_value(self, node):
777        return node["__value_"]["__cc"]
778
779
780class SetIteratorPrinter(AbstractRBTreeIteratorPrinter):
781    """Print a std::(multi)set iterator."""
782
783    def __init__(self, val):
784        self._initialize(val, _remove_generics(_prettify_typename(val.type)))
785
786    def _get_node_value(self, node):
787        return node["__value_"]
788
789
790class StdFposPrinter(object):
791    """Print a std::fpos or std::streampos."""
792
793    def __init__(self, val):
794        self.val = val
795
796    def to_string(self):
797        typename = _remove_generics(_prettify_typename(self.val.type))
798        offset = self.val["__off_"]
799        state = self.val["__st_"]
800        count = state["__count"]
801        value = state["__value"]["__wch"]
802        return "%s with stream offset:%s with state: {count:%s value:%s}" % (
803            typename, offset, count, value)
804
805
806class AbstractUnorderedCollectionPrinter(object):
807    """Abstract super class for std::unordered_(multi)[set|map]."""
808
809    def __init__(self, val):
810        self.val = val
811        self.table = val["__table_"]
812        self.sentinel = self.table["__p1_"]
813        self.size = int(_value_of_pair_first(self.table["__p2_"]))
814        node_base_type = self.sentinel.type.template_argument(0)
815        self.cast_type = node_base_type.template_argument(0)
816
817    def _list_it(self, sentinel_ptr):
818        next_ptr = _value_of_pair_first(sentinel_ptr)["__next_"]
819        while str(next_ptr.cast(_void_pointer_type)) != "0x0":
820            next_val = next_ptr.cast(self.cast_type).dereference()
821            for key_value in self._get_key_value(next_val):
822                yield "", key_value
823            next_ptr = next_val["__next_"]
824
825    def to_string(self):
826        typename = _remove_generics(_prettify_typename(self.val.type))
827        if self.size:
828            return "%s with %d elements" % (typename, self.size)
829        return "%s is empty" % typename
830
831    def _get_key_value(self, node):
832        """Subclasses should override to return a list of values to yield."""
833        raise NotImplementedError
834
835    def children(self):
836        return self if self.cast_type and self.size > 0 else iter(())
837
838    def __iter__(self):
839        return self._list_it(self.sentinel)
840
841
842class StdUnorderedSetPrinter(AbstractUnorderedCollectionPrinter):
843    """Print a std::unordered_(multi)set."""
844
845    def _get_key_value(self, node):
846        return [node["__value_"]]
847
848    def display_hint(self):
849        return "array"
850
851
852class StdUnorderedMapPrinter(AbstractUnorderedCollectionPrinter):
853    """Print a std::unordered_(multi)map."""
854
855    def _get_key_value(self, node):
856        key_value = node["__value_"]["__cc"]
857        return [key_value["first"], key_value["second"]]
858
859    def display_hint(self):
860        return "map"
861
862
863class AbstractHashMapIteratorPrinter(object):
864    """Abstract class for unordered collection iterators."""
865
866    def _initialize(self, val, addr):
867        self.val = val
868        self.typename = _remove_generics(_prettify_typename(self.val.type))
869        self.addr = addr
870        if self.addr:
871            self.node = self.addr.cast(self.cast_type).dereference()
872
873    def _get_key_value(self):
874        """Subclasses should override to return a list of values to yield."""
875        raise NotImplementedError
876
877    def to_string(self):
878        if not self.addr:
879            return "%s = end()" % self.typename
880        return "%s " % self.typename
881
882    def children(self):
883        return self if self.addr else iter(())
884
885    def __iter__(self):
886        for key_value in self._get_key_value():
887            yield "", key_value
888
889
890class StdUnorderedSetIteratorPrinter(AbstractHashMapIteratorPrinter):
891    """Print a std::(multi)set iterator."""
892
893    def __init__(self, val):
894        self.cast_type = val.type.template_argument(0)
895        self._initialize(val, val["__node_"])
896
897    def _get_key_value(self):
898        return [self.node["__value_"]]
899
900    def display_hint(self):
901        return "array"
902
903
904class StdUnorderedMapIteratorPrinter(AbstractHashMapIteratorPrinter):
905    """Print a std::(multi)map iterator."""
906
907    def __init__(self, val):
908        self.cast_type = val.type.template_argument(0).template_argument(0)
909        self._initialize(val, val["__i_"]["__node_"])
910
911    def _get_key_value(self):
912        key_value = self.node["__value_"]["__cc"]
913        return [key_value["first"], key_value["second"]]
914
915    def display_hint(self):
916        return "map"
917
918
919def _remove_std_prefix(typename):
920    match = re.match("^std::(.+)", typename)
921    return match.group(1) if match is not None else ""
922
923
924class LibcxxPrettyPrinter(object):
925    """PrettyPrinter object so gdb-commands like 'info pretty-printers' work."""
926
927    def __init__(self, name):
928        super(LibcxxPrettyPrinter, self).__init__()
929        self.name = name
930        self.enabled = True
931
932        self.lookup = {
933            "basic_string": StdStringPrinter,
934            "string": StdStringPrinter,
935            "string_view": StdStringViewPrinter,
936            "tuple": StdTuplePrinter,
937            "unique_ptr": StdUniquePtrPrinter,
938            "shared_ptr": StdSharedPointerPrinter,
939            "weak_ptr": StdSharedPointerPrinter,
940            "bitset": StdBitsetPrinter,
941            "deque": StdDequePrinter,
942            "list": StdListPrinter,
943            "queue": StdQueueOrStackPrinter,
944            "stack": StdQueueOrStackPrinter,
945            "priority_queue": StdPriorityQueuePrinter,
946            "map": StdMapPrinter,
947            "multimap": StdMapPrinter,
948            "set": StdSetPrinter,
949            "multiset": StdSetPrinter,
950            "vector": StdVectorPrinter,
951            "__map_iterator": MapIteratorPrinter,
952            "__map_const_iterator": MapIteratorPrinter,
953            "__tree_iterator": SetIteratorPrinter,
954            "__tree_const_iterator": SetIteratorPrinter,
955            "fpos": StdFposPrinter,
956            "unordered_set": StdUnorderedSetPrinter,
957            "unordered_multiset": StdUnorderedSetPrinter,
958            "unordered_map": StdUnorderedMapPrinter,
959            "unordered_multimap": StdUnorderedMapPrinter,
960            "__hash_map_iterator": StdUnorderedMapIteratorPrinter,
961            "__hash_map_const_iterator": StdUnorderedMapIteratorPrinter,
962            "__hash_iterator": StdUnorderedSetIteratorPrinter,
963            "__hash_const_iterator": StdUnorderedSetIteratorPrinter,
964        }
965
966        self.subprinters = []
967        for name, subprinter in self.lookup.items():
968            # Subprinters and names are used only for the rarely used command "info
969            # pretty" (and related), so the name of the first data structure it prints
970            # is a reasonable choice.
971            if subprinter not in self.subprinters:
972                subprinter.name = name
973                self.subprinters.append(subprinter)
974
975    def __call__(self, val):
976        """Return the pretty printer for a val, if the type is supported."""
977
978        # Do not handle any type that is not a struct/class.
979        if val.type.strip_typedefs().code != gdb.TYPE_CODE_STRUCT:
980            return None
981
982        # Don't attempt types known to be inside libstdcxx.
983        typename = val.type.name or val.type.tag or str(val.type)
984        match = re.match("^std::(__.*?)::", typename)
985        if match is not None and match.group(1) in ["__cxx1998",
986                                                    "__debug",
987                                                    "__7",
988                                                    "__g"]:
989            return None
990
991        # Handle any using declarations or other typedefs.
992        typename = _prettify_typename(val.type)
993        if not typename:
994            return None
995        without_generics = _remove_generics(typename)
996        lookup_name = _remove_std_prefix(without_generics)
997        if lookup_name in self.lookup:
998            return self.lookup[lookup_name](val)
999        return None
1000
1001
1002_libcxx_printer_name = "libcxx_pretty_printer"
1003
1004
1005# These are called for every binary object file, which could be thousands in
1006# certain pathological cases. Limit our pretty printers to the progspace.
1007def _register_libcxx_printers(event):
1008    progspace = event.new_objfile.progspace
1009    # It would be ideal to get the endianness at print time, but
1010    # gdb.execute clears gdb's internal wrap buffer, removing any values
1011    # already generated as part of a larger data structure, and there is
1012    # no python api to get the endianness. Mixed-endianness debugging
1013    # rare enough that this workaround should be adequate.
1014    _libcpp_big_endian = "big endian" in gdb.execute("show endian",
1015                                                     to_string=True)
1016
1017    if not getattr(progspace, _libcxx_printer_name, False):
1018        print("Loading libc++ pretty-printers.")
1019        gdb.printing.register_pretty_printer(
1020            progspace, LibcxxPrettyPrinter(_libcxx_printer_name))
1021        setattr(progspace, _libcxx_printer_name, True)
1022
1023
1024def _unregister_libcxx_printers(event):
1025    progspace = event.progspace
1026    if getattr(progspace, _libcxx_printer_name, False):
1027        for printer in progspace.pretty_printers:
1028            if getattr(printer, "name", "none") == _libcxx_printer_name:
1029                progspace.pretty_printers.remove(printer)
1030                setattr(progspace, _libcxx_printer_name, False)
1031                break
1032
1033
1034def register_libcxx_printer_loader():
1035    """Register event handlers to load libc++ pretty-printers."""
1036    gdb.events.new_objfile.connect(_register_libcxx_printers)
1037    gdb.events.clear_objfiles.connect(_unregister_libcxx_printers)
1038