]> gcc.gnu.org Git - gcc.git/blob - libstdc++-v3/python/libstdcxx/v6/xmethods.py
libstdc++: Fix std::deque::size() Xmethod [PR112491]
[gcc.git] / libstdc++-v3 / python / libstdcxx / v6 / xmethods.py
1 # Xmethods for libstdc++.
2
3 # Copyright (C) 2014-2022 Free Software Foundation, Inc.
4
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
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 not start['_M_node']:
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 first_node = obj['_M_impl']['_M_start']['_M_node']
207 index_node = first_node + int(idx) // self._bufsize
208 return index_node[0][idx % self._bufsize]
209
210
211 class DequeEmptyWorker(DequeWorkerBase):
212 def get_arg_types(self):
213 return None
214
215 def get_result_type(self, obj):
216 return get_bool_type()
217
218 def __call__(self, obj):
219 return (obj['_M_impl']['_M_start']['_M_cur'] ==
220 obj['_M_impl']['_M_finish']['_M_cur'])
221
222
223 class DequeSizeWorker(DequeWorkerBase):
224 def get_arg_types(self):
225 return None
226
227 def get_result_type(self, obj):
228 return get_std_size_type()
229
230 def __call__(self, obj):
231 return self.size(obj)
232
233
234 class DequeFrontWorker(DequeWorkerBase):
235 def get_arg_types(self):
236 return None
237
238 def get_result_type(self, obj):
239 return self._val_type
240
241 def __call__(self, obj):
242 return obj['_M_impl']['_M_start']['_M_cur'][0]
243
244
245 class DequeBackWorker(DequeWorkerBase):
246 def get_arg_types(self):
247 return None
248
249 def get_result_type(self, obj):
250 return self._val_type
251
252 def __call__(self, obj):
253 if (obj['_M_impl']['_M_finish']['_M_cur'] ==
254 obj['_M_impl']['_M_finish']['_M_first']):
255 prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1
256 return prev_node[0][self._bufsize - 1]
257 else:
258 return obj['_M_impl']['_M_finish']['_M_cur'][-1]
259
260
261 class DequeSubscriptWorker(DequeWorkerBase):
262 def get_arg_types(self):
263 return get_std_size_type()
264
265 def get_result_type(self, obj, subscript):
266 return self._val_type
267
268 def __call__(self, obj, subscript):
269 return self.index(obj, subscript)
270
271
272 class DequeAtWorker(DequeWorkerBase):
273 def get_arg_types(self):
274 return get_std_size_type()
275
276 def get_result_type(self, obj, index):
277 return self._val_type
278
279 def __call__(self, obj, index):
280 deque_size = int(self.size(obj))
281 if int(index) >= deque_size:
282 raise IndexError('Deque index "%d" should not be >= %d.' %
283 (int(index), deque_size))
284 else:
285 return self.index(obj, index)
286
287
288 class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
289 def __init__(self):
290 gdb.xmethod.XMethodMatcher.__init__(self,
291 matcher_name_prefix + 'deque')
292 self._method_dict = {
293 'empty': LibStdCxxXMethod('empty', DequeEmptyWorker),
294 'size': LibStdCxxXMethod('size', DequeSizeWorker),
295 'front': LibStdCxxXMethod('front', DequeFrontWorker),
296 'back': LibStdCxxXMethod('back', DequeBackWorker),
297 'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker),
298 'at': LibStdCxxXMethod('at', DequeAtWorker)
299 }
300 self.methods = [self._method_dict[m] for m in self._method_dict]
301
302 def match(self, class_type, method_name):
303 if not is_specialization_of(class_type, 'deque'):
304 return None
305 method = self._method_dict.get(method_name)
306 if method is None or not method.enabled:
307 return None
308 return method.worker_class(class_type.template_argument(0))
309
310 # Xmethods for std::forward_list
311
312
313 class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher):
314 def __init__(self, val_type, node_type):
315 self._val_type = val_type
316 self._node_type = node_type
317
318 def get_arg_types(self):
319 return None
320
321
322 class ForwardListEmptyWorker(ForwardListWorkerBase):
323 def get_result_type(self, obj):
324 return get_bool_type()
325
326 def __call__(self, obj):
327 return obj['_M_impl']['_M_head']['_M_next'] == 0
328
329
330 class ForwardListFrontWorker(ForwardListWorkerBase):
331 def get_result_type(self, obj):
332 return self._val_type
333
334 def __call__(self, obj):
335 node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type)
336 val_address = node['_M_storage']['_M_storage'].address
337 return val_address.cast(self._val_type.pointer()).dereference()
338
339
340 class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
341 def __init__(self):
342 matcher_name = matcher_name_prefix + 'forward_list'
343 gdb.xmethod.XMethodMatcher.__init__(self, matcher_name)
344 self._method_dict = {
345 'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker),
346 'front': LibStdCxxXMethod('front', ForwardListFrontWorker)
347 }
348 self.methods = [self._method_dict[m] for m in self._method_dict]
349
350 def match(self, class_type, method_name):
351 if not is_specialization_of(class_type, 'forward_list'):
352 return None
353 method = self._method_dict.get(method_name)
354 if method is None or not method.enabled:
355 return None
356 val_type = class_type.template_argument(0)
357 node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
358 return method.worker_class(val_type, node_type)
359
360 # Xmethods for std::list
361
362
363 class ListWorkerBase(gdb.xmethod.XMethodWorker):
364 def __init__(self, val_type, node_type):
365 self._val_type = val_type
366 self._node_type = node_type
367
368 def get_arg_types(self):
369 return None
370
371 def get_value_from_node(self, node):
372 node = node.dereference()
373 if node.type.fields()[1].name == '_M_data':
374 # C++03 implementation, node contains the value as a member
375 return node['_M_data']
376 # C++11 implementation, node stores value in __aligned_membuf
377 addr = node['_M_storage'].address
378 return addr.cast(self._val_type.pointer()).dereference()
379
380
381 class ListEmptyWorker(ListWorkerBase):
382 def get_result_type(self, obj):
383 return get_bool_type()
384
385 def __call__(self, obj):
386 base_node = obj['_M_impl']['_M_node']
387 if base_node['_M_next'] == base_node.address:
388 return True
389 else:
390 return False
391
392
393 class ListSizeWorker(ListWorkerBase):
394 def get_result_type(self, obj):
395 return get_std_size_type()
396
397 def __call__(self, obj):
398 begin_node = obj['_M_impl']['_M_node']['_M_next']
399 end_node = obj['_M_impl']['_M_node'].address
400 size = 0
401 while begin_node != end_node:
402 begin_node = begin_node['_M_next']
403 size += 1
404 return size
405
406
407 class ListFrontWorker(ListWorkerBase):
408 def get_result_type(self, obj):
409 return self._val_type
410
411 def __call__(self, obj):
412 node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
413 return self.get_value_from_node(node)
414
415
416 class ListBackWorker(ListWorkerBase):
417 def get_result_type(self, obj):
418 return self._val_type
419
420 def __call__(self, obj):
421 prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
422 return self.get_value_from_node(prev_node)
423
424
425 class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
426 def __init__(self):
427 gdb.xmethod.XMethodMatcher.__init__(self,
428 matcher_name_prefix + 'list')
429 self._method_dict = {
430 'empty': LibStdCxxXMethod('empty', ListEmptyWorker),
431 'size': LibStdCxxXMethod('size', ListSizeWorker),
432 'front': LibStdCxxXMethod('front', ListFrontWorker),
433 'back': LibStdCxxXMethod('back', ListBackWorker)
434 }
435 self.methods = [self._method_dict[m] for m in self._method_dict]
436
437 def match(self, class_type, method_name):
438 if not is_specialization_of(class_type, '(__cxx11::)?list'):
439 return None
440 method = self._method_dict.get(method_name)
441 if method is None or not method.enabled:
442 return None
443 val_type = class_type.template_argument(0)
444 node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
445 return method.worker_class(val_type, node_type)
446
447 # Xmethods for std::vector
448
449
450 class VectorWorkerBase(gdb.xmethod.XMethodWorker):
451 def __init__(self, val_type):
452 self._val_type = val_type
453
454 def size(self, obj):
455 if self._val_type.code == gdb.TYPE_CODE_BOOL:
456 start = obj['_M_impl']['_M_start']['_M_p']
457 finish = obj['_M_impl']['_M_finish']['_M_p']
458 finish_offset = obj['_M_impl']['_M_finish']['_M_offset']
459 bit_size = start.dereference().type.sizeof * 8
460 return (finish - start) * bit_size + finish_offset
461 else:
462 return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start']
463
464 def get(self, obj, index):
465 if self._val_type.code == gdb.TYPE_CODE_BOOL:
466 start = obj['_M_impl']['_M_start']['_M_p']
467 bit_size = start.dereference().type.sizeof * 8
468 valp = start + index // bit_size
469 offset = index % bit_size
470 return (valp.dereference() & (1 << offset)) > 0
471 else:
472 return obj['_M_impl']['_M_start'][index]
473
474
475 class VectorEmptyWorker(VectorWorkerBase):
476 def get_arg_types(self):
477 return None
478
479 def get_result_type(self, obj):
480 return get_bool_type()
481
482 def __call__(self, obj):
483 return int(self.size(obj)) == 0
484
485
486 class VectorSizeWorker(VectorWorkerBase):
487 def get_arg_types(self):
488 return None
489
490 def get_result_type(self, obj):
491 return get_std_size_type()
492
493 def __call__(self, obj):
494 return self.size(obj)
495
496
497 class VectorFrontWorker(VectorWorkerBase):
498 def get_arg_types(self):
499 return None
500
501 def get_result_type(self, obj):
502 return self._val_type
503
504 def __call__(self, obj):
505 return self.get(obj, 0)
506
507
508 class VectorBackWorker(VectorWorkerBase):
509 def get_arg_types(self):
510 return None
511
512 def get_result_type(self, obj):
513 return self._val_type
514
515 def __call__(self, obj):
516 return self.get(obj, int(self.size(obj)) - 1)
517
518
519 class VectorAtWorker(VectorWorkerBase):
520 def get_arg_types(self):
521 return get_std_size_type()
522
523 def get_result_type(self, obj, index):
524 return self._val_type
525
526 def __call__(self, obj, index):
527 size = int(self.size(obj))
528 if int(index) >= size:
529 raise IndexError('Vector index "%d" should not be >= %d.' %
530 ((int(index), size)))
531 return self.get(obj, int(index))
532
533
534 class VectorSubscriptWorker(VectorWorkerBase):
535 def get_arg_types(self):
536 return get_std_size_type()
537
538 def get_result_type(self, obj, subscript):
539 return self._val_type
540
541 def __call__(self, obj, subscript):
542 return self.get(obj, int(subscript))
543
544
545 class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
546 def __init__(self):
547 gdb.xmethod.XMethodMatcher.__init__(self,
548 matcher_name_prefix + 'vector')
549 self._method_dict = {
550 'size': LibStdCxxXMethod('size', VectorSizeWorker),
551 'empty': LibStdCxxXMethod('empty', VectorEmptyWorker),
552 'front': LibStdCxxXMethod('front', VectorFrontWorker),
553 'back': LibStdCxxXMethod('back', VectorBackWorker),
554 'at': LibStdCxxXMethod('at', VectorAtWorker),
555 'operator[]': LibStdCxxXMethod('operator[]',
556 VectorSubscriptWorker),
557 }
558 self.methods = [self._method_dict[m] for m in self._method_dict]
559
560 def match(self, class_type, method_name):
561 if not is_specialization_of(class_type, 'vector'):
562 return None
563 method = self._method_dict.get(method_name)
564 if method is None or not method.enabled:
565 return None
566 return method.worker_class(class_type.template_argument(0))
567
568 # Xmethods for associative containers
569
570
571 class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
572 def __init__(self, unordered):
573 self._unordered = unordered
574
575 def node_count(self, obj):
576 if self._unordered:
577 return obj['_M_h']['_M_element_count']
578 else:
579 return obj['_M_t']['_M_impl']['_M_node_count']
580
581 def get_arg_types(self):
582 return None
583
584
585 class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
586 def get_result_type(self, obj):
587 return get_bool_type()
588
589 def __call__(self, obj):
590 return int(self.node_count(obj)) == 0
591
592
593 class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
594 def get_result_type(self, obj):
595 return get_std_size_type()
596
597 def __call__(self, obj):
598 return self.node_count(obj)
599
600
601 class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
602 def __init__(self, name):
603 gdb.xmethod.XMethodMatcher.__init__(self,
604 matcher_name_prefix + name)
605 self._name = name
606 self._method_dict = {
607 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker),
608 'empty': LibStdCxxXMethod('empty',
609 AssociativeContainerEmptyWorker),
610 }
611 self.methods = [self._method_dict[m] for m in self._method_dict]
612
613 def match(self, class_type, method_name):
614 if not is_specialization_of(class_type, self._name):
615 return None
616 method = self._method_dict.get(method_name)
617 if method is None or not method.enabled:
618 return None
619 unordered = 'unordered' in self._name
620 return method.worker_class(unordered)
621
622 # Xmethods for std::unique_ptr
623
624
625 class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
626 """
627 Implement std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->().
628 """
629
630 def __init__(self, elem_type):
631 self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
632 if self._is_array:
633 self._elem_type = elem_type.target()
634 else:
635 self._elem_type = elem_type
636
637 def get_arg_types(self):
638 return None
639
640 def get_result_type(self, obj):
641 return self._elem_type.pointer()
642
643 def _supports(self, method_name):
644 # operator-> is not supported for unique_ptr<T[]>
645 return method_name == 'get' or not self._is_array
646
647 def __call__(self, obj):
648 impl_type = obj.dereference().type.fields()[0].type.tag
649 # Check for new implementations first:
650 if is_specialization_of(impl_type, '__uniq_ptr_(data|impl)'):
651 tuple_member = obj['_M_t']['_M_t']
652 elif is_specialization_of(impl_type, 'tuple'):
653 tuple_member = obj['_M_t']
654 else:
655 return None
656 tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
657 tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base
658 head_field = tuple_head_type.fields()[0]
659 if head_field.name == '_M_head_impl':
660 return tuple_member.cast(tuple_head_type)['_M_head_impl']
661 elif head_field.is_base_class:
662 return tuple_member.cast(head_field.type)
663 else:
664 return None
665
666
667 class UniquePtrDerefWorker(UniquePtrGetWorker):
668 """Implement std::unique_ptr<T>::operator*()."""
669
670 def __init__(self, elem_type):
671 UniquePtrGetWorker.__init__(self, elem_type)
672
673 def get_result_type(self, obj):
674 return self._elem_type
675
676 def _supports(self, method_name):
677 # operator* is not supported for unique_ptr<T[]>
678 return not self._is_array
679
680 def __call__(self, obj):
681 return UniquePtrGetWorker.__call__(self, obj).dereference()
682
683
684 class UniquePtrSubscriptWorker(UniquePtrGetWorker):
685 """Implement std::unique_ptr<T>::operator[](size_t)."""
686
687 def __init__(self, elem_type):
688 UniquePtrGetWorker.__init__(self, elem_type)
689
690 def get_arg_types(self):
691 return get_std_size_type()
692
693 def get_result_type(self, obj, index):
694 return self._elem_type
695
696 def _supports(self, method_name):
697 # operator[] is only supported for unique_ptr<T[]>
698 return self._is_array
699
700 def __call__(self, obj, index):
701 return UniquePtrGetWorker.__call__(self, obj)[index]
702
703
704 class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
705 def __init__(self):
706 gdb.xmethod.XMethodMatcher.__init__(self,
707 matcher_name_prefix + 'unique_ptr')
708 self._method_dict = {
709 'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
710 'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker),
711 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
712 'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker),
713 }
714 self.methods = [self._method_dict[m] for m in self._method_dict]
715
716 def match(self, class_type, method_name):
717 if not is_specialization_of(class_type, 'unique_ptr'):
718 return None
719 method = self._method_dict.get(method_name)
720 if method is None or not method.enabled:
721 return None
722 worker = method.worker_class(class_type.template_argument(0))
723 if worker._supports(method_name):
724 return worker
725 return None
726
727 # Xmethods for std::shared_ptr
728
729
730 class SharedPtrGetWorker(gdb.xmethod.XMethodWorker):
731 """
732 Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->().
733 """
734
735 def __init__(self, elem_type):
736 self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
737 if self._is_array:
738 self._elem_type = elem_type.target()
739 else:
740 self._elem_type = elem_type
741
742 def get_arg_types(self):
743 return None
744
745 def get_result_type(self, obj):
746 return self._elem_type.pointer()
747
748 def _supports(self, method_name):
749 # operator-> is not supported for shared_ptr<T[]>
750 return method_name == 'get' or not self._is_array
751
752 def __call__(self, obj):
753 return obj['_M_ptr']
754
755
756 class SharedPtrDerefWorker(SharedPtrGetWorker):
757 """Implement std::shared_ptr<T>::operator*()."""
758
759 def __init__(self, elem_type):
760 SharedPtrGetWorker.__init__(self, elem_type)
761
762 def get_result_type(self, obj):
763 return self._elem_type
764
765 def _supports(self, method_name):
766 # operator* is not supported for shared_ptr<T[]>
767 return not self._is_array
768
769 def __call__(self, obj):
770 return SharedPtrGetWorker.__call__(self, obj).dereference()
771
772
773 class SharedPtrSubscriptWorker(SharedPtrGetWorker):
774 """Implement std::shared_ptr<T>::operator[](size_t)."""
775
776 def __init__(self, elem_type):
777 SharedPtrGetWorker.__init__(self, elem_type)
778
779 def get_arg_types(self):
780 return get_std_size_type()
781
782 def get_result_type(self, obj, index):
783 return self._elem_type
784
785 def _supports(self, method_name):
786 # operator[] is only supported for shared_ptr<T[]>
787 return self._is_array
788
789 def __call__(self, obj, index):
790 # Check bounds if _elem_type is an array of known bound
791 m = re.match(r'.*\[(\d+)]$', str(self._elem_type))
792 if m and index >= int(m.group(1)):
793 raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
794 (self._elem_type, int(index), int(m.group(1))))
795 return SharedPtrGetWorker.__call__(self, obj)[index]
796
797
798 class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker):
799 """Implement std::shared_ptr<T>::use_count()."""
800
801 def __init__(self, elem_type):
802 pass
803
804 def get_arg_types(self):
805 return None
806
807 def get_result_type(self, obj):
808 return gdb.lookup_type('long')
809
810 def _supports(self, method_name):
811 return True
812
813 def __call__(self, obj):
814 refcounts = obj['_M_refcount']['_M_pi']
815 return refcounts['_M_use_count'] if refcounts else 0
816
817
818 class SharedPtrUniqueWorker(SharedPtrUseCountWorker):
819 """Implement std::shared_ptr<T>::unique()."""
820
821 def __init__(self, elem_type):
822 SharedPtrUseCountWorker.__init__(self, elem_type)
823
824 def get_result_type(self, obj):
825 return gdb.lookup_type('bool')
826
827 def __call__(self, obj):
828 return SharedPtrUseCountWorker.__call__(self, obj) == 1
829
830
831 class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
832 def __init__(self):
833 gdb.xmethod.XMethodMatcher.__init__(self,
834 matcher_name_prefix + 'shared_ptr')
835 self._method_dict = {
836 'get': LibStdCxxXMethod('get', SharedPtrGetWorker),
837 'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker),
838 'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker),
839 'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker),
840 'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker),
841 'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker),
842 }
843 self.methods = [self._method_dict[m] for m in self._method_dict]
844
845 def match(self, class_type, method_name):
846 if not is_specialization_of(class_type, 'shared_ptr'):
847 return None
848 method = self._method_dict.get(method_name)
849 if method is None or not method.enabled:
850 return None
851 worker = method.worker_class(class_type.template_argument(0))
852 if worker._supports(method_name):
853 return worker
854 return None
855 \f
856
857 def register_libstdcxx_xmethods(locus):
858 gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
859 gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
860 gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
861 gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
862 gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
863 gdb.xmethod.register_xmethod_matcher(
864 locus, AssociativeContainerMethodsMatcher('set'))
865 gdb.xmethod.register_xmethod_matcher(
866 locus, AssociativeContainerMethodsMatcher('map'))
867 gdb.xmethod.register_xmethod_matcher(
868 locus, AssociativeContainerMethodsMatcher('multiset'))
869 gdb.xmethod.register_xmethod_matcher(
870 locus, AssociativeContainerMethodsMatcher('multimap'))
871 gdb.xmethod.register_xmethod_matcher(
872 locus, AssociativeContainerMethodsMatcher('unordered_set'))
873 gdb.xmethod.register_xmethod_matcher(
874 locus, AssociativeContainerMethodsMatcher('unordered_map'))
875 gdb.xmethod.register_xmethod_matcher(
876 locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
877 gdb.xmethod.register_xmethod_matcher(
878 locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
879 gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())
880 gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher())
This page took 0.081472 seconds and 5 git commands to generate.