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