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