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