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