xref: /openbsd-src/gnu/llvm/libcxx/utils/gdb/libcxx/printers.py (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
146035553Spatrick#===----------------------------------------------------------------------===##
246035553Spatrick#
346035553Spatrick# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
446035553Spatrick# See https://llvm.org/LICENSE.txt for license information.
546035553Spatrick# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
646035553Spatrick#
746035553Spatrick#===----------------------------------------------------------------------===##
846035553Spatrick"""GDB pretty-printers for libc++.
946035553Spatrick
10*4bdff4beSrobertThese should work for objects compiled with either the stable ABI or the unstable ABI.
1146035553Spatrick"""
1246035553Spatrick
1346035553Spatrickfrom __future__ import print_function
1446035553Spatrick
1576d0caaeSpatrickimport math
1646035553Spatrickimport re
1746035553Spatrickimport gdb
1846035553Spatrick
1946035553Spatrick# One under-documented feature of the gdb pretty-printer API
2046035553Spatrick# is that clients can call any other member of the API
2146035553Spatrick# before they call to_string.
2246035553Spatrick# Therefore all self.FIELDs must be set in the pretty-printer's
2346035553Spatrick# __init__ function.
2446035553Spatrick
2546035553Spatrick_void_pointer_type = gdb.lookup_type("void").pointer()
2646035553Spatrick
2746035553Spatrick
2846035553Spatrick_long_int_type = gdb.lookup_type("unsigned long long")
2946035553Spatrick
3046035553Spatrick_libcpp_big_endian = False
3146035553Spatrick
3246035553Spatrickdef addr_as_long(addr):
3346035553Spatrick    return int(addr.cast(_long_int_type))
3446035553Spatrick
3546035553Spatrick
3646035553Spatrick# The size of a pointer in bytes.
3746035553Spatrick_pointer_size = _void_pointer_type.sizeof
3846035553Spatrick
3946035553Spatrick
4046035553Spatrickdef _remove_cxx_namespace(typename):
4146035553Spatrick    """Removed libc++ specific namespace from the type.
4246035553Spatrick
4346035553Spatrick    Arguments:
4446035553Spatrick      typename(string): A type, such as std::__u::something.
4546035553Spatrick
4646035553Spatrick    Returns:
4746035553Spatrick      A string without the libc++ specific part, such as std::something.
4846035553Spatrick    """
4946035553Spatrick
5046035553Spatrick    return re.sub("std::__.*?::", "std::", typename)
5146035553Spatrick
5246035553Spatrick
5346035553Spatrickdef _remove_generics(typename):
5446035553Spatrick    """Remove generics part of the type. Assumes typename is not empty.
5546035553Spatrick
5646035553Spatrick    Arguments:
5746035553Spatrick      typename(string): A type such as std::my_collection<element>.
5846035553Spatrick
5946035553Spatrick    Returns:
6046035553Spatrick      The prefix up to the generic part, such as std::my_collection.
6146035553Spatrick    """
6246035553Spatrick
6346035553Spatrick    match = re.match("^([^<]+)", typename)
6446035553Spatrick    return match.group(1)
6546035553Spatrick
6646035553Spatrick
67*4bdff4beSrobertdef _cc_field(node):
68*4bdff4beSrobert    """Previous versions of libcxx had inconsistent field naming naming. Handle
69*4bdff4beSrobert    both types.
70*4bdff4beSrobert    """
71*4bdff4beSrobert    try:
72*4bdff4beSrobert        return node["__value_"]["__cc_"]
73*4bdff4beSrobert    except:
74*4bdff4beSrobert        return node["__value_"]["__cc"]
75*4bdff4beSrobert
76*4bdff4beSrobert
77*4bdff4beSrobertdef _data_field(node):
78*4bdff4beSrobert    """Previous versions of libcxx had inconsistent field naming naming. Handle
79*4bdff4beSrobert    both types.
80*4bdff4beSrobert    """
81*4bdff4beSrobert    try:
82*4bdff4beSrobert        return node["__data_"]
83*4bdff4beSrobert    except:
84*4bdff4beSrobert        return node["__data"]
85*4bdff4beSrobert
86*4bdff4beSrobert
87*4bdff4beSrobertdef _size_field(node):
88*4bdff4beSrobert    """Previous versions of libcxx had inconsistent field naming naming. Handle
89*4bdff4beSrobert    both types.
90*4bdff4beSrobert    """
91*4bdff4beSrobert    try:
92*4bdff4beSrobert        return node["__size_"]
93*4bdff4beSrobert    except:
94*4bdff4beSrobert        return node["__size"]
95*4bdff4beSrobert
96*4bdff4beSrobert
9746035553Spatrick# Some common substitutions on the types to reduce visual clutter (A user who
9846035553Spatrick# wants to see the actual details can always use print/r).
9946035553Spatrick_common_substitutions = [
10046035553Spatrick    ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
10146035553Spatrick     "std::string"),
102037e7968Spatrick    ("std::basic_string_view<char, std::char_traits<char> >",
103037e7968Spatrick     "std::string_view"),
10446035553Spatrick]
10546035553Spatrick
10646035553Spatrick
10746035553Spatrickdef _prettify_typename(gdb_type):
10846035553Spatrick    """Returns a pretty name for the type, or None if no name can be found.
10946035553Spatrick
11046035553Spatrick    Arguments:
11146035553Spatrick      gdb_type(gdb.Type): A type object.
11246035553Spatrick
11346035553Spatrick    Returns:
11446035553Spatrick      A string, without type_defs, libc++ namespaces, and common substitutions
11546035553Spatrick      applied.
11646035553Spatrick    """
11746035553Spatrick
11846035553Spatrick    type_without_typedefs = gdb_type.strip_typedefs()
11946035553Spatrick    typename = type_without_typedefs.name or type_without_typedefs.tag or \
12046035553Spatrick        str(type_without_typedefs)
12146035553Spatrick    result = _remove_cxx_namespace(typename)
12246035553Spatrick    for find_str, subst_str in _common_substitutions:
12346035553Spatrick        result = re.sub(find_str, subst_str, result)
12446035553Spatrick    return result
12546035553Spatrick
12646035553Spatrick
12746035553Spatrickdef _typename_for_nth_generic_argument(gdb_type, n):
12846035553Spatrick    """Returns a pretty string for the nth argument of the given type.
12946035553Spatrick
13046035553Spatrick    Arguments:
13146035553Spatrick      gdb_type(gdb.Type): A type object, such as the one for std::map<int, int>
13246035553Spatrick      n: The (zero indexed) index of the argument to return.
13346035553Spatrick
13446035553Spatrick    Returns:
13546035553Spatrick      A string for the nth argument, such a "std::string"
13646035553Spatrick    """
13746035553Spatrick    element_type = gdb_type.template_argument(n)
13846035553Spatrick    return _prettify_typename(element_type)
13946035553Spatrick
14046035553Spatrick
14146035553Spatrickdef _typename_with_n_generic_arguments(gdb_type, n):
14246035553Spatrick    """Return a string for the type with the first n (1, ...) generic args."""
14346035553Spatrick
14446035553Spatrick    base_type = _remove_generics(_prettify_typename(gdb_type))
14546035553Spatrick    arg_list = [base_type]
14646035553Spatrick    template = "%s<"
14746035553Spatrick    for i in range(n):
14846035553Spatrick        arg_list.append(_typename_for_nth_generic_argument(gdb_type, i))
14946035553Spatrick        template += "%s, "
15046035553Spatrick    result = (template[:-2] + ">") % tuple(arg_list)
15146035553Spatrick    return result
15246035553Spatrick
15346035553Spatrick
15446035553Spatrickdef _typename_with_first_generic_argument(gdb_type):
15546035553Spatrick    return _typename_with_n_generic_arguments(gdb_type, 1)
15646035553Spatrick
15746035553Spatrick
15846035553Spatrickclass StdTuplePrinter(object):
15946035553Spatrick    """Print a std::tuple."""
16046035553Spatrick
16146035553Spatrick    class _Children(object):
16246035553Spatrick        """Class to iterate over the tuple's children."""
16346035553Spatrick
16446035553Spatrick        def __init__(self, val):
16546035553Spatrick            self.val = val
16646035553Spatrick            self.child_iter = iter(self.val["__base_"].type.fields())
16746035553Spatrick            self.count = 0
16846035553Spatrick
16946035553Spatrick        def __iter__(self):
17046035553Spatrick            return self
17146035553Spatrick
17246035553Spatrick        def __next__(self):
17346035553Spatrick            # child_iter raises StopIteration when appropriate.
17476d0caaeSpatrick            field_name = next(self.child_iter)
17546035553Spatrick            child = self.val["__base_"][field_name]["__value_"]
17646035553Spatrick            self.count += 1
17746035553Spatrick            return ("[%d]" % self.count, child)
17846035553Spatrick
179*4bdff4beSrobert        next = __next__  # Needed for GDB built against Python 2.7.
18046035553Spatrick
18146035553Spatrick    def __init__(self, val):
18246035553Spatrick        self.val = val
18346035553Spatrick
18446035553Spatrick    def to_string(self):
18546035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
18646035553Spatrick        if not self.val.type.fields():
18746035553Spatrick            return "empty %s" % typename
18846035553Spatrick        return "%s containing" % typename
18946035553Spatrick
19046035553Spatrick    def children(self):
19146035553Spatrick        if not self.val.type.fields():
19246035553Spatrick            return iter(())
19346035553Spatrick        return self._Children(self.val)
19446035553Spatrick
19546035553Spatrick
19646035553Spatrickdef _get_base_subobject(child_class_value, index=0):
19746035553Spatrick    """Returns the object's value in the form of the parent class at index.
19846035553Spatrick
19946035553Spatrick    This function effectively casts the child_class_value to the base_class's
20046035553Spatrick    type, but the type-to-cast to is stored in the field at index, and once
20146035553Spatrick    we know the field, we can just return the data.
20246035553Spatrick
20346035553Spatrick    Args:
20446035553Spatrick      child_class_value: the value to cast
20546035553Spatrick      index: the parent class index
20646035553Spatrick
20746035553Spatrick    Raises:
20846035553Spatrick      Exception: field at index was not a base-class field.
20946035553Spatrick    """
21046035553Spatrick
21146035553Spatrick    field = child_class_value.type.fields()[index]
21246035553Spatrick    if not field.is_base_class:
21346035553Spatrick        raise Exception("Not a base-class field.")
21446035553Spatrick    return child_class_value[field]
21546035553Spatrick
21646035553Spatrick
21746035553Spatrickdef _value_of_pair_first(value):
21846035553Spatrick    """Convenience for _get_base_subobject, for the common case."""
21946035553Spatrick    return _get_base_subobject(value, 0)["__value_"]
22046035553Spatrick
22146035553Spatrick
22246035553Spatrickclass StdStringPrinter(object):
22346035553Spatrick    """Print a std::string."""
22446035553Spatrick
22546035553Spatrick    def __init__(self, val):
22646035553Spatrick        self.val = val
22746035553Spatrick
22846035553Spatrick    def to_string(self):
22946035553Spatrick        """Build a python string from the data whether stored inline or separately."""
23046035553Spatrick        value_field = _value_of_pair_first(self.val["__r_"])
23146035553Spatrick        short_field = value_field["__s"]
23246035553Spatrick        short_size = short_field["__size_"]
233*4bdff4beSrobert        if short_field["__is_long_"]:
23446035553Spatrick            long_field = value_field["__l"]
23546035553Spatrick            data = long_field["__data_"]
23646035553Spatrick            size = long_field["__size_"]
23746035553Spatrick        else:
23846035553Spatrick            data = short_field["__data_"]
239*4bdff4beSrobert            size = short_field["__size_"]
24046035553Spatrick        return data.lazy_string(length=size)
24146035553Spatrick
24246035553Spatrick    def display_hint(self):
24346035553Spatrick        return "string"
24446035553Spatrick
24546035553Spatrick
246037e7968Spatrickclass StdStringViewPrinter(object):
247037e7968Spatrick    """Print a std::string_view."""
248037e7968Spatrick
249037e7968Spatrick    def __init__(self, val):
250037e7968Spatrick      self.val = val
251037e7968Spatrick
252*4bdff4beSrobert    def display_hint(self):
253*4bdff4beSrobert      return "string"
254*4bdff4beSrobert
255037e7968Spatrick    def to_string(self):  # pylint: disable=g-bad-name
256037e7968Spatrick      """GDB calls this to compute the pretty-printed form."""
257037e7968Spatrick
258*4bdff4beSrobert      ptr = _data_field(self.val)
259*4bdff4beSrobert      ptr = ptr.cast(ptr.type.target().strip_typedefs().pointer())
260*4bdff4beSrobert      size = _size_field(self.val)
261*4bdff4beSrobert      return ptr.lazy_string(length=size)
262037e7968Spatrick
263037e7968Spatrick
26446035553Spatrickclass StdUniquePtrPrinter(object):
26546035553Spatrick    """Print a std::unique_ptr."""
26646035553Spatrick
26746035553Spatrick    def __init__(self, val):
26846035553Spatrick        self.val = val
26946035553Spatrick        self.addr = _value_of_pair_first(self.val["__ptr_"])
27046035553Spatrick        self.pointee_type = self.val.type.template_argument(0)
27146035553Spatrick
27246035553Spatrick    def to_string(self):
27346035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
27446035553Spatrick        if not self.addr:
27546035553Spatrick            return "%s is nullptr" % typename
27646035553Spatrick        return ("%s<%s> containing" %
27746035553Spatrick                (typename,
27846035553Spatrick                 _remove_generics(_prettify_typename(self.pointee_type))))
27946035553Spatrick
28046035553Spatrick    def __iter__(self):
28146035553Spatrick        if self.addr:
28246035553Spatrick            yield "__ptr_", self.addr.cast(self.pointee_type.pointer())
28346035553Spatrick
28446035553Spatrick    def children(self):
28546035553Spatrick        return self
28646035553Spatrick
28746035553Spatrick
28846035553Spatrickclass StdSharedPointerPrinter(object):
28946035553Spatrick    """Print a std::shared_ptr."""
29046035553Spatrick
29146035553Spatrick    def __init__(self, val):
29246035553Spatrick        self.val = val
29346035553Spatrick        self.addr = self.val["__ptr_"]
29446035553Spatrick
29546035553Spatrick    def to_string(self):
29646035553Spatrick        """Returns self as a string."""
29746035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
29846035553Spatrick        pointee_type = _remove_generics(
29946035553Spatrick            _prettify_typename(self.val.type.template_argument(0)))
30046035553Spatrick        if not self.addr:
30146035553Spatrick            return "%s is nullptr" % typename
30246035553Spatrick        refcount = self.val["__cntrl_"]
30346035553Spatrick        if refcount != 0:
30476d0caaeSpatrick            try:
30546035553Spatrick                usecount = refcount["__shared_owners_"] + 1
30646035553Spatrick                weakcount = refcount["__shared_weak_owners_"]
30746035553Spatrick                if usecount == 0:
30846035553Spatrick                    state = "expired, weak %d" % weakcount
30946035553Spatrick                else:
31046035553Spatrick                    state = "count %d, weak %d" % (usecount, weakcount)
31176d0caaeSpatrick            except:
31276d0caaeSpatrick                # Debug info for a class with virtual functions is emitted
31376d0caaeSpatrick                # in the same place as its key function. That means that
31476d0caaeSpatrick                # for std::shared_ptr, __shared_owners_ is emitted into
31576d0caaeSpatrick                # into libcxx.[so|a] itself, rather than into the shared_ptr
31676d0caaeSpatrick                # instantiation point. So if libcxx.so was built without
31776d0caaeSpatrick                # debug info, these fields will be missing.
31876d0caaeSpatrick                state = "count ?, weak ? (libc++ missing debug info)"
31946035553Spatrick        return "%s<%s> %s containing" % (typename, pointee_type, state)
32046035553Spatrick
32146035553Spatrick    def __iter__(self):
32246035553Spatrick        if self.addr:
32346035553Spatrick            yield "__ptr_", self.addr
32446035553Spatrick
32546035553Spatrick    def children(self):
32646035553Spatrick        return self
32746035553Spatrick
32846035553Spatrick
32946035553Spatrickclass StdVectorPrinter(object):
33046035553Spatrick    """Print a std::vector."""
33146035553Spatrick
33246035553Spatrick    class _VectorBoolIterator(object):
33346035553Spatrick        """Class to iterate over the bool vector's children."""
33446035553Spatrick
33546035553Spatrick        def __init__(self, begin, size, bits_per_word):
33646035553Spatrick            self.item = begin
33746035553Spatrick            self.size = size
33846035553Spatrick            self.bits_per_word = bits_per_word
33946035553Spatrick            self.count = 0
34046035553Spatrick            self.offset = 0
34146035553Spatrick
34246035553Spatrick        def __iter__(self):
34346035553Spatrick            return self
34446035553Spatrick
34546035553Spatrick        def __next__(self):
34646035553Spatrick            """Retrieve the next element."""
34746035553Spatrick
34846035553Spatrick            self.count += 1
34946035553Spatrick            if self.count > self.size:
35046035553Spatrick                raise StopIteration
35146035553Spatrick            entry = self.item.dereference()
35246035553Spatrick            if entry & (1 << self.offset):
35346035553Spatrick                outbit = 1
35446035553Spatrick            else:
35546035553Spatrick                outbit = 0
35646035553Spatrick            self.offset += 1
35746035553Spatrick            if self.offset >= self.bits_per_word:
35846035553Spatrick                self.item += 1
35946035553Spatrick                self.offset = 0
36046035553Spatrick            return ("[%d]" % self.count, outbit)
36146035553Spatrick
362*4bdff4beSrobert        next = __next__  # Needed for GDB built against Python 2.7.
36346035553Spatrick
36446035553Spatrick    class _VectorIterator(object):
36546035553Spatrick        """Class to iterate over the non-bool vector's children."""
36646035553Spatrick
36746035553Spatrick        def __init__(self, begin, end):
36846035553Spatrick            self.item = begin
36946035553Spatrick            self.end = end
37046035553Spatrick            self.count = 0
37146035553Spatrick
37246035553Spatrick        def __iter__(self):
37346035553Spatrick            return self
37446035553Spatrick
37546035553Spatrick        def __next__(self):
37646035553Spatrick            self.count += 1
37746035553Spatrick            if self.item == self.end:
37846035553Spatrick                raise StopIteration
37946035553Spatrick            entry = self.item.dereference()
38046035553Spatrick            self.item += 1
38146035553Spatrick            return ("[%d]" % self.count, entry)
38246035553Spatrick
383*4bdff4beSrobert        next = __next__  # Needed for GDB built against Python 2.7.
38446035553Spatrick
38546035553Spatrick    def __init__(self, val):
38646035553Spatrick        """Set val, length, capacity, and iterator for bool and normal vectors."""
38746035553Spatrick        self.val = val
38846035553Spatrick        self.typename = _remove_generics(_prettify_typename(val.type))
38946035553Spatrick        begin = self.val["__begin_"]
39046035553Spatrick        if self.val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL:
39146035553Spatrick            self.typename += "<bool>"
39246035553Spatrick            self.length = self.val["__size_"]
39346035553Spatrick            bits_per_word = self.val["__bits_per_word"]
39446035553Spatrick            self.capacity = _value_of_pair_first(
39546035553Spatrick                self.val["__cap_alloc_"]) * bits_per_word
39646035553Spatrick            self.iterator = self._VectorBoolIterator(
39746035553Spatrick                begin, self.length, bits_per_word)
39846035553Spatrick        else:
39946035553Spatrick            end = self.val["__end_"]
40046035553Spatrick            self.length = end - begin
40146035553Spatrick            self.capacity = _get_base_subobject(
40246035553Spatrick                self.val["__end_cap_"])["__value_"] - begin
40346035553Spatrick            self.iterator = self._VectorIterator(begin, end)
40446035553Spatrick
40546035553Spatrick    def to_string(self):
40646035553Spatrick        return ("%s of length %d, capacity %d" %
40746035553Spatrick                (self.typename, self.length, self.capacity))
40846035553Spatrick
40946035553Spatrick    def children(self):
41046035553Spatrick        return self.iterator
41146035553Spatrick
41246035553Spatrick    def display_hint(self):
41346035553Spatrick        return "array"
41446035553Spatrick
41546035553Spatrick
41646035553Spatrickclass StdBitsetPrinter(object):
41746035553Spatrick    """Print a std::bitset."""
41846035553Spatrick
41946035553Spatrick    def __init__(self, val):
42046035553Spatrick        self.val = val
42146035553Spatrick        self.n_words = int(self.val["__n_words"])
42246035553Spatrick        self.bits_per_word = int(self.val["__bits_per_word"])
42376d0caaeSpatrick        self.bit_count = self.val.type.template_argument(0)
42446035553Spatrick        if self.n_words == 1:
42546035553Spatrick            self.values = [int(self.val["__first_"])]
42646035553Spatrick        else:
42746035553Spatrick            self.values = [int(self.val["__first_"][index])
42846035553Spatrick                           for index in range(self.n_words)]
42946035553Spatrick
43046035553Spatrick    def to_string(self):
43146035553Spatrick        typename = _prettify_typename(self.val.type)
43246035553Spatrick        return "%s" % typename
43346035553Spatrick
43446035553Spatrick    def _list_it(self):
43576d0caaeSpatrick        for bit in range(self.bit_count):
43676d0caaeSpatrick            word = bit // self.bits_per_word
43776d0caaeSpatrick            word_bit = bit % self.bits_per_word
43876d0caaeSpatrick            if self.values[word] & (1 << word_bit):
43976d0caaeSpatrick                yield ("[%d]" % bit, 1)
44046035553Spatrick
44146035553Spatrick    def __iter__(self):
44246035553Spatrick        return self._list_it()
44346035553Spatrick
44446035553Spatrick    def children(self):
44546035553Spatrick        return self
44646035553Spatrick
44746035553Spatrick
44846035553Spatrickclass StdDequePrinter(object):
44946035553Spatrick    """Print a std::deque."""
45046035553Spatrick
45146035553Spatrick    def __init__(self, val):
45246035553Spatrick        self.val = val
45346035553Spatrick        self.size = int(_value_of_pair_first(val["__size_"]))
45446035553Spatrick        self.start_ptr = self.val["__map_"]["__begin_"]
45546035553Spatrick        self.first_block_start_index = int(self.val["__start_"])
45646035553Spatrick        self.node_type = self.start_ptr.type
45746035553Spatrick        self.block_size = self._calculate_block_size(
45846035553Spatrick            val.type.template_argument(0))
45946035553Spatrick
46046035553Spatrick    def _calculate_block_size(self, element_type):
46146035553Spatrick        """Calculates the number of elements in a full block."""
46246035553Spatrick        size = element_type.sizeof
46346035553Spatrick        # Copied from struct __deque_block_size implementation of libcxx.
46446035553Spatrick        return 4096 / size if size < 256 else 16
46546035553Spatrick
46646035553Spatrick    def _bucket_it(self, start_addr, start_index, end_index):
46746035553Spatrick        for i in range(start_index, end_index):
46846035553Spatrick            yield i, (start_addr.dereference() + i).dereference()
46946035553Spatrick
47046035553Spatrick    def _list_it(self):
47146035553Spatrick        """Primary iteration worker."""
47246035553Spatrick        num_emitted = 0
47346035553Spatrick        current_addr = self.start_ptr
47446035553Spatrick        start_index = self.first_block_start_index
47546035553Spatrick        while num_emitted < self.size:
47646035553Spatrick            end_index = min(start_index + self.size -
47746035553Spatrick                            num_emitted, self.block_size)
47846035553Spatrick            for _, elem in self._bucket_it(current_addr, start_index, end_index):
47946035553Spatrick                yield "", elem
48046035553Spatrick            num_emitted += end_index - start_index
48146035553Spatrick            current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size) \
48246035553Spatrick                              .cast(self.node_type)
48346035553Spatrick            start_index = 0
48446035553Spatrick
48546035553Spatrick    def to_string(self):
48646035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
48746035553Spatrick        if self.size:
48846035553Spatrick            return "%s with %d elements" % (typename, self.size)
48946035553Spatrick        return "%s is empty" % typename
49046035553Spatrick
49146035553Spatrick    def __iter__(self):
49246035553Spatrick        return self._list_it()
49346035553Spatrick
49446035553Spatrick    def children(self):
49546035553Spatrick        return self
49646035553Spatrick
49746035553Spatrick    def display_hint(self):
49846035553Spatrick        return "array"
49946035553Spatrick
50046035553Spatrick
50146035553Spatrickclass StdListPrinter(object):
50246035553Spatrick    """Print a std::list."""
50346035553Spatrick
50446035553Spatrick    def __init__(self, val):
50546035553Spatrick        self.val = val
50646035553Spatrick        size_alloc_field = self.val["__size_alloc_"]
50746035553Spatrick        self.size = int(_value_of_pair_first(size_alloc_field))
50846035553Spatrick        dummy_node = self.val["__end_"]
50946035553Spatrick        self.nodetype = gdb.lookup_type(
51046035553Spatrick            re.sub("__list_node_base", "__list_node",
51146035553Spatrick                   str(dummy_node.type.strip_typedefs()))).pointer()
51246035553Spatrick        self.first_node = dummy_node["__next_"]
51346035553Spatrick
51446035553Spatrick    def to_string(self):
51546035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
51646035553Spatrick        if self.size:
51746035553Spatrick            return "%s with %d elements" % (typename, self.size)
51846035553Spatrick        return "%s is empty" % typename
51946035553Spatrick
52046035553Spatrick    def _list_iter(self):
52146035553Spatrick        current_node = self.first_node
52246035553Spatrick        for _ in range(self.size):
52346035553Spatrick            yield "", current_node.cast(self.nodetype).dereference()["__value_"]
52446035553Spatrick            current_node = current_node.dereference()["__next_"]
52546035553Spatrick
52646035553Spatrick    def __iter__(self):
52746035553Spatrick        return self._list_iter()
52846035553Spatrick
52946035553Spatrick    def children(self):
53046035553Spatrick        return self if self.nodetype else iter(())
53146035553Spatrick
53246035553Spatrick    def display_hint(self):
53346035553Spatrick        return "array"
53446035553Spatrick
53546035553Spatrick
53646035553Spatrickclass StdQueueOrStackPrinter(object):
53746035553Spatrick    """Print a std::queue or std::stack."""
53846035553Spatrick
53946035553Spatrick    def __init__(self, val):
54046035553Spatrick        self.val = val
54146035553Spatrick        self.underlying = val["c"]
54246035553Spatrick
54346035553Spatrick    def to_string(self):
54446035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
54546035553Spatrick        return "%s wrapping" % typename
54646035553Spatrick
54746035553Spatrick    def children(self):
54846035553Spatrick        return iter([("", self.underlying)])
54946035553Spatrick
55046035553Spatrick    def display_hint(self):
55146035553Spatrick        return "array"
55246035553Spatrick
55346035553Spatrick
55446035553Spatrickclass StdPriorityQueuePrinter(object):
55546035553Spatrick    """Print a std::priority_queue."""
55646035553Spatrick
55746035553Spatrick    def __init__(self, val):
55846035553Spatrick        self.val = val
55946035553Spatrick        self.underlying = val["c"]
56046035553Spatrick
56146035553Spatrick    def to_string(self):
56246035553Spatrick        # TODO(tamur): It would be nice to print the top element. The technical
56346035553Spatrick        # difficulty is that, the implementation refers to the underlying
56446035553Spatrick        # container, which is a generic class. libstdcxx pretty printers do not
56546035553Spatrick        # print the top element.
56646035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
56746035553Spatrick        return "%s wrapping" % typename
56846035553Spatrick
56946035553Spatrick    def children(self):
57046035553Spatrick        return iter([("", self.underlying)])
57146035553Spatrick
57246035553Spatrick    def display_hint(self):
57346035553Spatrick        return "array"
57446035553Spatrick
57546035553Spatrick
57646035553Spatrickclass RBTreeUtils(object):
57746035553Spatrick    """Utility class for std::(multi)map, and std::(multi)set and iterators."""
57846035553Spatrick
57946035553Spatrick    def __init__(self, cast_type, root):
58046035553Spatrick        self.cast_type = cast_type
58146035553Spatrick        self.root = root
58246035553Spatrick
58346035553Spatrick    def left_child(self, node):
58446035553Spatrick        result = node.cast(self.cast_type).dereference()["__left_"]
58546035553Spatrick        return result
58646035553Spatrick
58746035553Spatrick    def right_child(self, node):
58846035553Spatrick        result = node.cast(self.cast_type).dereference()["__right_"]
58946035553Spatrick        return result
59046035553Spatrick
59146035553Spatrick    def parent(self, node):
59246035553Spatrick        """Return the parent of node, if it exists."""
59346035553Spatrick        # If this is the root, then from the algorithm's point of view, it has no
59446035553Spatrick        # parent.
59546035553Spatrick        if node == self.root:
59646035553Spatrick            return None
59746035553Spatrick
59846035553Spatrick        # We don't have enough information to tell if this is the end_node (which
59946035553Spatrick        # doesn't have a __parent_ field), or the root (which doesn't have a parent
60046035553Spatrick        # from the algorithm's point of view), so cast_type may not be correct for
60146035553Spatrick        # this particular node. Use heuristics.
60246035553Spatrick
60346035553Spatrick        # The end_node's left child is the root. Note that when printing interators
60446035553Spatrick        # in isolation, the root is unknown.
60546035553Spatrick        if self.left_child(node) == self.root:
60646035553Spatrick            return None
60746035553Spatrick
60846035553Spatrick        parent = node.cast(self.cast_type).dereference()["__parent_"]
60946035553Spatrick        # If the value at the offset of __parent_ doesn't look like a valid pointer,
61046035553Spatrick        # then assume that node is the end_node (and therefore has no parent).
61146035553Spatrick        # End_node type has a pointer embedded, so should have pointer alignment.
61246035553Spatrick        if addr_as_long(parent) % _void_pointer_type.alignof:
61346035553Spatrick            return None
61446035553Spatrick        # This is ugly, but the only other option is to dereference an invalid
61546035553Spatrick        # pointer.  0x8000 is fairly arbitrary, but has had good results in
61646035553Spatrick        # practice.  If there was a way to tell if a pointer is invalid without
61746035553Spatrick        # actually dereferencing it and spewing error messages, that would be ideal.
61846035553Spatrick        if parent < 0x8000:
61946035553Spatrick            return None
62046035553Spatrick        return parent
62146035553Spatrick
62246035553Spatrick    def is_left_child(self, node):
62346035553Spatrick        parent = self.parent(node)
62446035553Spatrick        return parent is not None and self.left_child(parent) == node
62546035553Spatrick
62646035553Spatrick    def is_right_child(self, node):
62746035553Spatrick        parent = self.parent(node)
62846035553Spatrick        return parent is not None and self.right_child(parent) == node
62946035553Spatrick
63046035553Spatrick
63146035553Spatrickclass AbstractRBTreePrinter(object):
63246035553Spatrick    """Abstract super class for std::(multi)map, and std::(multi)set."""
63346035553Spatrick
63446035553Spatrick    def __init__(self, val):
63546035553Spatrick        self.val = val
63646035553Spatrick        tree = self.val["__tree_"]
63746035553Spatrick        self.size = int(_value_of_pair_first(tree["__pair3_"]))
63846035553Spatrick        dummy_root = tree["__pair1_"]
63946035553Spatrick        root = _value_of_pair_first(dummy_root)["__left_"]
64046035553Spatrick        cast_type = self._init_cast_type(val.type)
64146035553Spatrick        self.util = RBTreeUtils(cast_type, root)
64246035553Spatrick
64346035553Spatrick    def _get_key_value(self, node):
64446035553Spatrick        """Subclasses should override to return a list of values to yield."""
64546035553Spatrick        raise NotImplementedError
64646035553Spatrick
64746035553Spatrick    def _traverse(self):
64846035553Spatrick        """Traverses the binary search tree in order."""
64946035553Spatrick        current = self.util.root
65046035553Spatrick        skip_left_child = False
65146035553Spatrick        while True:
65246035553Spatrick            if not skip_left_child and self.util.left_child(current):
65346035553Spatrick                current = self.util.left_child(current)
65446035553Spatrick                continue
65546035553Spatrick            skip_left_child = False
65646035553Spatrick            for key_value in self._get_key_value(current):
65746035553Spatrick                yield "", key_value
65846035553Spatrick            right_child = self.util.right_child(current)
65946035553Spatrick            if right_child:
66046035553Spatrick                current = right_child
66146035553Spatrick                continue
66246035553Spatrick            while self.util.is_right_child(current):
66346035553Spatrick                current = self.util.parent(current)
66446035553Spatrick            if self.util.is_left_child(current):
66546035553Spatrick                current = self.util.parent(current)
66646035553Spatrick                skip_left_child = True
66746035553Spatrick                continue
66846035553Spatrick            break
66946035553Spatrick
67046035553Spatrick    def __iter__(self):
67146035553Spatrick        return self._traverse()
67246035553Spatrick
67346035553Spatrick    def children(self):
67446035553Spatrick        return self if self.util.cast_type and self.size > 0 else iter(())
67546035553Spatrick
67646035553Spatrick    def to_string(self):
67746035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
67846035553Spatrick        if self.size:
67946035553Spatrick            return "%s with %d elements" % (typename, self.size)
68046035553Spatrick        return "%s is empty" % typename
68146035553Spatrick
68246035553Spatrick
68346035553Spatrickclass StdMapPrinter(AbstractRBTreePrinter):
68446035553Spatrick    """Print a std::map or std::multimap."""
68546035553Spatrick
68646035553Spatrick    def _init_cast_type(self, val_type):
68746035553Spatrick        map_it_type = gdb.lookup_type(
688037e7968Spatrick            str(val_type.strip_typedefs()) + "::iterator").strip_typedefs()
68946035553Spatrick        tree_it_type = map_it_type.template_argument(0)
69046035553Spatrick        node_ptr_type = tree_it_type.template_argument(1)
69146035553Spatrick        return node_ptr_type
69246035553Spatrick
69346035553Spatrick    def display_hint(self):
69446035553Spatrick        return "map"
69546035553Spatrick
69646035553Spatrick    def _get_key_value(self, node):
697*4bdff4beSrobert        key_value = _cc_field(node.cast(self.util.cast_type).dereference())
69846035553Spatrick        return [key_value["first"], key_value["second"]]
69946035553Spatrick
70046035553Spatrick
70146035553Spatrickclass StdSetPrinter(AbstractRBTreePrinter):
70246035553Spatrick    """Print a std::set."""
70346035553Spatrick
70446035553Spatrick    def _init_cast_type(self, val_type):
70546035553Spatrick        set_it_type = gdb.lookup_type(
706037e7968Spatrick            str(val_type.strip_typedefs()) + "::iterator").strip_typedefs()
70746035553Spatrick        node_ptr_type = set_it_type.template_argument(1)
70846035553Spatrick        return node_ptr_type
70946035553Spatrick
71046035553Spatrick    def display_hint(self):
71146035553Spatrick        return "array"
71246035553Spatrick
71346035553Spatrick    def _get_key_value(self, node):
71446035553Spatrick        key_value = node.cast(self.util.cast_type).dereference()["__value_"]
71546035553Spatrick        return [key_value]
71646035553Spatrick
71746035553Spatrick
71846035553Spatrickclass AbstractRBTreeIteratorPrinter(object):
71946035553Spatrick    """Abstract super class for std::(multi)map, and std::(multi)set iterator."""
72046035553Spatrick
72146035553Spatrick    def _initialize(self, val, typename):
72246035553Spatrick        self.typename = typename
72346035553Spatrick        self.val = val
72446035553Spatrick        self.addr = self.val["__ptr_"]
72546035553Spatrick        cast_type = self.val.type.template_argument(1)
72646035553Spatrick        self.util = RBTreeUtils(cast_type, None)
72746035553Spatrick        if self.addr:
72846035553Spatrick            self.node = self.addr.cast(cast_type).dereference()
72946035553Spatrick
73046035553Spatrick    def _is_valid_node(self):
73146035553Spatrick        if not self.util.parent(self.addr):
73246035553Spatrick            return False
73346035553Spatrick        return self.util.is_left_child(self.addr) or \
73446035553Spatrick            self.util.is_right_child(self.addr)
73546035553Spatrick
73646035553Spatrick    def to_string(self):
73746035553Spatrick        if not self.addr:
73846035553Spatrick            return "%s is nullptr" % self.typename
73946035553Spatrick        return "%s " % self.typename
74046035553Spatrick
74146035553Spatrick    def _get_node_value(self, node):
74246035553Spatrick        raise NotImplementedError
74346035553Spatrick
74446035553Spatrick    def __iter__(self):
74546035553Spatrick        addr_str = "[%s]" % str(self.addr)
74646035553Spatrick        if not self._is_valid_node():
74746035553Spatrick            yield addr_str, " end()"
74846035553Spatrick        else:
74946035553Spatrick            yield addr_str, self._get_node_value(self.node)
75046035553Spatrick
75146035553Spatrick    def children(self):
75246035553Spatrick        return self if self.addr else iter(())
75346035553Spatrick
75446035553Spatrick
75546035553Spatrickclass MapIteratorPrinter(AbstractRBTreeIteratorPrinter):
75646035553Spatrick    """Print a std::(multi)map iterator."""
75746035553Spatrick
75846035553Spatrick    def __init__(self, val):
75946035553Spatrick        self._initialize(val["__i_"],
76046035553Spatrick                         _remove_generics(_prettify_typename(val.type)))
76146035553Spatrick
76246035553Spatrick    def _get_node_value(self, node):
763*4bdff4beSrobert        return _cc_field(node)
76446035553Spatrick
76546035553Spatrick
76646035553Spatrickclass SetIteratorPrinter(AbstractRBTreeIteratorPrinter):
76746035553Spatrick    """Print a std::(multi)set iterator."""
76846035553Spatrick
76946035553Spatrick    def __init__(self, val):
77046035553Spatrick        self._initialize(val, _remove_generics(_prettify_typename(val.type)))
77146035553Spatrick
77246035553Spatrick    def _get_node_value(self, node):
77346035553Spatrick        return node["__value_"]
77446035553Spatrick
77546035553Spatrick
77646035553Spatrickclass StdFposPrinter(object):
77746035553Spatrick    """Print a std::fpos or std::streampos."""
77846035553Spatrick
77946035553Spatrick    def __init__(self, val):
78046035553Spatrick        self.val = val
78146035553Spatrick
78246035553Spatrick    def to_string(self):
78346035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
78446035553Spatrick        offset = self.val["__off_"]
78546035553Spatrick        state = self.val["__st_"]
786*4bdff4beSrobert
787*4bdff4beSrobert        state_fields = []
788*4bdff4beSrobert        if state.type.code == gdb.TYPE_CODE_STRUCT:
789*4bdff4beSrobert            state_fields = [f.name for f in state.type.fields()]
790*4bdff4beSrobert
791*4bdff4beSrobert        state_string = ""
792*4bdff4beSrobert        if "__count" in state_fields and "__value" in state_fields:
79346035553Spatrick            count = state["__count"]
79446035553Spatrick            value = state["__value"]["__wch"]
795*4bdff4beSrobert            state_string = " with state: {count:%s value:%s}" % (count, value)
796*4bdff4beSrobert
797*4bdff4beSrobert        return "%s with stream offset:%s%s" % (typename, offset, state_string)
79846035553Spatrick
79946035553Spatrick
80046035553Spatrickclass AbstractUnorderedCollectionPrinter(object):
80146035553Spatrick    """Abstract super class for std::unordered_(multi)[set|map]."""
80246035553Spatrick
80346035553Spatrick    def __init__(self, val):
80446035553Spatrick        self.val = val
80546035553Spatrick        self.table = val["__table_"]
80646035553Spatrick        self.sentinel = self.table["__p1_"]
80746035553Spatrick        self.size = int(_value_of_pair_first(self.table["__p2_"]))
80846035553Spatrick        node_base_type = self.sentinel.type.template_argument(0)
80946035553Spatrick        self.cast_type = node_base_type.template_argument(0)
81046035553Spatrick
81146035553Spatrick    def _list_it(self, sentinel_ptr):
81246035553Spatrick        next_ptr = _value_of_pair_first(sentinel_ptr)["__next_"]
81346035553Spatrick        while str(next_ptr.cast(_void_pointer_type)) != "0x0":
81446035553Spatrick            next_val = next_ptr.cast(self.cast_type).dereference()
81546035553Spatrick            for key_value in self._get_key_value(next_val):
81646035553Spatrick                yield "", key_value
81746035553Spatrick            next_ptr = next_val["__next_"]
81846035553Spatrick
81946035553Spatrick    def to_string(self):
82046035553Spatrick        typename = _remove_generics(_prettify_typename(self.val.type))
82146035553Spatrick        if self.size:
82246035553Spatrick            return "%s with %d elements" % (typename, self.size)
82346035553Spatrick        return "%s is empty" % typename
82446035553Spatrick
82546035553Spatrick    def _get_key_value(self, node):
82646035553Spatrick        """Subclasses should override to return a list of values to yield."""
82746035553Spatrick        raise NotImplementedError
82846035553Spatrick
82946035553Spatrick    def children(self):
83046035553Spatrick        return self if self.cast_type and self.size > 0 else iter(())
83146035553Spatrick
83246035553Spatrick    def __iter__(self):
83346035553Spatrick        return self._list_it(self.sentinel)
83446035553Spatrick
83546035553Spatrick
83646035553Spatrickclass StdUnorderedSetPrinter(AbstractUnorderedCollectionPrinter):
83746035553Spatrick    """Print a std::unordered_(multi)set."""
83846035553Spatrick
83946035553Spatrick    def _get_key_value(self, node):
84046035553Spatrick        return [node["__value_"]]
84146035553Spatrick
84246035553Spatrick    def display_hint(self):
84346035553Spatrick        return "array"
84446035553Spatrick
84546035553Spatrick
84646035553Spatrickclass StdUnorderedMapPrinter(AbstractUnorderedCollectionPrinter):
84746035553Spatrick    """Print a std::unordered_(multi)map."""
84846035553Spatrick
84946035553Spatrick    def _get_key_value(self, node):
850*4bdff4beSrobert        key_value = _cc_field(node)
85146035553Spatrick        return [key_value["first"], key_value["second"]]
85246035553Spatrick
85346035553Spatrick    def display_hint(self):
85446035553Spatrick        return "map"
85546035553Spatrick
85646035553Spatrick
85746035553Spatrickclass AbstractHashMapIteratorPrinter(object):
85846035553Spatrick    """Abstract class for unordered collection iterators."""
85946035553Spatrick
86046035553Spatrick    def _initialize(self, val, addr):
86146035553Spatrick        self.val = val
86246035553Spatrick        self.typename = _remove_generics(_prettify_typename(self.val.type))
86346035553Spatrick        self.addr = addr
86446035553Spatrick        if self.addr:
86546035553Spatrick            self.node = self.addr.cast(self.cast_type).dereference()
86646035553Spatrick
86746035553Spatrick    def _get_key_value(self):
86846035553Spatrick        """Subclasses should override to return a list of values to yield."""
86946035553Spatrick        raise NotImplementedError
87046035553Spatrick
87146035553Spatrick    def to_string(self):
87246035553Spatrick        if not self.addr:
87346035553Spatrick            return "%s = end()" % self.typename
87446035553Spatrick        return "%s " % self.typename
87546035553Spatrick
87646035553Spatrick    def children(self):
87746035553Spatrick        return self if self.addr else iter(())
87846035553Spatrick
87946035553Spatrick    def __iter__(self):
88046035553Spatrick        for key_value in self._get_key_value():
88146035553Spatrick            yield "", key_value
88246035553Spatrick
88346035553Spatrick
88446035553Spatrickclass StdUnorderedSetIteratorPrinter(AbstractHashMapIteratorPrinter):
88546035553Spatrick    """Print a std::(multi)set iterator."""
88646035553Spatrick
88746035553Spatrick    def __init__(self, val):
88846035553Spatrick        self.cast_type = val.type.template_argument(0)
88946035553Spatrick        self._initialize(val, val["__node_"])
89046035553Spatrick
89146035553Spatrick    def _get_key_value(self):
89246035553Spatrick        return [self.node["__value_"]]
89346035553Spatrick
89446035553Spatrick    def display_hint(self):
89546035553Spatrick        return "array"
89646035553Spatrick
89746035553Spatrick
89846035553Spatrickclass StdUnorderedMapIteratorPrinter(AbstractHashMapIteratorPrinter):
89946035553Spatrick    """Print a std::(multi)map iterator."""
90046035553Spatrick
90146035553Spatrick    def __init__(self, val):
90246035553Spatrick        self.cast_type = val.type.template_argument(0).template_argument(0)
90346035553Spatrick        self._initialize(val, val["__i_"]["__node_"])
90446035553Spatrick
90546035553Spatrick    def _get_key_value(self):
906*4bdff4beSrobert        key_value = _cc_field(self.node)
90746035553Spatrick        return [key_value["first"], key_value["second"]]
90846035553Spatrick
90946035553Spatrick    def display_hint(self):
91046035553Spatrick        return "map"
91146035553Spatrick
91246035553Spatrick
91346035553Spatrickdef _remove_std_prefix(typename):
91446035553Spatrick    match = re.match("^std::(.+)", typename)
91546035553Spatrick    return match.group(1) if match is not None else ""
91646035553Spatrick
91746035553Spatrick
91846035553Spatrickclass LibcxxPrettyPrinter(object):
91946035553Spatrick    """PrettyPrinter object so gdb-commands like 'info pretty-printers' work."""
92046035553Spatrick
92146035553Spatrick    def __init__(self, name):
92246035553Spatrick        super(LibcxxPrettyPrinter, self).__init__()
92346035553Spatrick        self.name = name
92446035553Spatrick        self.enabled = True
92546035553Spatrick
92646035553Spatrick        self.lookup = {
92746035553Spatrick            "basic_string": StdStringPrinter,
92846035553Spatrick            "string": StdStringPrinter,
929037e7968Spatrick            "string_view": StdStringViewPrinter,
93046035553Spatrick            "tuple": StdTuplePrinter,
93146035553Spatrick            "unique_ptr": StdUniquePtrPrinter,
93246035553Spatrick            "shared_ptr": StdSharedPointerPrinter,
93346035553Spatrick            "weak_ptr": StdSharedPointerPrinter,
93446035553Spatrick            "bitset": StdBitsetPrinter,
93546035553Spatrick            "deque": StdDequePrinter,
93646035553Spatrick            "list": StdListPrinter,
93746035553Spatrick            "queue": StdQueueOrStackPrinter,
93846035553Spatrick            "stack": StdQueueOrStackPrinter,
93946035553Spatrick            "priority_queue": StdPriorityQueuePrinter,
94046035553Spatrick            "map": StdMapPrinter,
94146035553Spatrick            "multimap": StdMapPrinter,
94246035553Spatrick            "set": StdSetPrinter,
94346035553Spatrick            "multiset": StdSetPrinter,
94446035553Spatrick            "vector": StdVectorPrinter,
94546035553Spatrick            "__map_iterator": MapIteratorPrinter,
94646035553Spatrick            "__map_const_iterator": MapIteratorPrinter,
94746035553Spatrick            "__tree_iterator": SetIteratorPrinter,
94846035553Spatrick            "__tree_const_iterator": SetIteratorPrinter,
94946035553Spatrick            "fpos": StdFposPrinter,
95046035553Spatrick            "unordered_set": StdUnorderedSetPrinter,
95146035553Spatrick            "unordered_multiset": StdUnorderedSetPrinter,
95246035553Spatrick            "unordered_map": StdUnorderedMapPrinter,
95346035553Spatrick            "unordered_multimap": StdUnorderedMapPrinter,
95446035553Spatrick            "__hash_map_iterator": StdUnorderedMapIteratorPrinter,
95546035553Spatrick            "__hash_map_const_iterator": StdUnorderedMapIteratorPrinter,
95646035553Spatrick            "__hash_iterator": StdUnorderedSetIteratorPrinter,
95746035553Spatrick            "__hash_const_iterator": StdUnorderedSetIteratorPrinter,
95846035553Spatrick        }
95946035553Spatrick
96046035553Spatrick        self.subprinters = []
96146035553Spatrick        for name, subprinter in self.lookup.items():
96246035553Spatrick            # Subprinters and names are used only for the rarely used command "info
96346035553Spatrick            # pretty" (and related), so the name of the first data structure it prints
96446035553Spatrick            # is a reasonable choice.
96546035553Spatrick            if subprinter not in self.subprinters:
96646035553Spatrick                subprinter.name = name
96746035553Spatrick                self.subprinters.append(subprinter)
96846035553Spatrick
96946035553Spatrick    def __call__(self, val):
97046035553Spatrick        """Return the pretty printer for a val, if the type is supported."""
97146035553Spatrick
97246035553Spatrick        # Do not handle any type that is not a struct/class.
97346035553Spatrick        if val.type.strip_typedefs().code != gdb.TYPE_CODE_STRUCT:
97446035553Spatrick            return None
97546035553Spatrick
97646035553Spatrick        # Don't attempt types known to be inside libstdcxx.
97746035553Spatrick        typename = val.type.name or val.type.tag or str(val.type)
97846035553Spatrick        match = re.match("^std::(__.*?)::", typename)
979037e7968Spatrick        if match is not None and match.group(1) in ["__cxx1998",
98046035553Spatrick                                                    "__debug",
98146035553Spatrick                                                    "__7",
98246035553Spatrick                                                    "__g"]:
98346035553Spatrick            return None
98446035553Spatrick
98546035553Spatrick        # Handle any using declarations or other typedefs.
98646035553Spatrick        typename = _prettify_typename(val.type)
98746035553Spatrick        if not typename:
98846035553Spatrick            return None
98946035553Spatrick        without_generics = _remove_generics(typename)
99046035553Spatrick        lookup_name = _remove_std_prefix(without_generics)
99146035553Spatrick        if lookup_name in self.lookup:
99246035553Spatrick            return self.lookup[lookup_name](val)
99346035553Spatrick        return None
99446035553Spatrick
99546035553Spatrick
99646035553Spatrick_libcxx_printer_name = "libcxx_pretty_printer"
99746035553Spatrick
99846035553Spatrick
99946035553Spatrick# These are called for every binary object file, which could be thousands in
100046035553Spatrick# certain pathological cases. Limit our pretty printers to the progspace.
100146035553Spatrickdef _register_libcxx_printers(event):
100246035553Spatrick    progspace = event.new_objfile.progspace
100346035553Spatrick    # It would be ideal to get the endianness at print time, but
100446035553Spatrick    # gdb.execute clears gdb's internal wrap buffer, removing any values
100546035553Spatrick    # already generated as part of a larger data structure, and there is
100646035553Spatrick    # no python api to get the endianness. Mixed-endianness debugging
100746035553Spatrick    # rare enough that this workaround should be adequate.
100846035553Spatrick    _libcpp_big_endian = "big endian" in gdb.execute("show endian",
100946035553Spatrick                                                     to_string=True)
101046035553Spatrick
101146035553Spatrick    if not getattr(progspace, _libcxx_printer_name, False):
101246035553Spatrick        print("Loading libc++ pretty-printers.")
101346035553Spatrick        gdb.printing.register_pretty_printer(
101446035553Spatrick            progspace, LibcxxPrettyPrinter(_libcxx_printer_name))
101546035553Spatrick        setattr(progspace, _libcxx_printer_name, True)
101646035553Spatrick
101746035553Spatrick
101846035553Spatrickdef _unregister_libcxx_printers(event):
101946035553Spatrick    progspace = event.progspace
102046035553Spatrick    if getattr(progspace, _libcxx_printer_name, False):
102146035553Spatrick        for printer in progspace.pretty_printers:
102246035553Spatrick            if getattr(printer, "name", "none") == _libcxx_printer_name:
102346035553Spatrick                progspace.pretty_printers.remove(printer)
102446035553Spatrick                setattr(progspace, _libcxx_printer_name, False)
102546035553Spatrick                break
102646035553Spatrick
102746035553Spatrick
102846035553Spatrickdef register_libcxx_printer_loader():
102946035553Spatrick    """Register event handlers to load libc++ pretty-printers."""
103046035553Spatrick    gdb.events.new_objfile.connect(_register_libcxx_printers)
103146035553Spatrick    gdb.events.clear_objfiles.connect(_unregister_libcxx_printers)
1032