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