1# Xmethods for libstdc++. 2 3# Copyright (C) 2014-2016 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::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::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::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::(__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::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::%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 return obj['_M_t']['_M_head_impl'] 589 590class UniquePtrDerefWorker(UniquePtrGetWorker): 591 "Implements std::unique_ptr<T>::operator*()" 592 593 def __init__(self, elem_type): 594 UniquePtrGetWorker.__init__(self, elem_type) 595 596 def get_result_type(self, obj): 597 return self._elem_type 598 599 def _supports(self, method_name): 600 "operator* is not supported for unique_ptr<T[]>" 601 return not self._is_array 602 603 def __call__(self, obj): 604 return UniquePtrGetWorker.__call__(self, obj).dereference() 605 606class UniquePtrSubscriptWorker(UniquePtrGetWorker): 607 "Implements std::unique_ptr<T>::operator[](size_t)" 608 609 def __init__(self, elem_type): 610 UniquePtrGetWorker.__init__(self, elem_type) 611 612 def get_arg_types(self): 613 return get_std_size_type() 614 615 def get_result_type(self, obj, index): 616 return self._elem_type 617 618 def _supports(self, method_name): 619 "operator[] is only supported for unique_ptr<T[]>" 620 return self._is_array 621 622 def __call__(self, obj, index): 623 return UniquePtrGetWorker.__call__(self, obj)[index] 624 625class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher): 626 def __init__(self): 627 gdb.xmethod.XMethodMatcher.__init__(self, 628 matcher_name_prefix + 'unique_ptr') 629 self._method_dict = { 630 'get': LibStdCxxXMethod('get', UniquePtrGetWorker), 631 'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker), 632 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker), 633 'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker), 634 } 635 self.methods = [self._method_dict[m] for m in self._method_dict] 636 637 def match(self, class_type, method_name): 638 if not re.match('^std::unique_ptr<.*>$', class_type.tag): 639 return None 640 method = self._method_dict.get(method_name) 641 if method is None or not method.enabled: 642 return None 643 worker = method.worker_class(class_type.template_argument(0)) 644 if worker._supports(method_name): 645 return worker 646 return None 647 648# Xmethods for std::shared_ptr 649 650class SharedPtrGetWorker(gdb.xmethod.XMethodWorker): 651 "Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()" 652 653 def __init__(self, elem_type): 654 self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY 655 if self._is_array: 656 self._elem_type = elem_type.target() 657 else: 658 self._elem_type = elem_type 659 660 def get_arg_types(self): 661 return None 662 663 def get_result_type(self, obj): 664 return self._elem_type.pointer() 665 666 def __call__(self, obj): 667 return obj['_M_ptr'] 668 669class SharedPtrDerefWorker(SharedPtrGetWorker): 670 "Implements std::shared_ptr<T>::operator*()" 671 672 def __init__(self, elem_type): 673 SharedPtrGetWorker.__init__(self, elem_type) 674 675 def get_result_type(self, obj): 676 return self._elem_type 677 678 def __call__(self, obj): 679 return SharedPtrGetWorker.__call__(self, obj).dereference() 680 681class SharedPtrSubscriptWorker(SharedPtrGetWorker): 682 "Implements std::shared_ptr<T>::operator[](size_t)" 683 684 def __init__(self, elem_type): 685 SharedPtrGetWorker.__init__(self, elem_type) 686 687 def get_arg_types(self): 688 return get_std_size_type() 689 690 def get_result_type(self, obj, index): 691 return self._elem_type 692 693 def __call__(self, obj, index): 694 # Check bounds if _elem_type is an array of known bound 695 m = re.match('.*\[(\d+)]$', str(self._elem_type)) 696 if m and index >= int(m.group(1)): 697 raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' % 698 (self._elem_type, int(index), int(m.group(1)))) 699 return SharedPtrGetWorker.__call__(self, obj)[index] 700 701class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker): 702 "Implements std::shared_ptr<T>::use_count()" 703 704 def __init__(self, elem_type): 705 SharedPtrUseCountWorker.__init__(self, elem_type) 706 707 def get_arg_types(self): 708 return None 709 710 def get_result_type(self, obj): 711 return gdb.lookup_type('long') 712 713 def __call__(self, obj): 714 refcounts = ['_M_refcount']['_M_pi'] 715 return refcounts['_M_use_count'] if refcounts else 0 716 717class SharedPtrUniqueWorker(SharedPtrUseCountWorker): 718 "Implements std::shared_ptr<T>::unique()" 719 720 def __init__(self, elem_type): 721 SharedPtrUseCountWorker.__init__(self, elem_type) 722 723 def get_result_type(self, obj): 724 return gdb.lookup_type('bool') 725 726 def __call__(self, obj): 727 return SharedPtrUseCountWorker.__call__(self, obj) == 1 728 729class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher): 730 def __init__(self): 731 gdb.xmethod.XMethodMatcher.__init__(self, 732 matcher_name_prefix + 'shared_ptr') 733 self._method_dict = { 734 'get': LibStdCxxXMethod('get', SharedPtrGetWorker), 735 'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker), 736 'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker), 737 'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker), 738 'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker), 739 'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker), 740 } 741 self.methods = [self._method_dict[m] for m in self._method_dict] 742 743 def match(self, class_type, method_name): 744 if not re.match('^std::shared_ptr<.*>$', class_type.tag): 745 return None 746 method = self._method_dict.get(method_name) 747 if method is None or not method.enabled: 748 return None 749 return method.worker_class(class_type.template_argument(0)) 750 751def register_libstdcxx_xmethods(locus): 752 gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher()) 753 gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher()) 754 gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher()) 755 gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher()) 756 gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher()) 757 gdb.xmethod.register_xmethod_matcher( 758 locus, AssociativeContainerMethodsMatcher('set')) 759 gdb.xmethod.register_xmethod_matcher( 760 locus, AssociativeContainerMethodsMatcher('map')) 761 gdb.xmethod.register_xmethod_matcher( 762 locus, AssociativeContainerMethodsMatcher('multiset')) 763 gdb.xmethod.register_xmethod_matcher( 764 locus, AssociativeContainerMethodsMatcher('multimap')) 765 gdb.xmethod.register_xmethod_matcher( 766 locus, AssociativeContainerMethodsMatcher('unordered_set')) 767 gdb.xmethod.register_xmethod_matcher( 768 locus, AssociativeContainerMethodsMatcher('unordered_map')) 769 gdb.xmethod.register_xmethod_matcher( 770 locus, AssociativeContainerMethodsMatcher('unordered_multiset')) 771 gdb.xmethod.register_xmethod_matcher( 772 locus, AssociativeContainerMethodsMatcher('unordered_multimap')) 773 gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher()) 774 gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher()) 775