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