1# Pretty-printers for libstdc++. 2 3# Copyright (C) 2008-2018 Free Software Foundation, Inc. 4 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18import gdb 19import itertools 20import re 21import sys 22 23### Python 2 + Python 3 compatibility code 24 25# Resources about compatibility: 26# 27# * <http://pythonhosted.org/six/>: Documentation of the "six" module 28 29# FIXME: The handling of e.g. std::basic_string (at least on char) 30# probably needs updating to work with Python 3's new string rules. 31# 32# In particular, Python 3 has a separate type (called byte) for 33# bytestrings, and a special b"" syntax for the byte literals; the old 34# str() type has been redefined to always store Unicode text. 35# 36# We probably can't do much about this until this GDB PR is addressed: 37# <https://sourceware.org/bugzilla/show_bug.cgi?id=17138> 38 39if sys.version_info[0] > 2: 40 ### Python 3 stuff 41 Iterator = object 42 # Python 3 folds these into the normal functions. 43 imap = map 44 izip = zip 45 # Also, int subsumes long 46 long = int 47else: 48 ### Python 2 stuff 49 class Iterator: 50 """Compatibility mixin for iterators 51 52 Instead of writing next() methods for iterators, write 53 __next__() methods and use this mixin to make them work in 54 Python 2 as well as Python 3. 55 56 Idea stolen from the "six" documentation: 57 <http://pythonhosted.org/six/#six.Iterator> 58 """ 59 60 def next(self): 61 return self.__next__() 62 63 # In Python 2, we still need these from itertools 64 from itertools import imap, izip 65 66# Try to use the new-style pretty-printing if available. 67_use_gdb_pp = True 68try: 69 import gdb.printing 70except ImportError: 71 _use_gdb_pp = False 72 73# Try to install type-printers. 74_use_type_printing = False 75try: 76 import gdb.types 77 if hasattr(gdb.types, 'TypePrinter'): 78 _use_type_printing = True 79except ImportError: 80 pass 81 82# Starting with the type ORIG, search for the member type NAME. This 83# handles searching upward through superclasses. This is needed to 84# work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. 85def find_type(orig, name): 86 typ = orig.strip_typedefs() 87 while True: 88 # Strip cv-qualifiers. PR 67440. 89 search = '%s::%s' % (typ.unqualified(), name) 90 try: 91 return gdb.lookup_type(search) 92 except RuntimeError: 93 pass 94 # The type was not found, so try the superclass. We only need 95 # to check the first superclass, so we don't bother with 96 # anything fancier here. 97 field = typ.fields()[0] 98 if not field.is_base_class: 99 raise ValueError("Cannot find type %s::%s" % (str(orig), name)) 100 typ = field.type 101 102_versioned_namespace = '__8::' 103 104def is_specialization_of(type, template_name): 105 "Test if a type is a given template instantiation." 106 global _versioned_namespace 107 if _versioned_namespace: 108 return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), type) is not None 109 return re.match('^std::%s<.*>$' % template_name, type) is not None 110 111def strip_versioned_namespace(typename): 112 global _versioned_namespace 113 if _versioned_namespace: 114 return typename.replace(_versioned_namespace, '') 115 return typename 116 117def strip_inline_namespaces(type_str): 118 "Remove known inline namespaces from the canonical name of a type." 119 type_str = strip_versioned_namespace(type_str) 120 type_str = type_str.replace('std::__cxx11::', 'std::') 121 expt_ns = 'std::experimental::' 122 for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'): 123 type_str = type_str.replace(expt_ns+lfts_ns+'::', expt_ns) 124 fs_ns = expt_ns + 'filesystem::' 125 type_str = type_str.replace(fs_ns+'v1::', fs_ns) 126 return type_str 127 128def get_template_arg_list(type_obj): 129 "Return a type's template arguments as a list" 130 n = 0 131 template_args = [] 132 while True: 133 try: 134 template_args.append(type_obj.template_argument(n)) 135 except: 136 return template_args 137 n += 1 138 139class SmartPtrIterator(Iterator): 140 "An iterator for smart pointer types with a single 'child' value" 141 142 def __init__(self, val): 143 self.val = val 144 145 def __iter__(self): 146 return self 147 148 def __next__(self): 149 if self.val is None: 150 raise StopIteration 151 self.val, val = None, self.val 152 return ('get()', val) 153 154class SharedPointerPrinter: 155 "Print a shared_ptr or weak_ptr" 156 157 def __init__ (self, typename, val): 158 self.typename = strip_versioned_namespace(typename) 159 self.val = val 160 self.pointer = val['_M_ptr'] 161 162 def children (self): 163 return SmartPtrIterator(self.pointer) 164 165 def to_string (self): 166 state = 'empty' 167 refcounts = self.val['_M_refcount']['_M_pi'] 168 if refcounts != 0: 169 usecount = refcounts['_M_use_count'] 170 weakcount = refcounts['_M_weak_count'] 171 if usecount == 0: 172 state = 'expired, weak count %d' % weakcount 173 else: 174 state = 'use count %d, weak count %d' % (usecount, weakcount - 1) 175 return '%s<%s> (%s)' % (self.typename, str(self.val.type.template_argument(0)), state) 176 177class UniquePointerPrinter: 178 "Print a unique_ptr" 179 180 def __init__ (self, typename, val): 181 self.val = val 182 impl_type = val.type.fields()[0].type.tag 183 if is_specialization_of(impl_type, '__uniq_ptr_impl'): # New implementation 184 self.pointer = val['_M_t']['_M_t']['_M_head_impl'] 185 elif is_specialization_of(impl_type, 'tuple'): 186 self.pointer = val['_M_t']['_M_head_impl'] 187 else: 188 raise ValueError("Unsupported implementation for unique_ptr: %s" % impl_type) 189 190 def children (self): 191 return SmartPtrIterator(self.pointer) 192 193 def to_string (self): 194 return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0)))) 195 196def get_value_from_aligned_membuf(buf, valtype): 197 """Returns the value held in a __gnu_cxx::__aligned_membuf.""" 198 return buf['_M_storage'].address.cast(valtype.pointer()).dereference() 199 200def get_value_from_list_node(node): 201 """Returns the value held in an _List_node<_Val>""" 202 try: 203 member = node.type.fields()[1].name 204 if member == '_M_data': 205 # C++03 implementation, node contains the value as a member 206 return node['_M_data'] 207 elif member == '_M_storage': 208 # C++11 implementation, node stores value in __aligned_membuf 209 valtype = node.type.template_argument(0) 210 return get_value_from_aligned_membuf(node['_M_storage'], valtype) 211 except: 212 pass 213 raise ValueError("Unsupported implementation for %s" % str(node.type)) 214 215class StdListPrinter: 216 "Print a std::list" 217 218 class _iterator(Iterator): 219 def __init__(self, nodetype, head): 220 self.nodetype = nodetype 221 self.base = head['_M_next'] 222 self.head = head.address 223 self.count = 0 224 225 def __iter__(self): 226 return self 227 228 def __next__(self): 229 if self.base == self.head: 230 raise StopIteration 231 elt = self.base.cast(self.nodetype).dereference() 232 self.base = elt['_M_next'] 233 count = self.count 234 self.count = self.count + 1 235 val = get_value_from_list_node(elt) 236 return ('[%d]' % count, val) 237 238 def __init__(self, typename, val): 239 self.typename = strip_versioned_namespace(typename) 240 self.val = val 241 242 def children(self): 243 nodetype = find_type(self.val.type, '_Node') 244 nodetype = nodetype.strip_typedefs().pointer() 245 return self._iterator(nodetype, self.val['_M_impl']['_M_node']) 246 247 def to_string(self): 248 if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']: 249 return 'empty %s' % (self.typename) 250 return '%s' % (self.typename) 251 252class NodeIteratorPrinter: 253 def __init__(self, typename, val, contname): 254 self.val = val 255 self.typename = typename 256 self.contname = contname 257 258 def to_string(self): 259 if not self.val['_M_node']: 260 return 'non-dereferenceable iterator for std::%s' % (self.contname) 261 nodetype = find_type(self.val.type, '_Node') 262 nodetype = nodetype.strip_typedefs().pointer() 263 node = self.val['_M_node'].cast(nodetype).dereference() 264 return str(get_value_from_list_node(node)) 265 266class StdListIteratorPrinter(NodeIteratorPrinter): 267 "Print std::list::iterator" 268 269 def __init__(self, typename, val): 270 NodeIteratorPrinter.__init__(self, typename, val, 'list') 271 272class StdFwdListIteratorPrinter(NodeIteratorPrinter): 273 "Print std::forward_list::iterator" 274 275 def __init__(self, typename, val): 276 NodeIteratorPrinter.__init__(self, typename, val, 'forward_list') 277 278class StdSlistPrinter: 279 "Print a __gnu_cxx::slist" 280 281 class _iterator(Iterator): 282 def __init__(self, nodetype, head): 283 self.nodetype = nodetype 284 self.base = head['_M_head']['_M_next'] 285 self.count = 0 286 287 def __iter__(self): 288 return self 289 290 def __next__(self): 291 if self.base == 0: 292 raise StopIteration 293 elt = self.base.cast(self.nodetype).dereference() 294 self.base = elt['_M_next'] 295 count = self.count 296 self.count = self.count + 1 297 return ('[%d]' % count, elt['_M_data']) 298 299 def __init__(self, typename, val): 300 self.val = val 301 302 def children(self): 303 nodetype = find_type(self.val.type, '_Node') 304 nodetype = nodetype.strip_typedefs().pointer() 305 return self._iterator(nodetype, self.val) 306 307 def to_string(self): 308 if self.val['_M_head']['_M_next'] == 0: 309 return 'empty __gnu_cxx::slist' 310 return '__gnu_cxx::slist' 311 312class StdSlistIteratorPrinter: 313 "Print __gnu_cxx::slist::iterator" 314 315 def __init__(self, typename, val): 316 self.val = val 317 318 def to_string(self): 319 if not self.val['_M_node']: 320 return 'non-dereferenceable iterator for __gnu_cxx::slist' 321 nodetype = find_type(self.val.type, '_Node') 322 nodetype = nodetype.strip_typedefs().pointer() 323 return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data']) 324 325class StdVectorPrinter: 326 "Print a std::vector" 327 328 class _iterator(Iterator): 329 def __init__ (self, start, finish, bitvec): 330 self.bitvec = bitvec 331 if bitvec: 332 self.item = start['_M_p'] 333 self.so = start['_M_offset'] 334 self.finish = finish['_M_p'] 335 self.fo = finish['_M_offset'] 336 itype = self.item.dereference().type 337 self.isize = 8 * itype.sizeof 338 else: 339 self.item = start 340 self.finish = finish 341 self.count = 0 342 343 def __iter__(self): 344 return self 345 346 def __next__(self): 347 count = self.count 348 self.count = self.count + 1 349 if self.bitvec: 350 if self.item == self.finish and self.so >= self.fo: 351 raise StopIteration 352 elt = self.item.dereference() 353 if elt & (1 << self.so): 354 obit = 1 355 else: 356 obit = 0 357 self.so = self.so + 1 358 if self.so >= self.isize: 359 self.item = self.item + 1 360 self.so = 0 361 return ('[%d]' % count, obit) 362 else: 363 if self.item == self.finish: 364 raise StopIteration 365 elt = self.item.dereference() 366 self.item = self.item + 1 367 return ('[%d]' % count, elt) 368 369 def __init__(self, typename, val): 370 self.typename = strip_versioned_namespace(typename) 371 self.val = val 372 self.is_bool = val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL 373 374 def children(self): 375 return self._iterator(self.val['_M_impl']['_M_start'], 376 self.val['_M_impl']['_M_finish'], 377 self.is_bool) 378 379 def to_string(self): 380 start = self.val['_M_impl']['_M_start'] 381 finish = self.val['_M_impl']['_M_finish'] 382 end = self.val['_M_impl']['_M_end_of_storage'] 383 if self.is_bool: 384 start = self.val['_M_impl']['_M_start']['_M_p'] 385 so = self.val['_M_impl']['_M_start']['_M_offset'] 386 finish = self.val['_M_impl']['_M_finish']['_M_p'] 387 fo = self.val['_M_impl']['_M_finish']['_M_offset'] 388 itype = start.dereference().type 389 bl = 8 * itype.sizeof 390 length = (bl - so) + bl * ((finish - start) - 1) + fo 391 capacity = bl * (end - start) 392 return ('%s<bool> of length %d, capacity %d' 393 % (self.typename, int (length), int (capacity))) 394 else: 395 return ('%s of length %d, capacity %d' 396 % (self.typename, int (finish - start), int (end - start))) 397 398 def display_hint(self): 399 return 'array' 400 401class StdVectorIteratorPrinter: 402 "Print std::vector::iterator" 403 404 def __init__(self, typename, val): 405 self.val = val 406 407 def to_string(self): 408 if not self.val['_M_current']: 409 return 'non-dereferenceable iterator for std::vector' 410 return str(self.val['_M_current'].dereference()) 411 412class StdTuplePrinter: 413 "Print a std::tuple" 414 415 class _iterator(Iterator): 416 def __init__ (self, head): 417 self.head = head 418 419 # Set the base class as the initial head of the 420 # tuple. 421 nodes = self.head.type.fields () 422 if len (nodes) == 1: 423 # Set the actual head to the first pair. 424 self.head = self.head.cast (nodes[0].type) 425 elif len (nodes) != 0: 426 raise ValueError("Top of tuple tree does not consist of a single node.") 427 self.count = 0 428 429 def __iter__ (self): 430 return self 431 432 def __next__ (self): 433 # Check for further recursions in the inheritance tree. 434 # For a GCC 5+ tuple self.head is None after visiting all nodes: 435 if not self.head: 436 raise StopIteration 437 nodes = self.head.type.fields () 438 # For a GCC 4.x tuple there is a final node with no fields: 439 if len (nodes) == 0: 440 raise StopIteration 441 # Check that this iteration has an expected structure. 442 if len (nodes) > 2: 443 raise ValueError("Cannot parse more than 2 nodes in a tuple tree.") 444 445 if len (nodes) == 1: 446 # This is the last node of a GCC 5+ std::tuple. 447 impl = self.head.cast (nodes[0].type) 448 self.head = None 449 else: 450 # Either a node before the last node, or the last node of 451 # a GCC 4.x tuple (which has an empty parent). 452 453 # - Left node is the next recursion parent. 454 # - Right node is the actual class contained in the tuple. 455 456 # Process right node. 457 impl = self.head.cast (nodes[1].type) 458 459 # Process left node and set it as head. 460 self.head = self.head.cast (nodes[0].type) 461 462 self.count = self.count + 1 463 464 # Finally, check the implementation. If it is 465 # wrapped in _M_head_impl return that, otherwise return 466 # the value "as is". 467 fields = impl.type.fields () 468 if len (fields) < 1 or fields[0].name != "_M_head_impl": 469 return ('[%d]' % self.count, impl) 470 else: 471 return ('[%d]' % self.count, impl['_M_head_impl']) 472 473 def __init__ (self, typename, val): 474 self.typename = strip_versioned_namespace(typename) 475 self.val = val; 476 477 def children (self): 478 return self._iterator (self.val) 479 480 def to_string (self): 481 if len (self.val.type.fields ()) == 0: 482 return 'empty %s' % (self.typename) 483 return '%s containing' % (self.typename) 484 485class StdStackOrQueuePrinter: 486 "Print a std::stack or std::queue" 487 488 def __init__ (self, typename, val): 489 self.typename = strip_versioned_namespace(typename) 490 self.visualizer = gdb.default_visualizer(val['c']) 491 492 def children (self): 493 return self.visualizer.children() 494 495 def to_string (self): 496 return '%s wrapping: %s' % (self.typename, 497 self.visualizer.to_string()) 498 499 def display_hint (self): 500 if hasattr (self.visualizer, 'display_hint'): 501 return self.visualizer.display_hint () 502 return None 503 504class RbtreeIterator(Iterator): 505 """ 506 Turn an RB-tree-based container (std::map, std::set etc.) into 507 a Python iterable object. 508 """ 509 510 def __init__(self, rbtree): 511 self.size = rbtree['_M_t']['_M_impl']['_M_node_count'] 512 self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] 513 self.count = 0 514 515 def __iter__(self): 516 return self 517 518 def __len__(self): 519 return int (self.size) 520 521 def __next__(self): 522 if self.count == self.size: 523 raise StopIteration 524 result = self.node 525 self.count = self.count + 1 526 if self.count < self.size: 527 # Compute the next node. 528 node = self.node 529 if node.dereference()['_M_right']: 530 node = node.dereference()['_M_right'] 531 while node.dereference()['_M_left']: 532 node = node.dereference()['_M_left'] 533 else: 534 parent = node.dereference()['_M_parent'] 535 while node == parent.dereference()['_M_right']: 536 node = parent 537 parent = parent.dereference()['_M_parent'] 538 if node.dereference()['_M_right'] != parent: 539 node = parent 540 self.node = node 541 return result 542 543def get_value_from_Rb_tree_node(node): 544 """Returns the value held in an _Rb_tree_node<_Val>""" 545 try: 546 member = node.type.fields()[1].name 547 if member == '_M_value_field': 548 # C++03 implementation, node contains the value as a member 549 return node['_M_value_field'] 550 elif member == '_M_storage': 551 # C++11 implementation, node stores value in __aligned_membuf 552 valtype = node.type.template_argument(0) 553 return get_value_from_aligned_membuf(node['_M_storage'], valtype) 554 except: 555 pass 556 raise ValueError("Unsupported implementation for %s" % str(node.type)) 557 558# This is a pretty printer for std::_Rb_tree_iterator (which is 559# std::map::iterator), and has nothing to do with the RbtreeIterator 560# class above. 561class StdRbtreeIteratorPrinter: 562 "Print std::map::iterator, std::set::iterator, etc." 563 564 def __init__ (self, typename, val): 565 self.val = val 566 valtype = self.val.type.template_argument(0).strip_typedefs() 567 nodetype = '_Rb_tree_node<' + str(valtype) + '>' 568 if _versioned_namespace and typename.startswith('std::' + _versioned_namespace): 569 nodetype = _versioned_namespace + nodetype 570 nodetype = gdb.lookup_type('std::' + nodetype) 571 self.link_type = nodetype.strip_typedefs().pointer() 572 573 def to_string (self): 574 if not self.val['_M_node']: 575 return 'non-dereferenceable iterator for associative container' 576 node = self.val['_M_node'].cast(self.link_type).dereference() 577 return str(get_value_from_Rb_tree_node(node)) 578 579class StdDebugIteratorPrinter: 580 "Print a debug enabled version of an iterator" 581 582 def __init__ (self, typename, val): 583 self.val = val 584 585 # Just strip away the encapsulating __gnu_debug::_Safe_iterator 586 # and return the wrapped iterator value. 587 def to_string (self): 588 base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base') 589 itype = self.val.type.template_argument(0) 590 safe_seq = self.val.cast(base_type)['_M_sequence'] 591 if not safe_seq: 592 return str(self.val.cast(itype)) 593 if self.val['_M_version'] != safe_seq['_M_version']: 594 return "invalid iterator" 595 return str(self.val.cast(itype)) 596 597def num_elements(num): 598 """Return either "1 element" or "N elements" depending on the argument.""" 599 return '1 element' if num == 1 else '%d elements' % num 600 601class StdMapPrinter: 602 "Print a std::map or std::multimap" 603 604 # Turn an RbtreeIterator into a pretty-print iterator. 605 class _iter(Iterator): 606 def __init__(self, rbiter, type): 607 self.rbiter = rbiter 608 self.count = 0 609 self.type = type 610 611 def __iter__(self): 612 return self 613 614 def __next__(self): 615 if self.count % 2 == 0: 616 n = next(self.rbiter) 617 n = n.cast(self.type).dereference() 618 n = get_value_from_Rb_tree_node(n) 619 self.pair = n 620 item = n['first'] 621 else: 622 item = self.pair['second'] 623 result = ('[%d]' % self.count, item) 624 self.count = self.count + 1 625 return result 626 627 def __init__ (self, typename, val): 628 self.typename = strip_versioned_namespace(typename) 629 self.val = val 630 631 def to_string (self): 632 return '%s with %s' % (self.typename, 633 num_elements(len(RbtreeIterator (self.val)))) 634 635 def children (self): 636 rep_type = find_type(self.val.type, '_Rep_type') 637 node = find_type(rep_type, '_Link_type') 638 node = node.strip_typedefs() 639 return self._iter (RbtreeIterator (self.val), node) 640 641 def display_hint (self): 642 return 'map' 643 644class StdSetPrinter: 645 "Print a std::set or std::multiset" 646 647 # Turn an RbtreeIterator into a pretty-print iterator. 648 class _iter(Iterator): 649 def __init__(self, rbiter, type): 650 self.rbiter = rbiter 651 self.count = 0 652 self.type = type 653 654 def __iter__(self): 655 return self 656 657 def __next__(self): 658 item = next(self.rbiter) 659 item = item.cast(self.type).dereference() 660 item = get_value_from_Rb_tree_node(item) 661 # FIXME: this is weird ... what to do? 662 # Maybe a 'set' display hint? 663 result = ('[%d]' % self.count, item) 664 self.count = self.count + 1 665 return result 666 667 def __init__ (self, typename, val): 668 self.typename = strip_versioned_namespace(typename) 669 self.val = val 670 671 def to_string (self): 672 return '%s with %s' % (self.typename, 673 num_elements(len(RbtreeIterator (self.val)))) 674 675 def children (self): 676 rep_type = find_type(self.val.type, '_Rep_type') 677 node = find_type(rep_type, '_Link_type') 678 node = node.strip_typedefs() 679 return self._iter (RbtreeIterator (self.val), node) 680 681class StdBitsetPrinter: 682 "Print a std::bitset" 683 684 def __init__(self, typename, val): 685 self.typename = strip_versioned_namespace(typename) 686 self.val = val 687 688 def to_string (self): 689 # If template_argument handled values, we could print the 690 # size. Or we could use a regexp on the type. 691 return '%s' % (self.typename) 692 693 def children (self): 694 try: 695 # An empty bitset may not have any members which will 696 # result in an exception being thrown. 697 words = self.val['_M_w'] 698 except: 699 return [] 700 701 wtype = words.type 702 703 # The _M_w member can be either an unsigned long, or an 704 # array. This depends on the template specialization used. 705 # If it is a single long, convert to a single element list. 706 if wtype.code == gdb.TYPE_CODE_ARRAY: 707 tsize = wtype.target ().sizeof 708 else: 709 words = [words] 710 tsize = wtype.sizeof 711 712 nwords = wtype.sizeof / tsize 713 result = [] 714 byte = 0 715 while byte < nwords: 716 w = words[byte] 717 bit = 0 718 while w != 0: 719 if (w & 1) != 0: 720 # Another spot where we could use 'set'? 721 result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) 722 bit = bit + 1 723 w = w >> 1 724 byte = byte + 1 725 return result 726 727class StdDequePrinter: 728 "Print a std::deque" 729 730 class _iter(Iterator): 731 def __init__(self, node, start, end, last, buffer_size): 732 self.node = node 733 self.p = start 734 self.end = end 735 self.last = last 736 self.buffer_size = buffer_size 737 self.count = 0 738 739 def __iter__(self): 740 return self 741 742 def __next__(self): 743 if self.p == self.last: 744 raise StopIteration 745 746 result = ('[%d]' % self.count, self.p.dereference()) 747 self.count = self.count + 1 748 749 # Advance the 'cur' pointer. 750 self.p = self.p + 1 751 if self.p == self.end: 752 # If we got to the end of this bucket, move to the 753 # next bucket. 754 self.node = self.node + 1 755 self.p = self.node[0] 756 self.end = self.p + self.buffer_size 757 758 return result 759 760 def __init__(self, typename, val): 761 self.typename = strip_versioned_namespace(typename) 762 self.val = val 763 self.elttype = val.type.template_argument(0) 764 size = self.elttype.sizeof 765 if size < 512: 766 self.buffer_size = int (512 / size) 767 else: 768 self.buffer_size = 1 769 770 def to_string(self): 771 start = self.val['_M_impl']['_M_start'] 772 end = self.val['_M_impl']['_M_finish'] 773 774 delta_n = end['_M_node'] - start['_M_node'] - 1 775 delta_s = start['_M_last'] - start['_M_cur'] 776 delta_e = end['_M_cur'] - end['_M_first'] 777 778 size = self.buffer_size * delta_n + delta_s + delta_e 779 780 return '%s with %s' % (self.typename, num_elements(long(size))) 781 782 def children(self): 783 start = self.val['_M_impl']['_M_start'] 784 end = self.val['_M_impl']['_M_finish'] 785 return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], 786 end['_M_cur'], self.buffer_size) 787 788 def display_hint (self): 789 return 'array' 790 791class StdDequeIteratorPrinter: 792 "Print std::deque::iterator" 793 794 def __init__(self, typename, val): 795 self.val = val 796 797 def to_string(self): 798 if not self.val['_M_cur']: 799 return 'non-dereferenceable iterator for std::deque' 800 return str(self.val['_M_cur'].dereference()) 801 802class StdStringPrinter: 803 "Print a std::basic_string of some kind" 804 805 def __init__(self, typename, val): 806 self.val = val 807 self.new_string = typename.find("::__cxx11::basic_string") != -1 808 809 def to_string(self): 810 # Make sure &string works, too. 811 type = self.val.type 812 if type.code == gdb.TYPE_CODE_REF: 813 type = type.target () 814 815 # Calculate the length of the string so that to_string returns 816 # the string according to length, not according to first null 817 # encountered. 818 ptr = self.val ['_M_dataplus']['_M_p'] 819 if self.new_string: 820 length = self.val['_M_string_length'] 821 # https://sourceware.org/bugzilla/show_bug.cgi?id=17728 822 ptr = ptr.cast(ptr.type.strip_typedefs()) 823 else: 824 realtype = type.unqualified ().strip_typedefs () 825 reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer () 826 header = ptr.cast(reptype) - 1 827 length = header.dereference ()['_M_length'] 828 if hasattr(ptr, "lazy_string"): 829 return ptr.lazy_string (length = length) 830 return ptr.string (length = length) 831 832 def display_hint (self): 833 return 'string' 834 835class Tr1HashtableIterator(Iterator): 836 def __init__ (self, hash): 837 self.buckets = hash['_M_buckets'] 838 self.bucket = 0 839 self.bucket_count = hash['_M_bucket_count'] 840 self.node_type = find_type(hash.type, '_Node').pointer() 841 self.node = 0 842 while self.bucket != self.bucket_count: 843 self.node = self.buckets[self.bucket] 844 if self.node: 845 break 846 self.bucket = self.bucket + 1 847 848 def __iter__ (self): 849 return self 850 851 def __next__ (self): 852 if self.node == 0: 853 raise StopIteration 854 node = self.node.cast(self.node_type) 855 result = node.dereference()['_M_v'] 856 self.node = node.dereference()['_M_next']; 857 if self.node == 0: 858 self.bucket = self.bucket + 1 859 while self.bucket != self.bucket_count: 860 self.node = self.buckets[self.bucket] 861 if self.node: 862 break 863 self.bucket = self.bucket + 1 864 return result 865 866class StdHashtableIterator(Iterator): 867 def __init__(self, hash): 868 self.node = hash['_M_before_begin']['_M_nxt'] 869 self.node_type = find_type(hash.type, '__node_type').pointer() 870 871 def __iter__(self): 872 return self 873 874 def __next__(self): 875 if self.node == 0: 876 raise StopIteration 877 elt = self.node.cast(self.node_type).dereference() 878 self.node = elt['_M_nxt'] 879 valptr = elt['_M_storage'].address 880 valptr = valptr.cast(elt.type.template_argument(0).pointer()) 881 return valptr.dereference() 882 883class Tr1UnorderedSetPrinter: 884 "Print a tr1::unordered_set" 885 886 def __init__ (self, typename, val): 887 self.typename = strip_versioned_namespace(typename) 888 self.val = val 889 890 def hashtable (self): 891 if self.typename.startswith('std::tr1'): 892 return self.val 893 return self.val['_M_h'] 894 895 def to_string (self): 896 count = self.hashtable()['_M_element_count'] 897 return '%s with %s' % (self.typename, num_elements(count)) 898 899 @staticmethod 900 def format_count (i): 901 return '[%d]' % i 902 903 def children (self): 904 counter = imap (self.format_count, itertools.count()) 905 if self.typename.startswith('std::tr1'): 906 return izip (counter, Tr1HashtableIterator (self.hashtable())) 907 return izip (counter, StdHashtableIterator (self.hashtable())) 908 909class Tr1UnorderedMapPrinter: 910 "Print a tr1::unordered_map" 911 912 def __init__ (self, typename, val): 913 self.typename = strip_versioned_namespace(typename) 914 self.val = val 915 916 def hashtable (self): 917 if self.typename.startswith('std::tr1'): 918 return self.val 919 return self.val['_M_h'] 920 921 def to_string (self): 922 count = self.hashtable()['_M_element_count'] 923 return '%s with %s' % (self.typename, num_elements(count)) 924 925 @staticmethod 926 def flatten (list): 927 for elt in list: 928 for i in elt: 929 yield i 930 931 @staticmethod 932 def format_one (elt): 933 return (elt['first'], elt['second']) 934 935 @staticmethod 936 def format_count (i): 937 return '[%d]' % i 938 939 def children (self): 940 counter = imap (self.format_count, itertools.count()) 941 # Map over the hash table and flatten the result. 942 if self.typename.startswith('std::tr1'): 943 data = self.flatten (imap (self.format_one, Tr1HashtableIterator (self.hashtable()))) 944 # Zip the two iterators together. 945 return izip (counter, data) 946 data = self.flatten (imap (self.format_one, StdHashtableIterator (self.hashtable()))) 947 # Zip the two iterators together. 948 return izip (counter, data) 949 950 def display_hint (self): 951 return 'map' 952 953class StdForwardListPrinter: 954 "Print a std::forward_list" 955 956 class _iterator(Iterator): 957 def __init__(self, nodetype, head): 958 self.nodetype = nodetype 959 self.base = head['_M_next'] 960 self.count = 0 961 962 def __iter__(self): 963 return self 964 965 def __next__(self): 966 if self.base == 0: 967 raise StopIteration 968 elt = self.base.cast(self.nodetype).dereference() 969 self.base = elt['_M_next'] 970 count = self.count 971 self.count = self.count + 1 972 valptr = elt['_M_storage'].address 973 valptr = valptr.cast(elt.type.template_argument(0).pointer()) 974 return ('[%d]' % count, valptr.dereference()) 975 976 def __init__(self, typename, val): 977 self.val = val 978 self.typename = strip_versioned_namespace(typename) 979 980 def children(self): 981 nodetype = find_type(self.val.type, '_Node') 982 nodetype = nodetype.strip_typedefs().pointer() 983 return self._iterator(nodetype, self.val['_M_impl']['_M_head']) 984 985 def to_string(self): 986 if self.val['_M_impl']['_M_head']['_M_next'] == 0: 987 return 'empty %s' % self.typename 988 return '%s' % self.typename 989 990class SingleObjContainerPrinter(object): 991 "Base class for printers of containers of single objects" 992 993 def __init__ (self, val, viz, hint = None): 994 self.contained_value = val 995 self.visualizer = viz 996 self.hint = hint 997 998 def _recognize(self, type): 999 """Return TYPE as a string after applying type printers""" 1000 global _use_type_printing 1001 if not _use_type_printing: 1002 return str(type) 1003 return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(), 1004 type) or str(type) 1005 1006 class _contained(Iterator): 1007 def __init__ (self, val): 1008 self.val = val 1009 1010 def __iter__ (self): 1011 return self 1012 1013 def __next__(self): 1014 if self.val is None: 1015 raise StopIteration 1016 retval = self.val 1017 self.val = None 1018 return ('[contained value]', retval) 1019 1020 def children (self): 1021 if self.contained_value is None: 1022 return self._contained (None) 1023 if hasattr (self.visualizer, 'children'): 1024 return self.visualizer.children () 1025 return self._contained (self.contained_value) 1026 1027 def display_hint (self): 1028 # if contained value is a map we want to display in the same way 1029 if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'): 1030 return self.visualizer.display_hint () 1031 return self.hint 1032 1033class StdExpAnyPrinter(SingleObjContainerPrinter): 1034 "Print a std::any or std::experimental::any" 1035 1036 def __init__ (self, typename, val): 1037 self.typename = strip_versioned_namespace(typename) 1038 self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', self.typename, 1) 1039 self.val = val 1040 self.contained_type = None 1041 contained_value = None 1042 visualizer = None 1043 mgr = self.val['_M_manager'] 1044 if mgr != 0: 1045 func = gdb.block_for_pc(int(mgr.cast(gdb.lookup_type('intptr_t')))) 1046 if not func: 1047 raise ValueError("Invalid function pointer in %s" % self.typename) 1048 rx = r"""({0}::_Manager_\w+<.*>)::_S_manage""".format(typename) 1049 m = re.match(rx, func.function.name) 1050 if not m: 1051 raise ValueError("Unknown manager function in %s" % self.typename) 1052 1053 mgrname = m.group(1) 1054 # FIXME need to expand 'std::string' so that gdb.lookup_type works 1055 if 'std::string' in mgrname: 1056 mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1)) 1057 1058 mgrtype = gdb.lookup_type(mgrname) 1059 self.contained_type = mgrtype.template_argument(0) 1060 valptr = None 1061 if '::_Manager_internal' in mgrname: 1062 valptr = self.val['_M_storage']['_M_buffer'].address 1063 elif '::_Manager_external' in mgrname: 1064 valptr = self.val['_M_storage']['_M_ptr'] 1065 else: 1066 raise ValueError("Unknown manager function in %s" % self.typename) 1067 contained_value = valptr.cast(self.contained_type.pointer()).dereference() 1068 visualizer = gdb.default_visualizer(contained_value) 1069 super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer) 1070 1071 def to_string (self): 1072 if self.contained_type is None: 1073 return '%s [no contained value]' % self.typename 1074 desc = "%s containing " % self.typename 1075 if hasattr (self.visualizer, 'children'): 1076 return desc + self.visualizer.to_string () 1077 valtype = self._recognize (self.contained_type) 1078 return desc + strip_versioned_namespace(str(valtype)) 1079 1080class StdExpOptionalPrinter(SingleObjContainerPrinter): 1081 "Print a std::optional or std::experimental::optional" 1082 1083 def __init__ (self, typename, val): 1084 valtype = self._recognize (val.type.template_argument(0)) 1085 self.typename = strip_versioned_namespace(typename) 1086 self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, self.typename, 1) 1087 if not self.typename.startswith('std::experimental'): 1088 val = val['_M_payload'] 1089 self.val = val 1090 contained_value = val['_M_payload'] if self.val['_M_engaged'] else None 1091 visualizer = gdb.default_visualizer (val['_M_payload']) 1092 super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer) 1093 1094 def to_string (self): 1095 if self.contained_value is None: 1096 return "%s [no contained value]" % self.typename 1097 if hasattr (self.visualizer, 'children'): 1098 return "%s containing %s" % (self.typename, 1099 self.visualizer.to_string()) 1100 return self.typename 1101 1102class StdVariantPrinter(SingleObjContainerPrinter): 1103 "Print a std::variant" 1104 1105 def __init__(self, typename, val): 1106 alternatives = get_template_arg_list(val.type) 1107 self.typename = strip_versioned_namespace(typename) 1108 self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives])) 1109 self.index = val['_M_index'] 1110 if self.index >= len(alternatives): 1111 self.contained_type = None 1112 contained_value = None 1113 visualizer = None 1114 else: 1115 self.contained_type = alternatives[int(self.index)] 1116 addr = val['_M_u']['_M_first']['_M_storage'].address 1117 contained_value = addr.cast(self.contained_type.pointer()).dereference() 1118 visualizer = gdb.default_visualizer(contained_value) 1119 super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array') 1120 1121 def to_string(self): 1122 if self.contained_value is None: 1123 return "%s [no contained value]" % self.typename 1124 if hasattr(self.visualizer, 'children'): 1125 return "%s [index %d] containing %s" % (self.typename, self.index, 1126 self.visualizer.to_string()) 1127 return "%s [index %d]" % (self.typename, self.index) 1128 1129class StdNodeHandlePrinter(SingleObjContainerPrinter): 1130 "Print a container node handle" 1131 1132 def __init__(self, typename, val): 1133 self.value_type = val.type.template_argument(1) 1134 nodetype = val.type.template_argument(2).template_argument(0) 1135 self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node') 1136 self.is_map_node = val.type.template_argument(0) != self.value_type 1137 nodeptr = val['_M_ptr'] 1138 if nodeptr: 1139 if self.is_rb_tree_node: 1140 contained_value = get_value_from_Rb_tree_node(nodeptr.dereference()) 1141 else: 1142 contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'], 1143 self.value_type) 1144 visualizer = gdb.default_visualizer(contained_value) 1145 else: 1146 contained_value = None 1147 visualizer = None 1148 optalloc = val['_M_alloc'] 1149 self.alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None 1150 super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer, 1151 'array') 1152 1153 def to_string(self): 1154 desc = 'node handle for ' 1155 if not self.is_rb_tree_node: 1156 desc += 'unordered ' 1157 if self.is_map_node: 1158 desc += 'map'; 1159 else: 1160 desc += 'set'; 1161 1162 if self.contained_value: 1163 desc += ' with element' 1164 if hasattr(self.visualizer, 'children'): 1165 return "%s = %s" % (desc, self.visualizer.to_string()) 1166 return desc 1167 else: 1168 return 'empty %s' % desc 1169 1170class StdExpStringViewPrinter: 1171 "Print a std::basic_string_view or std::experimental::basic_string_view" 1172 1173 def __init__ (self, typename, val): 1174 self.val = val 1175 1176 def to_string (self): 1177 ptr = self.val['_M_str'] 1178 len = self.val['_M_len'] 1179 if hasattr (ptr, "lazy_string"): 1180 return ptr.lazy_string (length = len) 1181 return ptr.string (length = len) 1182 1183 def display_hint (self): 1184 return 'string' 1185 1186class StdExpPathPrinter: 1187 "Print a std::experimental::filesystem::path" 1188 1189 def __init__ (self, typename, val): 1190 self.val = val 1191 start = self.val['_M_cmpts']['_M_impl']['_M_start'] 1192 finish = self.val['_M_cmpts']['_M_impl']['_M_finish'] 1193 self.num_cmpts = int (finish - start) 1194 1195 def _path_type(self): 1196 t = str(self.val['_M_type']) 1197 if t[-9:] == '_Root_dir': 1198 return "root-directory" 1199 if t[-10:] == '_Root_name': 1200 return "root-name" 1201 return None 1202 1203 def to_string (self): 1204 path = "%s" % self.val ['_M_pathname'] 1205 if self.num_cmpts == 0: 1206 t = self._path_type() 1207 if t: 1208 path = '%s [%s]' % (path, t) 1209 return "filesystem::path %s" % path 1210 1211 class _iterator(Iterator): 1212 def __init__(self, cmpts): 1213 self.item = cmpts['_M_impl']['_M_start'] 1214 self.finish = cmpts['_M_impl']['_M_finish'] 1215 self.count = 0 1216 1217 def __iter__(self): 1218 return self 1219 1220 def __next__(self): 1221 if self.item == self.finish: 1222 raise StopIteration 1223 item = self.item.dereference() 1224 count = self.count 1225 self.count = self.count + 1 1226 self.item = self.item + 1 1227 path = item['_M_pathname'] 1228 t = StdExpPathPrinter(item.type.name, item)._path_type() 1229 if not t: 1230 t = count 1231 return ('[%s]' % t, path) 1232 1233 def children(self): 1234 return self._iterator(self.val['_M_cmpts']) 1235 1236 1237class StdPairPrinter: 1238 "Print a std::pair object, with 'first' and 'second' as children" 1239 1240 def __init__(self, typename, val): 1241 self.val = val 1242 1243 class _iter(Iterator): 1244 "An iterator for std::pair types. Returns 'first' then 'second'." 1245 1246 def __init__(self, val): 1247 self.val = val 1248 self.which = 'first' 1249 1250 def __iter__(self): 1251 return self 1252 1253 def __next__(self): 1254 if self.which is None: 1255 raise StopIteration 1256 which = self.which 1257 if which == 'first': 1258 self.which = 'second' 1259 else: 1260 self.which = None 1261 return (which, self.val[which]) 1262 1263 def children(self): 1264 return self._iter(self.val) 1265 1266 def to_string(self): 1267 return None 1268 1269 1270# A "regular expression" printer which conforms to the 1271# "SubPrettyPrinter" protocol from gdb.printing. 1272class RxPrinter(object): 1273 def __init__(self, name, function): 1274 super(RxPrinter, self).__init__() 1275 self.name = name 1276 self.function = function 1277 self.enabled = True 1278 1279 def invoke(self, value): 1280 if not self.enabled: 1281 return None 1282 1283 if value.type.code == gdb.TYPE_CODE_REF: 1284 if hasattr(gdb.Value,"referenced_value"): 1285 value = value.referenced_value() 1286 1287 return self.function(self.name, value) 1288 1289# A pretty-printer that conforms to the "PrettyPrinter" protocol from 1290# gdb.printing. It can also be used directly as an old-style printer. 1291class Printer(object): 1292 def __init__(self, name): 1293 super(Printer, self).__init__() 1294 self.name = name 1295 self.subprinters = [] 1296 self.lookup = {} 1297 self.enabled = True 1298 self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$') 1299 1300 def add(self, name, function): 1301 # A small sanity check. 1302 # FIXME 1303 if not self.compiled_rx.match(name): 1304 raise ValueError('libstdc++ programming error: "%s" does not match' % name) 1305 printer = RxPrinter(name, function) 1306 self.subprinters.append(printer) 1307 self.lookup[name] = printer 1308 1309 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION. 1310 def add_version(self, base, name, function): 1311 self.add(base + name, function) 1312 if _versioned_namespace: 1313 vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % _versioned_namespace, base) 1314 self.add(vbase + name, function) 1315 1316 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER. 1317 def add_container(self, base, name, function): 1318 self.add_version(base, name, function) 1319 self.add_version(base + '__cxx1998::', name, function) 1320 1321 @staticmethod 1322 def get_basic_type(type): 1323 # If it points to a reference, get the reference. 1324 if type.code == gdb.TYPE_CODE_REF: 1325 type = type.target () 1326 1327 # Get the unqualified type, stripped of typedefs. 1328 type = type.unqualified ().strip_typedefs () 1329 1330 return type.tag 1331 1332 def __call__(self, val): 1333 typename = self.get_basic_type(val.type) 1334 if not typename: 1335 return None 1336 1337 # All the types we match are template types, so we can use a 1338 # dictionary. 1339 match = self.compiled_rx.match(typename) 1340 if not match: 1341 return None 1342 1343 basename = match.group(1) 1344 1345 if val.type.code == gdb.TYPE_CODE_REF: 1346 if hasattr(gdb.Value,"referenced_value"): 1347 val = val.referenced_value() 1348 1349 if basename in self.lookup: 1350 return self.lookup[basename].invoke(val) 1351 1352 # Cannot find a pretty printer. Return None. 1353 return None 1354 1355libstdcxx_printer = None 1356 1357class TemplateTypePrinter(object): 1358 r""" 1359 A type printer for class templates with default template arguments. 1360 1361 Recognizes specializations of class templates and prints them without 1362 any template arguments that use a default template argument. 1363 Type printers are recursively applied to the template arguments. 1364 1365 e.g. replace "std::vector<T, std::allocator<T> >" with "std::vector<T>". 1366 """ 1367 1368 def __init__(self, name, defargs): 1369 self.name = name 1370 self.defargs = defargs 1371 self.enabled = True 1372 1373 class _recognizer(object): 1374 "The recognizer class for TemplateTypePrinter." 1375 1376 def __init__(self, name, defargs): 1377 self.name = name 1378 self.defargs = defargs 1379 # self.type_obj = None 1380 1381 def recognize(self, type_obj): 1382 """ 1383 If type_obj is a specialization of self.name that uses all the 1384 default template arguments for the class template, then return 1385 a string representation of the type without default arguments. 1386 Otherwise, return None. 1387 """ 1388 1389 if type_obj.tag is None: 1390 return None 1391 1392 if not type_obj.tag.startswith(self.name): 1393 return None 1394 1395 template_args = get_template_arg_list(type_obj) 1396 displayed_args = [] 1397 require_defaulted = False 1398 for n in range(len(template_args)): 1399 # The actual template argument in the type: 1400 targ = template_args[n] 1401 # The default template argument for the class template: 1402 defarg = self.defargs.get(n) 1403 if defarg is not None: 1404 # Substitute other template arguments into the default: 1405 defarg = defarg.format(*template_args) 1406 # Fail to recognize the type (by returning None) 1407 # unless the actual argument is the same as the default. 1408 try: 1409 if targ != gdb.lookup_type(defarg): 1410 return None 1411 except gdb.error: 1412 # Type lookup failed, just use string comparison: 1413 if targ.tag != defarg: 1414 return None 1415 # All subsequent args must have defaults: 1416 require_defaulted = True 1417 elif require_defaulted: 1418 return None 1419 else: 1420 # Recursively apply recognizers to the template argument 1421 # and add it to the arguments that will be displayed: 1422 displayed_args.append(self._recognize_subtype(targ)) 1423 1424 # This assumes no class templates in the nested-name-specifier: 1425 template_name = type_obj.tag[0:type_obj.tag.find('<')] 1426 template_name = strip_inline_namespaces(template_name) 1427 1428 return template_name + '<' + ', '.join(displayed_args) + '>' 1429 1430 def _recognize_subtype(self, type_obj): 1431 """Convert a gdb.Type to a string by applying recognizers, 1432 or if that fails then simply converting to a string.""" 1433 1434 if type_obj.code == gdb.TYPE_CODE_PTR: 1435 return self._recognize_subtype(type_obj.target()) + '*' 1436 if type_obj.code == gdb.TYPE_CODE_ARRAY: 1437 type_str = self._recognize_subtype(type_obj.target()) 1438 if str(type_obj.strip_typedefs()).endswith('[]'): 1439 return type_str + '[]' # array of unknown bound 1440 return "%s[%d]" % (type_str, type_obj.range()[1] + 1) 1441 if type_obj.code == gdb.TYPE_CODE_REF: 1442 return self._recognize_subtype(type_obj.target()) + '&' 1443 if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'): 1444 if type_obj.code == gdb.TYPE_CODE_RVALUE_REF: 1445 return self._recognize_subtype(type_obj.target()) + '&&' 1446 1447 type_str = gdb.types.apply_type_recognizers( 1448 gdb.types.get_type_recognizers(), type_obj) 1449 if type_str: 1450 return type_str 1451 return str(type_obj) 1452 1453 def instantiate(self): 1454 "Return a recognizer object for this type printer." 1455 return self._recognizer(self.name, self.defargs) 1456 1457def add_one_template_type_printer(obj, name, defargs): 1458 r""" 1459 Add a type printer for a class template with default template arguments. 1460 1461 Args: 1462 name (str): The template-name of the class template. 1463 defargs (dict int:string) The default template arguments. 1464 1465 Types in defargs can refer to the Nth template-argument using {N} 1466 (with zero-based indices). 1467 1468 e.g. 'unordered_map' has these defargs: 1469 { 2: 'std::hash<{0}>', 1470 3: 'std::equal_to<{0}>', 1471 4: 'std::allocator<std::pair<const {0}, {1}> >' } 1472 1473 """ 1474 printer = TemplateTypePrinter('std::'+name, defargs) 1475 gdb.types.register_type_printer(obj, printer) 1476 if _versioned_namespace: 1477 # Add second type printer for same type in versioned namespace: 1478 ns = 'std::' + _versioned_namespace 1479 # PR 86112 Cannot use dict comprehension here: 1480 defargs = dict((n, d.replace('std::', ns)) for (n,d) in defargs.items()) 1481 printer = TemplateTypePrinter(ns+name, defargs) 1482 gdb.types.register_type_printer(obj, printer) 1483 1484class FilteringTypePrinter(object): 1485 r""" 1486 A type printer that uses typedef names for common template specializations. 1487 1488 Args: 1489 match (str): The class template to recognize. 1490 name (str): The typedef-name that will be used instead. 1491 1492 Checks if a specialization of the class template 'match' is the same type 1493 as the typedef 'name', and prints it as 'name' instead. 1494 1495 e.g. if an instantiation of std::basic_istream<C, T> is the same type as 1496 std::istream then print it as std::istream. 1497 """ 1498 1499 def __init__(self, match, name): 1500 self.match = match 1501 self.name = name 1502 self.enabled = True 1503 1504 class _recognizer(object): 1505 "The recognizer class for TemplateTypePrinter." 1506 1507 def __init__(self, match, name): 1508 self.match = match 1509 self.name = name 1510 self.type_obj = None 1511 1512 def recognize(self, type_obj): 1513 """ 1514 If type_obj starts with self.match and is the same type as 1515 self.name then return self.name, otherwise None. 1516 """ 1517 if type_obj.tag is None: 1518 return None 1519 1520 if self.type_obj is None: 1521 if not type_obj.tag.startswith(self.match): 1522 # Filter didn't match. 1523 return None 1524 try: 1525 self.type_obj = gdb.lookup_type(self.name).strip_typedefs() 1526 except: 1527 pass 1528 if self.type_obj == type_obj: 1529 return strip_inline_namespaces(self.name) 1530 return None 1531 1532 def instantiate(self): 1533 "Return a recognizer object for this type printer." 1534 return self._recognizer(self.match, self.name) 1535 1536def add_one_type_printer(obj, match, name): 1537 printer = FilteringTypePrinter('std::' + match, 'std::' + name) 1538 gdb.types.register_type_printer(obj, printer) 1539 if _versioned_namespace: 1540 ns = 'std::' + _versioned_namespace 1541 printer = FilteringTypePrinter(ns + match, ns + name) 1542 gdb.types.register_type_printer(obj, printer) 1543 1544def register_type_printers(obj): 1545 global _use_type_printing 1546 1547 if not _use_type_printing: 1548 return 1549 1550 # Add type printers for typedefs std::string, std::wstring etc. 1551 for ch in ('', 'w', 'u16', 'u32'): 1552 add_one_type_printer(obj, 'basic_string', ch + 'string') 1553 add_one_type_printer(obj, '__cxx11::basic_string', 1554 '__cxx11::' + ch + 'string') 1555 add_one_type_printer(obj, 'basic_string_view', ch + 'string_view') 1556 1557 # Add type printers for typedefs std::istream, std::wistream etc. 1558 for ch in ('', 'w'): 1559 for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream', 1560 'filebuf', 'ifstream', 'ofstream', 'fstream'): 1561 add_one_type_printer(obj, 'basic_' + x, ch + x) 1562 for x in ('stringbuf', 'istringstream', 'ostringstream', 1563 'stringstream'): 1564 add_one_type_printer(obj, 'basic_' + x, ch + x) 1565 # <sstream> types are in __cxx11 namespace, but typedefs aren'x: 1566 add_one_type_printer(obj, '__cxx11::basic_' + x, ch + x) 1567 1568 # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc. 1569 for abi in ('', '__cxx11::'): 1570 for ch in ('', 'w'): 1571 add_one_type_printer(obj, abi + 'basic_regex', abi + ch + 'regex') 1572 for ch in ('c', 's', 'wc', 'ws'): 1573 add_one_type_printer(obj, abi + 'match_results', abi + ch + 'match') 1574 for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'): 1575 add_one_type_printer(obj, abi + x, abi + ch + x) 1576 1577 # Note that we can't have a printer for std::wstreampos, because 1578 # it is the same type as std::streampos. 1579 add_one_type_printer(obj, 'fpos', 'streampos') 1580 1581 # Add type printers for <chrono> typedefs. 1582 for dur in ('nanoseconds', 'microseconds', 'milliseconds', 1583 'seconds', 'minutes', 'hours'): 1584 add_one_type_printer(obj, 'duration', dur) 1585 1586 # Add type printers for <random> typedefs. 1587 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0') 1588 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand') 1589 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937') 1590 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64') 1591 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base') 1592 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base') 1593 add_one_type_printer(obj, 'discard_block_engine', 'ranlux24') 1594 add_one_type_printer(obj, 'discard_block_engine', 'ranlux48') 1595 add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b') 1596 1597 # Add type printers for experimental::basic_string_view typedefs. 1598 ns = 'experimental::fundamentals_v1::' 1599 for ch in ('', 'w', 'u16', 'u32'): 1600 add_one_type_printer(obj, ns + 'basic_string_view', 1601 ns + ch + 'string_view') 1602 1603 # Do not show defaulted template arguments in class templates. 1604 add_one_template_type_printer(obj, 'unique_ptr', 1605 { 1: 'std::default_delete<{0}>' }) 1606 add_one_template_type_printer(obj, 'deque', { 1: 'std::allocator<{0}>'}) 1607 add_one_template_type_printer(obj, 'forward_list', { 1: 'std::allocator<{0}>'}) 1608 add_one_template_type_printer(obj, 'list', { 1: 'std::allocator<{0}>'}) 1609 add_one_template_type_printer(obj, '__cxx11::list', { 1: 'std::allocator<{0}>'}) 1610 add_one_template_type_printer(obj, 'vector', { 1: 'std::allocator<{0}>'}) 1611 add_one_template_type_printer(obj, 'map', 1612 { 2: 'std::less<{0}>', 1613 3: 'std::allocator<std::pair<{0} const, {1}>>' }) 1614 add_one_template_type_printer(obj, 'multimap', 1615 { 2: 'std::less<{0}>', 1616 3: 'std::allocator<std::pair<{0} const, {1}>>' }) 1617 add_one_template_type_printer(obj, 'set', 1618 { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' }) 1619 add_one_template_type_printer(obj, 'multiset', 1620 { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' }) 1621 add_one_template_type_printer(obj, 'unordered_map', 1622 { 2: 'std::hash<{0}>', 1623 3: 'std::equal_to<{0}>', 1624 4: 'std::allocator<std::pair<{0} const, {1}>>'}) 1625 add_one_template_type_printer(obj, 'unordered_multimap', 1626 { 2: 'std::hash<{0}>', 1627 3: 'std::equal_to<{0}>', 1628 4: 'std::allocator<std::pair<{0} const, {1}>>'}) 1629 add_one_template_type_printer(obj, 'unordered_set', 1630 { 1: 'std::hash<{0}>', 1631 2: 'std::equal_to<{0}>', 1632 3: 'std::allocator<{0}>'}) 1633 add_one_template_type_printer(obj, 'unordered_multiset', 1634 { 1: 'std::hash<{0}>', 1635 2: 'std::equal_to<{0}>', 1636 3: 'std::allocator<{0}>'}) 1637 1638def register_libstdcxx_printers (obj): 1639 "Register libstdc++ pretty-printers with objfile Obj." 1640 1641 global _use_gdb_pp 1642 global libstdcxx_printer 1643 1644 if _use_gdb_pp: 1645 gdb.printing.register_pretty_printer(obj, libstdcxx_printer) 1646 else: 1647 if obj is None: 1648 obj = gdb 1649 obj.pretty_printers.append(libstdcxx_printer) 1650 1651 register_type_printers(obj) 1652 1653def build_libstdcxx_dictionary (): 1654 global libstdcxx_printer 1655 1656 libstdcxx_printer = Printer("libstdc++-v6") 1657 1658 # libstdc++ objects requiring pretty-printing. 1659 # In order from: 1660 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html 1661 libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter) 1662 libstdcxx_printer.add_version('std::__cxx11::', 'basic_string', StdStringPrinter) 1663 libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter) 1664 libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter) 1665 libstdcxx_printer.add_container('std::', 'list', StdListPrinter) 1666 libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter) 1667 libstdcxx_printer.add_container('std::', 'map', StdMapPrinter) 1668 libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter) 1669 libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter) 1670 libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter) 1671 libstdcxx_printer.add_version('std::', 'priority_queue', 1672 StdStackOrQueuePrinter) 1673 libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter) 1674 libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter) 1675 libstdcxx_printer.add_container('std::', 'set', StdSetPrinter) 1676 libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter) 1677 libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter) 1678 libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter) 1679 # vector<bool> 1680 1681 # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG. 1682 libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter) 1683 libstdcxx_printer.add('std::__debug::deque', StdDequePrinter) 1684 libstdcxx_printer.add('std::__debug::list', StdListPrinter) 1685 libstdcxx_printer.add('std::__debug::map', StdMapPrinter) 1686 libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter) 1687 libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter) 1688 libstdcxx_printer.add('std::__debug::priority_queue', 1689 StdStackOrQueuePrinter) 1690 libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter) 1691 libstdcxx_printer.add('std::__debug::set', StdSetPrinter) 1692 libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter) 1693 libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter) 1694 libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter) 1695 1696 # These are the TR1 and C++11 printers. 1697 # For array - the default GDB pretty-printer seems reasonable. 1698 libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter) 1699 libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter) 1700 libstdcxx_printer.add_container('std::', 'unordered_map', 1701 Tr1UnorderedMapPrinter) 1702 libstdcxx_printer.add_container('std::', 'unordered_set', 1703 Tr1UnorderedSetPrinter) 1704 libstdcxx_printer.add_container('std::', 'unordered_multimap', 1705 Tr1UnorderedMapPrinter) 1706 libstdcxx_printer.add_container('std::', 'unordered_multiset', 1707 Tr1UnorderedSetPrinter) 1708 libstdcxx_printer.add_container('std::', 'forward_list', 1709 StdForwardListPrinter) 1710 1711 libstdcxx_printer.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter) 1712 libstdcxx_printer.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter) 1713 libstdcxx_printer.add_version('std::tr1::', 'unordered_map', 1714 Tr1UnorderedMapPrinter) 1715 libstdcxx_printer.add_version('std::tr1::', 'unordered_set', 1716 Tr1UnorderedSetPrinter) 1717 libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap', 1718 Tr1UnorderedMapPrinter) 1719 libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset', 1720 Tr1UnorderedSetPrinter) 1721 1722 # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases. 1723 # The tr1 namespace containers do not have any debug equivalents, 1724 # so do not register printers for them. 1725 libstdcxx_printer.add('std::__debug::unordered_map', 1726 Tr1UnorderedMapPrinter) 1727 libstdcxx_printer.add('std::__debug::unordered_set', 1728 Tr1UnorderedSetPrinter) 1729 libstdcxx_printer.add('std::__debug::unordered_multimap', 1730 Tr1UnorderedMapPrinter) 1731 libstdcxx_printer.add('std::__debug::unordered_multiset', 1732 Tr1UnorderedSetPrinter) 1733 libstdcxx_printer.add('std::__debug::forward_list', 1734 StdForwardListPrinter) 1735 1736 # Library Fundamentals TS components 1737 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 1738 'any', StdExpAnyPrinter) 1739 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 1740 'optional', StdExpOptionalPrinter) 1741 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 1742 'basic_string_view', StdExpStringViewPrinter) 1743 # Filesystem TS components 1744 libstdcxx_printer.add_version('std::experimental::filesystem::v1::', 1745 'path', StdExpPathPrinter) 1746 libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::', 1747 'path', StdExpPathPrinter) 1748 libstdcxx_printer.add_version('std::filesystem::', 1749 'path', StdExpPathPrinter) 1750 libstdcxx_printer.add_version('std::filesystem::__cxx11::', 1751 'path', StdExpPathPrinter) 1752 1753 # C++17 components 1754 libstdcxx_printer.add_version('std::', 1755 'any', StdExpAnyPrinter) 1756 libstdcxx_printer.add_version('std::', 1757 'optional', StdExpOptionalPrinter) 1758 libstdcxx_printer.add_version('std::', 1759 'basic_string_view', StdExpStringViewPrinter) 1760 libstdcxx_printer.add_version('std::', 1761 'variant', StdVariantPrinter) 1762 libstdcxx_printer.add_version('std::', 1763 '_Node_handle', StdNodeHandlePrinter) 1764 1765 # Extensions. 1766 libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter) 1767 1768 if True: 1769 # These shouldn't be necessary, if GDB "print *i" worked. 1770 # But it often doesn't, so here they are. 1771 libstdcxx_printer.add_container('std::', '_List_iterator', 1772 StdListIteratorPrinter) 1773 libstdcxx_printer.add_container('std::', '_List_const_iterator', 1774 StdListIteratorPrinter) 1775 libstdcxx_printer.add_version('std::', '_Rb_tree_iterator', 1776 StdRbtreeIteratorPrinter) 1777 libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator', 1778 StdRbtreeIteratorPrinter) 1779 libstdcxx_printer.add_container('std::', '_Deque_iterator', 1780 StdDequeIteratorPrinter) 1781 libstdcxx_printer.add_container('std::', '_Deque_const_iterator', 1782 StdDequeIteratorPrinter) 1783 libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator', 1784 StdVectorIteratorPrinter) 1785 libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator', 1786 StdSlistIteratorPrinter) 1787 libstdcxx_printer.add_container('std::', '_Fwd_list_iterator', 1788 StdFwdListIteratorPrinter) 1789 libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator', 1790 StdFwdListIteratorPrinter) 1791 1792 # Debug (compiled with -D_GLIBCXX_DEBUG) printer 1793 # registrations. 1794 libstdcxx_printer.add('__gnu_debug::_Safe_iterator', 1795 StdDebugIteratorPrinter) 1796 1797build_libstdcxx_dictionary () 1798