1 # Pretty-printers for libstdc++. 2 3 # Copyright (C) 2008-2024 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 18 import gdb 19 import itertools 20 import re 21 import sys 22 import errno 23 import datetime 24 25 # Python 2 + Python 3 compatibility code 26 27 # Resources about compatibility: 28 # 29 # * <http://pythonhosted.org/six/>: Documentation of the "six" module 30 31 # FIXME: The handling of e.g. std::basic_string (at least on char) 32 # probably needs updating to work with Python 3's new string rules. 33 # 34 # In particular, Python 3 has a separate type (called byte) for 35 # bytestrings, and a special b"" syntax for the byte literals; the old 36 # str() type has been redefined to always store Unicode text. 37 # 38 # We probably can't do much about this until this GDB PR is addressed: 39 # <https://sourceware.org/bugzilla/show_bug.cgi?id=17138> 40 41 if sys.version_info[0] > 2: 42 # Python 3 stuff 43 Iterator = object 44 # Python 3 folds these into the normal functions. 45 imap = map 46 izip = zip 47 # Also, int subsumes long 48 long = int 49 _utc_timezone = datetime.timezone.utc 50 else: 51 # Python 2 stuff 52 class Iterator: 53 """Compatibility mixin for iterators 54 55 Instead of writing next() methods for iterators, write 56 __next__() methods and use this mixin to make them work in 57 Python 2 as well as Python 3. 58 59 Idea stolen from the "six" documentation: 60 <http://pythonhosted.org/six/#six.Iterator> 61 """ 62 63 def next(self): 64 return self.__next__() 65 66 # In Python 2, we still need these from itertools 67 from itertools import imap, izip 68 69 # Python 2 does not provide the datetime.UTC singleton. 70 class UTC(datetime.tzinfo): 71 """Concrete tzinfo class representing the UTC time zone.""" 72 73 def utcoffset(self, dt): 74 return datetime.timedelta(0) 75 76 def tzname(self, dt): 77 return "UTC" 78 79 def dst(self, dt): 80 return datetime.timedelta(0) 81 _utc_timezone = UTC() 82 83 # Try to use the new-style pretty-printing if available. 84 _use_gdb_pp = True 85 try: 86 import gdb.printing 87 except ImportError: 88 _use_gdb_pp = False 89 90 # Try to install type-printers. 91 _use_type_printing = False 92 try: 93 import gdb.types 94 if hasattr(gdb.types, 'TypePrinter'): 95 _use_type_printing = True 96 except ImportError: 97 pass 98 99 # Use the base class if available. 100 if hasattr(gdb, 'ValuePrinter'): 101 printer_base = gdb.ValuePrinter 102 else: 103 printer_base = object 104 105 # Starting with the type ORIG, search for the member type NAME. This 106 # handles searching upward through superclasses. This is needed to 107 # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. 108 109 110 def find_type(orig, name): 111 typ = orig.strip_typedefs() 112 while True: 113 # Use Type.tag to ignore cv-qualifiers. PR 67440. 114 search = '%s::%s' % (typ.tag, name) 115 try: 116 return gdb.lookup_type(search) 117 except RuntimeError: 118 pass 119 # The type was not found, so try the superclass. We only need 120 # to check the first superclass, so we don't bother with 121 # anything fancier here. 122 fields = typ.fields() 123 if len(fields) and fields[0].is_base_class: 124 typ = fields[0].type 125 else: 126 raise ValueError("Cannot find type %s::%s" % (str(orig), name)) 127 128 129 _versioned_namespace = '__8::' 130 131 132 def lookup_templ_spec(templ, *args): 133 """ 134 Lookup template specialization templ<args...>. 135 """ 136 t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args])) 137 try: 138 return gdb.lookup_type(t) 139 except gdb.error as e: 140 # Type not found, try again in versioned namespace. 141 global _versioned_namespace 142 if _versioned_namespace not in templ: 143 t = t.replace('::', '::' + _versioned_namespace, 1) 144 try: 145 return gdb.lookup_type(t) 146 except gdb.error: 147 # If that also fails, rethrow the original exception 148 pass 149 raise e 150 151 # Use this to find container node types instead of find_type, 152 # see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details. 153 def lookup_node_type(nodename, containertype): 154 """ 155 Lookup specialization of template nodename corresponding to containertype. 156 157 nodename - The name of a class template, as a String 158 containertype - The container, as a gdb.Type 159 160 Return a gdb.Type for the corresponding specialization of nodename, 161 or None if the type cannot be found. 162 163 e.g. lookup_node_type('_List_node', gdb.lookup_type('std::list<int>')) 164 will return a gdb.Type for the type std::_List_node<int>. 165 """ 166 # If nodename is unqualified, assume it's in namespace std. 167 if '::' not in nodename: 168 nodename = 'std::' + nodename 169 # Use either containertype's value_type or its first template argument. 170 try: 171 valtype = find_type(containertype, 'value_type') 172 except: 173 valtype = containertype.template_argument(0) 174 valtype = valtype.strip_typedefs() 175 try: 176 return lookup_templ_spec(nodename, valtype) 177 except gdb.error: 178 # For debug mode containers the node is in std::__cxx1998. 179 if is_member_of_namespace(nodename, 'std'): 180 if is_member_of_namespace(containertype, 'std::__cxx1998', 181 'std::__debug', '__gnu_debug'): 182 nodename = nodename.replace('::', '::__cxx1998::', 1) 183 try: 184 return lookup_templ_spec(nodename, valtype) 185 except gdb.error: 186 pass 187 return None 188 189 190 def is_member_of_namespace(typ, *namespaces): 191 """ 192 Test whether a type is a member of one of the specified namespaces. 193 The type can be specified as a string or a gdb.Type object. 194 """ 195 if isinstance(typ, gdb.Type): 196 typ = str(typ) 197 typ = strip_versioned_namespace(typ) 198 for namespace in namespaces: 199 if typ.startswith(namespace + '::'): 200 return True 201 return False 202 203 204 def is_specialization_of(x, template_name): 205 """ 206 Test whether a type is a specialization of the named class template. 207 The type can be specified as a string or a gdb.Type object. 208 The template should be the name of a class template as a string, 209 without any 'std' qualification. 210 """ 211 global _versioned_namespace 212 if isinstance(x, gdb.Type): 213 x = x.tag 214 template_name = '(%s)?%s' % (_versioned_namespace, template_name) 215 return re.match('^std::%s<.*>$' % template_name, x) is not None 216 217 218 def strip_versioned_namespace(typename): 219 global _versioned_namespace 220 return typename.replace(_versioned_namespace, '') 221 222 223 def strip_fundts_namespace(typ): 224 """Remove "fundamentals_vN" inline namespace from qualified type name.""" 225 pattern = r'^std::experimental::fundamentals_v\d::' 226 repl = 'std::experimental::' 227 if sys.version_info[0] == 2: 228 return re.sub(pattern, repl, typ, 1) 229 else: # Technically this needs Python 3.1 but nobody should be using 3.0 230 return re.sub(pattern, repl, typ, count=1) 231 232 233 def strip_inline_namespaces(type_str): 234 """Remove known inline namespaces from the canonical name of a type.""" 235 type_str = strip_versioned_namespace(type_str) 236 type_str = type_str.replace('std::__cxx11::', 'std::') 237 expt_ns = 'std::experimental::' 238 for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'): 239 type_str = type_str.replace(expt_ns + lfts_ns + '::', expt_ns) 240 fs_ns = expt_ns + 'filesystem::' 241 type_str = type_str.replace(fs_ns + 'v1::', fs_ns) 242 return type_str 243 244 245 def get_template_arg_list(type_obj): 246 """Return a type's template arguments as a list.""" 247 n = 0 248 template_args = [] 249 while True: 250 try: 251 template_args.append(type_obj.template_argument(n)) 252 except: 253 return template_args 254 n += 1 255 256 257 class SmartPtrIterator(Iterator): 258 """An iterator for smart pointer types with a single 'child' value.""" 259 260 def __init__(self, val): 261 self._val = val 262 263 def __iter__(self): 264 return self 265 266 def __next__(self): 267 if self._val is None: 268 raise StopIteration 269 self._val, val = None, self._val 270 return ('get()', val) 271 272 273 class SharedPointerPrinter(printer_base): 274 """ 275 Print a shared_ptr, weak_ptr, atomic<shared_ptr>, or atomic<weak_ptr>. 276 """ 277 278 def __init__(self, typename, val): 279 self._typename = strip_versioned_namespace(typename) 280 self._val = val 281 self._pointer = val['_M_ptr'] 282 283 def children(self): 284 return SmartPtrIterator(self._pointer) 285 286 # Return the _Sp_counted_base<>* that holds the refcounts. 287 def _get_refcounts(self): 288 if self._typename == 'std::atomic': 289 # A tagged pointer is stored as uintptr_t. 290 ptr_val = self._val['_M_refcount']['_M_val']['_M_i'] 291 ptr_val = ptr_val - (ptr_val % 2) # clear lock bit 292 ptr_type = find_type(self._val['_M_refcount'].type, 'pointer') 293 return ptr_val.cast(ptr_type) 294 return self._val['_M_refcount']['_M_pi'] 295 296 def to_string(self): 297 state = 'empty' 298 refcounts = self._get_refcounts() 299 targ = self._val.type.template_argument(0) 300 targ = strip_versioned_namespace(str(targ)) 301 302 if refcounts != 0: 303 usecount = refcounts['_M_use_count'] 304 weakcount = refcounts['_M_weak_count'] 305 if usecount == 0: 306 state = 'expired, weak count %d' % weakcount 307 else: 308 state = 'use count %d, weak count %d' % ( 309 usecount, weakcount - 1) 310 return '%s<%s> (%s)' % (self._typename, targ, state) 311 312 313 def _tuple_impl_get(val): 314 """Return the tuple element stored in a _Tuple_impl<N, T> base class.""" 315 bases = val.type.fields() 316 if not bases[-1].is_base_class: 317 raise ValueError( 318 "Unsupported implementation for std::tuple: %s" % str(val.type)) 319 # Get the _Head_base<N, T> base class: 320 head_base = val.cast(bases[-1].type) 321 fields = head_base.type.fields() 322 if len(fields) == 0: 323 raise ValueError( 324 "Unsupported implementation for std::tuple: %s" % str(val.type)) 325 if fields[0].name == '_M_head_impl': 326 # The tuple element is the _Head_base::_M_head_impl data member. 327 return head_base['_M_head_impl'] 328 elif fields[0].is_base_class: 329 # The tuple element is an empty base class of _Head_base. 330 # Cast to that empty base class. 331 return head_base.cast(fields[0].type) 332 else: 333 raise ValueError( 334 "Unsupported implementation for std::tuple: %s" % str(val.type)) 335 336 337 def tuple_get(n, val): 338 """Return the result of std::get<n>(val) on a std::tuple.""" 339 tuple_size = len(get_template_arg_list(val.type)) 340 if n > tuple_size: 341 raise ValueError("Out of range index for std::get<N> on std::tuple") 342 # Get the first _Tuple_impl<0, T...> base class: 343 node = val.cast(val.type.fields()[0].type) 344 while n > 0: 345 # Descend through the base classes until the Nth one. 346 node = node.cast(node.type.fields()[0].type) 347 n -= 1 348 return _tuple_impl_get(node) 349 350 351 def unique_ptr_get(val): 352 """Return the result of val.get() on a std::unique_ptr.""" 353 # std::unique_ptr<T, D> contains a std::tuple<D::pointer, D>, 354 # either as a direct data member _M_t (the old implementation) 355 # or within a data member of type __uniq_ptr_data. 356 impl_type = val.type.fields()[0].type.strip_typedefs() 357 # Check for new implementations first: 358 if is_specialization_of(impl_type, '__uniq_ptr_data') \ 359 or is_specialization_of(impl_type, '__uniq_ptr_impl'): 360 tuple_member = val['_M_t']['_M_t'] 361 elif is_specialization_of(impl_type, 'tuple'): 362 tuple_member = val['_M_t'] 363 else: 364 raise ValueError( 365 "Unsupported implementation for unique_ptr: %s" % str(impl_type)) 366 return tuple_get(0, tuple_member) 367 368 369 class UniquePointerPrinter(printer_base): 370 """Print a unique_ptr.""" 371 372 def __init__(self, typename, val): 373 self._val = val 374 375 def children(self): 376 return SmartPtrIterator(unique_ptr_get(self._val)) 377 378 def to_string(self): 379 t = self._val.type.template_argument(0) 380 return 'std::unique_ptr<{}>'.format(str(t)) 381 382 383 def get_value_from_aligned_membuf(buf, valtype): 384 """Return the value held in a __gnu_cxx::__aligned_membuf.""" 385 return buf['_M_storage'].address.cast(valtype.pointer()).dereference() 386 387 388 def get_value_from_list_node(node): 389 """Return the value held in an _List_node<_Val>.""" 390 try: 391 member = node.type.fields()[1].name 392 if member == '_M_data': 393 # C++03 implementation, node contains the value as a member 394 return node['_M_data'] 395 elif member == '_M_storage': 396 # C++11 implementation, node stores value in __aligned_membuf 397 valtype = node.type.template_argument(0) 398 return get_value_from_aligned_membuf(node['_M_storage'], valtype) 399 except: 400 pass 401 raise ValueError("Unsupported implementation for %s" % str(node.type)) 402 403 404 class StdListPrinter(printer_base): 405 """Print a std::list.""" 406 407 class _iterator(Iterator): 408 def __init__(self, nodetype, head): 409 self._nodetype = nodetype 410 self._base = head['_M_next'] 411 self._head = head.address 412 self._count = 0 413 414 def __iter__(self): 415 return self 416 417 def __next__(self): 418 if self._base == self._head: 419 raise StopIteration 420 elt = self._base.cast(self._nodetype).dereference() 421 self._base = elt['_M_next'] 422 count = self._count 423 self._count = self._count + 1 424 val = get_value_from_list_node(elt) 425 return ('[%d]' % count, val) 426 427 def __init__(self, typename, val): 428 self._typename = strip_versioned_namespace(typename) 429 self._val = val 430 431 def children(self): 432 nodetype = lookup_node_type('_List_node', self._val.type).pointer() 433 return self._iterator(nodetype, self._val['_M_impl']['_M_node']) 434 435 def to_string(self): 436 headnode = self._val['_M_impl']['_M_node'] 437 if headnode['_M_next'] == headnode.address: 438 return 'empty %s' % (self._typename) 439 return '%s' % (self._typename) 440 441 442 class NodeIteratorPrinter(printer_base): 443 def __init__(self, typename, val, contname, nodename): 444 self._val = val 445 self._typename = typename 446 self._contname = contname 447 self._nodetype = lookup_node_type(nodename, val.type) 448 449 def to_string(self): 450 if not self._val['_M_node']: 451 return 'non-dereferenceable iterator for std::%s' % (self._contname) 452 node = self._val['_M_node'].cast( 453 self._nodetype.pointer()).dereference() 454 return str(get_value_from_list_node(node)) 455 456 457 class StdListIteratorPrinter(NodeIteratorPrinter): 458 """Print std::list::iterator.""" 459 460 def __init__(self, typename, val): 461 NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node') 462 463 464 class StdFwdListIteratorPrinter(NodeIteratorPrinter): 465 """Print std::forward_list::iterator.""" 466 467 def __init__(self, typename, val): 468 NodeIteratorPrinter.__init__(self, typename, val, 'forward_list', 469 '_Fwd_list_node') 470 471 472 class StdSlistPrinter(printer_base): 473 """Print a __gnu_cxx::slist.""" 474 475 class _iterator(Iterator): 476 def __init__(self, nodetype, head): 477 self._nodetype = nodetype 478 self._base = head['_M_head']['_M_next'] 479 self._count = 0 480 481 def __iter__(self): 482 return self 483 484 def __next__(self): 485 if self._base == 0: 486 raise StopIteration 487 elt = self._base.cast(self._nodetype).dereference() 488 self._base = elt['_M_next'] 489 count = self._count 490 self._count = self._count + 1 491 return ('[%d]' % count, elt['_M_data']) 492 493 def __init__(self, typename, val): 494 self._val = val 495 496 def children(self): 497 nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self._val.type) 498 return self._iterator(nodetype.pointer(), self._val) 499 500 def to_string(self): 501 if self._val['_M_head']['_M_next'] == 0: 502 return 'empty __gnu_cxx::slist' 503 return '__gnu_cxx::slist' 504 505 506 class StdSlistIteratorPrinter(printer_base): 507 """Print __gnu_cxx::slist::iterator.""" 508 509 def __init__(self, typename, val): 510 self._val = val 511 512 def to_string(self): 513 if not self._val['_M_node']: 514 return 'non-dereferenceable iterator for __gnu_cxx::slist' 515 nodetype = lookup_node_type( 516 '__gnu_cxx::_Slist_node', self._val.type).pointer() 517 return str(self._val['_M_node'].cast(nodetype).dereference()['_M_data']) 518 519 520 class StdVectorPrinter(printer_base): 521 """Print a std::vector.""" 522 523 class _iterator(Iterator): 524 def __init__(self, start, finish, bitvec): 525 self._bitvec = bitvec 526 if bitvec: 527 self._item = start['_M_p'] 528 self._so = 0 529 self._finish = finish['_M_p'] 530 self._fo = finish['_M_offset'] 531 itype = self._item.dereference().type 532 self._isize = 8 * itype.sizeof 533 else: 534 self._item = start 535 self._finish = finish 536 self._count = 0 537 538 def __iter__(self): 539 return self 540 541 def __next__(self): 542 count = self._count 543 self._count = self._count + 1 544 if self._bitvec: 545 if self._item == self._finish and self._so >= self._fo: 546 raise StopIteration 547 elt = bool(self._item.dereference() & (1 << self._so)) 548 self._so = self._so + 1 549 if self._so >= self._isize: 550 self._item = self._item + 1 551 self._so = 0 552 return ('[%d]' % count, elt) 553 else: 554 if self._item == self._finish: 555 raise StopIteration 556 elt = self._item.dereference() 557 self._item = self._item + 1 558 return ('[%d]' % count, elt) 559 560 def __init__(self, typename, val): 561 self._typename = strip_versioned_namespace(typename) 562 self._val = val 563 self._is_bool = val.type.template_argument( 564 0).code == gdb.TYPE_CODE_BOOL 565 566 def children(self): 567 return self._iterator(self._val['_M_impl']['_M_start'], 568 self._val['_M_impl']['_M_finish'], 569 self._is_bool) 570 571 def to_string(self): 572 start = self._val['_M_impl']['_M_start'] 573 finish = self._val['_M_impl']['_M_finish'] 574 end = self._val['_M_impl']['_M_end_of_storage'] 575 if self._is_bool: 576 start = self._val['_M_impl']['_M_start']['_M_p'] 577 finish = self._val['_M_impl']['_M_finish']['_M_p'] 578 fo = self._val['_M_impl']['_M_finish']['_M_offset'] 579 itype = start.dereference().type 580 bl = 8 * itype.sizeof 581 length = bl * (finish - start) + fo 582 capacity = bl * (end - start) 583 return ('%s<bool> of length %d, capacity %d' 584 % (self._typename, int(length), int(capacity))) 585 else: 586 return ('%s of length %d, capacity %d' 587 % (self._typename, int(finish - start), int(end - start))) 588 589 def display_hint(self): 590 return 'array' 591 592 593 class StdVectorIteratorPrinter(printer_base): 594 """Print std::vector::iterator.""" 595 596 def __init__(self, typename, val): 597 self._val = val 598 599 def to_string(self): 600 if not self._val['_M_current']: 601 return 'non-dereferenceable iterator for std::vector' 602 return str(self._val['_M_current'].dereference()) 603 604 605 class StdBitIteratorPrinter(printer_base): 606 """Print std::vector<bool>'s _Bit_iterator and _Bit_const_iterator.""" 607 608 def __init__(self, typename, val): 609 self._val = val 610 611 def to_string(self): 612 if not self._val['_M_p']: 613 return 'non-dereferenceable iterator for std::vector<bool>' 614 return bool(self._val['_M_p'].dereference() 615 & (1 << self._val['_M_offset'])) 616 617 618 class StdBitReferencePrinter(printer_base): 619 """Print std::vector<bool>::reference.""" 620 621 def __init__(self, typename, val): 622 self._val = val 623 624 def to_string(self): 625 if not self._val['_M_p']: 626 return 'invalid std::vector<bool>::reference' 627 return bool(self._val['_M_p'].dereference() & (self._val['_M_mask'])) 628 629 630 class StdTuplePrinter(printer_base): 631 """Print a std::tuple.""" 632 633 class _iterator(Iterator): 634 @staticmethod 635 def _is_nonempty_tuple(nodes): 636 if len(nodes) == 2: 637 if is_specialization_of(nodes[1].type, '__tuple_base'): 638 return True 639 elif len(nodes) == 1: 640 return True 641 elif len(nodes) == 0: 642 return False 643 raise ValueError( 644 "Top of tuple tree does not consist of a single node.") 645 646 def __init__(self, head): 647 self._head = head 648 649 # Set the base class as the initial head of the 650 # tuple. 651 nodes = self._head.type.fields() 652 if self._is_nonempty_tuple(nodes): 653 # Set the actual head to the first pair. 654 self._head = self._head.cast(nodes[0].type) 655 self._count = 0 656 657 def __iter__(self): 658 return self 659 660 def __next__(self): 661 # Check for further recursions in the inheritance tree. 662 # For a GCC 5+ tuple self._head is None after visiting all nodes: 663 if not self._head: 664 raise StopIteration 665 nodes = self._head.type.fields() 666 # For a GCC 4.x tuple there is a final node with no fields: 667 if len(nodes) == 0: 668 raise StopIteration 669 # Check that this iteration has an expected structure. 670 if len(nodes) > 2: 671 raise ValueError( 672 "Cannot parse more than 2 nodes in a tuple tree.") 673 674 if len(nodes) == 1: 675 # This is the last node of a GCC 5+ std::tuple. 676 impl = self._head.cast(nodes[0].type) 677 self._head = None 678 else: 679 # Either a node before the last node, or the last node of 680 # a GCC 4.x tuple (which has an empty parent). 681 682 # - Left node is the next recursion parent. 683 # - Right node is the actual class contained in the tuple. 684 685 # Process right node. 686 impl = self._head.cast(nodes[1].type) 687 688 # Process left node and set it as head. 689 self._head = self._head.cast(nodes[0].type) 690 691 self._count = self._count + 1 692 693 # Finally, check the implementation. If it is 694 # wrapped in _M_head_impl return that, otherwise return 695 # the value "as is". 696 fields = impl.type.fields() 697 if len(fields) < 1 or fields[0].name != "_M_head_impl": 698 return ('[%d]' % (self._count - 1), impl) 699 else: 700 return ('[%d]' % (self._count - 1), impl['_M_head_impl']) 701 702 def __init__(self, typename, val): 703 self._typename = strip_versioned_namespace(typename) 704 self._val = val 705 706 def children(self): 707 return self._iterator(self._val) 708 709 def to_string(self): 710 if len(self._val.type.fields()) == 0: 711 return 'empty %s' % (self._typename) 712 return '%s containing' % (self._typename) 713 714 715 class StdStackOrQueuePrinter(printer_base): 716 """Print a std::stack or std::queue.""" 717 718 def __init__(self, typename, val): 719 self._typename = strip_versioned_namespace(typename) 720 self._visualizer = gdb.default_visualizer(val['c']) 721 722 def children(self): 723 return self._visualizer.children() 724 725 def to_string(self): 726 return '%s wrapping: %s' % (self._typename, 727 self._visualizer.to_string()) 728 729 def display_hint(self): 730 if hasattr(self._visualizer, 'display_hint'): 731 return self._visualizer.display_hint() 732 return None 733 734 735 class RbtreeIterator(Iterator): 736 """ 737 Turn an RB-tree-based container (std::map, std::set etc.) into 738 a Python iterable object. 739 """ 740 741 def __init__(self, rbtree): 742 self._size = rbtree['_M_t']['_M_impl']['_M_node_count'] 743 self._node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] 744 self._count = 0 745 746 def __iter__(self): 747 return self 748 749 def __len__(self): 750 return int(self._size) 751 752 def __next__(self): 753 if self._count == self._size: 754 raise StopIteration 755 result = self._node 756 self._count = self._count + 1 757 if self._count < self._size: 758 # Compute the next node. 759 node = self._node 760 if node.dereference()['_M_right']: 761 node = node.dereference()['_M_right'] 762 while node.dereference()['_M_left']: 763 node = node.dereference()['_M_left'] 764 else: 765 parent = node.dereference()['_M_parent'] 766 while node == parent.dereference()['_M_right']: 767 node = parent 768 parent = parent.dereference()['_M_parent'] 769 if node.dereference()['_M_right'] != parent: 770 node = parent 771 self._node = node 772 return result 773 774 775 def get_value_from_Rb_tree_node(node): 776 """Return the value held in an _Rb_tree_node<_Val>.""" 777 try: 778 member = node.type.fields()[1].name 779 if member == '_M_value_field': 780 # C++03 implementation, node contains the value as a member 781 return node['_M_value_field'] 782 elif member == '_M_storage': 783 # C++11 implementation, node stores value in __aligned_membuf 784 valtype = node.type.template_argument(0) 785 return get_value_from_aligned_membuf(node['_M_storage'], valtype) 786 except: 787 pass 788 raise ValueError("Unsupported implementation for %s" % str(node.type)) 789 790 # This is a pretty printer for std::_Rb_tree_iterator (which is 791 # std::map::iterator), and has nothing to do with the RbtreeIterator 792 # class above. 793 794 795 class StdRbtreeIteratorPrinter(printer_base): 796 """Print std::map::iterator, std::set::iterator, etc.""" 797 798 def __init__(self, typename, val): 799 self._val = val 800 nodetype = lookup_node_type('_Rb_tree_node', self._val.type) 801 self._link_type = nodetype.pointer() 802 803 def to_string(self): 804 if not self._val['_M_node']: 805 return 'non-dereferenceable iterator for associative container' 806 node = self._val['_M_node'].cast(self._link_type).dereference() 807 return str(get_value_from_Rb_tree_node(node)) 808 809 810 class StdDebugIteratorPrinter(printer_base): 811 """Print a debug enabled version of an iterator.""" 812 813 def __init__(self, typename, val): 814 self._val = val 815 816 # Just strip away the encapsulating __gnu_debug::_Safe_iterator 817 # and return the wrapped iterator value. 818 def to_string(self): 819 base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base') 820 itype = self._val.type.template_argument(0) 821 safe_seq = self._val.cast(base_type)['_M_sequence'] 822 if not safe_seq: 823 return str(self._val.cast(itype)) 824 if self._val['_M_version'] != safe_seq['_M_version']: 825 return "invalid iterator" 826 return str(self._val.cast(itype)) 827 828 829 def num_elements(num): 830 """Return either "1 element" or "N elements" depending on the argument.""" 831 return '1 element' if num == 1 else '%d elements' % num 832 833 834 class StdMapPrinter(printer_base): 835 """Print a std::map or std::multimap.""" 836 837 # Turn an RbtreeIterator into a pretty-print iterator. 838 class _iter(Iterator): 839 def __init__(self, rbiter, type): 840 self._rbiter = rbiter 841 self._count = 0 842 self._type = type 843 844 def __iter__(self): 845 return self 846 847 def __next__(self): 848 if self._count % 2 == 0: 849 n = next(self._rbiter) 850 n = n.cast(self._type).dereference() 851 n = get_value_from_Rb_tree_node(n) 852 self._pair = n 853 item = n['first'] 854 else: 855 item = self._pair['second'] 856 result = ('[%d]' % self._count, item) 857 self._count = self._count + 1 858 return result 859 860 def __init__(self, typename, val): 861 self._typename = strip_versioned_namespace(typename) 862 self._val = val 863 864 def to_string(self): 865 return '%s with %s' % (self._typename, 866 num_elements(len(RbtreeIterator(self._val)))) 867 868 def children(self): 869 node = lookup_node_type('_Rb_tree_node', self._val.type).pointer() 870 return self._iter(RbtreeIterator(self._val), node) 871 872 def display_hint(self): 873 return 'map' 874 875 876 class StdSetPrinter(printer_base): 877 """Print a std::set or std::multiset.""" 878 879 # Turn an RbtreeIterator into a pretty-print iterator. 880 class _iter(Iterator): 881 def __init__(self, rbiter, type): 882 self._rbiter = rbiter 883 self._count = 0 884 self._type = type 885 886 def __iter__(self): 887 return self 888 889 def __next__(self): 890 item = next(self._rbiter) 891 item = item.cast(self._type).dereference() 892 item = get_value_from_Rb_tree_node(item) 893 # FIXME: this is weird ... what to do? 894 # Maybe a 'set' display hint? 895 result = ('[%d]' % self._count, item) 896 self._count = self._count + 1 897 return result 898 899 def __init__(self, typename, val): 900 self._typename = strip_versioned_namespace(typename) 901 self._val = val 902 903 def to_string(self): 904 return '%s with %s' % (self._typename, 905 num_elements(len(RbtreeIterator(self._val)))) 906 907 def children(self): 908 node = lookup_node_type('_Rb_tree_node', self._val.type).pointer() 909 return self._iter(RbtreeIterator(self._val), node) 910 911 912 class StdBitsetPrinter(printer_base): 913 """Print a std::bitset.""" 914 915 def __init__(self, typename, val): 916 self._typename = strip_versioned_namespace(typename) 917 self._val = val 918 919 def to_string(self): 920 # If template_argument handled values, we could print the 921 # size. Or we could use a regexp on the type. 922 return '%s' % (self._typename) 923 924 def children(self): 925 try: 926 # An empty bitset may not have any members which will 927 # result in an exception being thrown. 928 words = self._val['_M_w'] 929 except: 930 return [] 931 932 wtype = words.type 933 934 # The _M_w member can be either an unsigned long, or an 935 # array. This depends on the template specialization used. 936 # If it is a single long, convert to a single element list. 937 if wtype.code == gdb.TYPE_CODE_ARRAY: 938 tsize = wtype.target().sizeof 939 else: 940 words = [words] 941 tsize = wtype.sizeof 942 943 nwords = wtype.sizeof / tsize 944 result = [] 945 byte = 0 946 while byte < nwords: 947 w = words[byte] 948 bit = 0 949 while w != 0: 950 if (w & 1) != 0: 951 # Another spot where we could use 'set'? 952 result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) 953 bit = bit + 1 954 w = w >> 1 955 byte = byte + 1 956 return result 957 958 959 class StdDequePrinter(printer_base): 960 """Print a std::deque.""" 961 962 class _iter(Iterator): 963 def __init__(self, node, start, end, last, buffer_size): 964 self._node = node 965 self._p = start 966 self._end = end 967 self._last = last 968 self._buffer_size = buffer_size 969 self._count = 0 970 971 def __iter__(self): 972 return self 973 974 def __next__(self): 975 if self._p == self._last: 976 raise StopIteration 977 978 result = ('[%d]' % self._count, self._p.dereference()) 979 self._count = self._count + 1 980 981 # Advance the 'cur' pointer. 982 self._p = self._p + 1 983 if self._p == self._end: 984 # If we got to the end of this bucket, move to the 985 # next bucket. 986 self._node = self._node + 1 987 self._p = self._node[0] 988 self._end = self._p + self._buffer_size 989 990 return result 991 992 def __init__(self, typename, val): 993 self._typename = strip_versioned_namespace(typename) 994 self._val = val 995 self._elttype = val.type.template_argument(0) 996 size = self._elttype.sizeof 997 if size < 512: 998 self._buffer_size = int(512 / size) 999 else: 1000 self._buffer_size = 1 1001 1002 def to_string(self): 1003 start = self._val['_M_impl']['_M_start'] 1004 end = self._val['_M_impl']['_M_finish'] 1005 1006 delta_n = end['_M_node'] - start['_M_node'] - 1 1007 delta_s = start['_M_last'] - start['_M_cur'] 1008 delta_e = end['_M_cur'] - end['_M_first'] 1009 1010 size = self._buffer_size * delta_n + delta_s + delta_e 1011 1012 return '%s with %s' % (self._typename, num_elements(long(size))) 1013 1014 def children(self): 1015 start = self._val['_M_impl']['_M_start'] 1016 end = self._val['_M_impl']['_M_finish'] 1017 return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], 1018 end['_M_cur'], self._buffer_size) 1019 1020 def display_hint(self): 1021 return 'array' 1022 1023 1024 class StdDequeIteratorPrinter(printer_base): 1025 """Print std::deque::iterator.""" 1026 1027 def __init__(self, typename, val): 1028 self._val = val 1029 1030 def to_string(self): 1031 if not self._val['_M_cur']: 1032 return 'non-dereferenceable iterator for std::deque' 1033 return str(self._val['_M_cur'].dereference()) 1034 1035 1036 class StdStringPrinter(printer_base): 1037 """Print a std::basic_string of some kind.""" 1038 1039 def __init__(self, typename, val): 1040 self._val = val 1041 self._new_string = typename.find("::__cxx11::basic_string") != -1 1042 1043 def to_string(self): 1044 # Make sure &string works, too. 1045 type = self._val.type 1046 if type.code == gdb.TYPE_CODE_REF: 1047 type = type.target() 1048 1049 # Calculate the length of the string so that to_string returns 1050 # the string according to length, not according to first null 1051 # encountered. 1052 ptr = self._val['_M_dataplus']['_M_p'] 1053 if self._new_string: 1054 length = self._val['_M_string_length'] 1055 # https://sourceware.org/bugzilla/show_bug.cgi?id=17728 1056 ptr = ptr.cast(ptr.type.strip_typedefs()) 1057 else: 1058 realtype = type.unqualified().strip_typedefs() 1059 reptype = gdb.lookup_type(str(realtype) + '::_Rep').pointer() 1060 header = ptr.cast(reptype) - 1 1061 length = header.dereference()['_M_length'] 1062 if hasattr(ptr, "lazy_string"): 1063 return ptr.lazy_string(length=length) 1064 return ptr.string(length=length) 1065 1066 def display_hint(self): 1067 return 'string' 1068 1069 1070 def access_streambuf_ptrs(streambuf): 1071 """Access the streambuf put area pointers.""" 1072 pbase = streambuf['_M_out_beg'] 1073 pptr = streambuf['_M_out_cur'] 1074 egptr = streambuf['_M_in_end'] 1075 return pbase, pptr, egptr 1076 1077 1078 class StdStringBufPrinter(printer_base): 1079 """Print a std::basic_stringbuf.""" 1080 1081 def __init__(self, _, val): 1082 self._val = val 1083 1084 def to_string(self): 1085 (pbase, pptr, egptr) = access_streambuf_ptrs(self._val) 1086 # Logic from basic_stringbuf::_M_high_mark() 1087 if pptr: 1088 if not egptr or pptr > egptr: 1089 return pbase.string(length=pptr - pbase) 1090 else: 1091 return pbase.string(length=egptr - pbase) 1092 return self._val['_M_string'] 1093 1094 def display_hint(self): 1095 return 'string' 1096 1097 1098 class StdStringStreamPrinter(printer_base): 1099 """Print a std::basic_stringstream.""" 1100 1101 def __init__(self, typename, val): 1102 self._val = val 1103 self._typename = typename 1104 1105 # Check if the stream was redirected. This is essentially: 1106 # val['_M_streambuf'] != val['_M_stringbuf'].address 1107 # However, GDB can't resolve the virtual inheritance, so we do that 1108 # manually. 1109 basetype = [f.type for f in val.type.fields() if f.is_base_class][0] 1110 gdb.set_convenience_variable('__stream', val.cast(basetype).address) 1111 self._streambuf = gdb.parse_and_eval('$__stream->rdbuf()') 1112 self._was_redirected = self._streambuf != val['_M_stringbuf'].address 1113 1114 def to_string(self): 1115 if self._was_redirected: 1116 return "%s redirected to %s" % ( 1117 self._typename, self._streambuf.dereference()) 1118 return self._val['_M_stringbuf'] 1119 1120 def display_hint(self): 1121 if self._was_redirected: 1122 return None 1123 return 'string' 1124 1125 1126 class Tr1HashtableIterator(Iterator): 1127 def __init__(self, hashtable): 1128 self._buckets = hashtable['_M_buckets'] 1129 self._bucket = 0 1130 self._bucket_count = hashtable['_M_bucket_count'] 1131 self._node_type = find_type(hashtable.type, '_Node').pointer() 1132 self._node = 0 1133 while self._bucket != self._bucket_count: 1134 self._node = self._buckets[self._bucket] 1135 if self._node: 1136 break 1137 self._bucket = self._bucket + 1 1138 1139 def __iter__(self): 1140 return self 1141 1142 def __next__(self): 1143 if self._node == 0: 1144 raise StopIteration 1145 node = self._node.cast(self._node_type) 1146 result = node.dereference()['_M_v'] 1147 self._node = node.dereference()['_M_next'] 1148 if self._node == 0: 1149 self._bucket = self._bucket + 1 1150 while self._bucket != self._bucket_count: 1151 self._node = self._buckets[self._bucket] 1152 if self._node: 1153 break 1154 self._bucket = self._bucket + 1 1155 return result 1156 1157 1158 class StdHashtableIterator(Iterator): 1159 def __init__(self, hashtable): 1160 self._node = hashtable['_M_before_begin']['_M_nxt'] 1161 valtype = hashtable.type.template_argument(1) 1162 cached = hashtable.type.template_argument(9).template_argument(0) 1163 node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype), 1164 'true' if cached else 'false') 1165 self._node_type = node_type.pointer() 1166 1167 def __iter__(self): 1168 return self 1169 1170 def __next__(self): 1171 if self._node == 0: 1172 raise StopIteration 1173 elt = self._node.cast(self._node_type).dereference() 1174 self._node = elt['_M_nxt'] 1175 valptr = elt['_M_storage'].address 1176 valptr = valptr.cast(elt.type.template_argument(0).pointer()) 1177 return valptr.dereference() 1178 1179 1180 class Tr1UnorderedSetPrinter(printer_base): 1181 """Print a std::unordered_set or tr1::unordered_set.""" 1182 1183 def __init__(self, typename, val): 1184 self._typename = strip_versioned_namespace(typename) 1185 self._val = val 1186 1187 def _hashtable(self): 1188 if self._typename.startswith('std::tr1'): 1189 return self._val 1190 return self._val['_M_h'] 1191 1192 def to_string(self): 1193 count = self._hashtable()['_M_element_count'] 1194 return '%s with %s' % (self._typename, num_elements(count)) 1195 1196 @staticmethod 1197 def _format_count(i): 1198 return '[%d]' % i 1199 1200 def children(self): 1201 counter = imap(self._format_count, itertools.count()) 1202 if self._typename.startswith('std::tr1'): 1203 return izip(counter, Tr1HashtableIterator(self._hashtable())) 1204 return izip(counter, StdHashtableIterator(self._hashtable())) 1205 1206 1207 class Tr1UnorderedMapPrinter(printer_base): 1208 """Print a std::unordered_map or tr1::unordered_map.""" 1209 1210 def __init__(self, typename, val): 1211 self._typename = strip_versioned_namespace(typename) 1212 self._val = val 1213 1214 def _hashtable(self): 1215 if self._typename.startswith('std::tr1'): 1216 return self._val 1217 return self._val['_M_h'] 1218 1219 def to_string(self): 1220 count = self._hashtable()['_M_element_count'] 1221 return '%s with %s' % (self._typename, num_elements(count)) 1222 1223 @staticmethod 1224 def _flatten(list): 1225 for elt in list: 1226 for i in elt: 1227 yield i 1228 1229 @staticmethod 1230 def _format_one(elt): 1231 return (elt['first'], elt['second']) 1232 1233 @staticmethod 1234 def _format_count(i): 1235 return '[%d]' % i 1236 1237 def children(self): 1238 counter = imap(self._format_count, itertools.count()) 1239 # Map over the hash table and flatten the result. 1240 if self._typename.startswith('std::tr1'): 1241 data = self._flatten( 1242 imap(self._format_one, Tr1HashtableIterator(self._hashtable()))) 1243 # Zip the two iterators together. 1244 return izip(counter, data) 1245 data = self._flatten( 1246 imap(self._format_one, StdHashtableIterator(self._hashtable()))) 1247 # Zip the two iterators together. 1248 return izip(counter, data) 1249 1250 def display_hint(self): 1251 return 'map' 1252 1253 1254 class StdForwardListPrinter(printer_base): 1255 """Print a std::forward_list.""" 1256 1257 class _iterator(Iterator): 1258 def __init__(self, nodetype, head): 1259 self._nodetype = nodetype 1260 self._base = head['_M_next'] 1261 self._count = 0 1262 1263 def __iter__(self): 1264 return self 1265 1266 def __next__(self): 1267 if self._base == 0: 1268 raise StopIteration 1269 elt = self._base.cast(self._nodetype).dereference() 1270 self._base = elt['_M_next'] 1271 count = self._count 1272 self._count = self._count + 1 1273 valptr = elt['_M_storage'].address 1274 valptr = valptr.cast(elt.type.template_argument(0).pointer()) 1275 return ('[%d]' % count, valptr.dereference()) 1276 1277 def __init__(self, typename, val): 1278 self._val = val 1279 self._typename = strip_versioned_namespace(typename) 1280 1281 def children(self): 1282 nodetype = lookup_node_type('_Fwd_list_node', self._val.type).pointer() 1283 return self._iterator(nodetype, self._val['_M_impl']['_M_head']) 1284 1285 def to_string(self): 1286 if self._val['_M_impl']['_M_head']['_M_next'] == 0: 1287 return 'empty %s' % self._typename 1288 return '%s' % self._typename 1289 1290 1291 class SingleObjContainerPrinter(printer_base): 1292 """Base class for printers of containers of single objects.""" 1293 1294 def __init__(self, val, viz, hint=None): 1295 self._contained_value = val 1296 self._visualizer = viz 1297 self._hint = hint 1298 1299 def _recognize(self, type): 1300 """Return type as a string after applying type printers.""" 1301 global _use_type_printing 1302 if not _use_type_printing: 1303 return str(type) 1304 return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(), 1305 type) or str(type) 1306 1307 class _contained(Iterator): 1308 def __init__(self, val): 1309 self._val = val 1310 1311 def __iter__(self): 1312 return self 1313 1314 def __next__(self): 1315 if self._val is None: 1316 raise StopIteration 1317 retval = self._val 1318 self._val = None 1319 return ('[contained value]', retval) 1320 1321 def children(self): 1322 if self._contained_value is None: 1323 return self._contained(None) 1324 if hasattr(self._visualizer, 'children'): 1325 return self._visualizer.children() 1326 return self._contained(self._contained_value) 1327 1328 def display_hint(self): 1329 if (hasattr(self._visualizer, 'children') 1330 and hasattr(self._visualizer, 'display_hint')): 1331 # If contained value is a map we want to display in the same way. 1332 return self._visualizer.display_hint() 1333 return self._hint 1334 1335 1336 def function_pointer_to_name(f): 1337 """Find the name of the function referred to by the gdb.Value f, 1338 which should contain a function pointer from the program.""" 1339 1340 # Turn the function pointer into an actual address. 1341 # This is needed to unpack ppc64 function descriptors. 1342 f = f.dereference().address 1343 1344 if sys.version_info[0] == 2: 1345 # Older versions of GDB need to use long for Python 2, 1346 # because int(f) on 64-bit big-endian values raises a 1347 # gdb.error saying "Cannot convert value to int." 1348 f = long(f) 1349 else: 1350 f = int(f) 1351 1352 try: 1353 # If the function can't be found older versions of GDB raise a 1354 # RuntimeError saying "Cannot locate object file for block." 1355 return gdb.block_for_pc(f).function.name 1356 except: 1357 return None 1358 1359 1360 class StdExpAnyPrinter(SingleObjContainerPrinter): 1361 """Print a std::any or std::experimental::any.""" 1362 1363 def __init__(self, typename, val): 1364 self._typename = strip_versioned_namespace(typename) 1365 self._typename = strip_fundts_namespace(self._typename) 1366 self._val = val 1367 self._contained_type = None 1368 contained_value = None 1369 visualizer = None 1370 mgr = self._val['_M_manager'] 1371 if mgr != 0: 1372 func = function_pointer_to_name(mgr) 1373 if not func: 1374 raise ValueError( 1375 "Invalid function pointer in %s" % (self._typename)) 1376 # We want to use this regular expression: 1377 # T::_Manager_xxx<.*>::_S_manage\(T::_Op, const T\*, T::_Arg\*\) 1378 # where T is std::any or std::experimental::any. 1379 # But we need to account for variances in demangled names 1380 # between GDB versions, e.g. 'enum T::_Op' instead of 'T::_Op'. 1381 rx = ( 1382 r"({0}::_Manager_\w+<.*>)::_S_manage\(" 1383 r"(enum )?{0}::_Op, (const {0}|{0} const) ?\*, " 1384 r"(union )?{0}::_Arg ?\*\)" 1385 ).format(typename) 1386 m = re.match(rx, func) 1387 if not m: 1388 raise ValueError( 1389 "Unknown manager function in %s" % self._typename) 1390 1391 mgrname = m.group(1) 1392 # FIXME need to expand 'std::string' so that gdb.lookup_type works 1393 if 'std::string' in mgrname: 1394 mgrtypes = [] 1395 for s in StdExpAnyPrinter._string_types(): 1396 try: 1397 x = re.sub(r"std::string(?!\w)", s, m.group(1)) 1398 # The following lookup might raise gdb.error if the 1399 # manager function was never instantiated for 's' in 1400 # the program, because there will be no such type. 1401 mgrtypes.append(gdb.lookup_type(x)) 1402 except gdb.error: 1403 pass 1404 if len(mgrtypes) != 1: 1405 # FIXME: this is unlikely in practice, but possible for 1406 # programs that use both old and new string types with 1407 # std::any in a single program. Can we do better? 1408 # Maybe find the address of each type's _S_manage and 1409 # compare to the address stored in _M_manager? 1410 raise ValueError( 1411 'Cannot uniquely determine std::string type ' 1412 'used in std::any' 1413 ) 1414 mgrtype = mgrtypes[0] 1415 else: 1416 mgrtype = gdb.lookup_type(mgrname) 1417 self._contained_type = mgrtype.template_argument(0) 1418 valptr = None 1419 if '::_Manager_internal' in mgrname: 1420 valptr = self._val['_M_storage']['_M_buffer'].address 1421 elif '::_Manager_external' in mgrname: 1422 valptr = self._val['_M_storage']['_M_ptr'] 1423 else: 1424 raise ValueError( 1425 "Unknown manager function in %s" % self._typename) 1426 contained_value = valptr.cast( 1427 self._contained_type.pointer()).dereference() 1428 visualizer = gdb.default_visualizer(contained_value) 1429 super(StdExpAnyPrinter, self).__init__(contained_value, visualizer) 1430 1431 def to_string(self): 1432 if self._contained_type is None: 1433 return '%s [no contained value]' % self._typename 1434 desc = "%s containing " % self._typename 1435 if hasattr(self._visualizer, 'children'): 1436 return desc + self._visualizer.to_string() 1437 valtype = self._recognize(self._contained_type) 1438 return desc + strip_versioned_namespace(str(valtype)) 1439 1440 @staticmethod 1441 def _string_types(): 1442 # This lookup for std::string might return the __cxx11 version, 1443 # but that's not necessarily the one used by the std::any 1444 # manager function we're trying to find. 1445 strings = {str(gdb.lookup_type('std::string').strip_typedefs())} 1446 # So also consider all the other possible std::string types! 1447 s = 'basic_string<char, std::char_traits<char>, std::allocator<char> >' 1448 quals = ['std::', 'std::__cxx11::', 1449 'std::' + _versioned_namespace] 1450 strings |= {q + s for q in quals} # set of unique strings 1451 return strings 1452 1453 1454 class StdExpOptionalPrinter(SingleObjContainerPrinter): 1455 """Print a std::optional or std::experimental::optional.""" 1456 1457 def __init__(self, typename, val): 1458 self._typename = strip_versioned_namespace(typename) 1459 self._typename = strip_fundts_namespace(self._typename) 1460 payload = val['_M_payload'] 1461 if self._typename.startswith('std::experimental'): 1462 engaged = val['_M_engaged'] 1463 contained_value = payload 1464 else: 1465 engaged = payload['_M_engaged'] 1466 contained_value = payload['_M_payload'] 1467 try: 1468 # Since GCC 9 1469 contained_value = contained_value['_M_value'] 1470 except: 1471 pass 1472 visualizer = gdb.default_visualizer(contained_value) 1473 if not engaged: 1474 contained_value = None 1475 super(StdExpOptionalPrinter, self).__init__( 1476 contained_value, visualizer) 1477 1478 def to_string(self): 1479 if self._contained_value is None: 1480 return "%s [no contained value]" % self._typename 1481 if hasattr(self._visualizer, 'children'): 1482 return "%s containing %s" % (self._typename, 1483 self._visualizer.to_string()) 1484 return self._typename 1485 1486 1487 class StdVariantPrinter(SingleObjContainerPrinter): 1488 """Print a std::variant.""" 1489 1490 def __init__(self, typename, val): 1491 alternatives = get_template_arg_list(val.type) 1492 self._typename = strip_versioned_namespace(typename) 1493 self._index = val['_M_index'] 1494 if self._index >= len(alternatives): 1495 self._contained_type = None 1496 contained_value = None 1497 visualizer = None 1498 else: 1499 self._contained_type = alternatives[int(self._index)] 1500 addr = val['_M_u']['_M_first']['_M_storage'].address 1501 contained_value = addr.cast( 1502 self._contained_type.pointer()).dereference() 1503 visualizer = gdb.default_visualizer(contained_value) 1504 super(StdVariantPrinter, self).__init__( 1505 contained_value, visualizer, 'array') 1506 1507 def to_string(self): 1508 if self._contained_value is None: 1509 return "%s [no contained value]" % self._typename 1510 if hasattr(self._visualizer, 'children'): 1511 return "%s [index %d] containing %s" % (self._typename, self._index, 1512 self._visualizer.to_string()) 1513 return "%s [index %d]" % (self._typename, self._index) 1514 1515 1516 class StdNodeHandlePrinter(SingleObjContainerPrinter): 1517 """Print a container node handle.""" 1518 1519 def __init__(self, typename, val): 1520 self._value_type = val.type.template_argument(1) 1521 nodetype = val.type.template_argument(2).template_argument(0) 1522 self._is_rb_tree_node = is_specialization_of( 1523 nodetype.name, '_Rb_tree_node') 1524 self._is_map_node = val.type.template_argument(0) != self._value_type 1525 nodeptr = val['_M_ptr'] 1526 if nodeptr: 1527 if self._is_rb_tree_node: 1528 contained_value = get_value_from_Rb_tree_node( 1529 nodeptr.dereference()) 1530 else: 1531 contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'], 1532 self._value_type) 1533 visualizer = gdb.default_visualizer(contained_value) 1534 else: 1535 contained_value = None 1536 visualizer = None 1537 optalloc = val['_M_alloc'] 1538 self._alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None 1539 super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer, 1540 'array') 1541 1542 def to_string(self): 1543 desc = 'node handle for ' 1544 if not self._is_rb_tree_node: 1545 desc += 'unordered ' 1546 if self._is_map_node: 1547 desc += 'map' 1548 else: 1549 desc += 'set' 1550 1551 if self._contained_value: 1552 desc += ' with element' 1553 if hasattr(self._visualizer, 'children'): 1554 return "%s = %s" % (desc, self._visualizer.to_string()) 1555 return desc 1556 else: 1557 return 'empty %s' % desc 1558 1559 1560 class StdExpStringViewPrinter(printer_base): 1561 """ 1562 Print a std::basic_string_view or std::experimental::basic_string_view 1563 """ 1564 1565 def __init__(self, typename, val): 1566 self._val = val 1567 1568 def to_string(self): 1569 ptr = self._val['_M_str'] 1570 len = self._val['_M_len'] 1571 if hasattr(ptr, "lazy_string"): 1572 return ptr.lazy_string(length=len) 1573 return ptr.string(length=len) 1574 1575 def display_hint(self): 1576 return 'string' 1577 1578 1579 class StdExpPathPrinter(printer_base): 1580 """Print a std::experimental::filesystem::path.""" 1581 1582 def __init__(self, typename, val): 1583 self._val = val 1584 self._typename = typename 1585 start = self._val['_M_cmpts']['_M_impl']['_M_start'] 1586 finish = self._val['_M_cmpts']['_M_impl']['_M_finish'] 1587 self._num_cmpts = int(finish - start) 1588 1589 def _path_type(self): 1590 t = str(self._val['_M_type']) 1591 if t[-9:] == '_Root_dir': 1592 return "root-directory" 1593 if t[-10:] == '_Root_name': 1594 return "root-name" 1595 return None 1596 1597 def to_string(self): 1598 path = "%s" % self._val['_M_pathname'] 1599 if self._num_cmpts == 0: 1600 t = self._path_type() 1601 if t: 1602 path = '%s [%s]' % (path, t) 1603 return "experimental::filesystem::path %s" % path 1604 1605 class _iterator(Iterator): 1606 def __init__(self, cmpts, pathtype): 1607 self._pathtype = pathtype 1608 self._item = cmpts['_M_impl']['_M_start'] 1609 self._finish = cmpts['_M_impl']['_M_finish'] 1610 self._count = 0 1611 1612 def __iter__(self): 1613 return self 1614 1615 def __next__(self): 1616 if self._item == self._finish: 1617 raise StopIteration 1618 item = self._item.dereference() 1619 count = self._count 1620 self._count = self._count + 1 1621 self._item = self._item + 1 1622 path = item['_M_pathname'] 1623 t = StdExpPathPrinter(self._pathtype, item)._path_type() 1624 if not t: 1625 t = count 1626 return ('[%s]' % t, path) 1627 1628 def children(self): 1629 return self._iterator(self._val['_M_cmpts'], self._typename) 1630 1631 1632 class StdPathPrinter(printer_base): 1633 """Print a std::filesystem::path.""" 1634 1635 def __init__(self, typename, val): 1636 self._val = val 1637 self._typename = typename 1638 impl = unique_ptr_get(self._val['_M_cmpts']['_M_impl']) 1639 self._type = impl.cast(gdb.lookup_type('uintptr_t')) & 3 1640 if self._type == 0: 1641 self._impl = impl 1642 else: 1643 self._impl = None 1644 1645 def _path_type(self): 1646 t = str(self._type.cast(gdb.lookup_type(self._typename + '::_Type'))) 1647 if t[-9:] == '_Root_dir': 1648 return "root-directory" 1649 if t[-10:] == '_Root_name': 1650 return "root-name" 1651 return None 1652 1653 def to_string(self): 1654 path = "%s" % self._val['_M_pathname'] 1655 if self._type != 0: 1656 t = self._path_type() 1657 if t: 1658 path = '%s [%s]' % (path, t) 1659 return "filesystem::path %s" % path 1660 1661 class _iterator(Iterator): 1662 def __init__(self, impl, pathtype): 1663 self._pathtype = pathtype 1664 if impl: 1665 # We can't access _Impl::_M_size because _Impl is incomplete 1666 # so cast to int* to access the _M_size member at offset zero, 1667 int_type = gdb.lookup_type('int') 1668 cmpt_type = gdb.lookup_type(pathtype + '::_Cmpt') 1669 char_type = gdb.lookup_type('char') 1670 impl = impl.cast(int_type.pointer()) 1671 size = impl.dereference() 1672 #self._capacity = (impl + 1).dereference() 1673 if hasattr(gdb.Type, 'alignof'): 1674 sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof) 1675 else: 1676 sizeof_Impl = 2 * int_type.sizeof 1677 begin = impl.cast(char_type.pointer()) + sizeof_Impl 1678 self._item = begin.cast(cmpt_type.pointer()) 1679 self._finish = self._item + size 1680 self._count = 0 1681 else: 1682 self._item = None 1683 self._finish = None 1684 1685 def __iter__(self): 1686 return self 1687 1688 def __next__(self): 1689 if self._item == self._finish: 1690 raise StopIteration 1691 item = self._item.dereference() 1692 count = self._count 1693 self._count = self._count + 1 1694 self._item = self._item + 1 1695 path = item['_M_pathname'] 1696 t = StdPathPrinter(self._pathtype, item)._path_type() 1697 if not t: 1698 t = count 1699 return ('[%s]' % t, path) 1700 1701 def children(self): 1702 return self._iterator(self._impl, self._typename) 1703 1704 1705 class StdPairPrinter(printer_base): 1706 """Print a std::pair object, with 'first' and 'second' as children.""" 1707 1708 def __init__(self, typename, val): 1709 self._val = val 1710 1711 class _iter(Iterator): 1712 """An iterator for std::pair types. Returns 'first' then 'second'.""" 1713 1714 def __init__(self, val): 1715 self._val = val 1716 self._which = 'first' 1717 1718 def __iter__(self): 1719 return self 1720 1721 def __next__(self): 1722 if self._which is None: 1723 raise StopIteration 1724 which = self._which 1725 if which == 'first': 1726 self._which = 'second' 1727 else: 1728 self._which = None 1729 return (which, self._val[which]) 1730 1731 def children(self): 1732 return self._iter(self._val) 1733 1734 def to_string(self): 1735 return None 1736 1737 1738 class StdCmpCatPrinter(printer_base): 1739 """Print a comparison category object.""" 1740 1741 def __init__(self, typename, val): 1742 self._typename = typename[typename.rfind(':') + 1:] 1743 self._val = val['_M_value'] 1744 1745 def to_string(self): 1746 if self._typename == 'strong_ordering' and self._val == 0: 1747 name = 'equal' 1748 else: 1749 names = {2: 'unordered', -1: 'less', 0: 'equivalent', 1: 'greater'} 1750 name = names[int(self._val)] 1751 return 'std::{}::{}'.format(self._typename, name) 1752 1753 1754 class StdErrorCodePrinter(printer_base): 1755 """Print a std::error_code or std::error_condition.""" 1756 1757 _system_is_posix = None # Whether std::system_category() use errno values. 1758 1759 def __init__(self, typename, val): 1760 self._val = val 1761 self._typename = strip_versioned_namespace(typename) 1762 # Do this only once ... 1763 if StdErrorCodePrinter._system_is_posix is None: 1764 try: 1765 import posix 1766 StdErrorCodePrinter._system_is_posix = True 1767 except ImportError: 1768 StdErrorCodePrinter._system_is_posix = False 1769 1770 @staticmethod 1771 def _find_errc_enum(name): 1772 typ = gdb.lookup_type(name) 1773 if typ is not None and typ.code == gdb.TYPE_CODE_ENUM: 1774 return typ 1775 return None 1776 1777 @classmethod 1778 def _find_standard_errc_enum(cls, name): 1779 for ns in ['', _versioned_namespace]: 1780 try: 1781 qname = 'std::{}{}'.format(ns, name) 1782 return cls._find_errc_enum(qname) 1783 except RuntimeError: 1784 pass 1785 1786 @classmethod 1787 def _match_net_ts_category(cls, cat): 1788 net_cats = ['stream', 'socket', 'ip::resolver'] 1789 for c in net_cats: 1790 func = c + '_category()' 1791 for ns in ['', _versioned_namespace]: 1792 ns = 'std::{}experimental::net::v1'.format(ns) 1793 sym = gdb.lookup_symbol('{}::{}::__c'.format(ns, func))[0] 1794 if sym is not None: 1795 if cat == sym.value().address: 1796 name = 'net::' + func 1797 enum = cls._find_errc_enum('{}::{}_errc'.format(ns, c)) 1798 return (name, enum) 1799 return (None, None) 1800 1801 @classmethod 1802 def _category_info(cls, cat): 1803 """Return details of a std::error_category.""" 1804 1805 name = None 1806 enum = None 1807 is_errno = False 1808 1809 # Try these first, or we get "warning: RTTI symbol not found" when 1810 # using cat.dynamic_type on the local class types for Net TS 1811 # categories. 1812 func, enum = cls._match_net_ts_category(cat) 1813 if func is not None: 1814 return (None, func, enum, is_errno) 1815 1816 # This might give a warning for a program-defined category defined as 1817 # a local class, but there doesn't seem to be any way to avoid that. 1818 typ = cat.dynamic_type.target() 1819 # Shortcuts for the known categories defined by libstdc++. 1820 if typ.tag.endswith('::generic_error_category'): 1821 name = 'generic' 1822 is_errno = True 1823 if typ.tag.endswith('::system_error_category'): 1824 name = 'system' 1825 is_errno = cls._system_is_posix 1826 if typ.tag.endswith('::future_error_category'): 1827 name = 'future' 1828 enum = cls._find_standard_errc_enum('future_errc') 1829 if typ.tag.endswith('::io_error_category'): 1830 name = 'io' 1831 enum = cls._find_standard_errc_enum('io_errc') 1832 1833 if name is None: 1834 try: 1835 # Want to call std::error_category::name() override, but it's 1836 # unsafe: https://sourceware.org/bugzilla/show_bug.cgi?id=28856 1837 # gdb.set_convenience_variable('__cat', cat) 1838 # return '"%s"' % gdb.parse_and_eval('$__cat->name()').string() 1839 pass 1840 except: 1841 pass 1842 return (name, typ.tag, enum, is_errno) 1843 1844 @staticmethod 1845 def _unqualified_name(name): 1846 """ 1847 Strip any nested-name-specifier from name to give an unqualified name. 1848 """ 1849 return name.split('::')[-1] 1850 1851 def to_string(self): 1852 value = self._val['_M_value'] 1853 cat = self._val['_M_cat'] 1854 name, alt_name, enum, is_errno = self._category_info(cat) 1855 if value == 0: 1856 default_cats = {'error_code': 'system', 1857 'error_condition': 'generic'} 1858 if name == default_cats[self._unqualified_name(self._typename)]: 1859 return self._typename + ' = { }' # default-constructed value 1860 1861 strval = str(value) 1862 if is_errno and value != 0: 1863 try: 1864 strval = errno.errorcode[int(value)] 1865 except: 1866 pass 1867 elif enum is not None: 1868 strval = self._unqualified_name(str(value.cast(enum))) 1869 1870 if name is not None: 1871 name = '"%s"' % name 1872 else: 1873 name = alt_name 1874 return '%s = {%s: %s}' % (self._typename, name, strval) 1875 1876 1877 class StdRegexStatePrinter(printer_base): 1878 """Print a state node in the NFA for a std::regex.""" 1879 1880 def __init__(self, typename, val): 1881 self._val = val 1882 self._typename = typename 1883 1884 def to_string(self): 1885 opcode = str(self._val['_M_opcode']) 1886 if opcode: 1887 opcode = opcode[25:] 1888 next_id = self._val['_M_next'] 1889 1890 variants = {'repeat': 'alt', 'alternative': 'alt', 1891 'subexpr_begin': 'subexpr', 'subexpr_end': 'subexpr', 1892 'line_begin_assertion': None, 'line_end_assertion': None, 1893 'word_boundary': 'neg', 'subexpr_lookahead': 'neg', 1894 'backref': 'backref_index', 1895 'match': None, 'accept': None, 1896 'dummy': None, 'unknown': None 1897 } 1898 v = variants[opcode] 1899 1900 s = "opcode={}, next={}".format(opcode, next_id) 1901 if v is not None and self._val['_M_' + v] is not None: 1902 s = "{}, {}={}".format(s, v, self._val['_M_' + v]) 1903 return "{%s}" % (s) 1904 1905 1906 class StdSpanPrinter(printer_base): 1907 """Print a std::span.""" 1908 1909 class _iterator(Iterator): 1910 def __init__(self, begin, size): 1911 self._count = 0 1912 self._begin = begin 1913 self._size = size 1914 1915 def __iter__(self): 1916 return self 1917 1918 def __next__(self): 1919 if self._count == self._size: 1920 raise StopIteration 1921 1922 count = self._count 1923 self._count = self._count + 1 1924 return '[%d]' % count, (self._begin + count).dereference() 1925 1926 def __init__(self, typename, val): 1927 self._typename = strip_versioned_namespace(typename) 1928 self._val = val 1929 size_max = gdb.parse_and_eval('static_cast<std::size_t>(-1)') 1930 if val.type.template_argument(1) == size_max: 1931 self._size = val['_M_extent']['_M_extent_value'] 1932 else: 1933 self._size = val.type.template_argument(1) 1934 1935 def to_string(self): 1936 return '%s of length %d' % (self._typename, self._size) 1937 1938 def children(self): 1939 return self._iterator(self._val['_M_ptr'], self._size) 1940 1941 def display_hint(self): 1942 return 'array' 1943 1944 1945 class StdInitializerListPrinter(printer_base): 1946 """Print a std::initializer_list.""" 1947 1948 def __init__(self, typename, val): 1949 self._typename = typename 1950 self._val = val 1951 self._size = val['_M_len'] 1952 1953 def to_string(self): 1954 return '%s of length %d' % (self._typename, self._size) 1955 1956 def children(self): 1957 return StdSpanPrinter._iterator(self._val['_M_array'], self._size) 1958 1959 def display_hint(self): 1960 return 'array' 1961 1962 1963 class StdAtomicPrinter(printer_base): 1964 """Print a std:atomic.""" 1965 1966 def __init__(self, typename, val): 1967 self._typename = strip_versioned_namespace(typename) 1968 self._val = val 1969 self._shptr_printer = None 1970 self._value_type = self._val.type.template_argument(0) 1971 if self._value_type.tag is not None: 1972 typ = strip_versioned_namespace(self._value_type.tag) 1973 if (typ.startswith('std::shared_ptr<') 1974 or typ.startswith('std::weak_ptr<')): 1975 impl = val['_M_impl'] 1976 self._shptr_printer = SharedPointerPrinter(typename, impl) 1977 self.children = self._shptr_children 1978 1979 def _shptr_children(self): 1980 return SmartPtrIterator(self._shptr_printer._pointer) 1981 1982 def to_string(self): 1983 if self._shptr_printer is not None: 1984 return self._shptr_printer.to_string() 1985 1986 if self._value_type.code == gdb.TYPE_CODE_INT: 1987 val = self._val['_M_i'] 1988 elif self._value_type.code == gdb.TYPE_CODE_FLT: 1989 val = self._val['_M_fp'] 1990 elif self._value_type.code == gdb.TYPE_CODE_PTR: 1991 val = self._val['_M_b']['_M_p'] 1992 elif self._value_type.code == gdb.TYPE_CODE_BOOL: 1993 val = self._val['_M_base']['_M_i'] 1994 else: 1995 val = self._val['_M_i'] 1996 return '%s<%s> = { %s }' % (self._typename, str(self._value_type), val) 1997 1998 1999 class StdFormatArgsPrinter(printer_base): 2000 """Print a std::basic_format_args.""" 2001 # TODO: add printer for basic_format_arg<Context> and print out children. 2002 # TODO: add printer for __format::_ArgStore<Context, Args...>. 2003 2004 def __init__(self, typename, val): 2005 self._typename = strip_versioned_namespace(typename) 2006 self._val = val 2007 2008 def to_string(self): 2009 targs = get_template_arg_list(self._val.type) 2010 char_type = get_template_arg_list(targs[0])[1] 2011 if char_type == gdb.lookup_type('char'): 2012 typ = 'std::format_args' 2013 elif char_type == gdb.lookup_type('wchar_t'): 2014 typ = 'std::wformat_args' 2015 else: 2016 typ = 'std::basic_format_args' 2017 2018 size = self._val['_M_packed_size'] 2019 if size == 1: 2020 return "%s with 1 argument" % (typ) 2021 if size == 0: 2022 size = self._val['_M_unpacked_size'] 2023 return "%s with %d arguments" % (typ, size) 2024 2025 2026 class StdChronoDurationPrinter(printer_base): 2027 """Print a std::chrono::duration.""" 2028 2029 def __init__(self, typename, val): 2030 self._typename = strip_versioned_namespace(typename) 2031 self._val = val 2032 2033 def _ratio(self): 2034 # TODO use reduced period i.e. duration::period 2035 period = self._val.type.template_argument(1) 2036 num = period.template_argument(0) 2037 den = period.template_argument(1) 2038 return (num, den) 2039 2040 def _suffix(self): 2041 num, den = self._ratio() 2042 if num == 1: 2043 if den == 1: 2044 return 's' 2045 if den == 1000: 2046 return 'ms' 2047 if den == 1000000: 2048 return 'us' 2049 if den == 1000000000: 2050 return 'ns' 2051 elif den == 1: 2052 if num == 60: 2053 return 'min' 2054 if num == 3600: 2055 return 'h' 2056 if num == 86400: 2057 return 'd' 2058 return '[{}]s'.format(num) 2059 return "[{}/{}]s".format(num, den) 2060 2061 def to_string(self): 2062 r = self._val['__r'] 2063 if r.type.strip_typedefs().code == gdb.TYPE_CODE_FLT: 2064 r = "%g" % r 2065 return "std::chrono::duration = {{ {}{} }}".format(r, self._suffix()) 2066 2067 2068 class StdChronoTimePointPrinter(printer_base): 2069 """Print a std::chrono::time_point.""" 2070 2071 def __init__(self, typename, val): 2072 self._typename = strip_versioned_namespace(typename) 2073 self._val = val 2074 2075 def _clock(self): 2076 clock = self._val.type.template_argument(0) 2077 name = strip_versioned_namespace(clock.name) 2078 if name == 'std::chrono::_V2::system_clock' \ 2079 or name == 'std::chrono::system_clock': 2080 return ('std::chrono::sys_time', 0) 2081 # XXX need to remove leap seconds from utc, gps, and tai 2082 if name == 'std::chrono::utc_clock': 2083 return ('std::chrono::utc_time', None) # XXX 2084 if name == 'std::chrono::gps_clock': 2085 return ('std::chrono::gps_time', None) # XXX 315964809 2086 if name == 'std::chrono::tai_clock': 2087 return ('std::chrono::tai_time', None) # XXX -378691210 2088 if name == 'std::filesystem::__file_clock': 2089 return ('std::chrono::file_time', 6437664000) 2090 if name == 'std::chrono::local_t': 2091 return ('std::chrono::local_time', 0) 2092 return ('{} time_point'.format(name), None) 2093 2094 def to_string(self, abbrev=False): 2095 clock, offset = self._clock() 2096 d = self._val['__d'] 2097 r = d['__r'] 2098 printer = StdChronoDurationPrinter(d.type.name, d) 2099 suffix = printer._suffix() 2100 time = '' 2101 if offset is not None: 2102 num, den = printer._ratio() 2103 secs = (r * num / den) + offset 2104 try: 2105 dt = datetime.datetime.fromtimestamp(secs, _utc_timezone) 2106 time = ' [{:%Y-%m-%d %H:%M:%S}]'.format(dt) 2107 except: 2108 pass 2109 s = '%d%s%s' % (r, suffix, time) 2110 if abbrev: 2111 return s 2112 return '%s = { %s }' % (clock, s) 2113 2114 2115 class StdChronoZonedTimePrinter(printer_base): 2116 """Print a std::chrono::zoned_time.""" 2117 2118 def __init__(self, typename, val): 2119 self._typename = strip_versioned_namespace(typename) 2120 self._val = val 2121 2122 def to_string(self): 2123 zone = self._val['_M_zone'].dereference()['_M_name'] 2124 time = self._val['_M_tp'] 2125 printer = StdChronoTimePointPrinter(time.type.name, time) 2126 time = printer.to_string(True) 2127 return 'std::chrono::zoned_time = {{ {} {} }}'.format(zone, time) 2128 2129 2130 months = [None, 'January', 'February', 'March', 'April', 'May', 'June', 2131 'July', 'August', 'September', 'October', 'November', 'December'] 2132 2133 weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 2134 'Saturday', 'Sunday'] 2135 2136 2137 class StdChronoCalendarPrinter(printer_base): 2138 """Print a std::chrono::day, std::chrono::month, std::chrono::year etc.""" 2139 2140 def __init__(self, typename, val): 2141 self._typename = strip_versioned_namespace(typename) 2142 self._val = val 2143 2144 def to_string(self): 2145 val = self._val 2146 typ = self._typename 2147 if 'month' in typ and typ != 'std::chrono::year_month_day_last': 2148 m = val['_M_m'] 2149 if typ.startswith('std::chrono::year'): 2150 y = val['_M_y'] 2151 2152 if typ == 'std::chrono::day': 2153 return '{}'.format(int(val['_M_d'])) 2154 if typ == 'std::chrono::month': 2155 if m < 1 or m >= len(months): 2156 return "%d is not a valid month" % m 2157 return months[m] 2158 if typ == 'std::chrono::year': 2159 return '{}y'.format(y) 2160 if typ == 'std::chrono::weekday': 2161 wd = val['_M_wd'] 2162 if wd < 0 or wd >= len(weekdays): 2163 return "%d is not a valid weekday" % wd 2164 return '{}'.format(weekdays[wd]) 2165 if typ == 'std::chrono::weekday_indexed': 2166 return '{}[{}]'.format(val['_M_wd'], int(val['_M_index'])) 2167 if typ == 'std::chrono::weekday_last': 2168 return '{}[last]'.format(val['_M_wd']) 2169 if typ == 'std::chrono::month_day': 2170 return '{}/{}'.format(m, val['_M_d']) 2171 if typ == 'std::chrono::month_day_last': 2172 return '{}/last'.format(m) 2173 if typ == 'std::chrono::month_weekday': 2174 return '{}/{}'.format(m, val['_M_wdi']) 2175 if typ == 'std::chrono::month_weekday_last': 2176 return '{}/{}'.format(m, val['_M_wdl']) 2177 if typ == 'std::chrono::year_month': 2178 return '{}/{}'.format(y, m) 2179 if typ == 'std::chrono::year_month_day': 2180 return '{}/{}/{}'.format(y, m, val['_M_d']) 2181 if typ == 'std::chrono::year_month_day_last': 2182 return '{}/{}'.format(y, val['_M_mdl']) 2183 if typ == 'std::chrono::year_month_weekday': 2184 return '{}/{}/{}'.format(y, m, val['_M_wdi']) 2185 if typ == 'std::chrono::year_month_weekday_last': 2186 return '{}/{}/{}'.format(y, m, val['_M_wdl']) 2187 if typ.startswith('std::chrono::hh_mm_ss'): 2188 fract = '' 2189 if val['fractional_width'] != 0: 2190 fract = '.{:0{}d}'.format(int(val['_M_ss']['_M_r']), 2191 int(val['fractional_width'])) 2192 h = int(val['_M_h']['__r']) 2193 m = int(val['_M_m']['__r']) 2194 s = int(val['_M_s']['__r']) 2195 if val['_M_is_neg']: 2196 h = -h 2197 return '{:02}:{:02}:{:02}{}'.format(h, m, s, fract) 2198 2199 2200 class StdChronoTimeZonePrinter(printer_base): 2201 """Print a chrono::time_zone or chrono::time_zone_link.""" 2202 2203 def __init__(self, typename, val): 2204 self._typename = strip_versioned_namespace(typename) 2205 self._val = val 2206 2207 def to_string(self): 2208 str = '%s = %s' % (self._typename, self._val['_M_name']) 2209 if self._typename.endswith("_link"): 2210 str += ' -> %s' % (self._val['_M_target']) 2211 return str 2212 2213 2214 class StdChronoLeapSecondPrinter(printer_base): 2215 """Print a chrono::leap_second.""" 2216 2217 def __init__(self, typename, val): 2218 self._typename = strip_versioned_namespace(typename) 2219 self._val = val 2220 2221 def to_string(self): 2222 date = self._val['_M_s']['__r'] 2223 neg = '+-'[date < 0] 2224 return '%s %d (%c)' % (self._typename, abs(date), neg) 2225 2226 2227 class StdChronoTzdbPrinter(printer_base): 2228 """Print a chrono::tzdb.""" 2229 2230 def __init__(self, typename, val): 2231 self._typename = strip_versioned_namespace(typename) 2232 self._val = val 2233 2234 def to_string(self): 2235 return '%s %s' % (self._typename, self._val['version']) 2236 2237 2238 class StdChronoTimeZoneRulePrinter(printer_base): 2239 """Print a chrono::time_zone rule.""" 2240 2241 def __init__(self, typename, val): 2242 self._typename = strip_versioned_namespace(typename) 2243 self._val = val 2244 2245 def to_string(self): 2246 on = self._val['on'] 2247 kind = on['kind'] 2248 month = months[on['month']] 2249 suffixes = {1: 'st', 2: 'nd', 3: 'rd', 2250 21: 'st', 22: 'nd', 23: 'rd', 31: 'st'} 2251 day = on['day_of_month'] 2252 ordinal_day = '{}{}'.format(day, suffixes.get(day, 'th')) 2253 if kind == 0: # DayOfMonth 2254 start = '{} {}'.format(month, ordinal_day) 2255 else: 2256 weekday = weekdays[on['day_of_week']] 2257 if kind == 1: # LastWeekDay 2258 start = 'last {} in {}'.format(weekday, month) 2259 else: 2260 if kind == 2: # LessEq 2261 direction = ('last', '<=') 2262 else: 2263 direction = ('first', '>=') 2264 day = on['day_of_month'] 2265 start = '{} {} {} {} {}'.format(direction[0], weekday, 2266 direction[1], month, 2267 ordinal_day) 2268 return 'time_zone rule {} from {} to {} starting on {}'.format( 2269 self._val['name'], self._val['from'], self._val['to'], start) 2270 2271 2272 class StdLocalePrinter(printer_base): 2273 """Print a std::locale.""" 2274 2275 def __init__(self, typename, val): 2276 self._val = val 2277 self._typename = typename 2278 2279 def to_string(self): 2280 names = self._val['_M_impl']['_M_names'] 2281 mod = '' 2282 if names[0] == 0: 2283 name = '*' 2284 else: 2285 cats = gdb.parse_and_eval(self._typename + '::_S_categories') 2286 ncat = gdb.parse_and_eval(self._typename + '::_S_categories_size') 2287 n = names[0].string() 2288 cat = cats[0].string() 2289 name = '{}={}'.format(cat, n) 2290 cat_names = {cat: n} 2291 i = 1 2292 while i < ncat and names[i] != 0: 2293 n = names[i].string() 2294 cat = cats[i].string() 2295 name = '{};{}={}'.format(name, cat, n) 2296 cat_names[cat] = n 2297 i = i + 1 2298 uniq_names = set(cat_names.values()) 2299 if len(uniq_names) == 1: 2300 name = n 2301 elif len(uniq_names) == 2: 2302 n1, n2 = (uniq_names) 2303 name_list = list(cat_names.values()) 2304 other = None 2305 if name_list.count(n1) == 1: 2306 name = n2 2307 other = n1 2308 elif name_list.count(n2) == 1: 2309 name = n1 2310 other = n2 2311 if other is not None: 2312 cat = next(c for c, n in cat_names.items() if n == other) 2313 mod = ' with "{}={}"'.format(cat, other) 2314 return 'std::locale = "{}"{}'.format(name, mod) 2315 2316 class StdIntegralConstantPrinter(printer_base): 2317 """Print a std::true_type or std::false_type.""" 2318 2319 def __init__(self, typename, val): 2320 self._val = val 2321 self._typename = typename 2322 2323 def to_string(self): 2324 value_type = self._val.type.template_argument(0) 2325 value = self._val.type.template_argument(1) 2326 if value_type.code == gdb.TYPE_CODE_BOOL: 2327 if value: 2328 return "std::true_type" 2329 else: 2330 return "std::false_type" 2331 typename = strip_versioned_namespace(self._typename) 2332 return "{}<{}, {}>".format(typename, value_type, value) 2333 2334 class StdTextEncodingPrinter(printer_base): 2335 """Print a std::text_encoding.""" 2336 2337 def __init__(self, typename, val): 2338 self._val = val 2339 self._typename = typename 2340 2341 def to_string(self): 2342 rep = self._val['_M_rep'].dereference() 2343 if rep['_M_id'] == 1: 2344 return self._val['_M_name'] 2345 if rep['_M_id'] == 2: 2346 return 'unknown' 2347 return rep['_M_name'] 2348 2349 # A "regular expression" printer which conforms to the 2350 # "SubPrettyPrinter" protocol from gdb.printing. 2351 class RxPrinter(object): 2352 def __init__(self, name, function): 2353 super(RxPrinter, self).__init__() 2354 self.name = name 2355 self._function = function 2356 self.enabled = True 2357 2358 def invoke(self, value): 2359 if not self.enabled: 2360 return None 2361 2362 if value.type.code == gdb.TYPE_CODE_REF: 2363 if hasattr(gdb.Value, "referenced_value"): 2364 value = value.referenced_value() 2365 2366 return self._function(self.name, value) 2367 2368 # A pretty-printer that conforms to the "PrettyPrinter" protocol from 2369 # gdb.printing. It can also be used directly as an old-style printer. 2370 2371 2372 class Printer(object): 2373 def __init__(self, name): 2374 super(Printer, self).__init__() 2375 self.name = name 2376 self._subprinters = [] 2377 self._lookup = {} 2378 self.enabled = True 2379 self._compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$') 2380 2381 def add(self, name, function): 2382 # A small sanity check. 2383 # FIXME 2384 if not self._compiled_rx.match(name): 2385 raise ValueError( 2386 'libstdc++ programming error: "%s" does not match' % name) 2387 printer = RxPrinter(name, function) 2388 self._subprinters.append(printer) 2389 self._lookup[name] = printer 2390 2391 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION. 2392 def add_version(self, base, name, function): 2393 self.add(base + name, function) 2394 if '__cxx11' not in base: 2395 vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % 2396 _versioned_namespace, base) 2397 self.add(vbase + name, function) 2398 2399 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER. 2400 def add_container(self, base, name, function): 2401 self.add_version(base, name, function) 2402 self.add_version(base + '__cxx1998::', name, function) 2403 2404 @staticmethod 2405 def get_basic_type(type): 2406 # If it points to a reference, get the reference. 2407 if type.code == gdb.TYPE_CODE_REF: 2408 type = type.target() 2409 2410 # Get the unqualified type, stripped of typedefs. 2411 type = type.unqualified().strip_typedefs() 2412 2413 return type.tag 2414 2415 def __call__(self, val): 2416 typename = self.get_basic_type(val.type) 2417 if not typename: 2418 return None 2419 2420 # All the types we match are template types, so we can use a 2421 # dictionary. 2422 match = self._compiled_rx.match(typename) 2423 if not match: 2424 return None 2425 2426 basename = match.group(1) 2427 2428 if val.type.code == gdb.TYPE_CODE_REF: 2429 if hasattr(gdb.Value, "referenced_value"): 2430 val = val.referenced_value() 2431 2432 if basename in self._lookup: 2433 return self._lookup[basename].invoke(val) 2434 2435 # Cannot find a pretty printer. Return None. 2436 return None 2437 2438 2439 libstdcxx_printer = None 2440 2441 2442 class TemplateTypePrinter(object): 2443 """ 2444 A type printer for class templates with default template arguments. 2445 2446 Recognizes specializations of class templates and prints them without 2447 any template arguments that use a default template argument. 2448 Type printers are recursively applied to the template arguments. 2449 2450 e.g. replace 'std::vector<T, std::allocator<T> >' with 'std::vector<T>'. 2451 """ 2452 2453 def __init__(self, name, defargs): 2454 self.name = name 2455 self._defargs = defargs 2456 self.enabled = True 2457 2458 class _recognizer(object): 2459 """The recognizer class for TemplateTypePrinter.""" 2460 2461 def __init__(self, name, defargs): 2462 self.name = name 2463 self._defargs = defargs 2464 # self._type_obj = None 2465 2466 def recognize(self, type_obj): 2467 """ 2468 If type_obj is a specialization of self.name that uses all the 2469 default template arguments for the class template, then return 2470 a string representation of the type without default arguments. 2471 Otherwise, return None. 2472 """ 2473 2474 if type_obj.tag is None: 2475 return None 2476 2477 if not type_obj.tag.startswith(self.name): 2478 return None 2479 2480 template_args = get_template_arg_list(type_obj) 2481 displayed_args = [] 2482 require_defaulted = False 2483 for n in range(len(template_args)): 2484 # The actual template argument in the type: 2485 targ = template_args[n] 2486 # The default template argument for the class template: 2487 defarg = self._defargs.get(n) 2488 if defarg is not None: 2489 # Substitute other template arguments into the default: 2490 defarg = defarg.format(*template_args) 2491 # Fail to recognize the type (by returning None) 2492 # unless the actual argument is the same as the default. 2493 try: 2494 if targ != gdb.lookup_type(defarg): 2495 return None 2496 except gdb.error: 2497 # Type lookup failed, just use string comparison: 2498 if targ.tag != defarg: 2499 return None 2500 # All subsequent args must have defaults: 2501 require_defaulted = True 2502 elif require_defaulted: 2503 return None 2504 else: 2505 # Recursively apply recognizers to the template argument 2506 # and add it to the arguments that will be displayed: 2507 displayed_args.append(self._recognize_subtype(targ)) 2508 2509 # This assumes no class templates in the nested-name-specifier: 2510 template_name = type_obj.tag[0:type_obj.tag.find('<')] 2511 template_name = strip_inline_namespaces(template_name) 2512 2513 return template_name + '<' + ', '.join(displayed_args) + '>' 2514 2515 def _recognize_subtype(self, type_obj): 2516 """Convert a gdb.Type to a string by applying recognizers, 2517 or if that fails then simply converting to a string.""" 2518 2519 if type_obj.code == gdb.TYPE_CODE_PTR: 2520 return self._recognize_subtype(type_obj.target()) + '*' 2521 if type_obj.code == gdb.TYPE_CODE_ARRAY: 2522 type_str = self._recognize_subtype(type_obj.target()) 2523 if str(type_obj.strip_typedefs()).endswith('[]'): 2524 return type_str + '[]' # array of unknown bound 2525 return "%s[%d]" % (type_str, type_obj.range()[1] + 1) 2526 if type_obj.code == gdb.TYPE_CODE_REF: 2527 return self._recognize_subtype(type_obj.target()) + '&' 2528 if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'): 2529 if type_obj.code == gdb.TYPE_CODE_RVALUE_REF: 2530 return self._recognize_subtype(type_obj.target()) + '&&' 2531 2532 type_str = gdb.types.apply_type_recognizers( 2533 gdb.types.get_type_recognizers(), type_obj) 2534 if type_str: 2535 return type_str 2536 return str(type_obj) 2537 2538 def instantiate(self): 2539 """Return a recognizer object for this type printer.""" 2540 return self._recognizer(self.name, self._defargs) 2541 2542 2543 def add_one_template_type_printer(obj, name, defargs): 2544 """ 2545 Add a type printer for a class template with default template arguments. 2546 2547 Args: 2548 name (str): The template-name of the class template. 2549 defargs (dict int:string) The default template arguments. 2550 2551 Types in defargs can refer to the Nth template-argument using {N} 2552 (with zero-based indices). 2553 2554 e.g. 'unordered_map' has these defargs: 2555 { 2: 'std::hash<{0}>', 2556 3: 'std::equal_to<{0}>', 2557 4: 'std::allocator<std::pair<const {0}, {1}> >' } 2558 """ 2559 printer = TemplateTypePrinter('std::' + name, defargs) 2560 gdb.types.register_type_printer(obj, printer) 2561 2562 # Add type printer for same type in debug namespace: 2563 printer = TemplateTypePrinter('std::__debug::' + name, defargs) 2564 gdb.types.register_type_printer(obj, printer) 2565 2566 if '__cxx11' not in name: 2567 # Add second type printer for same type in versioned namespace: 2568 ns = 'std::' + _versioned_namespace 2569 # PR 86112 Cannot use dict comprehension here: 2570 defargs = dict((n, d.replace('std::', ns)) 2571 for (n, d) in defargs.items()) 2572 printer = TemplateTypePrinter(ns + name, defargs) 2573 gdb.types.register_type_printer(obj, printer) 2574 2575 # Add type printer for same type in debug namespace: 2576 printer = TemplateTypePrinter('std::__debug::' + name, defargs) 2577 gdb.types.register_type_printer(obj, printer) 2578 2579 2580 class FilteringTypePrinter(object): 2581 """ 2582 A type printer that uses typedef names for common template specializations. 2583 2584 Args: 2585 template (str): The class template to recognize. 2586 name (str): The typedef-name that will be used instead. 2587 targ1 (str, optional): The first template argument. Defaults to None. 2588 2589 Checks if a specialization of the class template 'template' is the same type 2590 as the typedef 'name', and prints it as 'name' instead. 2591 2592 e.g. if an instantiation of std::basic_istream<C, T> is the same type as 2593 std::istream then print it as std::istream. 2594 2595 If targ1 is provided (not None), match only template specializations with 2596 this type as the first template argument, e.g. if template='basic_string' 2597 and targ1='char' then only match 'basic_string<char,...>' and not 2598 'basic_string<wchar_t,...>'. This rejects non-matching specializations 2599 more quickly, without needing to do GDB type lookups. 2600 """ 2601 2602 def __init__(self, template, name, targ1=None): 2603 self._template = template 2604 self.name = name 2605 self._targ1 = targ1 2606 self.enabled = True 2607 2608 class _recognizer(object): 2609 """The recognizer class for FilteringTypePrinter.""" 2610 2611 def __init__(self, template, name, targ1): 2612 self._template = template 2613 self.name = name 2614 self._targ1 = targ1 2615 self._type_obj = None 2616 2617 def recognize(self, type_obj): 2618 """ 2619 If type_obj starts with self._template and is the same type as 2620 self.name then return self.name, otherwise None. 2621 """ 2622 if type_obj.tag is None: 2623 return None 2624 2625 if self._type_obj is None: 2626 if self._targ1 is not None: 2627 s = '{}<{}'.format(self._template, self._targ1) 2628 if not type_obj.tag.startswith(s): 2629 # Filter didn't match. 2630 return None 2631 elif not type_obj.tag.startswith(self._template): 2632 # Filter didn't match. 2633 return None 2634 2635 try: 2636 self._type_obj = gdb.lookup_type( 2637 self.name).strip_typedefs() 2638 except: 2639 pass 2640 2641 if self._type_obj is None: 2642 return None 2643 2644 t1 = gdb.types.get_basic_type(self._type_obj) 2645 t2 = gdb.types.get_basic_type(type_obj) 2646 if t1 == t2: 2647 return strip_inline_namespaces(self.name) 2648 2649 # Workaround ambiguous typedefs matching both std:: and 2650 # std::__cxx11:: symbols. 2651 if self._template.split('::')[-1] == 'basic_string': 2652 s1 = self._type_obj.tag.replace('__cxx11::', '') 2653 s2 = type_obj.tag.replace('__cxx11::', '') 2654 if s1 == s2: 2655 return strip_inline_namespaces(self.name) 2656 2657 return None 2658 2659 def instantiate(self): 2660 """Return a recognizer object for this type printer.""" 2661 return self._recognizer(self._template, self.name, self._targ1) 2662 2663 2664 def add_one_type_printer(obj, template, name, targ1=None): 2665 printer = FilteringTypePrinter('std::' + template, 'std::' + name, targ1) 2666 gdb.types.register_type_printer(obj, printer) 2667 if '__cxx11' not in template: 2668 ns = 'std::' + _versioned_namespace 2669 printer = FilteringTypePrinter(ns + template, ns + name, targ1) 2670 gdb.types.register_type_printer(obj, printer) 2671 2672 2673 def register_type_printers(obj): 2674 global _use_type_printing 2675 2676 if not _use_type_printing: 2677 return 2678 2679 # Add type printers for typedefs std::string, std::wstring etc. 2680 for ch in (('', 'char'), 2681 ('w', 'wchar_t'), 2682 ('u8', 'char8_t'), 2683 ('u16', 'char16_t'), 2684 ('u32', 'char32_t')): 2685 add_one_type_printer(obj, 'basic_string', ch[0] + 'string', ch[1]) 2686 add_one_type_printer(obj, '__cxx11::basic_string', 2687 ch[0] + 'string', ch[1]) 2688 # Typedefs for __cxx11::basic_string used to be in namespace __cxx11: 2689 add_one_type_printer(obj, '__cxx11::basic_string', 2690 '__cxx11::' + ch[0] + 'string', ch[1]) 2691 add_one_type_printer(obj, 'basic_string_view', 2692 ch[0] + 'string_view', ch[1]) 2693 2694 # Add type printers for typedefs std::istream, std::wistream etc. 2695 for ch in (('', 'char'), ('w', 'wchar_t')): 2696 for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream', 2697 'filebuf', 'ifstream', 'ofstream', 'fstream'): 2698 add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1]) 2699 for x in ('stringbuf', 'istringstream', 'ostringstream', 2700 'stringstream'): 2701 add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1]) 2702 # <sstream> types are in __cxx11 namespace, but typedefs aren't: 2703 add_one_type_printer(obj, '__cxx11::basic_' + x, ch[0] + x, ch[1]) 2704 2705 # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc. 2706 for abi in ('', '__cxx11::'): 2707 for ch in (('', 'char'), ('w', 'wchar_t')): 2708 add_one_type_printer(obj, abi + 'basic_regex', 2709 abi + ch[0] + 'regex', ch[1]) 2710 for ch in ('c', 's', 'wc', 'ws'): 2711 add_one_type_printer( 2712 obj, abi + 'match_results', abi + ch + 'match') 2713 for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'): 2714 add_one_type_printer(obj, abi + x, abi + ch + x) 2715 2716 # Note that we can't have a printer for std::wstreampos, because 2717 # it is the same type as std::streampos. 2718 add_one_type_printer(obj, 'fpos', 'streampos') 2719 2720 # Add type printers for <chrono> typedefs. 2721 for dur in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds', 2722 'minutes', 'hours', 'days', 'weeks', 'years', 'months'): 2723 add_one_type_printer(obj, 'chrono::duration', 'chrono::' + dur) 2724 2725 # Add type printers for <random> typedefs. 2726 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0') 2727 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand') 2728 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937') 2729 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64') 2730 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base') 2731 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base') 2732 add_one_type_printer(obj, 'discard_block_engine', 'ranlux24') 2733 add_one_type_printer(obj, 'discard_block_engine', 'ranlux48') 2734 add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b') 2735 2736 # Add type printers for experimental::basic_string_view typedefs. 2737 ns = 'experimental::fundamentals_v1::' 2738 for ch in (('', 'char'), 2739 ('w', 'wchar_t'), 2740 ('u8', 'char8_t'), 2741 ('u16', 'char16_t'), 2742 ('u32', 'char32_t')): 2743 add_one_type_printer(obj, ns + 'basic_string_view', 2744 ns + ch[0] + 'string_view', ch[1]) 2745 2746 # Do not show defaulted template arguments in class templates. 2747 add_one_template_type_printer(obj, 'unique_ptr', 2748 {1: 'std::default_delete<{0}>'}) 2749 add_one_template_type_printer(obj, 'deque', {1: 'std::allocator<{0}>'}) 2750 add_one_template_type_printer( 2751 obj, 'forward_list', {1: 'std::allocator<{0}>'}) 2752 add_one_template_type_printer(obj, 'list', {1: 'std::allocator<{0}>'}) 2753 add_one_template_type_printer( 2754 obj, '__cxx11::list', {1: 'std::allocator<{0}>'}) 2755 add_one_template_type_printer(obj, 'vector', {1: 'std::allocator<{0}>'}) 2756 add_one_template_type_printer(obj, 'map', 2757 {2: 'std::less<{0}>', 2758 3: 'std::allocator<std::pair<{0} const, {1}>>'}) 2759 add_one_template_type_printer(obj, 'multimap', 2760 {2: 'std::less<{0}>', 2761 3: 'std::allocator<std::pair<{0} const, {1}>>'}) 2762 add_one_template_type_printer(obj, 'set', 2763 {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'}) 2764 add_one_template_type_printer(obj, 'multiset', 2765 {1: 'std::less<{0}>', 2: 'std::allocator<{0}>'}) 2766 add_one_template_type_printer(obj, 'unordered_map', 2767 {2: 'std::hash<{0}>', 2768 3: 'std::equal_to<{0}>', 2769 4: 'std::allocator<std::pair<{0} const, {1}>>'}) 2770 add_one_template_type_printer(obj, 'unordered_multimap', 2771 {2: 'std::hash<{0}>', 2772 3: 'std::equal_to<{0}>', 2773 4: 'std::allocator<std::pair<{0} const, {1}>>'}) 2774 add_one_template_type_printer(obj, 'unordered_set', 2775 {1: 'std::hash<{0}>', 2776 2: 'std::equal_to<{0}>', 2777 3: 'std::allocator<{0}>'}) 2778 add_one_template_type_printer(obj, 'unordered_multiset', 2779 {1: 'std::hash<{0}>', 2780 2: 'std::equal_to<{0}>', 2781 3: 'std::allocator<{0}>'}) 2782 2783 2784 def register_libstdcxx_printers(obj): 2785 """Register libstdc++ pretty-printers with objfile Obj.""" 2786 2787 global _use_gdb_pp 2788 global libstdcxx_printer 2789 2790 if _use_gdb_pp: 2791 gdb.printing.register_pretty_printer(obj, libstdcxx_printer) 2792 else: 2793 if obj is None: 2794 obj = gdb 2795 obj.pretty_printers.append(libstdcxx_printer) 2796 2797 register_type_printers(obj) 2798 2799 2800 def build_libstdcxx_dictionary(): 2801 global libstdcxx_printer 2802 2803 libstdcxx_printer = Printer("libstdc++-v6") 2804 2805 # libstdc++ objects requiring pretty-printing. 2806 # In order from: 2807 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html 2808 libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter) 2809 libstdcxx_printer.add_version( 2810 'std::__cxx11::', 'basic_string', StdStringPrinter) 2811 libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter) 2812 libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter) 2813 libstdcxx_printer.add_container('std::', 'list', StdListPrinter) 2814 libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter) 2815 libstdcxx_printer.add_container('std::', 'map', StdMapPrinter) 2816 libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter) 2817 libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter) 2818 libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter) 2819 libstdcxx_printer.add_version('std::', 'priority_queue', 2820 StdStackOrQueuePrinter) 2821 libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter) 2822 libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter) 2823 libstdcxx_printer.add_container('std::', 'set', StdSetPrinter) 2824 libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter) 2825 libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter) 2826 libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter) 2827 # vector<bool> 2828 libstdcxx_printer.add_version('std::', 'locale', StdLocalePrinter) 2829 2830 libstdcxx_printer.add_version('std::', 'integral_constant', 2831 StdIntegralConstantPrinter) 2832 libstdcxx_printer.add_version('std::', 'text_encoding', 2833 StdTextEncodingPrinter) 2834 2835 if hasattr(gdb.Value, 'dynamic_type'): 2836 libstdcxx_printer.add_version('std::', 'error_code', 2837 StdErrorCodePrinter) 2838 libstdcxx_printer.add_version('std::', 'error_condition', 2839 StdErrorCodePrinter) 2840 2841 # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG. 2842 libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter) 2843 libstdcxx_printer.add('std::__debug::deque', StdDequePrinter) 2844 libstdcxx_printer.add('std::__debug::list', StdListPrinter) 2845 libstdcxx_printer.add('std::__debug::map', StdMapPrinter) 2846 libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter) 2847 libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter) 2848 libstdcxx_printer.add('std::__debug::set', StdSetPrinter) 2849 libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter) 2850 2851 # These are the TR1 and C++11 printers. 2852 # For array - the default GDB pretty-printer seems reasonable. 2853 libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter) 2854 libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter) 2855 libstdcxx_printer.add_container('std::', 'unordered_map', 2856 Tr1UnorderedMapPrinter) 2857 libstdcxx_printer.add_container('std::', 'unordered_set', 2858 Tr1UnorderedSetPrinter) 2859 libstdcxx_printer.add_container('std::', 'unordered_multimap', 2860 Tr1UnorderedMapPrinter) 2861 libstdcxx_printer.add_container('std::', 'unordered_multiset', 2862 Tr1UnorderedSetPrinter) 2863 libstdcxx_printer.add_container('std::', 'forward_list', 2864 StdForwardListPrinter) 2865 2866 libstdcxx_printer.add_version( 2867 'std::tr1::', 'shared_ptr', SharedPointerPrinter) 2868 libstdcxx_printer.add_version( 2869 'std::tr1::', 'weak_ptr', SharedPointerPrinter) 2870 libstdcxx_printer.add_version('std::tr1::', 'unordered_map', 2871 Tr1UnorderedMapPrinter) 2872 libstdcxx_printer.add_version('std::tr1::', 'unordered_set', 2873 Tr1UnorderedSetPrinter) 2874 libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap', 2875 Tr1UnorderedMapPrinter) 2876 libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset', 2877 Tr1UnorderedSetPrinter) 2878 2879 libstdcxx_printer.add_version('std::', 'initializer_list', 2880 StdInitializerListPrinter) 2881 libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter) 2882 libstdcxx_printer.add_version( 2883 'std::', 'basic_stringbuf', StdStringBufPrinter) 2884 libstdcxx_printer.add_version( 2885 'std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter) 2886 for sstream in ('istringstream', 'ostringstream', 'stringstream'): 2887 libstdcxx_printer.add_version( 2888 'std::', 'basic_' + sstream, StdStringStreamPrinter) 2889 libstdcxx_printer.add_version( 2890 'std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter) 2891 2892 libstdcxx_printer.add_version('std::chrono::', 'duration', 2893 StdChronoDurationPrinter) 2894 libstdcxx_printer.add_version('std::chrono::', 'time_point', 2895 StdChronoTimePointPrinter) 2896 2897 # std::regex components 2898 libstdcxx_printer.add_version('std::__detail::', '_State', 2899 StdRegexStatePrinter) 2900 2901 # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases. 2902 # The tr1 namespace containers do not have any debug equivalents, 2903 # so do not register printers for them. 2904 libstdcxx_printer.add('std::__debug::unordered_map', 2905 Tr1UnorderedMapPrinter) 2906 libstdcxx_printer.add('std::__debug::unordered_set', 2907 Tr1UnorderedSetPrinter) 2908 libstdcxx_printer.add('std::__debug::unordered_multimap', 2909 Tr1UnorderedMapPrinter) 2910 libstdcxx_printer.add('std::__debug::unordered_multiset', 2911 Tr1UnorderedSetPrinter) 2912 libstdcxx_printer.add('std::__debug::forward_list', 2913 StdForwardListPrinter) 2914 2915 # Library Fundamentals TS components 2916 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 2917 'any', StdExpAnyPrinter) 2918 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 2919 'optional', StdExpOptionalPrinter) 2920 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', 2921 'basic_string_view', StdExpStringViewPrinter) 2922 # Filesystem TS components 2923 libstdcxx_printer.add_version('std::experimental::filesystem::v1::', 2924 'path', StdExpPathPrinter) 2925 libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::', 2926 'path', StdExpPathPrinter) 2927 libstdcxx_printer.add_version('std::filesystem::', 2928 'path', StdPathPrinter) 2929 libstdcxx_printer.add_version('std::filesystem::__cxx11::', 2930 'path', StdPathPrinter) 2931 2932 # C++17 components 2933 libstdcxx_printer.add_version('std::', 2934 'any', StdExpAnyPrinter) 2935 libstdcxx_printer.add_version('std::', 2936 'optional', StdExpOptionalPrinter) 2937 libstdcxx_printer.add_version('std::', 2938 'basic_string_view', StdExpStringViewPrinter) 2939 libstdcxx_printer.add_version('std::', 2940 'variant', StdVariantPrinter) 2941 libstdcxx_printer.add_version('std::', 2942 '_Node_handle', StdNodeHandlePrinter) 2943 2944 # C++20 components 2945 libstdcxx_printer.add_version( 2946 'std::', 'partial_ordering', StdCmpCatPrinter) 2947 libstdcxx_printer.add_version('std::', 'weak_ordering', StdCmpCatPrinter) 2948 libstdcxx_printer.add_version('std::', 'strong_ordering', StdCmpCatPrinter) 2949 libstdcxx_printer.add_version('std::', 'span', StdSpanPrinter) 2950 libstdcxx_printer.add_version('std::', 'basic_format_args', 2951 StdFormatArgsPrinter) 2952 for c in ['day', 'month', 'year', 'weekday', 'weekday_indexed', 'weekday_last', 2953 'month_day', 'month_day_last', 'month_weekday', 'month_weekday_last', 2954 'year_month', 'year_month_day', 'year_month_day_last', 2955 'year_month_weekday', 'year_month_weekday_last', 'hh_mm_ss']: 2956 libstdcxx_printer.add_version('std::chrono::', c, 2957 StdChronoCalendarPrinter) 2958 libstdcxx_printer.add_version('std::chrono::', 'time_zone', 2959 StdChronoTimeZonePrinter) 2960 libstdcxx_printer.add_version('std::chrono::', 'time_zone_link', 2961 StdChronoTimeZonePrinter) 2962 libstdcxx_printer.add_version('std::chrono::', 'zoned_time', 2963 StdChronoZonedTimePrinter) 2964 libstdcxx_printer.add_version('std::chrono::', 'leap_second', 2965 StdChronoLeapSecondPrinter) 2966 libstdcxx_printer.add_version( 2967 'std::chrono::', 'tzdb', StdChronoTzdbPrinter) 2968 # libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule', 2969 # StdChronoTimeZoneRulePrinter) 2970 2971 # Extensions. 2972 libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter) 2973 2974 if True: 2975 # These shouldn't be necessary, if GDB "print *i" worked. 2976 # But it often doesn't, so here they are. 2977 libstdcxx_printer.add_container('std::', '_List_iterator', 2978 StdListIteratorPrinter) 2979 libstdcxx_printer.add_container('std::', '_List_const_iterator', 2980 StdListIteratorPrinter) 2981 libstdcxx_printer.add_version('std::', '_Rb_tree_iterator', 2982 StdRbtreeIteratorPrinter) 2983 libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator', 2984 StdRbtreeIteratorPrinter) 2985 libstdcxx_printer.add_container('std::', '_Deque_iterator', 2986 StdDequeIteratorPrinter) 2987 libstdcxx_printer.add_container('std::', '_Deque_const_iterator', 2988 StdDequeIteratorPrinter) 2989 libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator', 2990 StdVectorIteratorPrinter) 2991 libstdcxx_printer.add_container('std::', '_Bit_iterator', 2992 StdBitIteratorPrinter) 2993 libstdcxx_printer.add_container('std::', '_Bit_const_iterator', 2994 StdBitIteratorPrinter) 2995 libstdcxx_printer.add_container('std::', '_Bit_reference', 2996 StdBitReferencePrinter) 2997 libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator', 2998 StdSlistIteratorPrinter) 2999 libstdcxx_printer.add_container('std::', '_Fwd_list_iterator', 3000 StdFwdListIteratorPrinter) 3001 libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator', 3002 StdFwdListIteratorPrinter) 3003 3004 # Debug (compiled with -D_GLIBCXX_DEBUG) printer 3005 # registrations. 3006 libstdcxx_printer.add('__gnu_debug::_Safe_iterator', 3007 StdDebugIteratorPrinter) 3008 3009 3010 build_libstdcxx_dictionary() 3011