1 # Xmethods for libstdc++.
3 # Copyright (C) 2014-2016 Free Software Foundation, Inc.
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.
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.
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/>.
22 matcher_name_prefix
= 'libstdc++::'
25 return gdb
.lookup_type('bool')
27 def get_std_size_type():
28 return gdb
.lookup_type('std::size_t')
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
35 # Xmethods for std::array
37 class ArrayWorkerBase(gdb
.xmethod
.XMethodWorker
):
38 def __init__(self
, val_type
, size
):
39 self
._val
_type
= val_type
43 nullptr
= gdb
.parse_and_eval('(void *) 0')
44 return nullptr
.cast(self
._val
_type
.pointer()).dereference()
46 class ArraySizeWorker(ArrayWorkerBase
):
47 def __init__(self
, val_type
, size
):
48 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
50 def get_arg_types(self
):
53 def get_result_type(self
, obj
):
54 return get_std_size_type()
56 def __call__(self
, obj
):
59 class ArrayEmptyWorker(ArrayWorkerBase
):
60 def __init__(self
, val_type
, size
):
61 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
63 def get_arg_types(self
):
66 def get_result_type(self
, obj
):
67 return get_bool_type()
69 def __call__(self
, obj
):
70 return (int(self
._size
) == 0)
72 class ArrayFrontWorker(ArrayWorkerBase
):
73 def __init__(self
, val_type
, size
):
74 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
76 def get_arg_types(self
):
79 def get_result_type(self
, obj
):
82 def __call__(self
, obj
):
83 if int(self
._size
) > 0:
84 return obj
['_M_elems'][0]
86 return self
.null_value()
88 class ArrayBackWorker(ArrayWorkerBase
):
89 def __init__(self
, val_type
, size
):
90 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
92 def get_arg_types(self
):
95 def get_result_type(self
, obj
):
98 def __call__(self
, obj
):
99 if int(self
._size
) > 0:
100 return obj
['_M_elems'][self
._size
- 1]
102 return self
.null_value()
104 class ArrayAtWorker(ArrayWorkerBase
):
105 def __init__(self
, val_type
, size
):
106 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
108 def get_arg_types(self
):
109 return get_std_size_type()
111 def get_result_type(self
, obj
, index
):
112 return self
._val
_type
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
]
120 class ArraySubscriptWorker(ArrayWorkerBase
):
121 def __init__(self
, val_type
, size
):
122 ArrayWorkerBase
.__init
__(self
, val_type
, size
)
124 def get_arg_types(self
):
125 return get_std_size_type()
127 def get_result_type(self
, obj
, index
):
128 return self
._val
_type
130 def __call__(self
, obj
, index
):
131 if int(self
._size
) > 0:
132 return obj
['_M_elems'][index
]
134 return self
.null_value()
136 class ArrayMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
148 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
150 def match(self
, class_type
, method_name
):
151 if not re
.match('^std::array<.*>$', class_type
.tag
):
153 method
= self
._method
_dict
.get(method_name
)
154 if method
is None or not method
.enabled
:
157 value_type
= class_type
.template_argument(0)
158 size
= class_type
.template_argument(1)
161 return method
.worker_class(value_type
, size
)
163 # Xmethods for std::deque
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
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
)
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
]
182 class DequeEmptyWorker(DequeWorkerBase
):
183 def get_arg_types(self
):
186 def get_result_type(self
, obj
):
187 return get_bool_type()
189 def __call__(self
, obj
):
190 return (obj
['_M_impl']['_M_start']['_M_cur'] ==
191 obj
['_M_impl']['_M_finish']['_M_cur'])
193 class DequeSizeWorker(DequeWorkerBase
):
194 def get_arg_types(self
):
197 def get_result_type(self
, obj
):
198 return get_std_size_type()
200 def __call__(self
, obj
):
201 return self
.size(obj
)
203 class DequeFrontWorker(DequeWorkerBase
):
204 def get_arg_types(self
):
207 def get_result_type(self
, obj
):
208 return self
._val
_type
210 def __call__(self
, obj
):
211 return obj
['_M_impl']['_M_start']['_M_cur'][0]
213 class DequeBackWorker(DequeWorkerBase
):
214 def get_arg_types(self
):
217 def get_result_type(self
, obj
):
218 return self
._val
_type
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]
226 return obj
['_M_impl']['_M_finish']['_M_cur'][-1]
228 class DequeSubscriptWorker(DequeWorkerBase
):
229 def get_arg_types(self
):
230 return get_std_size_type()
232 def get_result_type(self
, obj
, subscript
):
233 return self
._val
_type
235 def __call__(self
, obj
, subscript
):
236 return self
.index(obj
, subscript
)
238 class DequeAtWorker(DequeWorkerBase
):
239 def get_arg_types(self
):
240 return get_std_size_type()
242 def get_result_type(self
, obj
, index
):
243 return self
._val
_type
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
))
251 return self
.index(obj
, index
)
253 class DequeMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
)
265 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
267 def match(self
, class_type
, method_name
):
268 if not re
.match('^std::deque<.*>$', class_type
.tag
):
270 method
= self
._method
_dict
.get(method_name
)
271 if method
is None or not method
.enabled
:
273 return method
.worker_class(class_type
.template_argument(0))
275 # Xmethods for std::forward_list
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
282 def get_arg_types(self
):
285 class ForwardListEmptyWorker(ForwardListWorkerBase
):
286 def get_result_type(self
, obj
):
287 return get_bool_type()
289 def __call__(self
, obj
):
290 return obj
['_M_impl']['_M_head']['_M_next'] == 0
292 class ForwardListFrontWorker(ForwardListWorkerBase
):
293 def get_result_type(self
, obj
):
294 return self
._val
_type
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()
301 class ForwardListMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
)
309 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
311 def match(self
, class_type
, method_name
):
312 if not re
.match('^std::forward_list<.*>$', class_type
.tag
):
314 method
= self
._method
_dict
.get(method_name
)
315 if method
is None or not method
.enabled
:
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
)
321 # Xmethods for std::list
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
328 def get_arg_types(self
):
331 class ListEmptyWorker(ListWorkerBase
):
332 def get_result_type(self
, obj
):
333 return get_bool_type()
335 def __call__(self
, obj
):
336 base_node
= obj
['_M_impl']['_M_node']
337 if base_node
['_M_next'] == base_node
.address
:
342 class ListSizeWorker(ListWorkerBase
):
343 def get_result_type(self
, obj
):
344 return get_std_size_type()
346 def __call__(self
, obj
):
347 begin_node
= obj
['_M_impl']['_M_node']['_M_next']
348 end_node
= obj
['_M_impl']['_M_node'].address
350 while begin_node
!= end_node
:
351 begin_node
= begin_node
['_M_next']
355 class ListFrontWorker(ListWorkerBase
):
356 def get_result_type(self
, obj
):
357 return self
._val
_type
359 def __call__(self
, obj
):
360 node
= obj
['_M_impl']['_M_node']['_M_next'].cast(self
._node
_type
)
361 return node
['_M_data']
363 class ListBackWorker(ListWorkerBase
):
364 def get_result_type(self
, obj
):
365 return self
._val
_type
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']
371 class ListMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
)
381 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
383 def match(self
, class_type
, method_name
):
384 if not re
.match('^std::list<.*>$', class_type
.tag
):
386 method
= self
._method
_dict
.get(method_name
)
387 if method
is None or not method
.enabled
:
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
)
393 # Xmethods for std::vector
395 class VectorWorkerBase(gdb
.xmethod
.XMethodWorker
):
396 def __init__(self
, val_type
):
397 self
._val
_type
= val_type
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
407 return obj
['_M_impl']['_M_finish'] - obj
['_M_impl']['_M_start']
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
417 return obj
['_M_impl']['_M_start'][index
]
419 class VectorEmptyWorker(VectorWorkerBase
):
420 def get_arg_types(self
):
423 def get_result_type(self
, obj
):
424 return get_bool_type()
426 def __call__(self
, obj
):
427 return int(self
.size(obj
)) == 0
429 class VectorSizeWorker(VectorWorkerBase
):
430 def get_arg_types(self
):
433 def get_result_type(self
, obj
):
434 return get_std_size_type()
436 def __call__(self
, obj
):
437 return self
.size(obj
)
439 class VectorFrontWorker(VectorWorkerBase
):
440 def get_arg_types(self
):
443 def get_result_type(self
, obj
):
444 return self
._val
_type
446 def __call__(self
, obj
):
447 return self
.get(obj
, 0)
449 class VectorBackWorker(VectorWorkerBase
):
450 def get_arg_types(self
):
453 def get_result_type(self
, obj
):
454 return self
._val
_type
456 def __call__(self
, obj
):
457 return self
.get(obj
, int(self
.size(obj
)) - 1)
459 class VectorAtWorker(VectorWorkerBase
):
460 def get_arg_types(self
):
461 return get_std_size_type()
463 def get_result_type(self
, obj
, index
):
464 return self
._val
_type
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
))
473 class VectorSubscriptWorker(VectorWorkerBase
):
474 def get_arg_types(self
):
475 return get_std_size_type()
477 def get_result_type(self
, obj
, subscript
):
478 return self
._val
_type
480 def __call__(self
, obj
, subscript
):
481 return self
.get(obj
, int(subscript
))
483 class VectorMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
496 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
498 def match(self
, class_type
, method_name
):
499 if not re
.match('^std::vector<.*>$', class_type
.tag
):
501 method
= self
._method
_dict
.get(method_name
)
502 if method
is None or not method
.enabled
:
504 return method
.worker_class(class_type
.template_argument(0))
506 # Xmethods for associative containers
508 class AssociativeContainerWorkerBase(gdb
.xmethod
.XMethodWorker
):
509 def __init__(self
, unordered
):
510 self
._unordered
= unordered
512 def node_count(self
, obj
):
514 return obj
['_M_h']['_M_element_count']
516 return obj
['_M_t']['_M_impl']['_M_node_count']
518 def get_arg_types(self
):
521 class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase
):
522 def get_result_type(self
, obj
):
523 return get_bool_type()
525 def __call__(self
, obj
):
526 return int(self
.node_count(obj
)) == 0
528 class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase
):
529 def get_result_type(self
, obj
):
530 return get_std_size_type()
532 def __call__(self
, obj
):
533 return self
.node_count(obj
)
535 class AssociativeContainerMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
536 def __init__(self
, name
):
537 gdb
.xmethod
.XMethodMatcher
.__init
__(self
,
538 matcher_name_prefix
+ name
)
540 self
._method
_dict
= {
541 'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker
),
542 'empty': LibStdCxxXMethod('empty',
543 AssociativeContainerEmptyWorker
),
545 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
547 def match(self
, class_type
, method_name
):
548 if not re
.match('^std::%s<.*>$' % self
._name
, class_type
.tag
):
550 method
= self
._method
_dict
.get(method_name
)
551 if method
is None or not method
.enabled
:
553 unordered
= 'unordered' in self
._name
554 return method
.worker_class(unordered
)
556 # Xmethods for std::unique_ptr
558 class UniquePtrGetWorker(gdb
.xmethod
.XMethodWorker
):
559 def __init__(self
, elem_type
):
560 self
._elem
_type
= elem_type
562 def get_arg_types(self
):
565 def get_result_type(self
, obj
):
566 return self
._elem
_type
.pointer()
568 def __call__(self
, obj
):
569 return obj
['_M_t']['_M_head_impl']
571 class UniquePtrDerefWorker(UniquePtrGetWorker
):
572 def __init__(self
, elem_type
):
573 UniquePtrGetWorker
.__init
__(self
, elem_type
)
575 def get_result_type(self
, obj
):
576 return self
._elem
_type
578 def __call__(self
, obj
):
579 return UniquePtrGetWorker
.__call
__(self
, obj
).dereference()
581 class UniquePtrMethodsMatcher(gdb
.xmethod
.XMethodMatcher
):
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
),
590 self
.methods
= [self
._method
_dict
[m
] for m
in self
._method
_dict
]
592 def match(self
, class_type
, method_name
):
593 if not re
.match('^std::unique_ptr<.*>$', class_type
.tag
):
595 method
= self
._method
_dict
.get(method_name
)
596 if method
is None or not method
.enabled
:
598 return method
.worker_class(class_type
.template_argument(0))
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())