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