xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/python/libstdcxx/v6/xmethods.py (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
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
18import gdb
19import gdb.xmethod
20import re
21
22matcher_name_prefix = 'libstdc++::'
23
24
25def get_bool_type():
26    return gdb.lookup_type('bool')
27
28def get_std_size_type():
29    return gdb.lookup_type('std::size_t')
30
31_versioned_namespace = '__8::'
32
33def 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
45class 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
53class 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
63class 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
77class 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
91class 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
108class 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
125class 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
142class 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
159class 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
190class 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
215class 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
227class 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
238class 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
249class 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
265class 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
276class 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
292class 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
317class 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
326class 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
334class 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
344class 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
367class 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
385class 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
397class 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
411class 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
420class 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
429class 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
454class 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
479class 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
490class 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
501class 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
512class 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
523class 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
538class 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
549class 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
575class 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
589class 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
597class 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
605class 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
629class 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
671class 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
688class 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
708class 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
734class 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
760class 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
777class 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
802class 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
822class 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
835class 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
860
861def 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())
885