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