]>
Commit | Line | Data |
---|---|---|
e96d4167 | 1 | # Xmethods for libstdc++. |
3ef8d391 | 2 | |
fbd26352 | 3 | # Copyright (C) 2014-2019 Free Software Foundation, Inc. |
3ef8d391 | 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 | ||
d3a75429 | 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 | ||
e96d4167 | 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): | |
c8b1b26c | 38 | def __init__(self, val_type, size): |
39 | self._val_type = val_type | |
e96d4167 | 40 | self._size = size |
41 | ||
42 | def null_value(self): | |
43 | nullptr = gdb.parse_and_eval('(void *) 0') | |
c8b1b26c | 44 | return nullptr.cast(self._val_type.pointer()).dereference() |
e96d4167 | 45 | |
46 | class ArraySizeWorker(ArrayWorkerBase): | |
c8b1b26c | 47 | def __init__(self, val_type, size): |
48 | ArrayWorkerBase.__init__(self, val_type, size) | |
e96d4167 | 49 | |
50 | def get_arg_types(self): | |
51 | return None | |
52 | ||
d3a75429 | 53 | def get_result_type(self, obj): |
54 | return get_std_size_type() | |
55 | ||
e96d4167 | 56 | def __call__(self, obj): |
57 | return self._size | |
58 | ||
59 | class ArrayEmptyWorker(ArrayWorkerBase): | |
c8b1b26c | 60 | def __init__(self, val_type, size): |
61 | ArrayWorkerBase.__init__(self, val_type, size) | |
e96d4167 | 62 | |
63 | def get_arg_types(self): | |
64 | return None | |
65 | ||
d3a75429 | 66 | def get_result_type(self, obj): |
67 | return get_bool_type() | |
68 | ||
e96d4167 | 69 | def __call__(self, obj): |
70 | return (int(self._size) == 0) | |
71 | ||
72 | class ArrayFrontWorker(ArrayWorkerBase): | |
c8b1b26c | 73 | def __init__(self, val_type, size): |
74 | ArrayWorkerBase.__init__(self, val_type, size) | |
e96d4167 | 75 | |
76 | def get_arg_types(self): | |
77 | return None | |
78 | ||
d3a75429 | 79 | def get_result_type(self, obj): |
80 | return self._val_type | |
81 | ||
e96d4167 | 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): | |
c8b1b26c | 89 | def __init__(self, val_type, size): |
90 | ArrayWorkerBase.__init__(self, val_type, size) | |
e96d4167 | 91 | |
92 | def get_arg_types(self): | |
93 | return None | |
94 | ||
d3a75429 | 95 | def get_result_type(self, obj): |
96 | return self._val_type | |
97 | ||
e96d4167 | 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): | |
c8b1b26c | 105 | def __init__(self, val_type, size): |
106 | ArrayWorkerBase.__init__(self, val_type, size) | |
e96d4167 | 107 | |
108 | def get_arg_types(self): | |
d3a75429 | 109 | return get_std_size_type() |
110 | ||
111 | def get_result_type(self, obj, index): | |
112 | return self._val_type | |
e96d4167 | 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): | |
c8b1b26c | 121 | def __init__(self, val_type, size): |
122 | ArrayWorkerBase.__init__(self, val_type, size) | |
e96d4167 | 123 | |
124 | def get_arg_types(self): | |
d3a75429 | 125 | return get_std_size_type() |
126 | ||
127 | def get_result_type(self, obj, index): | |
128 | return self._val_type | |
e96d4167 | 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() | |
3ef8d391 | 135 | |
e96d4167 | 136 | class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher): |
3ef8d391 | 137 | def __init__(self): |
e96d4167 | 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): | |
d813c3cd | 151 | if not re.match('^std::(__\d+::)?array<.*>$', class_type.tag): |
e96d4167 | 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): | |
c8b1b26c | 166 | def __init__(self, val_type): |
d3a75429 | 167 | self._val_type = val_type |
50c1af91 | 168 | self._bufsize = 512 // val_type.sizeof or 1 |
e96d4167 | 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 | ||
8c77b933 | 177 | def index(self, obj, idx): |
e96d4167 | 178 | first_node = obj['_M_impl']['_M_start']['_M_node'] |
50c1af91 | 179 | index_node = first_node + int(idx) // self._bufsize |
8c77b933 | 180 | return index_node[0][idx % self._bufsize] |
e96d4167 | 181 | |
182 | class DequeEmptyWorker(DequeWorkerBase): | |
183 | def get_arg_types(self): | |
184 | return None | |
185 | ||
d3a75429 | 186 | def get_result_type(self, obj): |
187 | return get_bool_type() | |
188 | ||
e96d4167 | 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 | ||
d3a75429 | 197 | def get_result_type(self, obj): |
198 | return get_std_size_type() | |
199 | ||
e96d4167 | 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 | ||
d3a75429 | 207 | def get_result_type(self, obj): |
208 | return self._val_type | |
209 | ||
e96d4167 | 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 | ||
d3a75429 | 217 | def get_result_type(self, obj): |
218 | return self._val_type | |
219 | ||
e96d4167 | 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): | |
d3a75429 | 230 | return get_std_size_type() |
231 | ||
232 | def get_result_type(self, obj, subscript): | |
233 | return self._val_type | |
e96d4167 | 234 | |
235 | def __call__(self, obj, subscript): | |
236 | return self.index(obj, subscript) | |
237 | ||
238 | class DequeAtWorker(DequeWorkerBase): | |
239 | def get_arg_types(self): | |
d3a75429 | 240 | return get_std_size_type() |
241 | ||
242 | def get_result_type(self, obj, index): | |
243 | return self._val_type | |
e96d4167 | 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): | |
d813c3cd | 268 | if not re.match('^std::(__\d+::)?deque<.*>$', class_type.tag): |
e96d4167 | 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): | |
c8b1b26c | 278 | def __init__(self, val_type, node_type): |
279 | self._val_type = val_type | |
e96d4167 | 280 | self._node_type = node_type |
3ef8d391 | 281 | |
282 | def get_arg_types(self): | |
283 | return None | |
284 | ||
e96d4167 | 285 | class ForwardListEmptyWorker(ForwardListWorkerBase): |
d3a75429 | 286 | def get_result_type(self, obj): |
287 | return get_bool_type() | |
288 | ||
e96d4167 | 289 | def __call__(self, obj): |
290 | return obj['_M_impl']['_M_head']['_M_next'] == 0 | |
291 | ||
292 | class ForwardListFrontWorker(ForwardListWorkerBase): | |
d3a75429 | 293 | def get_result_type(self, obj): |
294 | return self._val_type | |
295 | ||
3ef8d391 | 296 | def __call__(self, obj): |
e96d4167 | 297 | node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type) |
c8b1b26c | 298 | val_address = node['_M_storage']['_M_storage'].address |
299 | return val_address.cast(self._val_type.pointer()).dereference() | |
3ef8d391 | 300 | |
e96d4167 | 301 | class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher): |
3ef8d391 | 302 | def __init__(self): |
e96d4167 | 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): | |
d813c3cd | 312 | if not re.match('^std::(__\d+::)?forward_list<.*>$', class_type.tag): |
e96d4167 | 313 | return None |
314 | method = self._method_dict.get(method_name) | |
315 | if method is None or not method.enabled: | |
316 | return None | |
c8b1b26c | 317 | val_type = class_type.template_argument(0) |
e96d4167 | 318 | node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer() |
c8b1b26c | 319 | return method.worker_class(val_type, node_type) |
e96d4167 | 320 | |
321 | # Xmethods for std::list | |
322 | ||
323 | class ListWorkerBase(gdb.xmethod.XMethodWorker): | |
d3a75429 | 324 | def __init__(self, val_type, node_type): |
325 | self._val_type = val_type | |
e96d4167 | 326 | self._node_type = node_type |
327 | ||
328 | def get_arg_types(self): | |
329 | return None | |
330 | ||
8c77b933 | 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 | ||
e96d4167 | 340 | class ListEmptyWorker(ListWorkerBase): |
d3a75429 | 341 | def get_result_type(self, obj): |
342 | return get_bool_type() | |
343 | ||
e96d4167 | 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): | |
d3a75429 | 352 | def get_result_type(self, obj): |
353 | return get_std_size_type() | |
354 | ||
e96d4167 | 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): | |
d3a75429 | 365 | def get_result_type(self, obj): |
366 | return self._val_type | |
367 | ||
e96d4167 | 368 | def __call__(self, obj): |
369 | node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type) | |
8c77b933 | 370 | return self.get_value_from_node(node) |
e96d4167 | 371 | |
372 | class ListBackWorker(ListWorkerBase): | |
d3a75429 | 373 | def get_result_type(self, obj): |
374 | return self._val_type | |
375 | ||
e96d4167 | 376 | def __call__(self, obj): |
377 | prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type) | |
8c77b933 | 378 | return self.get_value_from_node(prev_node) |
e96d4167 | 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): | |
d813c3cd | 393 | if not re.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type.tag): |
e96d4167 | 394 | return None |
395 | method = self._method_dict.get(method_name) | |
396 | if method is None or not method.enabled: | |
397 | return None | |
d3a75429 | 398 | val_type = class_type.template_argument(0) |
e96d4167 | 399 | node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer() |
d3a75429 | 400 | return method.worker_class(val_type, node_type) |
e96d4167 | 401 | |
402 | # Xmethods for std::vector | |
403 | ||
404 | class VectorWorkerBase(gdb.xmethod.XMethodWorker): | |
c8b1b26c | 405 | def __init__(self, val_type): |
406 | self._val_type = val_type | |
e96d4167 | 407 | |
408 | def size(self, obj): | |
c8b1b26c | 409 | if self._val_type.code == gdb.TYPE_CODE_BOOL: |
e96d4167 | 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): | |
c8b1b26c | 419 | if self._val_type.code == gdb.TYPE_CODE_BOOL: |
e96d4167 | 420 | start = obj['_M_impl']['_M_start']['_M_p'] |
421 | bit_size = start.dereference().type.sizeof * 8 | |
50c1af91 | 422 | valp = start + index // bit_size |
e96d4167 | 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 | ||
d3a75429 | 432 | def get_result_type(self, obj): |
433 | return get_bool_type() | |
434 | ||
e96d4167 | 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 | ||
d3a75429 | 442 | def get_result_type(self, obj): |
443 | return get_std_size_type() | |
444 | ||
e96d4167 | 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 | ||
d3a75429 | 452 | def get_result_type(self, obj): |
453 | return self._val_type | |
454 | ||
e96d4167 | 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 | |
3ef8d391 | 461 | |
d3a75429 | 462 | def get_result_type(self, obj): |
463 | return self._val_type | |
464 | ||
e96d4167 | 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): | |
d3a75429 | 470 | return get_std_size_type() |
471 | ||
472 | def get_result_type(self, obj, index): | |
473 | return self._val_type | |
e96d4167 | 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): | |
3ef8d391 | 483 | def get_arg_types(self): |
d3a75429 | 484 | return get_std_size_type() |
485 | ||
486 | def get_result_type(self, obj, subscript): | |
487 | return self._val_type | |
3ef8d391 | 488 | |
489 | def __call__(self, obj, subscript): | |
e96d4167 | 490 | return self.get(obj, int(subscript)) |
3ef8d391 | 491 | |
492 | class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher): | |
493 | def __init__(self): | |
494 | gdb.xmethod.XMethodMatcher.__init__(self, | |
495 | matcher_name_prefix + 'vector') | |
e96d4167 | 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] | |
3ef8d391 | 506 | |
507 | def match(self, class_type, method_name): | |
d813c3cd | 508 | if not re.match('^std::(__\d+::)?vector<.*>$', class_type.tag): |
3ef8d391 | 509 | return None |
e96d4167 | 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)) | |
3ef8d391 | 514 | |
3090ad0a | 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): | |
d3a75429 | 531 | def get_result_type(self, obj): |
532 | return get_bool_type() | |
533 | ||
3090ad0a | 534 | def __call__(self, obj): |
535 | return int(self.node_count(obj)) == 0 | |
536 | ||
537 | class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase): | |
d3a75429 | 538 | def get_result_type(self, obj): |
539 | return get_std_size_type() | |
540 | ||
3090ad0a | 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): | |
d813c3cd | 557 | if not re.match('^std::(__\d+::)?%s<.*>$' % self._name, class_type.tag): |
3090ad0a | 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 | ||
3ef8d391 | 565 | # Xmethods for std::unique_ptr |
566 | ||
567 | class UniquePtrGetWorker(gdb.xmethod.XMethodWorker): | |
ac98398d | 568 | "Implements std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->()" |
569 | ||
d3a75429 | 570 | def __init__(self, elem_type): |
ac98398d | 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 | |
3ef8d391 | 576 | |
577 | def get_arg_types(self): | |
578 | return None | |
579 | ||
d3a75429 | 580 | def get_result_type(self, obj): |
581 | return self._elem_type.pointer() | |
582 | ||
ac98398d | 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 | ||
3ef8d391 | 587 | def __call__(self, obj): |
bc8a7bf0 | 588 | impl_type = obj.dereference().type.fields()[0].type.tag |
d813c3cd | 589 | if re.match('^std::(__\d+::)?__uniq_ptr_impl<.*>$', impl_type): # New implementation |
bc8a7bf0 | 590 | return obj['_M_t']['_M_t']['_M_head_impl'] |
d813c3cd | 591 | elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type): |
bc8a7bf0 | 592 | return obj['_M_t']['_M_head_impl'] |
593 | return None | |
3ef8d391 | 594 | |
595 | class UniquePtrDerefWorker(UniquePtrGetWorker): | |
ac98398d | 596 | "Implements std::unique_ptr<T>::operator*()" |
597 | ||
d3a75429 | 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 | |
3ef8d391 | 603 | |
ac98398d | 604 | def _supports(self, method_name): |
605 | "operator* is not supported for unique_ptr<T[]>" | |
606 | return not self._is_array | |
607 | ||
3ef8d391 | 608 | def __call__(self, obj): |
609 | return UniquePtrGetWorker.__call__(self, obj).dereference() | |
610 | ||
ac98398d | 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 | ||
3ef8d391 | 630 | class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher): |
631 | def __init__(self): | |
632 | gdb.xmethod.XMethodMatcher.__init__(self, | |
633 | matcher_name_prefix + 'unique_ptr') | |
d3a75429 | 634 | self._method_dict = { |
635 | 'get': LibStdCxxXMethod('get', UniquePtrGetWorker), | |
a3c0438d | 636 | 'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker), |
d3a75429 | 637 | 'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker), |
ac98398d | 638 | 'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker), |
d3a75429 | 639 | } |
640 | self.methods = [self._method_dict[m] for m in self._method_dict] | |
3ef8d391 | 641 | |
642 | def match(self, class_type, method_name): | |
d813c3cd | 643 | if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag): |
3ef8d391 | 644 | return None |
d3a75429 | 645 | method = self._method_dict.get(method_name) |
646 | if method is None or not method.enabled: | |
647 | return None | |
ac98398d | 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): | |
d813c3cd | 761 | if not re.match('^std::(__\d+::)?shared_ptr<.*>$', class_type.tag): |
ac98398d | 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 | |
3ef8d391 | 770 | \f |
771 | def register_libstdcxx_xmethods(locus): | |
e96d4167 | 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()) | |
3ef8d391 | 776 | gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher()) |
3090ad0a | 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')) | |
3ef8d391 | 793 | gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher()) |
ac98398d | 794 | gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher()) |