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