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