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