1# Xmethods for libstdc++.
2
3# Copyright (C) 2014-2016 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
24def get_bool_type():
25    return gdb.lookup_type('bool')
26
27def get_std_size_type():
28    return gdb.lookup_type('std::size_t')
29
30class 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
37class 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
46class 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
59class 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
72class 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
88class 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
104class 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
120class 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
136class 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::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
165class 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
182class 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
193class 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
203class 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
213class 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
228class 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
238class 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
253class 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::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
277class 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
285class 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
292class 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
301class 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::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
323class 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
340class 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
351class 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
364class 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
372class 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
380class 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::(__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
404class 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
428class 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
438class 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
448class 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
458class 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
468class 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
482class 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
492class 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::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
517class 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
530class 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
537class 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
544class 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::%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
567class 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        return obj['_M_t']['_M_head_impl']
589
590class UniquePtrDerefWorker(UniquePtrGetWorker):
591    "Implements std::unique_ptr<T>::operator*()"
592
593    def __init__(self, elem_type):
594        UniquePtrGetWorker.__init__(self, elem_type)
595
596    def get_result_type(self, obj):
597        return self._elem_type
598
599    def _supports(self, method_name):
600        "operator* is not supported for unique_ptr<T[]>"
601        return not self._is_array
602
603    def __call__(self, obj):
604        return UniquePtrGetWorker.__call__(self, obj).dereference()
605
606class UniquePtrSubscriptWorker(UniquePtrGetWorker):
607    "Implements std::unique_ptr<T>::operator[](size_t)"
608
609    def __init__(self, elem_type):
610        UniquePtrGetWorker.__init__(self, elem_type)
611
612    def get_arg_types(self):
613        return get_std_size_type()
614
615    def get_result_type(self, obj, index):
616        return self._elem_type
617
618    def _supports(self, method_name):
619        "operator[] is only supported for unique_ptr<T[]>"
620        return self._is_array
621
622    def __call__(self, obj, index):
623        return UniquePtrGetWorker.__call__(self, obj)[index]
624
625class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
626    def __init__(self):
627        gdb.xmethod.XMethodMatcher.__init__(self,
628                                            matcher_name_prefix + 'unique_ptr')
629        self._method_dict = {
630            'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
631            'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker),
632            'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
633            'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker),
634        }
635        self.methods = [self._method_dict[m] for m in self._method_dict]
636
637    def match(self, class_type, method_name):
638        if not re.match('^std::unique_ptr<.*>$', class_type.tag):
639            return None
640        method = self._method_dict.get(method_name)
641        if method is None or not method.enabled:
642            return None
643        worker = method.worker_class(class_type.template_argument(0))
644        if worker._supports(method_name):
645            return worker
646        return None
647
648# Xmethods for std::shared_ptr
649
650class SharedPtrGetWorker(gdb.xmethod.XMethodWorker):
651    "Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()"
652
653    def __init__(self, elem_type):
654        self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
655        if self._is_array:
656            self._elem_type = elem_type.target()
657        else:
658            self._elem_type = elem_type
659
660    def get_arg_types(self):
661        return None
662
663    def get_result_type(self, obj):
664        return self._elem_type.pointer()
665
666    def __call__(self, obj):
667        return obj['_M_ptr']
668
669class SharedPtrDerefWorker(SharedPtrGetWorker):
670    "Implements std::shared_ptr<T>::operator*()"
671
672    def __init__(self, elem_type):
673        SharedPtrGetWorker.__init__(self, elem_type)
674
675    def get_result_type(self, obj):
676        return self._elem_type
677
678    def __call__(self, obj):
679        return SharedPtrGetWorker.__call__(self, obj).dereference()
680
681class SharedPtrSubscriptWorker(SharedPtrGetWorker):
682    "Implements std::shared_ptr<T>::operator[](size_t)"
683
684    def __init__(self, elem_type):
685        SharedPtrGetWorker.__init__(self, elem_type)
686
687    def get_arg_types(self):
688        return get_std_size_type()
689
690    def get_result_type(self, obj, index):
691        return self._elem_type
692
693    def __call__(self, obj, index):
694        # Check bounds if _elem_type is an array of known bound
695        m = re.match('.*\[(\d+)]$', str(self._elem_type))
696        if m and index >= int(m.group(1)):
697            raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
698                             (self._elem_type, int(index), int(m.group(1))))
699        return SharedPtrGetWorker.__call__(self, obj)[index]
700
701class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker):
702    "Implements std::shared_ptr<T>::use_count()"
703
704    def __init__(self, elem_type):
705        SharedPtrUseCountWorker.__init__(self, elem_type)
706
707    def get_arg_types(self):
708        return None
709
710    def get_result_type(self, obj):
711        return gdb.lookup_type('long')
712
713    def __call__(self, obj):
714        refcounts = ['_M_refcount']['_M_pi']
715        return refcounts['_M_use_count'] if refcounts else 0
716
717class SharedPtrUniqueWorker(SharedPtrUseCountWorker):
718    "Implements std::shared_ptr<T>::unique()"
719
720    def __init__(self, elem_type):
721        SharedPtrUseCountWorker.__init__(self, elem_type)
722
723    def get_result_type(self, obj):
724        return gdb.lookup_type('bool')
725
726    def __call__(self, obj):
727        return SharedPtrUseCountWorker.__call__(self, obj) == 1
728
729class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
730    def __init__(self):
731        gdb.xmethod.XMethodMatcher.__init__(self,
732                                            matcher_name_prefix + 'shared_ptr')
733        self._method_dict = {
734            'get': LibStdCxxXMethod('get', SharedPtrGetWorker),
735            'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker),
736            'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker),
737            'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker),
738            'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker),
739            'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker),
740        }
741        self.methods = [self._method_dict[m] for m in self._method_dict]
742
743    def match(self, class_type, method_name):
744        if not re.match('^std::shared_ptr<.*>$', class_type.tag):
745            return None
746        method = self._method_dict.get(method_name)
747        if method is None or not method.enabled:
748            return None
749        return method.worker_class(class_type.template_argument(0))
750
751def register_libstdcxx_xmethods(locus):
752    gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
753    gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
754    gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
755    gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
756    gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
757    gdb.xmethod.register_xmethod_matcher(
758        locus, AssociativeContainerMethodsMatcher('set'))
759    gdb.xmethod.register_xmethod_matcher(
760        locus, AssociativeContainerMethodsMatcher('map'))
761    gdb.xmethod.register_xmethod_matcher(
762        locus, AssociativeContainerMethodsMatcher('multiset'))
763    gdb.xmethod.register_xmethod_matcher(
764        locus, AssociativeContainerMethodsMatcher('multimap'))
765    gdb.xmethod.register_xmethod_matcher(
766        locus, AssociativeContainerMethodsMatcher('unordered_set'))
767    gdb.xmethod.register_xmethod_matcher(
768        locus, AssociativeContainerMethodsMatcher('unordered_map'))
769    gdb.xmethod.register_xmethod_matcher(
770        locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
771    gdb.xmethod.register_xmethod_matcher(
772        locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
773    gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())
774    gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher())
775