1# Xmethods for libstdc++. 2 3# Copyright (C) 2014-2022 Free Software Foundation, Inc. 4 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18import gdb 19import gdb.xmethod 20import re 21 22matcher_name_prefix = 'libstdc++::' 23 24 25def get_bool_type(): 26 return gdb.lookup_type('bool') 27 28def get_std_size_type(): 29 return gdb.lookup_type('std::size_t') 30 31_versioned_namespace = '__8::' 32 33def is_specialization_of(x, template_name): 34 """ 35 Test whether a type is a specialization of the named class template. 36 The type can be specified as a string or a gdb.Type object. 37 The template should be the name of a class template as a string, 38 without any 'std' qualification. 39 """ 40 if isinstance(x, gdb.Type): 41 x = x.tag 42 template_name = '(%s)?%s' % (_versioned_namespace, template_name) 43 return re.match(r'^std::(__\d::)?%s<.*>$' % template_name, x) is not None 44 45class LibStdCxxXMethod(gdb.xmethod.XMethod): 46 def __init__(self, name, worker_class): 47 gdb.xmethod.XMethod.__init__(self, name) 48 self.worker_class = worker_class 49 50# Xmethods for std::array 51 52 53class ArrayWorkerBase(gdb.xmethod.XMethodWorker): 54 def __init__(self, val_type, size): 55 self._val_type = val_type 56 self._size = size 57 58 def null_value(self): 59 nullptr = gdb.parse_and_eval('(void *) 0') 60 return nullptr.cast(self._val_type.pointer()).dereference() 61 62 63class ArraySizeWorker(ArrayWorkerBase): 64 def __init__(self, val_type, size): 65 ArrayWorkerBase.__init__(self, val_type, size) 66 67 def get_arg_types(self): 68 return None 69 70 def get_result_type(self, obj): 71 return get_std_size_type() 72 73 def __call__(self, obj): 74 return self._size 75 76 77class ArrayEmptyWorker(ArrayWorkerBase): 78 def __init__(self, val_type, size): 79 ArrayWorkerBase.__init__(self, val_type, size) 80 81 def get_arg_types(self): 82 return None 83 84 def get_result_type(self, obj): 85 return get_bool_type() 86 87 def __call__(self, obj): 88 return (int(self._size) == 0) 89 90 91class ArrayFrontWorker(ArrayWorkerBase): 92 def __init__(self, val_type, size): 93 ArrayWorkerBase.__init__(self, val_type, size) 94 95 def get_arg_types(self): 96 return None 97 98 def get_result_type(self, obj): 99 return self._val_type 100 101 def __call__(self, obj): 102 if int(self._size) > 0: 103 return obj['_M_elems'][0] 104 else: 105 return self.null_value() 106 107 108class ArrayBackWorker(ArrayWorkerBase): 109 def __init__(self, val_type, size): 110 ArrayWorkerBase.__init__(self, val_type, size) 111 112 def get_arg_types(self): 113 return None 114 115 def get_result_type(self, obj): 116 return self._val_type 117 118 def __call__(self, obj): 119 if int(self._size) > 0: 120 return obj['_M_elems'][self._size - 1] 121 else: 122 return self.null_value() 123 124 125class ArrayAtWorker(ArrayWorkerBase): 126 def __init__(self, val_type, size): 127 ArrayWorkerBase.__init__(self, val_type, size) 128 129 def get_arg_types(self): 130 return get_std_size_type() 131 132 def get_result_type(self, obj, index): 133 return self._val_type 134 135 def __call__(self, obj, index): 136 if int(index) >= int(self._size): 137 raise IndexError('Array index "%d" should not be >= %d.' % 138 ((int(index), self._size))) 139 return obj['_M_elems'][index] 140 141 142class ArraySubscriptWorker(ArrayWorkerBase): 143 def __init__(self, val_type, size): 144 ArrayWorkerBase.__init__(self, val_type, size) 145 146 def get_arg_types(self): 147 return get_std_size_type() 148 149 def get_result_type(self, obj, index): 150 return self._val_type 151 152 def __call__(self, obj, index): 153 if int(self._size) > 0: 154 return obj['_M_elems'][index] 155 else: 156 return self.null_value() 157 158 159class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher): 160 def __init__(self): 161 gdb.xmethod.XMethodMatcher.__init__(self, 162 matcher_name_prefix + 'array') 163 self._method_dict = { 164 'size': LibStdCxxXMethod('size', ArraySizeWorker), 165 'empty': LibStdCxxXMethod('empty', ArrayEmptyWorker), 166 'front': LibStdCxxXMethod('front', ArrayFrontWorker), 167 'back': LibStdCxxXMethod('back', ArrayBackWorker), 168 'at': LibStdCxxXMethod('at', ArrayAtWorker), 169 'operator[]': LibStdCxxXMethod('operator[]', ArraySubscriptWorker), 170 } 171 self.methods = [self._method_dict[m] for m in self._method_dict] 172 173 def match(self, class_type, method_name): 174 if not is_specialization_of(class_type, 'array'): 175 return None 176 method = self._method_dict.get(method_name) 177 if method is None or not method.enabled: 178 return None 179 try: 180 value_type = class_type.template_argument(0) 181 size = class_type.template_argument(1) 182 except: 183 return None 184 return method.worker_class(value_type, size) 185 186 187# Xmethods for std::deque 188 189 190class DequeWorkerBase(gdb.xmethod.XMethodWorker): 191 def __init__(self, val_type): 192 self._val_type = val_type 193 self._bufsize = 512 // val_type.sizeof or 1 194 195 def size(self, obj): 196 start = obj['_M_impl']['_M_start'] 197 finish = obj['_M_impl']['_M_finish'] 198 if start['_M_cur'] == finish['_M_cur']: 199 return 0 200 return (self._bufsize 201 * (finish['_M_node'] - start['_M_node'] - 1) 202 + (finish['_M_cur'] - finish['_M_first']) 203 + (start['_M_last'] - start['_M_cur'])) 204 205 def index(self, obj, idx): 206 start = obj['_M_impl']['_M_start'] 207 first_node_size = start['_M_last'] - start['_M_cur'] 208 if idx < first_node_size: 209 return start['_M_cur'][idx] 210 idx = idx - first_node_size 211 index_node = start['_M_node'][1 + int(idx) // self._bufsize] 212 return index_node[idx % self._bufsize] 213 214 215class DequeEmptyWorker(DequeWorkerBase): 216 def get_arg_types(self): 217 return None 218 219 def get_result_type(self, obj): 220 return get_bool_type() 221 222 def __call__(self, obj): 223 return (obj['_M_impl']['_M_start']['_M_cur'] == 224 obj['_M_impl']['_M_finish']['_M_cur']) 225 226 227class DequeSizeWorker(DequeWorkerBase): 228 def get_arg_types(self): 229 return None 230 231 def get_result_type(self, obj): 232 return get_std_size_type() 233 234 def __call__(self, obj): 235 return self.size(obj) 236 237 238class DequeFrontWorker(DequeWorkerBase): 239 def get_arg_types(self): 240 return None 241 242 def get_result_type(self, obj): 243 return self._val_type 244 245 def __call__(self, obj): 246 return obj['_M_impl']['_M_start']['_M_cur'][0] 247 248 249class DequeBackWorker(DequeWorkerBase): 250 def get_arg_types(self): 251 return None 252 253 def get_result_type(self, obj): 254 return self._val_type 255 256 def __call__(self, obj): 257 if (obj['_M_impl']['_M_finish']['_M_cur'] == 258 obj['_M_impl']['_M_finish']['_M_first']): 259 prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1 260 return prev_node[0][self._bufsize - 1] 261 else: 262 return obj['_M_impl']['_M_finish']['_M_cur'][-1] 263 264 265class DequeSubscriptWorker(DequeWorkerBase): 266 def get_arg_types(self): 267 return get_std_size_type() 268 269 def get_result_type(self, obj, subscript): 270 return self._val_type 271 272 def __call__(self, obj, subscript): 273 return self.index(obj, subscript) 274 275 276class DequeAtWorker(DequeWorkerBase): 277 def get_arg_types(self): 278 return get_std_size_type() 279 280 def get_result_type(self, obj, index): 281 return self._val_type 282 283 def __call__(self, obj, index): 284 deque_size = int(self.size(obj)) 285 if int(index) >= deque_size: 286 raise IndexError('Deque index "%d" should not be >= %d.' % 287 (int(index), deque_size)) 288 else: 289 return self.index(obj, index) 290 291 292class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher): 293 def __init__(self): 294 gdb.xmethod.XMethodMatcher.__init__(self, 295 matcher_name_prefix + 'deque') 296 self._method_dict = { 297 'empty': LibStdCxxXMethod('empty', DequeEmptyWorker), 298 'size': LibStdCxxXMethod('size', DequeSizeWorker), 299 'front': LibStdCxxXMethod('front', DequeFrontWorker), 300 'back': LibStdCxxXMethod('back', DequeBackWorker), 301 'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker), 302 'at': LibStdCxxXMethod('at', DequeAtWorker) 303 } 304 self.methods = [self._method_dict[m] for m in self._method_dict] 305 306 def match(self, class_type, method_name): 307 if not is_specialization_of(class_type, 'deque'): 308 return None 309 method = self._method_dict.get(method_name) 310 if method is None or not method.enabled: 311 return None 312 return method.worker_class(class_type.template_argument(0)) 313 314# Xmethods for std::forward_list 315 316 317class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher): 318 def __init__(self, val_type, node_type): 319 self._val_type = val_type 320 self._node_type = node_type 321 322 def get_arg_types(self): 323 return None 324 325 326class ForwardListEmptyWorker(ForwardListWorkerBase): 327 def get_result_type(self, obj): 328 return get_bool_type() 329 330 def __call__(self, obj): 331 return obj['_M_impl']['_M_head']['_M_next'] == 0 332 333 334class ForwardListFrontWorker(ForwardListWorkerBase): 335 def get_result_type(self, obj): 336 return self._val_type 337 338 def __call__(self, obj): 339 node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type) 340 val_address = node['_M_storage']['_M_storage'].address 341 return val_address.cast(self._val_type.pointer()).dereference() 342 343 344class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher): 345 def __init__(self): 346 matcher_name = matcher_name_prefix + 'forward_list' 347 gdb.xmethod.XMethodMatcher.__init__(self, matcher_name) 348 self._method_dict = { 349 'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker), 350 'front': LibStdCxxXMethod('front', ForwardListFrontWorker) 351 } 352 self.methods = [self._method_dict[m] for m in self._method_dict] 353 354 def match(self, class_type, method_name): 355 if not is_specialization_of(class_type, 'forward_list'): 356 return None 357 method = self._method_dict.get(method_name) 358 if method is None or not method.enabled: 359 return None 360 val_type = class_type.template_argument(0) 361 node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer() 362 return method.worker_class(val_type, node_type) 363 364# Xmethods for std::list 365 366 367class ListWorkerBase(gdb.xmethod.XMethodWorker): 368 def __init__(self, val_type, node_type): 369 self._val_type = val_type 370 self._node_type = node_type 371 372 def get_arg_types(self): 373 return None 374 375 def get_value_from_node(self, node): 376 node = node.dereference() 377 if node.type.fields()[1].name == '_M_data': 378 # C++03 implementation, node contains the value as a member 379 return node['_M_data'] 380 # C++11 implementation, node stores value in __aligned_membuf 381 addr = node['_M_storage'].address 382 return addr.cast(self._val_type.pointer()).dereference() 383 384 385class ListEmptyWorker(ListWorkerBase): 386 def get_result_type(self, obj): 387 return get_bool_type() 388 389 def __call__(self, obj): 390 base_node = obj['_M_impl']['_M_node'] 391 if base_node['_M_next'] == base_node.address: 392 return True 393 else: 394 return False 395 396 397class ListSizeWorker(ListWorkerBase): 398 def get_result_type(self, obj): 399 return get_std_size_type() 400 401 def __call__(self, obj): 402 begin_node = obj['_M_impl']['_M_node']['_M_next'] 403 end_node = obj['_M_impl']['_M_node'].address 404 size = 0 405 while begin_node != end_node: 406 begin_node = begin_node['_M_next'] 407 size += 1 408 return size 409 410 411class ListFrontWorker(ListWorkerBase): 412 def get_result_type(self, obj): 413 return self._val_type 414 415 def __call__(self, obj): 416 node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type) 417 return self.get_value_from_node(node) 418 419 420class ListBackWorker(ListWorkerBase): 421 def get_result_type(self, obj): 422 return self._val_type 423 424 def __call__(self, obj): 425 prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type) 426 return self.get_value_from_node(prev_node) 427 428 429class ListMethodsMatcher(gdb.xmethod.XMethodMatcher): 430 def __init__(self): 431 gdb.xmethod.XMethodMatcher.__init__(self, 432 matcher_name_prefix + 'list') 433 self._method_dict = { 434 'empty': LibStdCxxXMethod('empty', ListEmptyWorker), 435 'size': LibStdCxxXMethod('size', ListSizeWorker), 436 'front': LibStdCxxXMethod('front', ListFrontWorker), 437 'back': LibStdCxxXMethod('back', ListBackWorker) 438 } 439 self.methods = [self._method_dict[m] for m in self._method_dict] 440 441 def match(self, class_type, method_name): 442 if not is_specialization_of(class_type, '(__cxx11::)?list'): 443 return None 444 method = self._method_dict.get(method_name) 445 if method is None or not method.enabled: 446 return None 447 val_type = class_type.template_argument(0) 448 node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer() 449 return method.worker_class(val_type, node_type) 450 451# Xmethods for std::vector 452 453 454class VectorWorkerBase(gdb.xmethod.XMethodWorker): 455 def __init__(self, val_type): 456 self._val_type = val_type 457 458 def size(self, obj): 459 if self._val_type.code == gdb.TYPE_CODE_BOOL: 460 start = obj['_M_impl']['_M_start']['_M_p'] 461 finish = obj['_M_impl']['_M_finish']['_M_p'] 462 finish_offset = obj['_M_impl']['_M_finish']['_M_offset'] 463 bit_size = start.dereference().type.sizeof * 8 464 return (finish - start) * bit_size + finish_offset 465 else: 466 return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start'] 467 468 def get(self, obj, index): 469 if self._val_type.code == gdb.TYPE_CODE_BOOL: 470 start = obj['_M_impl']['_M_start']['_M_p'] 471 bit_size = start.dereference().type.sizeof * 8 472 valp = start + index // bit_size 473 offset = index % bit_size 474 return (valp.dereference() & (1 << offset)) > 0 475 else: 476 return obj['_M_impl']['_M_start'][index] 477 478 479class VectorEmptyWorker(VectorWorkerBase): 480 def get_arg_types(self): 481 return None 482 483 def get_result_type(self, obj): 484 return get_bool_type() 485 486 def __call__(self, obj): 487 return int(self.size(obj)) == 0 488 489 490class VectorSizeWorker(VectorWorkerBase): 491 def get_arg_types(self): 492 return None 493 494 def get_result_type(self, obj): 495 return get_std_size_type() 496 497 def __call__(self, obj): 498 return self.size(obj) 499 500 501class VectorFrontWorker(VectorWorkerBase): 502 def get_arg_types(self): 503 return None 504 505 def get_result_type(self, obj): 506 return self._val_type 507 508 def __call__(self, obj): 509 return self.get(obj, 0) 510 511 512class VectorBackWorker(VectorWorkerBase): 513 def get_arg_types(self): 514 return None 515 516 def get_result_type(self, obj): 517 return self._val_type 518 519 def __call__(self, obj): 520 return self.get(obj, int(self.size(obj)) - 1) 521 522 523class VectorAtWorker(VectorWorkerBase): 524 def get_arg_types(self): 525 return get_std_size_type() 526 527 def get_result_type(self, obj, index): 528 return self._val_type 529 530 def __call__(self, obj, index): 531 size = int(self.size(obj)) 532 if int(index) >= size: 533 raise IndexError('Vector index "%d" should not be >= %d.' % 534 ((int(index), size))) 535 return self.get(obj, int(index)) 536 537 538class VectorSubscriptWorker(VectorWorkerBase): 539 def get_arg_types(self): 540 return get_std_size_type() 541 542 def get_result_type(self, obj, subscript): 543 return self._val_type 544 545 def __call__(self, obj, subscript): 546 return self.get(obj, int(subscript)) 547 548 549class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher): 550 def __init__(self): 551 gdb.xmethod.XMethodMatcher.__init__(self, 552 matcher_name_prefix + 'vector') 553 self._method_dict = { 554 'size': LibStdCxxXMethod('size', VectorSizeWorker), 555 'empty': LibStdCxxXMethod('empty', VectorEmptyWorker), 556 'front': LibStdCxxXMethod('front', VectorFrontWorker), 557 'back': LibStdCxxXMethod('back', VectorBackWorker), 558 'at': LibStdCxxXMethod('at', VectorAtWorker), 559 'operator[]': LibStdCxxXMethod('operator[]', 560 VectorSubscriptWorker), 561 } 562 self.methods = [self._method_dict[m] for m in self._method_dict] 563 564 def match(self, class_type, method_name): 565 if not is_specialization_of(class_type, 'vector'): 566 return None 567 method = self._method_dict.get(method_name) 568 if method is None or not method.enabled: 569 return None 570 return method.worker_class(class_type.template_argument(0)) 571 572# Xmethods for associative containers 573 574 575class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker): 576 def __init__(self, unordered): 577 self._unordered = unordered 578 579 def node_count(self, obj): 580 if self._unordered: 581 return obj['_M_h']['_M_element_count'] 582 else: 583 return obj['_M_t']['_M_impl']['_M_node_count'] 584 585 def get_arg_types(self): 586 return None 587 588 589class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase): 590 def get_result_type(self, obj): 591 return get_bool_type() 592 593 def __call__(self, obj): 594 return int(self.node_count(obj)) == 0 595 596 597class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase): 598 def get_result_type(self, obj): 599 return get_std_size_type() 600 601 def __call__(self, obj): 602 return self.node_count(obj) 603 604 605class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher): 606 def __init__(self, name): 607 gdb.xmethod.XMethodMatcher.__init__(self, 608 matcher_name_prefix + name) 609 self._name = name 610 self._method_dict = { 611 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker), 612 'empty': LibStdCxxXMethod('empty', 613 AssociativeContainerEmptyWorker), 614 } 615 self.methods = [self._method_dict[m] for m in self._method_dict] 616 617 def match(self, class_type, method_name): 618 if not is_specialization_of(class_type, self._name): 619 return None 620 method = self._method_dict.get(method_name) 621 if method is None or not method.enabled: 622 return None 623 unordered = 'unordered' in self._name 624 return method.worker_class(unordered) 625 626# Xmethods for std::unique_ptr 627 628 629class UniquePtrGetWorker(gdb.xmethod.XMethodWorker): 630 """ 631 Implement std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->(). 632 """ 633 634 def __init__(self, elem_type): 635 self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY 636 if self._is_array: 637 self._elem_type = elem_type.target() 638 else: 639 self._elem_type = elem_type 640 641 def get_arg_types(self): 642 return None 643 644 def get_result_type(self, obj): 645 return self._elem_type.pointer() 646 647 def _supports(self, method_name): 648 # operator-> is not supported for unique_ptr<T[]> 649 return method_name == 'get' or not self._is_array 650 651 def __call__(self, obj): 652 impl_type = obj.dereference().type.fields()[0].type.tag 653 # Check for new implementations first: 654 if is_specialization_of(impl_type, '__uniq_ptr_(data|impl)'): 655 tuple_member = obj['_M_t']['_M_t'] 656 elif is_specialization_of(impl_type, 'tuple'): 657 tuple_member = obj['_M_t'] 658 else: 659 return None 660 tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl 661 tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base 662 head_field = tuple_head_type.fields()[0] 663 if head_field.name == '_M_head_impl': 664 return tuple_member.cast(tuple_head_type)['_M_head_impl'] 665 elif head_field.is_base_class: 666 return tuple_member.cast(head_field.type) 667 else: 668 return None 669 670 671class UniquePtrDerefWorker(UniquePtrGetWorker): 672 """Implement std::unique_ptr<T>::operator*().""" 673 674 def __init__(self, elem_type): 675 UniquePtrGetWorker.__init__(self, elem_type) 676 677 def get_result_type(self, obj): 678 return self._elem_type 679 680 def _supports(self, method_name): 681 # operator* is not supported for unique_ptr<T[]> 682 return not self._is_array 683 684 def __call__(self, obj): 685 return UniquePtrGetWorker.__call__(self, obj).dereference() 686 687 688class UniquePtrSubscriptWorker(UniquePtrGetWorker): 689 """Implement std::unique_ptr<T>::operator[](size_t).""" 690 691 def __init__(self, elem_type): 692 UniquePtrGetWorker.__init__(self, elem_type) 693 694 def get_arg_types(self): 695 return get_std_size_type() 696 697 def get_result_type(self, obj, index): 698 return self._elem_type 699 700 def _supports(self, method_name): 701 # operator[] is only supported for unique_ptr<T[]> 702 return self._is_array 703 704 def __call__(self, obj, index): 705 return UniquePtrGetWorker.__call__(self, obj)[index] 706 707 708class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher): 709 def __init__(self): 710 gdb.xmethod.XMethodMatcher.__init__(self, 711 matcher_name_prefix + 'unique_ptr') 712 self._method_dict = { 713 'get': LibStdCxxXMethod('get', UniquePtrGetWorker), 714 'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker), 715 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker), 716 'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker), 717 } 718 self.methods = [self._method_dict[m] for m in self._method_dict] 719 720 def match(self, class_type, method_name): 721 if not is_specialization_of(class_type, 'unique_ptr'): 722 return None 723 method = self._method_dict.get(method_name) 724 if method is None or not method.enabled: 725 return None 726 worker = method.worker_class(class_type.template_argument(0)) 727 if worker._supports(method_name): 728 return worker 729 return None 730 731# Xmethods for std::shared_ptr 732 733 734class SharedPtrGetWorker(gdb.xmethod.XMethodWorker): 735 """ 736 Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->(). 737 """ 738 739 def __init__(self, elem_type): 740 self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY 741 if self._is_array: 742 self._elem_type = elem_type.target() 743 else: 744 self._elem_type = elem_type 745 746 def get_arg_types(self): 747 return None 748 749 def get_result_type(self, obj): 750 return self._elem_type.pointer() 751 752 def _supports(self, method_name): 753 # operator-> is not supported for shared_ptr<T[]> 754 return method_name == 'get' or not self._is_array 755 756 def __call__(self, obj): 757 return obj['_M_ptr'] 758 759 760class SharedPtrDerefWorker(SharedPtrGetWorker): 761 """Implement std::shared_ptr<T>::operator*().""" 762 763 def __init__(self, elem_type): 764 SharedPtrGetWorker.__init__(self, elem_type) 765 766 def get_result_type(self, obj): 767 return self._elem_type 768 769 def _supports(self, method_name): 770 # operator* is not supported for shared_ptr<T[]> 771 return not self._is_array 772 773 def __call__(self, obj): 774 return SharedPtrGetWorker.__call__(self, obj).dereference() 775 776 777class SharedPtrSubscriptWorker(SharedPtrGetWorker): 778 """Implement std::shared_ptr<T>::operator[](size_t).""" 779 780 def __init__(self, elem_type): 781 SharedPtrGetWorker.__init__(self, elem_type) 782 783 def get_arg_types(self): 784 return get_std_size_type() 785 786 def get_result_type(self, obj, index): 787 return self._elem_type 788 789 def _supports(self, method_name): 790 # operator[] is only supported for shared_ptr<T[]> 791 return self._is_array 792 793 def __call__(self, obj, index): 794 # Check bounds if _elem_type is an array of known bound 795 m = re.match(r'.*\[(\d+)]$', str(self._elem_type)) 796 if m and index >= int(m.group(1)): 797 raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' % 798 (self._elem_type, int(index), int(m.group(1)))) 799 return SharedPtrGetWorker.__call__(self, obj)[index] 800 801 802class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker): 803 """Implement std::shared_ptr<T>::use_count().""" 804 805 def __init__(self, elem_type): 806 pass 807 808 def get_arg_types(self): 809 return None 810 811 def get_result_type(self, obj): 812 return gdb.lookup_type('long') 813 814 def _supports(self, method_name): 815 return True 816 817 def __call__(self, obj): 818 refcounts = obj['_M_refcount']['_M_pi'] 819 return refcounts['_M_use_count'] if refcounts else 0 820 821 822class SharedPtrUniqueWorker(SharedPtrUseCountWorker): 823 """Implement std::shared_ptr<T>::unique().""" 824 825 def __init__(self, elem_type): 826 SharedPtrUseCountWorker.__init__(self, elem_type) 827 828 def get_result_type(self, obj): 829 return gdb.lookup_type('bool') 830 831 def __call__(self, obj): 832 return SharedPtrUseCountWorker.__call__(self, obj) == 1 833 834 835class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher): 836 def __init__(self): 837 gdb.xmethod.XMethodMatcher.__init__(self, 838 matcher_name_prefix + 'shared_ptr') 839 self._method_dict = { 840 'get': LibStdCxxXMethod('get', SharedPtrGetWorker), 841 'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker), 842 'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker), 843 'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker), 844 'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker), 845 'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker), 846 } 847 self.methods = [self._method_dict[m] for m in self._method_dict] 848 849 def match(self, class_type, method_name): 850 if not is_specialization_of(class_type, 'shared_ptr'): 851 return None 852 method = self._method_dict.get(method_name) 853 if method is None or not method.enabled: 854 return None 855 worker = method.worker_class(class_type.template_argument(0)) 856 if worker._supports(method_name): 857 return worker 858 return None 859 860 861def register_libstdcxx_xmethods(locus): 862 gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher()) 863 gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher()) 864 gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher()) 865 gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher()) 866 gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher()) 867 gdb.xmethod.register_xmethod_matcher( 868 locus, AssociativeContainerMethodsMatcher('set')) 869 gdb.xmethod.register_xmethod_matcher( 870 locus, AssociativeContainerMethodsMatcher('map')) 871 gdb.xmethod.register_xmethod_matcher( 872 locus, AssociativeContainerMethodsMatcher('multiset')) 873 gdb.xmethod.register_xmethod_matcher( 874 locus, AssociativeContainerMethodsMatcher('multimap')) 875 gdb.xmethod.register_xmethod_matcher( 876 locus, AssociativeContainerMethodsMatcher('unordered_set')) 877 gdb.xmethod.register_xmethod_matcher( 878 locus, AssociativeContainerMethodsMatcher('unordered_map')) 879 gdb.xmethod.register_xmethod_matcher( 880 locus, AssociativeContainerMethodsMatcher('unordered_multiset')) 881 gdb.xmethod.register_xmethod_matcher( 882 locus, AssociativeContainerMethodsMatcher('unordered_multimap')) 883 gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher()) 884 gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher()) 885