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