1 # Xmethods for libstdc++.
3 # Copyright (C) 2014-2023 Free Software Foundation, Inc.
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.
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.
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/>.
22 matcher_name_prefix
= 'libstdc++::'
26 return gdb
.lookup_type('bool')
29 def get_std_size_type():
30 return gdb
.lookup_type('std::size_t')
33 class LibStdCxxXMethod(gdb
.xmethod
.XMethod
):
34 def __init__(self
, name
, worker_class
):
35 gdb
.xmethod
.XMethod
.__init
__(self
, name
)
36 self
.worker_class
= worker_class
38 # Xmethods for std::array
41 class ArrayWorkerBase(gdb
.xmethod
.XMethodWorker
):
42 def __init__(self
, val_type
, size
):
43 self
._val
_type
= val_type
47 nullptr
= gdb
.parse_and_eval('(void *) 0')
48 return nullptr
.cast(self
._val
_type
.pointer()).dereference()
51 class ArraySizeWorker(ArrayWorkerBase
):
52 def __init__(self
, val_type
, size
):
53 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
55 def get_arg_types(self
):
58 def get_result_type(self
, obj
):
59 return get_std_size_type()
61 def __call__(self
, obj
):
65 class ArrayEmptyWorker(ArrayWorkerBase
):
66 def __init__(self
, val_type
, size
):
67 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
69 def get_arg_types(self
):
72 def get_result_type(self
, obj
):
73 return get_bool_type()
75 def __call__(self
, obj
):
76 return (int(self
._size
) == 0)
79 class ArrayFrontWorker(ArrayWorkerBase
):
80 def __init__(self
, val_type
, size
):
81 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
83 def get_arg_types(self
):
86 def get_result_type(self
, obj
):
89 def __call__(self
, obj
):
90 if int(self
._size
) > 0:
91 return obj
['_M_elems'][0]
93 return self
.null_value()
96 class ArrayBackWorker(ArrayWorkerBase
):
97 def __init__(self
, val_type
, size
):
98 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
100 def get_arg_types(self
):
103 def get_result_type(self
, obj
):
104 return self
._val
_type
106 def __call__(self
, obj
):
107 if int(self
._size
) > 0:
108 return obj
['_M_elems'][self
._size
- 1]
110 return self
.null_value()
113 class ArrayAtWorker(ArrayWorkerBase
):
114 def __init__(self
, val_type
, size
):
115 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
117 def get_arg_types(self
):
118 return get_std_size_type()
120 def get_result_type(self
, obj
, index
):
121 return self
._val
_type
123 def __call__(self
, obj
, index
):
124 if int(index
) >= int(self
._size
):
125 raise IndexError('Array index "%d" should not be >= %d.' %
126 ((int(index
), self
._size
)))
127 return obj
['_M_elems'][index
]
130 class ArraySubscriptWorker(ArrayWorkerBase
):
131 def __init__(self
, val_type
, size
):
132 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
134 def get_arg_types(self
):
135 return get_std_size_type()
137 def get_result_type(self
, obj
, index
):
138 return self
._val
_type
140 def __call__(self
, obj
, index
):
141 if int(self
._size
) > 0:
142 return obj
['_M_elems'][index
]
144 return self
.null_value()
147 class ArrayMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
149 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
150 matcher_name_prefix
+ 'array')
151 self
._method
_dict
= {
152 'size': LibStdCxxXMethod('size', ArraySizeWorker
),
153 'empty': LibStdCxxXMethod('empty', ArrayEmptyWorker
),
154 'front': LibStdCxxXMethod('front', ArrayFrontWorker
),
155 'back': LibStdCxxXMethod('back', ArrayBackWorker
),
156 'at': LibStdCxxXMethod('at', ArrayAtWorker
),
157 'operator[]': LibStdCxxXMethod('operator[]', ArraySubscriptWorker
),
159 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
161 def match(self
, class_type
, method_name
):
162 if not re
.match('^std::(__\d+::)?array<.*>$', class_type
.tag
):
164 method
= self
._method
_dict
.get(method_name
)
165 if method
is None or not method
.enabled
:
168 value_type
= class_type
.template_argument(0)
169 size
= class_type
.template_argument(1)
172 return method
.worker_class(value_type
, size
)
174 # Xmethods for std::deque
177 class DequeWorkerBase(gdb
.xmethod
.XMethodWorker
):
178 def __init__(self
, val_type
):
179 self
._val
_type
= val_type
180 self
._bufsize
= 512 // val_type
.sizeof
or 1
183 first_node
= obj
['_M_impl']['_M_start']['_M_node']
184 last_node
= obj
['_M_impl']['_M_finish']['_M_node']
185 cur
= obj
['_M_impl']['_M_finish']['_M_cur']
186 first
= obj
['_M_impl']['_M_finish']['_M_first']
187 return (last_node
- first_node
) * self
._bufsize
+ (cur
- first
)
189 def index(self
, obj
, idx
):
190 first_node
= obj
['_M_impl']['_M_start']['_M_node']
191 index_node
= first_node
+ int(idx
) // self
._bufsize
192 return index_node
[0][idx
% self
._bufsize
]
195 class DequeEmptyWorker(DequeWorkerBase
):
196 def get_arg_types(self
):
199 def get_result_type(self
, obj
):
200 return get_bool_type()
202 def __call__(self
, obj
):
203 return (obj
['_M_impl']['_M_start']['_M_cur'] ==
204 obj
['_M_impl']['_M_finish']['_M_cur'])
207 class DequeSizeWorker(DequeWorkerBase
):
208 def get_arg_types(self
):
211 def get_result_type(self
, obj
):
212 return get_std_size_type()
214 def __call__(self
, obj
):
215 return self
.size(obj
)
218 class DequeFrontWorker(DequeWorkerBase
):
219 def get_arg_types(self
):
222 def get_result_type(self
, obj
):
223 return self
._val
_type
225 def __call__(self
, obj
):
226 return obj
['_M_impl']['_M_start']['_M_cur'][0]
229 class DequeBackWorker(DequeWorkerBase
):
230 def get_arg_types(self
):
233 def get_result_type(self
, obj
):
234 return self
._val
_type
236 def __call__(self
, obj
):
237 if (obj
['_M_impl']['_M_finish']['_M_cur'] ==
238 obj
['_M_impl']['_M_finish']['_M_first']):
239 prev_node
= obj
['_M_impl']['_M_finish']['_M_node'] - 1
240 return prev_node
[0][self
._bufsize
- 1]
242 return obj
['_M_impl']['_M_finish']['_M_cur'][-1]
245 class DequeSubscriptWorker(DequeWorkerBase
):
246 def get_arg_types(self
):
247 return get_std_size_type()
249 def get_result_type(self
, obj
, subscript
):
250 return self
._val
_type
252 def __call__(self
, obj
, subscript
):
253 return self
.index(obj
, subscript
)
256 class DequeAtWorker(DequeWorkerBase
):
257 def get_arg_types(self
):
258 return get_std_size_type()
260 def get_result_type(self
, obj
, index
):
261 return self
._val
_type
263 def __call__(self
, obj
, index
):
264 deque_size
= int(self
.size(obj
))
265 if int(index
) >= deque_size
:
266 raise IndexError('Deque index "%d" should not be >= %d.' %
267 (int(index
), deque_size
))
269 return self
.index(obj
, index
)
272 class DequeMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
274 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
275 matcher_name_prefix
+ 'deque')
276 self
._method
_dict
= {
277 'empty': LibStdCxxXMethod('empty', DequeEmptyWorker
),
278 'size': LibStdCxxXMethod('size', DequeSizeWorker
),
279 'front': LibStdCxxXMethod('front', DequeFrontWorker
),
280 'back': LibStdCxxXMethod('back', DequeBackWorker
),
281 'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker
),
282 'at': LibStdCxxXMethod('at', DequeAtWorker
)
284 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
286 def match(self
, class_type
, method_name
):
287 if not re
.match('^std::(__\d+::)?deque<.*>$', class_type
.tag
):
289 method
= self
._method
_dict
.get(method_name
)
290 if method
is None or not method
.enabled
:
292 return method
.worker_class(class_type
.template_argument(0))
294 # Xmethods for std::forward_list
297 class ForwardListWorkerBase(gdb
.xmethod
.XMethodMatcher
):
298 def __init__(self
, val_type
, node_type
):
299 self
._val
_type
= val_type
300 self
._node
_type
= node_type
302 def get_arg_types(self
):
306 class ForwardListEmptyWorker(ForwardListWorkerBase
):
307 def get_result_type(self
, obj
):
308 return get_bool_type()
310 def __call__(self
, obj
):
311 return obj
['_M_impl']['_M_head']['_M_next'] == 0
314 class ForwardListFrontWorker(ForwardListWorkerBase
):
315 def get_result_type(self
, obj
):
316 return self
._val
_type
318 def __call__(self
, obj
):
319 node
= obj
['_M_impl']['_M_head']['_M_next'].cast(self
._node
_type
)
320 val_address
= node
['_M_storage']['_M_storage'].address
321 return val_address
.cast(self
._val
_type
.pointer()).dereference()
324 class ForwardListMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
326 matcher_name
= matcher_name_prefix
+ 'forward_list'
327 gdb
.xmethod
.XMethodMatcher
.__init
__(self
, matcher_name
)
328 self
._method
_dict
= {
329 'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker
),
330 'front': LibStdCxxXMethod('front', ForwardListFrontWorker
)
332 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
334 def match(self
, class_type
, method_name
):
335 if not re
.match('^std::(__\d+::)?forward_list<.*>$', class_type
.tag
):
337 method
= self
._method
_dict
.get(method_name
)
338 if method
is None or not method
.enabled
:
340 val_type
= class_type
.template_argument(0)
341 node_type
= gdb
.lookup_type(str(class_type
) + '::_Node').pointer()
342 return method
.worker_class(val_type
, node_type
)
344 # Xmethods for std::list
347 class ListWorkerBase(gdb
.xmethod
.XMethodWorker
):
348 def __init__(self
, val_type
, node_type
):
349 self
._val
_type
= val_type
350 self
._node
_type
= node_type
352 def get_arg_types(self
):
355 def get_value_from_node(self
, node
):
356 node
= node
.dereference()
357 if node
.type.fields()[1].name
== '_M_data':
358 # C++03 implementation, node contains the value as a member
359 return node
['_M_data']
360 # C++11 implementation, node stores value in __aligned_membuf
361 addr
= node
['_M_storage'].address
362 return addr
.cast(self
._val
_type
.pointer()).dereference()
365 class ListEmptyWorker(ListWorkerBase
):
366 def get_result_type(self
, obj
):
367 return get_bool_type()
369 def __call__(self
, obj
):
370 base_node
= obj
['_M_impl']['_M_node']
371 if base_node
['_M_next'] == base_node
.address
:
377 class ListSizeWorker(ListWorkerBase
):
378 def get_result_type(self
, obj
):
379 return get_std_size_type()
381 def __call__(self
, obj
):
382 begin_node
= obj
['_M_impl']['_M_node']['_M_next']
383 end_node
= obj
['_M_impl']['_M_node'].address
385 while begin_node
!= end_node
:
386 begin_node
= begin_node
['_M_next']
391 class ListFrontWorker(ListWorkerBase
):
392 def get_result_type(self
, obj
):
393 return self
._val
_type
395 def __call__(self
, obj
):
396 node
= obj
['_M_impl']['_M_node']['_M_next'].cast(self
._node
_type
)
397 return self
.get_value_from_node(node
)
400 class ListBackWorker(ListWorkerBase
):
401 def get_result_type(self
, obj
):
402 return self
._val
_type
404 def __call__(self
, obj
):
405 prev_node
= obj
['_M_impl']['_M_node']['_M_prev'].cast(self
._node
_type
)
406 return self
.get_value_from_node(prev_node
)
409 class ListMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
411 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
412 matcher_name_prefix
+ 'list')
413 self
._method
_dict
= {
414 'empty': LibStdCxxXMethod('empty', ListEmptyWorker
),
415 'size': LibStdCxxXMethod('size', ListSizeWorker
),
416 'front': LibStdCxxXMethod('front', ListFrontWorker
),
417 'back': LibStdCxxXMethod('back', ListBackWorker
)
419 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
421 def match(self
, class_type
, method_name
):
422 if not re
.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type
.tag
):
424 method
= self
._method
_dict
.get(method_name
)
425 if method
is None or not method
.enabled
:
427 val_type
= class_type
.template_argument(0)
428 node_type
= gdb
.lookup_type(str(class_type
) + '::_Node').pointer()
429 return method
.worker_class(val_type
, node_type
)
431 # Xmethods for std::vector
434 class VectorWorkerBase(gdb
.xmethod
.XMethodWorker
):
435 def __init__(self
, val_type
):
436 self
._val
_type
= val_type
439 if self
._val
_type
.code
== gdb
.TYPE_CODE_BOOL
:
440 start
= obj
['_M_impl']['_M_start']['_M_p']
441 finish
= obj
['_M_impl']['_M_finish']['_M_p']
442 finish_offset
= obj
['_M_impl']['_M_finish']['_M_offset']
443 bit_size
= start
.dereference().type.sizeof
* 8
444 return (finish
- start
) * bit_size
+ finish_offset
446 return obj
['_M_impl']['_M_finish'] - obj
['_M_impl']['_M_start']
448 def get(self
, obj
, index
):
449 if self
._val
_type
.code
== gdb
.TYPE_CODE_BOOL
:
450 start
= obj
['_M_impl']['_M_start']['_M_p']
451 bit_size
= start
.dereference().type.sizeof
* 8
452 valp
= start
+ index
// bit_size
453 offset
= index
% bit_size
454 return (valp
.dereference() & (1 << offset
)) > 0
456 return obj
['_M_impl']['_M_start'][index
]
459 class VectorEmptyWorker(VectorWorkerBase
):
460 def get_arg_types(self
):
463 def get_result_type(self
, obj
):
464 return get_bool_type()
466 def __call__(self
, obj
):
467 return int(self
.size(obj
)) == 0
470 class VectorSizeWorker(VectorWorkerBase
):
471 def get_arg_types(self
):
474 def get_result_type(self
, obj
):
475 return get_std_size_type()
477 def __call__(self
, obj
):
478 return self
.size(obj
)
481 class VectorFrontWorker(VectorWorkerBase
):
482 def get_arg_types(self
):
485 def get_result_type(self
, obj
):
486 return self
._val
_type
488 def __call__(self
, obj
):
489 return self
.get(obj
, 0)
492 class VectorBackWorker(VectorWorkerBase
):
493 def get_arg_types(self
):
496 def get_result_type(self
, obj
):
497 return self
._val
_type
499 def __call__(self
, obj
):
500 return self
.get(obj
, int(self
.size(obj
)) - 1)
503 class VectorAtWorker(VectorWorkerBase
):
504 def get_arg_types(self
):
505 return get_std_size_type()
507 def get_result_type(self
, obj
, index
):
508 return self
._val
_type
510 def __call__(self
, obj
, index
):
511 size
= int(self
.size(obj
))
512 if int(index
) >= size
:
513 raise IndexError('Vector index "%d" should not be >= %d.' %
514 ((int(index
), size
)))
515 return self
.get(obj
, int(index
))
518 class VectorSubscriptWorker(VectorWorkerBase
):
519 def get_arg_types(self
):
520 return get_std_size_type()
522 def get_result_type(self
, obj
, subscript
):
523 return self
._val
_type
525 def __call__(self
, obj
, subscript
):
526 return self
.get(obj
, int(subscript
))
529 class VectorMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
531 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
532 matcher_name_prefix
+ 'vector')
533 self
._method
_dict
= {
534 'size': LibStdCxxXMethod('size', VectorSizeWorker
),
535 'empty': LibStdCxxXMethod('empty', VectorEmptyWorker
),
536 'front': LibStdCxxXMethod('front', VectorFrontWorker
),
537 'back': LibStdCxxXMethod('back', VectorBackWorker
),
538 'at': LibStdCxxXMethod('at', VectorAtWorker
),
539 'operator[]': LibStdCxxXMethod('operator[]',
540 VectorSubscriptWorker
),
542 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
544 def match(self
, class_type
, method_name
):
545 if not re
.match('^std::(__\d+::)?vector<.*>$', class_type
.tag
):
547 method
= self
._method
_dict
.get(method_name
)
548 if method
is None or not method
.enabled
:
550 return method
.worker_class(class_type
.template_argument(0))
552 # Xmethods for associative containers
555 class AssociativeContainerWorkerBase(gdb
.xmethod
.XMethodWorker
):
556 def __init__(self
, unordered
):
557 self
._unordered
= unordered
559 def node_count(self
, obj
):
561 return obj
['_M_h']['_M_element_count']
563 return obj
['_M_t']['_M_impl']['_M_node_count']
565 def get_arg_types(self
):
569 class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase
):
570 def get_result_type(self
, obj
):
571 return get_bool_type()
573 def __call__(self
, obj
):
574 return int(self
.node_count(obj
)) == 0
577 class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase
):
578 def get_result_type(self
, obj
):
579 return get_std_size_type()
581 def __call__(self
, obj
):
582 return self
.node_count(obj
)
585 class AssociativeContainerMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
586 def __init__(self
, name
):
587 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
588 matcher_name_prefix
+ name
)
590 self
._method
_dict
= {
591 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker
),
592 'empty': LibStdCxxXMethod('empty',
593 AssociativeContainerEmptyWorker
),
595 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
597 def match(self
, class_type
, method_name
):
598 if not re
.match('^std::(__\d+::)?%s<.*>$' % self
._name
, class_type
.tag
):
600 method
= self
._method
_dict
.get(method_name
)
601 if method
is None or not method
.enabled
:
603 unordered
= 'unordered' in self
._name
604 return method
.worker_class(unordered
)
606 # Xmethods for std::unique_ptr
609 class UniquePtrGetWorker(gdb
.xmethod
.XMethodWorker
):
610 "Implements std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->()"
612 def __init__(self
, elem_type
):
613 self
._is
_array
= elem_type
.code
== gdb
.TYPE_CODE_ARRAY
615 self
._elem
_type
= elem_type
.target()
617 self
._elem
_type
= elem_type
619 def get_arg_types(self
):
622 def get_result_type(self
, obj
):
623 return self
._elem
_type
.pointer()
625 def _supports(self
, method_name
):
626 "operator-> is not supported for unique_ptr<T[]>"
627 return method_name
== 'get' or not self
._is
_array
629 def __call__(self
, obj
):
630 impl_type
= obj
.dereference().type.fields()[0].type.tag
631 # Check for new implementations first:
632 if re
.match('^std::(__\d+::)?__uniq_ptr_(data|impl)<.*>$', impl_type
):
633 tuple_member
= obj
['_M_t']['_M_t']
634 elif re
.match('^std::(__\d+::)?tuple<.*>$', impl_type
):
635 tuple_member
= obj
['_M_t']
638 tuple_impl_type
= tuple_member
.type.fields()[0].type # _Tuple_impl
639 tuple_head_type
= tuple_impl_type
.fields()[1].type # _Head_base
640 head_field
= tuple_head_type
.fields()[0]
641 if head_field
.name
== '_M_head_impl':
642 return tuple_member
.cast(tuple_head_type
)['_M_head_impl']
643 elif head_field
.is_base_class
:
644 return tuple_member
.cast(head_field
.type)
649 class UniquePtrDerefWorker(UniquePtrGetWorker
):
650 "Implements std::unique_ptr<T>::operator*()"
652 def __init__(self
, elem_type
):
653 UniquePtrGetWorker
.__init
__(self
, elem_type
)
655 def get_result_type(self
, obj
):
656 return self
._elem
_type
658 def _supports(self
, method_name
):
659 "operator* is not supported for unique_ptr<T[]>"
660 return not self
._is
_array
662 def __call__(self
, obj
):
663 return UniquePtrGetWorker
.__call
__(self
, obj
).dereference()
666 class UniquePtrSubscriptWorker(UniquePtrGetWorker
):
667 "Implements std::unique_ptr<T>::operator[](size_t)"
669 def __init__(self
, elem_type
):
670 UniquePtrGetWorker
.__init
__(self
, elem_type
)
672 def get_arg_types(self
):
673 return get_std_size_type()
675 def get_result_type(self
, obj
, index
):
676 return self
._elem
_type
678 def _supports(self
, method_name
):
679 "operator[] is only supported for unique_ptr<T[]>"
680 return self
._is
_array
682 def __call__(self
, obj
, index
):
683 return UniquePtrGetWorker
.__call
__(self
, obj
)[index
]
686 class UniquePtrMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
688 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
689 matcher_name_prefix
+ 'unique_ptr')
690 self
._method
_dict
= {
691 'get': LibStdCxxXMethod('get', UniquePtrGetWorker
),
692 'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker
),
693 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker
),
694 'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker
),
696 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
698 def match(self
, class_type
, method_name
):
699 if not re
.match('^std::(__\d+::)?unique_ptr<.*>$', class_type
.tag
):
701 method
= self
._method
_dict
.get(method_name
)
702 if method
is None or not method
.enabled
:
704 worker
= method
.worker_class(class_type
.template_argument(0))
705 if worker
._supports
(method_name
):
709 # Xmethods for std::shared_ptr
712 class SharedPtrGetWorker(gdb
.xmethod
.XMethodWorker
):
713 "Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()"
715 def __init__(self
, elem_type
):
716 self
._is
_array
= elem_type
.code
== gdb
.TYPE_CODE_ARRAY
718 self
._elem
_type
= elem_type
.target()
720 self
._elem
_type
= elem_type
722 def get_arg_types(self
):
725 def get_result_type(self
, obj
):
726 return self
._elem
_type
.pointer()
728 def _supports(self
, method_name
):
729 "operator-> is not supported for shared_ptr<T[]>"
730 return method_name
== 'get' or not self
._is
_array
732 def __call__(self
, obj
):
736 class SharedPtrDerefWorker(SharedPtrGetWorker
):
737 "Implements std::shared_ptr<T>::operator*()"
739 def __init__(self
, elem_type
):
740 SharedPtrGetWorker
.__init
__(self
, elem_type
)
742 def get_result_type(self
, obj
):
743 return self
._elem
_type
745 def _supports(self
, method_name
):
746 "operator* is not supported for shared_ptr<T[]>"
747 return not self
._is
_array
749 def __call__(self
, obj
):
750 return SharedPtrGetWorker
.__call
__(self
, obj
).dereference()
753 class SharedPtrSubscriptWorker(SharedPtrGetWorker
):
754 "Implements std::shared_ptr<T>::operator[](size_t)"
756 def __init__(self
, elem_type
):
757 SharedPtrGetWorker
.__init
__(self
, elem_type
)
759 def get_arg_types(self
):
760 return get_std_size_type()
762 def get_result_type(self
, obj
, index
):
763 return self
._elem
_type
765 def _supports(self
, method_name
):
766 "operator[] is only supported for shared_ptr<T[]>"
767 return self
._is
_array
769 def __call__(self
, obj
, index
):
770 # Check bounds if _elem_type is an array of known bound
771 m
= re
.match('.*\[(\d+)]$', str(self
._elem
_type
))
772 if m
and index
>= int(m
.group(1)):
773 raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
774 (self
._elem
_type
, int(index
), int(m
.group(1))))
775 return SharedPtrGetWorker
.__call
__(self
, obj
)[index
]
778 class SharedPtrUseCountWorker(gdb
.xmethod
.XMethodWorker
):
779 "Implements std::shared_ptr<T>::use_count()"
781 def __init__(self
, elem_type
):
784 def get_arg_types(self
):
787 def get_result_type(self
, obj
):
788 return gdb
.lookup_type('long')
790 def _supports(self
, method_name
):
793 def __call__(self
, obj
):
794 refcounts
= obj
['_M_refcount']['_M_pi']
795 return refcounts
['_M_use_count'] if refcounts
else 0
798 class SharedPtrUniqueWorker(SharedPtrUseCountWorker
):
799 "Implements std::shared_ptr<T>::unique()"
801 def __init__(self
, elem_type
):
802 SharedPtrUseCountWorker
.__init
__(self
, elem_type
)
804 def get_result_type(self
, obj
):
805 return gdb
.lookup_type('bool')
807 def __call__(self
, obj
):
808 return SharedPtrUseCountWorker
.__call
__(self
, obj
) == 1
811 class SharedPtrMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
813 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
814 matcher_name_prefix
+ 'shared_ptr')
815 self
._method
_dict
= {
816 'get': LibStdCxxXMethod('get', SharedPtrGetWorker
),
817 'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker
),
818 'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker
),
819 'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker
),
820 'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker
),
821 'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker
),
823 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
825 def match(self
, class_type
, method_name
):
826 if not re
.match('^std::(__\d+::)?shared_ptr<.*>$', class_type
.tag
):
828 method
= self
._method
_dict
.get(method_name
)
829 if method
is None or not method
.enabled
:
831 worker
= method
.worker_class(class_type
.template_argument(0))
832 if worker
._supports
(method_name
):
837 def register_libstdcxx_xmethods(locus
):
838 gdb
.xmethod
.register_xmethod_matcher(locus
, ArrayMethodsMatcher())
839 gdb
.xmethod
.register_xmethod_matcher(locus
, ForwardListMethodsMatcher())
840 gdb
.xmethod
.register_xmethod_matcher(locus
, DequeMethodsMatcher())
841 gdb
.xmethod
.register_xmethod_matcher(locus
, ListMethodsMatcher())
842 gdb
.xmethod
.register_xmethod_matcher(locus
, VectorMethodsMatcher())
843 gdb
.xmethod
.register_xmethod_matcher(
844 locus
, AssociativeContainerMethodsMatcher('set'))
845 gdb
.xmethod
.register_xmethod_matcher(
846 locus
, AssociativeContainerMethodsMatcher('map'))
847 gdb
.xmethod
.register_xmethod_matcher(
848 locus
, AssociativeContainerMethodsMatcher('multiset'))
849 gdb
.xmethod
.register_xmethod_matcher(
850 locus
, AssociativeContainerMethodsMatcher('multimap'))
851 gdb
.xmethod
.register_xmethod_matcher(
852 locus
, AssociativeContainerMethodsMatcher('unordered_set'))
853 gdb
.xmethod
.register_xmethod_matcher(
854 locus
, AssociativeContainerMethodsMatcher('unordered_map'))
855 gdb
.xmethod
.register_xmethod_matcher(
856 locus
, AssociativeContainerMethodsMatcher('unordered_multiset'))
857 gdb
.xmethod
.register_xmethod_matcher(
858 locus
, AssociativeContainerMethodsMatcher('unordered_multimap'))
859 gdb
.xmethod
.register_xmethod_matcher(locus
, UniquePtrMethodsMatcher())
860 gdb
.xmethod
.register_xmethod_matcher(locus
, SharedPtrMethodsMatcher())