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