cpp-d1064d
[cross.git] / i686-linux-gnu-4.7 / usr / share / gcc-8 / python / libstdcxx / v6 / xmethods.py
1 # Xmethods for libstdc++.
2
3 # Copyright (C) 2014-2018 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         if re.match('^std::(__\d+::)?__uniq_ptr_impl<.*>$', impl_type): # New implementation
590             return obj['_M_t']['_M_t']['_M_head_impl']
591         elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type):
592             return obj['_M_t']['_M_head_impl']
593         return None
594
595 class UniquePtrDerefWorker(UniquePtrGetWorker):
596     "Implements std::unique_ptr<T>::operator*()"
597
598     def __init__(self, elem_type):
599         UniquePtrGetWorker.__init__(self, elem_type)
600
601     def get_result_type(self, obj):
602         return self._elem_type
603
604     def _supports(self, method_name):
605         "operator* is not supported for unique_ptr<T[]>"
606         return not self._is_array
607
608     def __call__(self, obj):
609         return UniquePtrGetWorker.__call__(self, obj).dereference()
610
611 class UniquePtrSubscriptWorker(UniquePtrGetWorker):
612     "Implements std::unique_ptr<T>::operator[](size_t)"
613
614     def __init__(self, elem_type):
615         UniquePtrGetWorker.__init__(self, elem_type)
616
617     def get_arg_types(self):
618         return get_std_size_type()
619
620     def get_result_type(self, obj, index):
621         return self._elem_type
622
623     def _supports(self, method_name):
624         "operator[] is only supported for unique_ptr<T[]>"
625         return self._is_array
626
627     def __call__(self, obj, index):
628         return UniquePtrGetWorker.__call__(self, obj)[index]
629
630 class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
631     def __init__(self):
632         gdb.xmethod.XMethodMatcher.__init__(self,
633                                             matcher_name_prefix + 'unique_ptr')
634         self._method_dict = {
635             'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
636             'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker),
637             'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
638             'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker),
639         }
640         self.methods = [self._method_dict[m] for m in self._method_dict]
641
642     def match(self, class_type, method_name):
643         if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag):
644             return None
645         method = self._method_dict.get(method_name)
646         if method is None or not method.enabled:
647             return None
648         worker = method.worker_class(class_type.template_argument(0))
649         if worker._supports(method_name):
650             return worker
651         return None
652
653 # Xmethods for std::shared_ptr
654
655 class SharedPtrGetWorker(gdb.xmethod.XMethodWorker):
656     "Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()"
657
658     def __init__(self, elem_type):
659         self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
660         if self._is_array:
661             self._elem_type = elem_type.target()
662         else:
663             self._elem_type = elem_type
664
665     def get_arg_types(self):
666         return None
667
668     def get_result_type(self, obj):
669         return self._elem_type.pointer()
670
671     def _supports(self, method_name):
672         "operator-> is not supported for shared_ptr<T[]>"
673         return method_name == 'get' or not self._is_array
674
675     def __call__(self, obj):
676         return obj['_M_ptr']
677
678 class SharedPtrDerefWorker(SharedPtrGetWorker):
679     "Implements std::shared_ptr<T>::operator*()"
680
681     def __init__(self, elem_type):
682         SharedPtrGetWorker.__init__(self, elem_type)
683
684     def get_result_type(self, obj):
685         return self._elem_type
686
687     def _supports(self, method_name):
688         "operator* is not supported for shared_ptr<T[]>"
689         return not self._is_array
690
691     def __call__(self, obj):
692         return SharedPtrGetWorker.__call__(self, obj).dereference()
693
694 class SharedPtrSubscriptWorker(SharedPtrGetWorker):
695     "Implements std::shared_ptr<T>::operator[](size_t)"
696
697     def __init__(self, elem_type):
698         SharedPtrGetWorker.__init__(self, elem_type)
699
700     def get_arg_types(self):
701         return get_std_size_type()
702
703     def get_result_type(self, obj, index):
704         return self._elem_type
705
706     def _supports(self, method_name):
707         "operator[] is only supported for shared_ptr<T[]>"
708         return self._is_array
709
710     def __call__(self, obj, index):
711         # Check bounds if _elem_type is an array of known bound
712         m = re.match('.*\[(\d+)]$', str(self._elem_type))
713         if m and index >= int(m.group(1)):
714             raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
715                              (self._elem_type, int(index), int(m.group(1))))
716         return SharedPtrGetWorker.__call__(self, obj)[index]
717
718 class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker):
719     "Implements std::shared_ptr<T>::use_count()"
720
721     def __init__(self, elem_type):
722         SharedPtrUseCountWorker.__init__(self, elem_type)
723
724     def get_arg_types(self):
725         return None
726
727     def get_result_type(self, obj):
728         return gdb.lookup_type('long')
729
730     def __call__(self, obj):
731         refcounts = ['_M_refcount']['_M_pi']
732         return refcounts['_M_use_count'] if refcounts else 0
733
734 class SharedPtrUniqueWorker(SharedPtrUseCountWorker):
735     "Implements std::shared_ptr<T>::unique()"
736
737     def __init__(self, elem_type):
738         SharedPtrUseCountWorker.__init__(self, elem_type)
739
740     def get_result_type(self, obj):
741         return gdb.lookup_type('bool')
742
743     def __call__(self, obj):
744         return SharedPtrUseCountWorker.__call__(self, obj) == 1
745
746 class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
747     def __init__(self):
748         gdb.xmethod.XMethodMatcher.__init__(self,
749                                             matcher_name_prefix + 'shared_ptr')
750         self._method_dict = {
751             'get': LibStdCxxXMethod('get', SharedPtrGetWorker),
752             'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker),
753             'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker),
754             'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker),
755             'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker),
756             'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker),
757         }
758         self.methods = [self._method_dict[m] for m in self._method_dict]
759
760     def match(self, class_type, method_name):
761         if not re.match('^std::(__\d+::)?shared_ptr<.*>$', class_type.tag):
762             return None
763         method = self._method_dict.get(method_name)
764         if method is None or not method.enabled:
765             return None
766         worker = method.worker_class(class_type.template_argument(0))
767         if worker._supports(method_name):
768             return worker
769         return None
770 \f
771 def register_libstdcxx_xmethods(locus):
772     gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
773     gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
774     gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
775     gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
776     gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
777     gdb.xmethod.register_xmethod_matcher(
778         locus, AssociativeContainerMethodsMatcher('set'))
779     gdb.xmethod.register_xmethod_matcher(
780         locus, AssociativeContainerMethodsMatcher('map'))
781     gdb.xmethod.register_xmethod_matcher(
782         locus, AssociativeContainerMethodsMatcher('multiset'))
783     gdb.xmethod.register_xmethod_matcher(
784         locus, AssociativeContainerMethodsMatcher('multimap'))
785     gdb.xmethod.register_xmethod_matcher(
786         locus, AssociativeContainerMethodsMatcher('unordered_set'))
787     gdb.xmethod.register_xmethod_matcher(
788         locus, AssociativeContainerMethodsMatcher('unordered_map'))
789     gdb.xmethod.register_xmethod_matcher(
790         locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
791     gdb.xmethod.register_xmethod_matcher(
792         locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
793     gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())
794     gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher())