1 # Xmethods for libstdc++.
3 # Copyright (C) 2014-2024 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')
28 def get_std_size_type():
29 return gdb
.lookup_type('std::size_t')
31 _versioned_namespace
= '__8::'
33 def is_specialization_of(x
, template_name
):
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.
40 if isinstance(x
, gdb
.Type
):
42 template_name
= '(%s)?%s' % (_versioned_namespace
, template_name
)
43 return re
.match(r
'^std::(__\d::)?%s<.*>$' % template_name
, x
) is not None
45 class LibStdCxxXMethod(gdb
.xmethod
.XMethod
):
46 def __init__(self
, name
, worker_class
):
47 gdb
.xmethod
.XMethod
.__init
__(self
, name
)
48 self
.worker_class
= worker_class
50 # Xmethods for std::array
53 class ArrayWorkerBase(gdb
.xmethod
.XMethodWorker
):
54 def __init__(self
, val_type
, size
):
55 self
._val
_type
= val_type
59 nullptr
= gdb
.parse_and_eval('(void *) 0')
60 return nullptr
.cast(self
._val
_type
.pointer()).dereference()
63 class ArraySizeWorker(ArrayWorkerBase
):
64 def __init__(self
, val_type
, size
):
65 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
67 def get_arg_types(self
):
70 def get_result_type(self
, obj
):
71 return get_std_size_type()
73 def __call__(self
, obj
):
77 class ArrayEmptyWorker(ArrayWorkerBase
):
78 def __init__(self
, val_type
, size
):
79 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
81 def get_arg_types(self
):
84 def get_result_type(self
, obj
):
85 return get_bool_type()
87 def __call__(self
, obj
):
88 return (int(self
._size
) == 0)
91 class ArrayFrontWorker(ArrayWorkerBase
):
92 def __init__(self
, val_type
, size
):
93 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
95 def get_arg_types(self
):
98 def get_result_type(self
, obj
):
101 def __call__(self
, obj
):
102 if int(self
._size
) > 0:
103 return obj
['_M_elems'][0]
105 return self
.null_value()
108 class ArrayBackWorker(ArrayWorkerBase
):
109 def __init__(self
, val_type
, size
):
110 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
112 def get_arg_types(self
):
115 def get_result_type(self
, obj
):
116 return self
._val
_type
118 def __call__(self
, obj
):
119 if int(self
._size
) > 0:
120 return obj
['_M_elems'][self
._size
- 1]
122 return self
.null_value()
125 class ArrayAtWorker(ArrayWorkerBase
):
126 def __init__(self
, val_type
, size
):
127 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
129 def get_arg_types(self
):
130 return get_std_size_type()
132 def get_result_type(self
, obj
, index
):
133 return self
._val
_type
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
]
142 class ArraySubscriptWorker(ArrayWorkerBase
):
143 def __init__(self
, val_type
, size
):
144 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
146 def get_arg_types(self
):
147 return get_std_size_type()
149 def get_result_type(self
, obj
, index
):
150 return self
._val
_type
152 def __call__(self
, obj
, index
):
153 if int(self
._size
) > 0:
154 return obj
['_M_elems'][index
]
156 return self
.null_value()
159 class ArrayMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
171 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
173 def match(self
, class_type
, method_name
):
174 if not is_specialization_of(class_type
, 'array'):
176 method
= self
._method
_dict
.get(method_name
)
177 if method
is None or not method
.enabled
:
180 value_type
= class_type
.template_argument(0)
181 size
= class_type
.template_argument(1)
184 return method
.worker_class(value_type
, size
)
187 # Xmethods for std::deque
190 class 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
196 start
= obj
['_M_impl']['_M_start']
197 finish
= obj
['_M_impl']['_M_finish']
198 if start
['_M_cur'] == finish
['_M_cur']:
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']))
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
]
215 class DequeEmptyWorker(DequeWorkerBase
):
216 def get_arg_types(self
):
219 def get_result_type(self
, obj
):
220 return get_bool_type()
222 def __call__(self
, obj
):
223 return (obj
['_M_impl']['_M_start']['_M_cur'] ==
224 obj
['_M_impl']['_M_finish']['_M_cur'])
227 class DequeSizeWorker(DequeWorkerBase
):
228 def get_arg_types(self
):
231 def get_result_type(self
, obj
):
232 return get_std_size_type()
234 def __call__(self
, obj
):
235 return self
.size(obj
)
238 class DequeFrontWorker(DequeWorkerBase
):
239 def get_arg_types(self
):
242 def get_result_type(self
, obj
):
243 return self
._val
_type
245 def __call__(self
, obj
):
246 return obj
['_M_impl']['_M_start']['_M_cur'][0]
249 class DequeBackWorker(DequeWorkerBase
):
250 def get_arg_types(self
):
253 def get_result_type(self
, obj
):
254 return self
._val
_type
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]
262 return obj
['_M_impl']['_M_finish']['_M_cur'][-1]
265 class DequeSubscriptWorker(DequeWorkerBase
):
266 def get_arg_types(self
):
267 return get_std_size_type()
269 def get_result_type(self
, obj
, subscript
):
270 return self
._val
_type
272 def __call__(self
, obj
, subscript
):
273 return self
.index(obj
, subscript
)
276 class DequeAtWorker(DequeWorkerBase
):
277 def get_arg_types(self
):
278 return get_std_size_type()
280 def get_result_type(self
, obj
, index
):
281 return self
._val
_type
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
))
289 return self
.index(obj
, index
)
292 class DequeMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
)
304 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
306 def match(self
, class_type
, method_name
):
307 if not is_specialization_of(class_type
, 'deque'):
309 method
= self
._method
_dict
.get(method_name
)
310 if method
is None or not method
.enabled
:
312 return method
.worker_class(class_type
.template_argument(0))
314 # Xmethods for std::forward_list
317 class ForwardListWorkerBase(gdb
.xmethod
.XMethodMatcher
):
318 def __init__(self
, val_type
, node_type
):
319 self
._val
_type
= val_type
320 self
._node
_type
= node_type
322 def get_arg_types(self
):
326 class ForwardListEmptyWorker(ForwardListWorkerBase
):
327 def get_result_type(self
, obj
):
328 return get_bool_type()
330 def __call__(self
, obj
):
331 return obj
['_M_impl']['_M_head']['_M_next'] == 0
334 class ForwardListFrontWorker(ForwardListWorkerBase
):
335 def get_result_type(self
, obj
):
336 return self
._val
_type
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()
344 class ForwardListMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
)
352 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
354 def match(self
, class_type
, method_name
):
355 if not is_specialization_of(class_type
, 'forward_list'):
357 method
= self
._method
_dict
.get(method_name
)
358 if method
is None or not method
.enabled
:
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
)
364 # Xmethods for std::list
367 class ListWorkerBase(gdb
.xmethod
.XMethodWorker
):
368 def __init__(self
, val_type
, node_type
):
369 self
._val
_type
= val_type
370 self
._node
_type
= node_type
372 def get_arg_types(self
):
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()
385 class ListEmptyWorker(ListWorkerBase
):
386 def get_result_type(self
, obj
):
387 return get_bool_type()
389 def __call__(self
, obj
):
390 base_node
= obj
['_M_impl']['_M_node']
391 if base_node
['_M_next'] == base_node
.address
:
397 class ListSizeWorker(ListWorkerBase
):
398 def get_result_type(self
, obj
):
399 return get_std_size_type()
401 def __call__(self
, obj
):
402 begin_node
= obj
['_M_impl']['_M_node']['_M_next']
403 end_node
= obj
['_M_impl']['_M_node'].address
405 while begin_node
!= end_node
:
406 begin_node
= begin_node
['_M_next']
411 class ListFrontWorker(ListWorkerBase
):
412 def get_result_type(self
, obj
):
413 return self
._val
_type
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
)
420 class ListBackWorker(ListWorkerBase
):
421 def get_result_type(self
, obj
):
422 return self
._val
_type
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
)
429 class ListMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
)
439 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
441 def match(self
, class_type
, method_name
):
442 if not is_specialization_of(class_type
, '(__cxx11::)?list'):
444 method
= self
._method
_dict
.get(method_name
)
445 if method
is None or not method
.enabled
:
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
)
451 # Xmethods for std::vector
454 class VectorWorkerBase(gdb
.xmethod
.XMethodWorker
):
455 def __init__(self
, val_type
):
456 self
._val
_type
= val_type
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
466 return obj
['_M_impl']['_M_finish'] - obj
['_M_impl']['_M_start']
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
476 return obj
['_M_impl']['_M_start'][index
]
479 class VectorEmptyWorker(VectorWorkerBase
):
480 def get_arg_types(self
):
483 def get_result_type(self
, obj
):
484 return get_bool_type()
486 def __call__(self
, obj
):
487 return int(self
.size(obj
)) == 0
490 class VectorSizeWorker(VectorWorkerBase
):
491 def get_arg_types(self
):
494 def get_result_type(self
, obj
):
495 return get_std_size_type()
497 def __call__(self
, obj
):
498 return self
.size(obj
)
501 class VectorFrontWorker(VectorWorkerBase
):
502 def get_arg_types(self
):
505 def get_result_type(self
, obj
):
506 return self
._val
_type
508 def __call__(self
, obj
):
509 return self
.get(obj
, 0)
512 class VectorBackWorker(VectorWorkerBase
):
513 def get_arg_types(self
):
516 def get_result_type(self
, obj
):
517 return self
._val
_type
519 def __call__(self
, obj
):
520 return self
.get(obj
, int(self
.size(obj
)) - 1)
523 class VectorAtWorker(VectorWorkerBase
):
524 def get_arg_types(self
):
525 return get_std_size_type()
527 def get_result_type(self
, obj
, index
):
528 return self
._val
_type
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
))
538 class VectorSubscriptWorker(VectorWorkerBase
):
539 def get_arg_types(self
):
540 return get_std_size_type()
542 def get_result_type(self
, obj
, subscript
):
543 return self
._val
_type
545 def __call__(self
, obj
, subscript
):
546 return self
.get(obj
, int(subscript
))
549 class VectorMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
562 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
564 def match(self
, class_type
, method_name
):
565 if not is_specialization_of(class_type
, 'vector'):
567 method
= self
._method
_dict
.get(method_name
)
568 if method
is None or not method
.enabled
:
570 return method
.worker_class(class_type
.template_argument(0))
572 # Xmethods for associative containers
575 class AssociativeContainerWorkerBase(gdb
.xmethod
.XMethodWorker
):
576 def __init__(self
, unordered
):
577 self
._unordered
= unordered
579 def node_count(self
, obj
):
581 return obj
['_M_h']['_M_element_count']
583 return obj
['_M_t']['_M_impl']['_M_node_count']
585 def get_arg_types(self
):
589 class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase
):
590 def get_result_type(self
, obj
):
591 return get_bool_type()
593 def __call__(self
, obj
):
594 return int(self
.node_count(obj
)) == 0
597 class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase
):
598 def get_result_type(self
, obj
):
599 return get_std_size_type()
601 def __call__(self
, obj
):
602 return self
.node_count(obj
)
605 class AssociativeContainerMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
606 def __init__(self
, name
):
607 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
608 matcher_name_prefix
+ name
)
610 self
._method
_dict
= {
611 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker
),
612 'empty': LibStdCxxXMethod('empty',
613 AssociativeContainerEmptyWorker
),
615 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
617 def match(self
, class_type
, method_name
):
618 if not is_specialization_of(class_type
, self
._name
):
620 method
= self
._method
_dict
.get(method_name
)
621 if method
is None or not method
.enabled
:
623 unordered
= 'unordered' in self
._name
624 return method
.worker_class(unordered
)
626 # Xmethods for std::unique_ptr
629 class UniquePtrGetWorker(gdb
.xmethod
.XMethodWorker
):
631 Implement std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->().
634 def __init__(self
, elem_type
):
635 self
._is
_array
= elem_type
.code
== gdb
.TYPE_CODE_ARRAY
637 self
._elem
_type
= elem_type
.target()
639 self
._elem
_type
= elem_type
641 def get_arg_types(self
):
644 def get_result_type(self
, obj
):
645 return self
._elem
_type
.pointer()
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
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']
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)
671 class UniquePtrDerefWorker(UniquePtrGetWorker
):
672 """Implement std::unique_ptr<T>::operator*()."""
674 def __init__(self
, elem_type
):
675 UniquePtrGetWorker
.__init
__(self
, elem_type
)
677 def get_result_type(self
, obj
):
678 return self
._elem
_type
680 def _supports(self
, method_name
):
681 # operator* is not supported for unique_ptr<T[]>
682 return not self
._is
_array
684 def __call__(self
, obj
):
685 return UniquePtrGetWorker
.__call
__(self
, obj
).dereference()
688 class UniquePtrSubscriptWorker(UniquePtrGetWorker
):
689 """Implement std::unique_ptr<T>::operator[](size_t)."""
691 def __init__(self
, elem_type
):
692 UniquePtrGetWorker
.__init
__(self
, elem_type
)
694 def get_arg_types(self
):
695 return get_std_size_type()
697 def get_result_type(self
, obj
, index
):
698 return self
._elem
_type
700 def _supports(self
, method_name
):
701 # operator[] is only supported for unique_ptr<T[]>
702 return self
._is
_array
704 def __call__(self
, obj
, index
):
705 return UniquePtrGetWorker
.__call
__(self
, obj
)[index
]
708 class UniquePtrMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
718 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
720 def match(self
, class_type
, method_name
):
721 if not is_specialization_of(class_type
, 'unique_ptr'):
723 method
= self
._method
_dict
.get(method_name
)
724 if method
is None or not method
.enabled
:
726 worker
= method
.worker_class(class_type
.template_argument(0))
727 if worker
._supports
(method_name
):
731 # Xmethods for std::shared_ptr
734 class SharedPtrGetWorker(gdb
.xmethod
.XMethodWorker
):
736 Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->().
739 def __init__(self
, elem_type
):
740 self
._is
_array
= elem_type
.code
== gdb
.TYPE_CODE_ARRAY
742 self
._elem
_type
= elem_type
.target()
744 self
._elem
_type
= elem_type
746 def get_arg_types(self
):
749 def get_result_type(self
, obj
):
750 return self
._elem
_type
.pointer()
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
756 def __call__(self
, obj
):
760 class SharedPtrDerefWorker(SharedPtrGetWorker
):
761 """Implement std::shared_ptr<T>::operator*()."""
763 def __init__(self
, elem_type
):
764 SharedPtrGetWorker
.__init
__(self
, elem_type
)
766 def get_result_type(self
, obj
):
767 return self
._elem
_type
769 def _supports(self
, method_name
):
770 # operator* is not supported for shared_ptr<T[]>
771 return not self
._is
_array
773 def __call__(self
, obj
):
774 return SharedPtrGetWorker
.__call
__(self
, obj
).dereference()
777 class SharedPtrSubscriptWorker(SharedPtrGetWorker
):
778 """Implement std::shared_ptr<T>::operator[](size_t)."""
780 def __init__(self
, elem_type
):
781 SharedPtrGetWorker
.__init
__(self
, elem_type
)
783 def get_arg_types(self
):
784 return get_std_size_type()
786 def get_result_type(self
, obj
, index
):
787 return self
._elem
_type
789 def _supports(self
, method_name
):
790 # operator[] is only supported for shared_ptr<T[]>
791 return self
._is
_array
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
]
802 class SharedPtrUseCountWorker(gdb
.xmethod
.XMethodWorker
):
803 """Implement std::shared_ptr<T>::use_count()."""
805 def __init__(self
, elem_type
):
808 def get_arg_types(self
):
811 def get_result_type(self
, obj
):
812 return gdb
.lookup_type('long')
814 def _supports(self
, method_name
):
817 def __call__(self
, obj
):
818 refcounts
= obj
['_M_refcount']['_M_pi']
819 return refcounts
['_M_use_count'] if refcounts
else 0
822 class SharedPtrUniqueWorker(SharedPtrUseCountWorker
):
823 """Implement std::shared_ptr<T>::unique()."""
825 def __init__(self
, elem_type
):
826 SharedPtrUseCountWorker
.__init
__(self
, elem_type
)
828 def get_result_type(self
, obj
):
829 return gdb
.lookup_type('bool')
831 def __call__(self
, obj
):
832 return SharedPtrUseCountWorker
.__call
__(self
, obj
) == 1
835 class SharedPtrMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
847 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
849 def match(self
, class_type
, method_name
):
850 if not is_specialization_of(class_type
, 'shared_ptr'):
852 method
= self
._method
_dict
.get(method_name
)
853 if method
is None or not method
.enabled
:
855 worker
= method
.worker_class(class_type
.template_argument(0))
856 if worker
._supports
(method_name
):
861 def 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())