]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/python/libstdcxx/v6/xmethods.py
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / python / libstdcxx / v6 / xmethods.py
1 # Xmethods for libstdc++.
2
3 # Copyright (C) 2014-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
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::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, index):
178 first_node = obj['_M_impl']['_M_start']['_M_node']
179 index_node = first_node + index / self._bufsize
180 return index_node[0][index % 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::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::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 class 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
342 class 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
355 class 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
363 class 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
371 class 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::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
395 class 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
419 class 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
429 class 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
439 class 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
449 class 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
459 class 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
473 class 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
483 class 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
508 class 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
521 class 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
528 class 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
535 class 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
558 class 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
571 class 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
581 class 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->', UniquePtrGetWorker),
588 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
589 }
590 self.methods = [self._method_dict[m] for m in self._method_dict]
591
592 def match(self, class_type, method_name):
593 if not re.match('^std::unique_ptr<.*>$', class_type.tag):
594 return None
595 method = self._method_dict.get(method_name)
596 if method is None or not method.enabled:
597 return None
598 return method.worker_class(class_type.template_argument(0))
599 \f
600 def register_libstdcxx_xmethods(locus):
601 gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
602 gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
603 gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
604 gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
605 gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
606 gdb.xmethod.register_xmethod_matcher(
607 locus, AssociativeContainerMethodsMatcher('set'))
608 gdb.xmethod.register_xmethod_matcher(
609 locus, AssociativeContainerMethodsMatcher('map'))
610 gdb.xmethod.register_xmethod_matcher(
611 locus, AssociativeContainerMethodsMatcher('multiset'))
612 gdb.xmethod.register_xmethod_matcher(
613 locus, AssociativeContainerMethodsMatcher('multimap'))
614 gdb.xmethod.register_xmethod_matcher(
615 locus, AssociativeContainerMethodsMatcher('unordered_set'))
616 gdb.xmethod.register_xmethod_matcher(
617 locus, AssociativeContainerMethodsMatcher('unordered_map'))
618 gdb.xmethod.register_xmethod_matcher(
619 locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
620 gdb.xmethod.register_xmethod_matcher(
621 locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
622 gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())