xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/python/libstdcxx/v6/xmethods.py (revision c9496f6b604074a9451a67df576a5b423068e71e)
1# Xmethods for libstdc++.
2
3# Copyright (C) 2014-2015 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
331class ListEmptyWorker(ListWorkerBase):
332    def get_result_type(self, obj):
333        return get_bool_type()
334
335    def __call__(self, obj):
336        base_node = obj['_M_impl']['_M_node']
337        if base_node['_M_next'] == base_node.address:
338            return True
339        else:
340            return False
341
342class ListSizeWorker(ListWorkerBase):
343    def get_result_type(self, obj):
344        return get_std_size_type()
345
346    def __call__(self, obj):
347        begin_node = obj['_M_impl']['_M_node']['_M_next']
348        end_node = obj['_M_impl']['_M_node'].address
349        size = 0
350        while begin_node != end_node:
351            begin_node = begin_node['_M_next']
352            size += 1
353        return size
354
355class ListFrontWorker(ListWorkerBase):
356    def get_result_type(self, obj):
357        return self._val_type
358
359    def __call__(self, obj):
360        node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
361        return node['_M_data']
362
363class ListBackWorker(ListWorkerBase):
364    def get_result_type(self, obj):
365        return self._val_type
366
367    def __call__(self, obj):
368        prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
369        return prev_node['_M_data']
370
371class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
372    def __init__(self):
373        gdb.xmethod.XMethodMatcher.__init__(self,
374                                            matcher_name_prefix + 'list')
375        self._method_dict = {
376            'empty': LibStdCxxXMethod('empty', ListEmptyWorker),
377            'size': LibStdCxxXMethod('size', ListSizeWorker),
378            'front': LibStdCxxXMethod('front', ListFrontWorker),
379            'back': LibStdCxxXMethod('back', ListBackWorker)
380        }
381        self.methods = [self._method_dict[m] for m in self._method_dict]
382
383    def match(self, class_type, method_name):
384        if not re.match('^std::(__cxx11::)?list<.*>$', class_type.tag):
385            return None
386        method = self._method_dict.get(method_name)
387        if method is None or not method.enabled:
388            return None
389        val_type = class_type.template_argument(0)
390        node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
391        return method.worker_class(val_type, node_type)
392
393# Xmethods for std::vector
394
395class VectorWorkerBase(gdb.xmethod.XMethodWorker):
396    def __init__(self, val_type):
397        self._val_type = val_type
398
399    def size(self, obj):
400        if self._val_type.code == gdb.TYPE_CODE_BOOL:
401            start = obj['_M_impl']['_M_start']['_M_p']
402            finish = obj['_M_impl']['_M_finish']['_M_p']
403            finish_offset = obj['_M_impl']['_M_finish']['_M_offset']
404            bit_size = start.dereference().type.sizeof * 8
405            return (finish - start) * bit_size + finish_offset
406        else:
407            return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start']
408
409    def get(self, obj, index):
410        if self._val_type.code == gdb.TYPE_CODE_BOOL:
411            start = obj['_M_impl']['_M_start']['_M_p']
412            bit_size = start.dereference().type.sizeof * 8
413            valp = start + index // bit_size
414            offset = index % bit_size
415            return (valp.dereference() & (1 << offset)) > 0
416        else:
417            return obj['_M_impl']['_M_start'][index]
418
419class VectorEmptyWorker(VectorWorkerBase):
420    def get_arg_types(self):
421        return None
422
423    def get_result_type(self, obj):
424        return get_bool_type()
425
426    def __call__(self, obj):
427        return int(self.size(obj)) == 0
428
429class VectorSizeWorker(VectorWorkerBase):
430    def get_arg_types(self):
431        return None
432
433    def get_result_type(self, obj):
434        return get_std_size_type()
435
436    def __call__(self, obj):
437        return self.size(obj)
438
439class VectorFrontWorker(VectorWorkerBase):
440    def get_arg_types(self):
441        return None
442
443    def get_result_type(self, obj):
444        return self._val_type
445
446    def __call__(self, obj):
447        return self.get(obj, 0)
448
449class VectorBackWorker(VectorWorkerBase):
450    def get_arg_types(self):
451        return None
452
453    def get_result_type(self, obj):
454        return self._val_type
455
456    def __call__(self, obj):
457        return self.get(obj, int(self.size(obj)) - 1)
458
459class VectorAtWorker(VectorWorkerBase):
460    def get_arg_types(self):
461        return get_std_size_type()
462
463    def get_result_type(self, obj, index):
464        return self._val_type
465
466    def __call__(self, obj, index):
467        size = int(self.size(obj))
468        if int(index) >= size:
469            raise IndexError('Vector index "%d" should not be >= %d.' %
470                             ((int(index), size)))
471        return self.get(obj, int(index))
472
473class VectorSubscriptWorker(VectorWorkerBase):
474    def get_arg_types(self):
475        return get_std_size_type()
476
477    def get_result_type(self, obj, subscript):
478        return self._val_type
479
480    def __call__(self, obj, subscript):
481        return self.get(obj, int(subscript))
482
483class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
484    def __init__(self):
485        gdb.xmethod.XMethodMatcher.__init__(self,
486                                            matcher_name_prefix + 'vector')
487        self._method_dict = {
488            'size': LibStdCxxXMethod('size', VectorSizeWorker),
489            'empty': LibStdCxxXMethod('empty', VectorEmptyWorker),
490            'front': LibStdCxxXMethod('front', VectorFrontWorker),
491            'back': LibStdCxxXMethod('back', VectorBackWorker),
492            'at': LibStdCxxXMethod('at', VectorAtWorker),
493            'operator[]': LibStdCxxXMethod('operator[]',
494                                           VectorSubscriptWorker),
495        }
496        self.methods = [self._method_dict[m] for m in self._method_dict]
497
498    def match(self, class_type, method_name):
499        if not re.match('^std::vector<.*>$', class_type.tag):
500            return None
501        method = self._method_dict.get(method_name)
502        if method is None or not method.enabled:
503            return None
504        return method.worker_class(class_type.template_argument(0))
505
506# Xmethods for associative containers
507
508class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
509    def __init__(self, unordered):
510        self._unordered = unordered
511
512    def node_count(self, obj):
513        if self._unordered:
514            return obj['_M_h']['_M_element_count']
515        else:
516            return obj['_M_t']['_M_impl']['_M_node_count']
517
518    def get_arg_types(self):
519        return None
520
521class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
522    def get_result_type(self, obj):
523        return get_bool_type()
524
525    def __call__(self, obj):
526        return int(self.node_count(obj)) == 0
527
528class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
529    def get_result_type(self, obj):
530        return get_std_size_type()
531
532    def __call__(self, obj):
533        return self.node_count(obj)
534
535class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
536    def __init__(self, name):
537        gdb.xmethod.XMethodMatcher.__init__(self,
538                                            matcher_name_prefix + name)
539        self._name = name
540        self._method_dict = {
541            'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker),
542            'empty': LibStdCxxXMethod('empty',
543                                      AssociativeContainerEmptyWorker),
544        }
545        self.methods = [self._method_dict[m] for m in self._method_dict]
546
547    def match(self, class_type, method_name):
548        if not re.match('^std::%s<.*>$' % self._name, class_type.tag):
549            return None
550        method = self._method_dict.get(method_name)
551        if method is None or not method.enabled:
552            return None
553        unordered = 'unordered' in self._name
554        return method.worker_class(unordered)
555
556# Xmethods for std::unique_ptr
557
558class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
559    def __init__(self, elem_type):
560        self._elem_type = elem_type
561
562    def get_arg_types(self):
563        return None
564
565    def get_result_type(self, obj):
566        return self._elem_type.pointer()
567
568    def __call__(self, obj):
569        return obj['_M_t']['_M_head_impl']
570
571class UniquePtrDerefWorker(UniquePtrGetWorker):
572    def __init__(self, elem_type):
573        UniquePtrGetWorker.__init__(self, elem_type)
574
575    def get_result_type(self, obj):
576        return self._elem_type
577
578    def __call__(self, obj):
579        return UniquePtrGetWorker.__call__(self, obj).dereference()
580
581class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
582    def __init__(self):
583        gdb.xmethod.XMethodMatcher.__init__(self,
584                                            matcher_name_prefix + 'unique_ptr')
585        self._method_dict = {
586            'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
587            'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
588        }
589        self.methods = [self._method_dict[m] for m in self._method_dict]
590
591    def match(self, class_type, method_name):
592        if not re.match('^std::unique_ptr<.*>$', class_type.tag):
593            return None
594        method = self._method_dict.get(method_name)
595        if method is None or not method.enabled:
596            return None
597        return method.worker_class(class_type.template_argument(0))
598
599def register_libstdcxx_xmethods(locus):
600    gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
601    gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
602    gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
603    gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
604    gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
605    gdb.xmethod.register_xmethod_matcher(
606        locus, AssociativeContainerMethodsMatcher('set'))
607    gdb.xmethod.register_xmethod_matcher(
608        locus, AssociativeContainerMethodsMatcher('map'))
609    gdb.xmethod.register_xmethod_matcher(
610        locus, AssociativeContainerMethodsMatcher('multiset'))
611    gdb.xmethod.register_xmethod_matcher(
612        locus, AssociativeContainerMethodsMatcher('multimap'))
613    gdb.xmethod.register_xmethod_matcher(
614        locus, AssociativeContainerMethodsMatcher('unordered_set'))
615    gdb.xmethod.register_xmethod_matcher(
616        locus, AssociativeContainerMethodsMatcher('unordered_map'))
617    gdb.xmethod.register_xmethod_matcher(
618        locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
619    gdb.xmethod.register_xmethod_matcher(
620        locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
621    gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())
622