]>
Commit | Line | Data |
---|---|---|
b0a6074c | 1 | # Pretty-printers for libstdc++. |
b1986f6e | 2 | |
fbd26352 | 3 | # Copyright (C) 2008-2019 Free Software Foundation, Inc. |
b1986f6e | 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 | ||
623653ee | 18 | import gdb |
b1986f6e | 19 | import itertools |
20 | import re | |
b0a6074c | 21 | import sys |
22 | ||
23 | ### Python 2 + Python 3 compatibility code | |
24 | ||
25 | # Resources about compatibility: | |
26 | # | |
27 | # * <http://pythonhosted.org/six/>: Documentation of the "six" module | |
28 | ||
29 | # FIXME: The handling of e.g. std::basic_string (at least on char) | |
30 | # probably needs updating to work with Python 3's new string rules. | |
31 | # | |
32 | # In particular, Python 3 has a separate type (called byte) for | |
33 | # bytestrings, and a special b"" syntax for the byte literals; the old | |
34 | # str() type has been redefined to always store Unicode text. | |
35 | # | |
36 | # We probably can't do much about this until this GDB PR is addressed: | |
37 | # <https://sourceware.org/bugzilla/show_bug.cgi?id=17138> | |
38 | ||
39 | if sys.version_info[0] > 2: | |
40 | ### Python 3 stuff | |
41 | Iterator = object | |
42 | # Python 3 folds these into the normal functions. | |
43 | imap = map | |
44 | izip = zip | |
45 | # Also, int subsumes long | |
46 | long = int | |
47 | else: | |
48 | ### Python 2 stuff | |
49 | class Iterator: | |
50 | """Compatibility mixin for iterators | |
51 | ||
52 | Instead of writing next() methods for iterators, write | |
53 | __next__() methods and use this mixin to make them work in | |
54 | Python 2 as well as Python 3. | |
55 | ||
56 | Idea stolen from the "six" documentation: | |
57 | <http://pythonhosted.org/six/#six.Iterator> | |
58 | """ | |
59 | ||
60 | def next(self): | |
61 | return self.__next__() | |
62 | ||
63 | # In Python 2, we still need these from itertools | |
64 | from itertools import imap, izip | |
b1986f6e | 65 | |
510f22a9 | 66 | # Try to use the new-style pretty-printing if available. |
67 | _use_gdb_pp = True | |
68 | try: | |
69 | import gdb.printing | |
70 | except ImportError: | |
71 | _use_gdb_pp = False | |
72 | ||
0ed3336a | 73 | # Try to install type-printers. |
74 | _use_type_printing = False | |
75 | try: | |
76 | import gdb.types | |
77 | if hasattr(gdb.types, 'TypePrinter'): | |
78 | _use_type_printing = True | |
79 | except ImportError: | |
80 | pass | |
81 | ||
cd587d4d | 82 | # Starting with the type ORIG, search for the member type NAME. This |
83 | # handles searching upward through superclasses. This is needed to | |
84 | # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. | |
85 | def find_type(orig, name): | |
86 | typ = orig.strip_typedefs() | |
87 | while True: | |
3541f29c | 88 | # Strip cv-qualifiers. PR 67440. |
89 | search = '%s::%s' % (typ.unqualified(), name) | |
cd587d4d | 90 | try: |
91 | return gdb.lookup_type(search) | |
92 | except RuntimeError: | |
93 | pass | |
94 | # The type was not found, so try the superclass. We only need | |
95 | # to check the first superclass, so we don't bother with | |
96 | # anything fancier here. | |
97 | field = typ.fields()[0] | |
98 | if not field.is_base_class: | |
3a30bda9 | 99 | raise ValueError("Cannot find type %s::%s" % (str(orig), name)) |
cd587d4d | 100 | typ = field.type |
101 | ||
6f20076a | 102 | _versioned_namespace = '__8::' |
d813c3cd | 103 | |
023f288a | 104 | def is_specialization_of(x, template_name): |
d4f6ff2a | 105 | "Test if a type is a given template instantiation." |
d813c3cd | 106 | global _versioned_namespace |
023f288a | 107 | if type(x) is gdb.Type: |
108 | x = x.tag | |
d813c3cd | 109 | if _versioned_namespace: |
023f288a | 110 | return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None |
111 | return re.match('^std::%s<.*>$' % template_name, x) is not None | |
d813c3cd | 112 | |
113 | def strip_versioned_namespace(typename): | |
114 | global _versioned_namespace | |
115 | if _versioned_namespace: | |
116 | return typename.replace(_versioned_namespace, '') | |
117 | return typename | |
118 | ||
d4f6ff2a | 119 | def strip_inline_namespaces(type_str): |
120 | "Remove known inline namespaces from the canonical name of a type." | |
121 | type_str = strip_versioned_namespace(type_str) | |
122 | type_str = type_str.replace('std::__cxx11::', 'std::') | |
123 | expt_ns = 'std::experimental::' | |
124 | for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'): | |
125 | type_str = type_str.replace(expt_ns+lfts_ns+'::', expt_ns) | |
126 | fs_ns = expt_ns + 'filesystem::' | |
127 | type_str = type_str.replace(fs_ns+'v1::', fs_ns) | |
128 | return type_str | |
129 | ||
130 | def get_template_arg_list(type_obj): | |
131 | "Return a type's template arguments as a list" | |
132 | n = 0 | |
133 | template_args = [] | |
134 | while True: | |
135 | try: | |
136 | template_args.append(type_obj.template_argument(n)) | |
137 | except: | |
138 | return template_args | |
139 | n += 1 | |
140 | ||
13b767f5 | 141 | class SmartPtrIterator(Iterator): |
142 | "An iterator for smart pointer types with a single 'child' value" | |
143 | ||
144 | def __init__(self, val): | |
145 | self.val = val | |
146 | ||
147 | def __iter__(self): | |
148 | return self | |
149 | ||
150 | def __next__(self): | |
151 | if self.val is None: | |
152 | raise StopIteration | |
153 | self.val, val = None, self.val | |
154 | return ('get()', val) | |
155 | ||
6c2e05ff | 156 | class SharedPointerPrinter: |
157 | "Print a shared_ptr or weak_ptr" | |
b1986f6e | 158 | |
159 | def __init__ (self, typename, val): | |
d813c3cd | 160 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 161 | self.val = val |
13b767f5 | 162 | self.pointer = val['_M_ptr'] |
163 | ||
164 | def children (self): | |
165 | return SmartPtrIterator(self.pointer) | |
b1986f6e | 166 | |
167 | def to_string (self): | |
6c2e05ff | 168 | state = 'empty' |
169 | refcounts = self.val['_M_refcount']['_M_pi'] | |
170 | if refcounts != 0: | |
171 | usecount = refcounts['_M_use_count'] | |
172 | weakcount = refcounts['_M_weak_count'] | |
173 | if usecount == 0: | |
13b767f5 | 174 | state = 'expired, weak count %d' % weakcount |
6c2e05ff | 175 | else: |
13b767f5 | 176 | state = 'use count %d, weak count %d' % (usecount, weakcount - 1) |
073fe8cf | 177 | return '%s<%s> (%s)' % (self.typename, str(self.val.type.template_argument(0)), state) |
b1986f6e | 178 | |
179 | class UniquePointerPrinter: | |
180 | "Print a unique_ptr" | |
181 | ||
510f22a9 | 182 | def __init__ (self, typename, val): |
b1986f6e | 183 | self.val = val |
13b767f5 | 184 | impl_type = val.type.fields()[0].type.tag |
d813c3cd | 185 | if is_specialization_of(impl_type, '__uniq_ptr_impl'): # New implementation |
13b767f5 | 186 | self.pointer = val['_M_t']['_M_t']['_M_head_impl'] |
d813c3cd | 187 | elif is_specialization_of(impl_type, 'tuple'): |
13b767f5 | 188 | self.pointer = val['_M_t']['_M_head_impl'] |
bc8a7bf0 | 189 | else: |
13b767f5 | 190 | raise ValueError("Unsupported implementation for unique_ptr: %s" % impl_type) |
191 | ||
192 | def children (self): | |
193 | return SmartPtrIterator(self.pointer) | |
194 | ||
195 | def to_string (self): | |
073fe8cf | 196 | return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0)))) |
b1986f6e | 197 | |
67218f06 | 198 | def get_value_from_aligned_membuf(buf, valtype): |
199 | """Returns the value held in a __gnu_cxx::__aligned_membuf.""" | |
200 | return buf['_M_storage'].address.cast(valtype.pointer()).dereference() | |
201 | ||
41129c36 | 202 | def get_value_from_list_node(node): |
203 | """Returns the value held in an _List_node<_Val>""" | |
204 | try: | |
205 | member = node.type.fields()[1].name | |
206 | if member == '_M_data': | |
207 | # C++03 implementation, node contains the value as a member | |
208 | return node['_M_data'] | |
209 | elif member == '_M_storage': | |
210 | # C++11 implementation, node stores value in __aligned_membuf | |
67218f06 | 211 | valtype = node.type.template_argument(0) |
212 | return get_value_from_aligned_membuf(node['_M_storage'], valtype) | |
41129c36 | 213 | except: |
214 | pass | |
215 | raise ValueError("Unsupported implementation for %s" % str(node.type)) | |
216 | ||
b1986f6e | 217 | class StdListPrinter: |
218 | "Print a std::list" | |
219 | ||
b0a6074c | 220 | class _iterator(Iterator): |
b1986f6e | 221 | def __init__(self, nodetype, head): |
222 | self.nodetype = nodetype | |
223 | self.base = head['_M_next'] | |
224 | self.head = head.address | |
225 | self.count = 0 | |
226 | ||
227 | def __iter__(self): | |
228 | return self | |
229 | ||
b0a6074c | 230 | def __next__(self): |
b1986f6e | 231 | if self.base == self.head: |
232 | raise StopIteration | |
233 | elt = self.base.cast(self.nodetype).dereference() | |
234 | self.base = elt['_M_next'] | |
235 | count = self.count | |
236 | self.count = self.count + 1 | |
41129c36 | 237 | val = get_value_from_list_node(elt) |
238 | return ('[%d]' % count, val) | |
b1986f6e | 239 | |
19791f4a | 240 | def __init__(self, typename, val): |
d813c3cd | 241 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 242 | self.val = val |
243 | ||
244 | def children(self): | |
cd587d4d | 245 | nodetype = find_type(self.val.type, '_Node') |
246 | nodetype = nodetype.strip_typedefs().pointer() | |
b1986f6e | 247 | return self._iterator(nodetype, self.val['_M_impl']['_M_node']) |
248 | ||
249 | def to_string(self): | |
250 | if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']: | |
19791f4a | 251 | return 'empty %s' % (self.typename) |
252 | return '%s' % (self.typename) | |
b1986f6e | 253 | |
db4f7f88 | 254 | class NodeIteratorPrinter: |
255 | def __init__(self, typename, val, contname): | |
b1986f6e | 256 | self.val = val |
19791f4a | 257 | self.typename = typename |
db4f7f88 | 258 | self.contname = contname |
b1986f6e | 259 | |
260 | def to_string(self): | |
ec3e3110 | 261 | if not self.val['_M_node']: |
db4f7f88 | 262 | return 'non-dereferenceable iterator for std::%s' % (self.contname) |
cd587d4d | 263 | nodetype = find_type(self.val.type, '_Node') |
264 | nodetype = nodetype.strip_typedefs().pointer() | |
41129c36 | 265 | node = self.val['_M_node'].cast(nodetype).dereference() |
d989a3e0 | 266 | return str(get_value_from_list_node(node)) |
b1986f6e | 267 | |
db4f7f88 | 268 | class StdListIteratorPrinter(NodeIteratorPrinter): |
269 | "Print std::list::iterator" | |
270 | ||
271 | def __init__(self, typename, val): | |
272 | NodeIteratorPrinter.__init__(self, typename, val, 'list') | |
273 | ||
274 | class StdFwdListIteratorPrinter(NodeIteratorPrinter): | |
275 | "Print std::forward_list::iterator" | |
276 | ||
277 | def __init__(self, typename, val): | |
278 | NodeIteratorPrinter.__init__(self, typename, val, 'forward_list') | |
279 | ||
b1986f6e | 280 | class StdSlistPrinter: |
281 | "Print a __gnu_cxx::slist" | |
282 | ||
b0a6074c | 283 | class _iterator(Iterator): |
b1986f6e | 284 | def __init__(self, nodetype, head): |
285 | self.nodetype = nodetype | |
286 | self.base = head['_M_head']['_M_next'] | |
287 | self.count = 0 | |
288 | ||
289 | def __iter__(self): | |
290 | return self | |
291 | ||
b0a6074c | 292 | def __next__(self): |
b1986f6e | 293 | if self.base == 0: |
294 | raise StopIteration | |
295 | elt = self.base.cast(self.nodetype).dereference() | |
296 | self.base = elt['_M_next'] | |
297 | count = self.count | |
298 | self.count = self.count + 1 | |
299 | return ('[%d]' % count, elt['_M_data']) | |
300 | ||
510f22a9 | 301 | def __init__(self, typename, val): |
b1986f6e | 302 | self.val = val |
303 | ||
304 | def children(self): | |
cd587d4d | 305 | nodetype = find_type(self.val.type, '_Node') |
306 | nodetype = nodetype.strip_typedefs().pointer() | |
b1986f6e | 307 | return self._iterator(nodetype, self.val) |
308 | ||
309 | def to_string(self): | |
310 | if self.val['_M_head']['_M_next'] == 0: | |
311 | return 'empty __gnu_cxx::slist' | |
312 | return '__gnu_cxx::slist' | |
313 | ||
314 | class StdSlistIteratorPrinter: | |
315 | "Print __gnu_cxx::slist::iterator" | |
316 | ||
510f22a9 | 317 | def __init__(self, typename, val): |
b1986f6e | 318 | self.val = val |
319 | ||
320 | def to_string(self): | |
ec3e3110 | 321 | if not self.val['_M_node']: |
322 | return 'non-dereferenceable iterator for __gnu_cxx::slist' | |
cd587d4d | 323 | nodetype = find_type(self.val.type, '_Node') |
324 | nodetype = nodetype.strip_typedefs().pointer() | |
d989a3e0 | 325 | return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data']) |
b1986f6e | 326 | |
327 | class StdVectorPrinter: | |
328 | "Print a std::vector" | |
329 | ||
b0a6074c | 330 | class _iterator(Iterator): |
58486663 | 331 | def __init__ (self, start, finish, bitvec): |
332 | self.bitvec = bitvec | |
333 | if bitvec: | |
334 | self.item = start['_M_p'] | |
335 | self.so = start['_M_offset'] | |
336 | self.finish = finish['_M_p'] | |
337 | self.fo = finish['_M_offset'] | |
338 | itype = self.item.dereference().type | |
339 | self.isize = 8 * itype.sizeof | |
340 | else: | |
341 | self.item = start | |
342 | self.finish = finish | |
b1986f6e | 343 | self.count = 0 |
344 | ||
345 | def __iter__(self): | |
346 | return self | |
347 | ||
b0a6074c | 348 | def __next__(self): |
b1986f6e | 349 | count = self.count |
350 | self.count = self.count + 1 | |
58486663 | 351 | if self.bitvec: |
352 | if self.item == self.finish and self.so >= self.fo: | |
353 | raise StopIteration | |
354 | elt = self.item.dereference() | |
f42bd93b | 355 | if elt & (1 << self.so): |
356 | obit = 1 | |
357 | else: | |
358 | obit = 0 | |
58486663 | 359 | self.so = self.so + 1 |
360 | if self.so >= self.isize: | |
361 | self.item = self.item + 1 | |
362 | self.so = 0 | |
363 | return ('[%d]' % count, obit) | |
364 | else: | |
365 | if self.item == self.finish: | |
366 | raise StopIteration | |
367 | elt = self.item.dereference() | |
368 | self.item = self.item + 1 | |
369 | return ('[%d]' % count, elt) | |
b1986f6e | 370 | |
19791f4a | 371 | def __init__(self, typename, val): |
d813c3cd | 372 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 373 | self.val = val |
58486663 | 374 | self.is_bool = val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL |
b1986f6e | 375 | |
376 | def children(self): | |
377 | return self._iterator(self.val['_M_impl']['_M_start'], | |
58486663 | 378 | self.val['_M_impl']['_M_finish'], |
379 | self.is_bool) | |
b1986f6e | 380 | |
381 | def to_string(self): | |
382 | start = self.val['_M_impl']['_M_start'] | |
383 | finish = self.val['_M_impl']['_M_finish'] | |
384 | end = self.val['_M_impl']['_M_end_of_storage'] | |
58486663 | 385 | if self.is_bool: |
386 | start = self.val['_M_impl']['_M_start']['_M_p'] | |
387 | so = self.val['_M_impl']['_M_start']['_M_offset'] | |
388 | finish = self.val['_M_impl']['_M_finish']['_M_p'] | |
389 | fo = self.val['_M_impl']['_M_finish']['_M_offset'] | |
390 | itype = start.dereference().type | |
391 | bl = 8 * itype.sizeof | |
392 | length = (bl - so) + bl * ((finish - start) - 1) + fo | |
393 | capacity = bl * (end - start) | |
394 | return ('%s<bool> of length %d, capacity %d' | |
395 | % (self.typename, int (length), int (capacity))) | |
396 | else: | |
397 | return ('%s of length %d, capacity %d' | |
398 | % (self.typename, int (finish - start), int (end - start))) | |
b1986f6e | 399 | |
400 | def display_hint(self): | |
401 | return 'array' | |
402 | ||
403 | class StdVectorIteratorPrinter: | |
404 | "Print std::vector::iterator" | |
405 | ||
510f22a9 | 406 | def __init__(self, typename, val): |
b1986f6e | 407 | self.val = val |
408 | ||
409 | def to_string(self): | |
ec3e3110 | 410 | if not self.val['_M_current']: |
411 | return 'non-dereferenceable iterator for std::vector' | |
d989a3e0 | 412 | return str(self.val['_M_current'].dereference()) |
b1986f6e | 413 | |
ebe3b39c | 414 | class StdTuplePrinter: |
415 | "Print a std::tuple" | |
416 | ||
b0a6074c | 417 | class _iterator(Iterator): |
023f288a | 418 | @staticmethod |
419 | def _is_nonempty_tuple (nodes): | |
420 | if len (nodes) == 2: | |
421 | if is_specialization_of (nodes[1].type, '__tuple_base'): | |
422 | return True | |
423 | elif len (nodes) == 1: | |
424 | return True | |
425 | elif len (nodes) == 0: | |
426 | return False | |
427 | raise ValueError("Top of tuple tree does not consist of a single node.") | |
428 | ||
ebe3b39c | 429 | def __init__ (self, head): |
430 | self.head = head | |
431 | ||
432 | # Set the base class as the initial head of the | |
433 | # tuple. | |
434 | nodes = self.head.type.fields () | |
023f288a | 435 | if self._is_nonempty_tuple (nodes): |
7fe76953 | 436 | # Set the actual head to the first pair. |
437 | self.head = self.head.cast (nodes[0].type) | |
ebe3b39c | 438 | self.count = 0 |
439 | ||
440 | def __iter__ (self): | |
441 | return self | |
442 | ||
b0a6074c | 443 | def __next__ (self): |
ebe3b39c | 444 | # Check for further recursions in the inheritance tree. |
c62683a7 | 445 | # For a GCC 5+ tuple self.head is None after visiting all nodes: |
446 | if not self.head: | |
447 | raise StopIteration | |
448 | nodes = self.head.type.fields () | |
449 | # For a GCC 4.x tuple there is a final node with no fields: | |
ebe3b39c | 450 | if len (nodes) == 0: |
451 | raise StopIteration | |
452 | # Check that this iteration has an expected structure. | |
c62683a7 | 453 | if len (nodes) > 2: |
3a30bda9 | 454 | raise ValueError("Cannot parse more than 2 nodes in a tuple tree.") |
ebe3b39c | 455 | |
c62683a7 | 456 | if len (nodes) == 1: |
457 | # This is the last node of a GCC 5+ std::tuple. | |
458 | impl = self.head.cast (nodes[0].type) | |
459 | self.head = None | |
460 | else: | |
461 | # Either a node before the last node, or the last node of | |
462 | # a GCC 4.x tuple (which has an empty parent). | |
463 | ||
464 | # - Left node is the next recursion parent. | |
465 | # - Right node is the actual class contained in the tuple. | |
ebe3b39c | 466 | |
c62683a7 | 467 | # Process right node. |
468 | impl = self.head.cast (nodes[1].type) | |
469 | ||
470 | # Process left node and set it as head. | |
471 | self.head = self.head.cast (nodes[0].type) | |
ebe3b39c | 472 | |
ebe3b39c | 473 | self.count = self.count + 1 |
474 | ||
475 | # Finally, check the implementation. If it is | |
476 | # wrapped in _M_head_impl return that, otherwise return | |
477 | # the value "as is". | |
478 | fields = impl.type.fields () | |
479 | if len (fields) < 1 or fields[0].name != "_M_head_impl": | |
480 | return ('[%d]' % self.count, impl) | |
481 | else: | |
482 | return ('[%d]' % self.count, impl['_M_head_impl']) | |
483 | ||
484 | def __init__ (self, typename, val): | |
d813c3cd | 485 | self.typename = strip_versioned_namespace(typename) |
ebe3b39c | 486 | self.val = val; |
487 | ||
488 | def children (self): | |
489 | return self._iterator (self.val) | |
490 | ||
491 | def to_string (self): | |
7fe76953 | 492 | if len (self.val.type.fields ()) == 0: |
493 | return 'empty %s' % (self.typename) | |
ebe3b39c | 494 | return '%s containing' % (self.typename) |
495 | ||
b1986f6e | 496 | class StdStackOrQueuePrinter: |
497 | "Print a std::stack or std::queue" | |
498 | ||
499 | def __init__ (self, typename, val): | |
d813c3cd | 500 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 501 | self.visualizer = gdb.default_visualizer(val['c']) |
502 | ||
503 | def children (self): | |
504 | return self.visualizer.children() | |
505 | ||
506 | def to_string (self): | |
507 | return '%s wrapping: %s' % (self.typename, | |
508 | self.visualizer.to_string()) | |
509 | ||
510 | def display_hint (self): | |
511 | if hasattr (self.visualizer, 'display_hint'): | |
512 | return self.visualizer.display_hint () | |
513 | return None | |
514 | ||
b0a6074c | 515 | class RbtreeIterator(Iterator): |
1dc84a99 | 516 | """ |
517 | Turn an RB-tree-based container (std::map, std::set etc.) into | |
518 | a Python iterable object. | |
519 | """ | |
520 | ||
b1986f6e | 521 | def __init__(self, rbtree): |
522 | self.size = rbtree['_M_t']['_M_impl']['_M_node_count'] | |
523 | self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] | |
524 | self.count = 0 | |
525 | ||
526 | def __iter__(self): | |
527 | return self | |
528 | ||
529 | def __len__(self): | |
530 | return int (self.size) | |
531 | ||
b0a6074c | 532 | def __next__(self): |
b1986f6e | 533 | if self.count == self.size: |
534 | raise StopIteration | |
535 | result = self.node | |
536 | self.count = self.count + 1 | |
537 | if self.count < self.size: | |
538 | # Compute the next node. | |
539 | node = self.node | |
540 | if node.dereference()['_M_right']: | |
541 | node = node.dereference()['_M_right'] | |
542 | while node.dereference()['_M_left']: | |
543 | node = node.dereference()['_M_left'] | |
544 | else: | |
545 | parent = node.dereference()['_M_parent'] | |
546 | while node == parent.dereference()['_M_right']: | |
547 | node = parent | |
548 | parent = parent.dereference()['_M_parent'] | |
549 | if node.dereference()['_M_right'] != parent: | |
550 | node = parent | |
551 | self.node = node | |
552 | return result | |
553 | ||
1fcecb12 | 554 | def get_value_from_Rb_tree_node(node): |
555 | """Returns the value held in an _Rb_tree_node<_Val>""" | |
556 | try: | |
557 | member = node.type.fields()[1].name | |
558 | if member == '_M_value_field': | |
559 | # C++03 implementation, node contains the value as a member | |
560 | return node['_M_value_field'] | |
561 | elif member == '_M_storage': | |
41129c36 | 562 | # C++11 implementation, node stores value in __aligned_membuf |
67218f06 | 563 | valtype = node.type.template_argument(0) |
564 | return get_value_from_aligned_membuf(node['_M_storage'], valtype) | |
1fcecb12 | 565 | except: |
566 | pass | |
3a30bda9 | 567 | raise ValueError("Unsupported implementation for %s" % str(node.type)) |
1fcecb12 | 568 | |
b1986f6e | 569 | # This is a pretty printer for std::_Rb_tree_iterator (which is |
570 | # std::map::iterator), and has nothing to do with the RbtreeIterator | |
571 | # class above. | |
572 | class StdRbtreeIteratorPrinter: | |
1dc84a99 | 573 | "Print std::map::iterator, std::set::iterator, etc." |
b1986f6e | 574 | |
510f22a9 | 575 | def __init__ (self, typename, val): |
b1986f6e | 576 | self.val = val |
726854a8 | 577 | valtype = self.val.type.template_argument(0).strip_typedefs() |
d813c3cd | 578 | nodetype = '_Rb_tree_node<' + str(valtype) + '>' |
579 | if _versioned_namespace and typename.startswith('std::' + _versioned_namespace): | |
580 | nodetype = _versioned_namespace + nodetype | |
581 | nodetype = gdb.lookup_type('std::' + nodetype) | |
726854a8 | 582 | self.link_type = nodetype.strip_typedefs().pointer() |
b1986f6e | 583 | |
584 | def to_string (self): | |
ec3e3110 | 585 | if not self.val['_M_node']: |
586 | return 'non-dereferenceable iterator for associative container' | |
726854a8 | 587 | node = self.val['_M_node'].cast(self.link_type).dereference() |
d989a3e0 | 588 | return str(get_value_from_Rb_tree_node(node)) |
b1986f6e | 589 | |
19791f4a | 590 | class StdDebugIteratorPrinter: |
591 | "Print a debug enabled version of an iterator" | |
592 | ||
510f22a9 | 593 | def __init__ (self, typename, val): |
19791f4a | 594 | self.val = val |
595 | ||
596 | # Just strip away the encapsulating __gnu_debug::_Safe_iterator | |
597 | # and return the wrapped iterator value. | |
598 | def to_string (self): | |
cbd50187 | 599 | base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base') |
db4f7f88 | 600 | itype = self.val.type.template_argument(0) |
cbd50187 | 601 | safe_seq = self.val.cast(base_type)['_M_sequence'] |
db4f7f88 | 602 | if not safe_seq: |
603 | return str(self.val.cast(itype)) | |
604 | if self.val['_M_version'] != safe_seq['_M_version']: | |
cbd50187 | 605 | return "invalid iterator" |
d989a3e0 | 606 | return str(self.val.cast(itype)) |
b1986f6e | 607 | |
ee6bf894 | 608 | def num_elements(num): |
609 | """Return either "1 element" or "N elements" depending on the argument.""" | |
610 | return '1 element' if num == 1 else '%d elements' % num | |
611 | ||
b1986f6e | 612 | class StdMapPrinter: |
613 | "Print a std::map or std::multimap" | |
614 | ||
615 | # Turn an RbtreeIterator into a pretty-print iterator. | |
b0a6074c | 616 | class _iter(Iterator): |
b1986f6e | 617 | def __init__(self, rbiter, type): |
618 | self.rbiter = rbiter | |
619 | self.count = 0 | |
620 | self.type = type | |
621 | ||
622 | def __iter__(self): | |
623 | return self | |
624 | ||
b0a6074c | 625 | def __next__(self): |
b1986f6e | 626 | if self.count % 2 == 0: |
b0a6074c | 627 | n = next(self.rbiter) |
1fcecb12 | 628 | n = n.cast(self.type).dereference() |
629 | n = get_value_from_Rb_tree_node(n) | |
b1986f6e | 630 | self.pair = n |
631 | item = n['first'] | |
632 | else: | |
633 | item = self.pair['second'] | |
634 | result = ('[%d]' % self.count, item) | |
635 | self.count = self.count + 1 | |
636 | return result | |
637 | ||
638 | def __init__ (self, typename, val): | |
d813c3cd | 639 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 640 | self.val = val |
b1986f6e | 641 | |
642 | def to_string (self): | |
ee6bf894 | 643 | return '%s with %s' % (self.typename, |
644 | num_elements(len(RbtreeIterator (self.val)))) | |
b1986f6e | 645 | |
646 | def children (self): | |
cd587d4d | 647 | rep_type = find_type(self.val.type, '_Rep_type') |
648 | node = find_type(rep_type, '_Link_type') | |
649 | node = node.strip_typedefs() | |
650 | return self._iter (RbtreeIterator (self.val), node) | |
b1986f6e | 651 | |
652 | def display_hint (self): | |
653 | return 'map' | |
654 | ||
655 | class StdSetPrinter: | |
656 | "Print a std::set or std::multiset" | |
657 | ||
658 | # Turn an RbtreeIterator into a pretty-print iterator. | |
b0a6074c | 659 | class _iter(Iterator): |
b1986f6e | 660 | def __init__(self, rbiter, type): |
661 | self.rbiter = rbiter | |
662 | self.count = 0 | |
663 | self.type = type | |
664 | ||
665 | def __iter__(self): | |
666 | return self | |
667 | ||
b0a6074c | 668 | def __next__(self): |
669 | item = next(self.rbiter) | |
1fcecb12 | 670 | item = item.cast(self.type).dereference() |
671 | item = get_value_from_Rb_tree_node(item) | |
b1986f6e | 672 | # FIXME: this is weird ... what to do? |
673 | # Maybe a 'set' display hint? | |
674 | result = ('[%d]' % self.count, item) | |
675 | self.count = self.count + 1 | |
676 | return result | |
677 | ||
678 | def __init__ (self, typename, val): | |
d813c3cd | 679 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 680 | self.val = val |
b1986f6e | 681 | |
682 | def to_string (self): | |
ee6bf894 | 683 | return '%s with %s' % (self.typename, |
684 | num_elements(len(RbtreeIterator (self.val)))) | |
b1986f6e | 685 | |
686 | def children (self): | |
cd587d4d | 687 | rep_type = find_type(self.val.type, '_Rep_type') |
688 | node = find_type(rep_type, '_Link_type') | |
689 | node = node.strip_typedefs() | |
690 | return self._iter (RbtreeIterator (self.val), node) | |
b1986f6e | 691 | |
692 | class StdBitsetPrinter: | |
693 | "Print a std::bitset" | |
694 | ||
19791f4a | 695 | def __init__(self, typename, val): |
d813c3cd | 696 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 697 | self.val = val |
698 | ||
699 | def to_string (self): | |
700 | # If template_argument handled values, we could print the | |
701 | # size. Or we could use a regexp on the type. | |
19791f4a | 702 | return '%s' % (self.typename) |
b1986f6e | 703 | |
704 | def children (self): | |
85e3666c | 705 | try: |
706 | # An empty bitset may not have any members which will | |
707 | # result in an exception being thrown. | |
708 | words = self.val['_M_w'] | |
709 | except: | |
710 | return [] | |
711 | ||
b1986f6e | 712 | wtype = words.type |
713 | ||
714 | # The _M_w member can be either an unsigned long, or an | |
715 | # array. This depends on the template specialization used. | |
716 | # If it is a single long, convert to a single element list. | |
717 | if wtype.code == gdb.TYPE_CODE_ARRAY: | |
718 | tsize = wtype.target ().sizeof | |
719 | else: | |
720 | words = [words] | |
85e3666c | 721 | tsize = wtype.sizeof |
b1986f6e | 722 | |
723 | nwords = wtype.sizeof / tsize | |
724 | result = [] | |
725 | byte = 0 | |
726 | while byte < nwords: | |
727 | w = words[byte] | |
728 | bit = 0 | |
729 | while w != 0: | |
730 | if (w & 1) != 0: | |
731 | # Another spot where we could use 'set'? | |
732 | result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) | |
733 | bit = bit + 1 | |
734 | w = w >> 1 | |
735 | byte = byte + 1 | |
736 | return result | |
737 | ||
738 | class StdDequePrinter: | |
739 | "Print a std::deque" | |
740 | ||
b0a6074c | 741 | class _iter(Iterator): |
b1986f6e | 742 | def __init__(self, node, start, end, last, buffer_size): |
743 | self.node = node | |
744 | self.p = start | |
745 | self.end = end | |
746 | self.last = last | |
747 | self.buffer_size = buffer_size | |
748 | self.count = 0 | |
749 | ||
750 | def __iter__(self): | |
751 | return self | |
752 | ||
b0a6074c | 753 | def __next__(self): |
b1986f6e | 754 | if self.p == self.last: |
755 | raise StopIteration | |
756 | ||
757 | result = ('[%d]' % self.count, self.p.dereference()) | |
758 | self.count = self.count + 1 | |
759 | ||
760 | # Advance the 'cur' pointer. | |
761 | self.p = self.p + 1 | |
762 | if self.p == self.end: | |
763 | # If we got to the end of this bucket, move to the | |
764 | # next bucket. | |
765 | self.node = self.node + 1 | |
766 | self.p = self.node[0] | |
767 | self.end = self.p + self.buffer_size | |
768 | ||
769 | return result | |
770 | ||
19791f4a | 771 | def __init__(self, typename, val): |
d813c3cd | 772 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 773 | self.val = val |
774 | self.elttype = val.type.template_argument(0) | |
775 | size = self.elttype.sizeof | |
776 | if size < 512: | |
777 | self.buffer_size = int (512 / size) | |
778 | else: | |
779 | self.buffer_size = 1 | |
780 | ||
781 | def to_string(self): | |
782 | start = self.val['_M_impl']['_M_start'] | |
783 | end = self.val['_M_impl']['_M_finish'] | |
784 | ||
785 | delta_n = end['_M_node'] - start['_M_node'] - 1 | |
786 | delta_s = start['_M_last'] - start['_M_cur'] | |
787 | delta_e = end['_M_cur'] - end['_M_first'] | |
788 | ||
789 | size = self.buffer_size * delta_n + delta_s + delta_e | |
790 | ||
ee6bf894 | 791 | return '%s with %s' % (self.typename, num_elements(long(size))) |
b1986f6e | 792 | |
793 | def children(self): | |
794 | start = self.val['_M_impl']['_M_start'] | |
795 | end = self.val['_M_impl']['_M_finish'] | |
796 | return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], | |
797 | end['_M_cur'], self.buffer_size) | |
798 | ||
799 | def display_hint (self): | |
800 | return 'array' | |
801 | ||
802 | class StdDequeIteratorPrinter: | |
803 | "Print std::deque::iterator" | |
804 | ||
510f22a9 | 805 | def __init__(self, typename, val): |
b1986f6e | 806 | self.val = val |
807 | ||
808 | def to_string(self): | |
ec3e3110 | 809 | if not self.val['_M_cur']: |
810 | return 'non-dereferenceable iterator for std::deque' | |
d989a3e0 | 811 | return str(self.val['_M_cur'].dereference()) |
b1986f6e | 812 | |
813 | class StdStringPrinter: | |
814 | "Print a std::basic_string of some kind" | |
815 | ||
510f22a9 | 816 | def __init__(self, typename, val): |
b1986f6e | 817 | self.val = val |
63f54259 | 818 | self.new_string = typename.find("::__cxx11::basic_string") != -1 |
b1986f6e | 819 | |
820 | def to_string(self): | |
ffa1c35e | 821 | # Make sure &string works, too. |
822 | type = self.val.type | |
823 | if type.code == gdb.TYPE_CODE_REF: | |
824 | type = type.target () | |
825 | ||
826 | # Calculate the length of the string so that to_string returns | |
827 | # the string according to length, not according to first null | |
828 | # encountered. | |
829 | ptr = self.val ['_M_dataplus']['_M_p'] | |
63f54259 | 830 | if self.new_string: |
831 | length = self.val['_M_string_length'] | |
832 | # https://sourceware.org/bugzilla/show_bug.cgi?id=17728 | |
833 | ptr = ptr.cast(ptr.type.strip_typedefs()) | |
834 | else: | |
835 | realtype = type.unqualified ().strip_typedefs () | |
836 | reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer () | |
837 | header = ptr.cast(reptype) - 1 | |
838 | length = header.dereference ()['_M_length'] | |
4c4fb6b0 | 839 | if hasattr(ptr, "lazy_string"): |
63f54259 | 840 | return ptr.lazy_string (length = length) |
841 | return ptr.string (length = length) | |
b1986f6e | 842 | |
843 | def display_hint (self): | |
844 | return 'string' | |
845 | ||
b0a6074c | 846 | class Tr1HashtableIterator(Iterator): |
b1986f6e | 847 | def __init__ (self, hash): |
611894d1 | 848 | self.buckets = hash['_M_buckets'] |
849 | self.bucket = 0 | |
850 | self.bucket_count = hash['_M_bucket_count'] | |
851 | self.node_type = find_type(hash.type, '_Node').pointer() | |
852 | self.node = 0 | |
853 | while self.bucket != self.bucket_count: | |
854 | self.node = self.buckets[self.bucket] | |
855 | if self.node: | |
856 | break | |
85e3666c | 857 | self.bucket = self.bucket + 1 |
b1986f6e | 858 | |
859 | def __iter__ (self): | |
860 | return self | |
861 | ||
b0a6074c | 862 | def __next__ (self): |
cecc3a9a | 863 | if self.node == 0: |
b1986f6e | 864 | raise StopIteration |
cecc3a9a | 865 | node = self.node.cast(self.node_type) |
866 | result = node.dereference()['_M_v'] | |
611894d1 | 867 | self.node = node.dereference()['_M_next']; |
868 | if self.node == 0: | |
869 | self.bucket = self.bucket + 1 | |
870 | while self.bucket != self.bucket_count: | |
871 | self.node = self.buckets[self.bucket] | |
872 | if self.node: | |
873 | break | |
874 | self.bucket = self.bucket + 1 | |
b1986f6e | 875 | return result |
876 | ||
b0a6074c | 877 | class StdHashtableIterator(Iterator): |
611894d1 | 878 | def __init__(self, hash): |
b0a82d23 | 879 | self.node = hash['_M_before_begin']['_M_nxt'] |
611894d1 | 880 | self.node_type = find_type(hash.type, '__node_type').pointer() |
881 | ||
882 | def __iter__(self): | |
883 | return self | |
884 | ||
b0a6074c | 885 | def __next__(self): |
611894d1 | 886 | if self.node == 0: |
887 | raise StopIteration | |
888 | elt = self.node.cast(self.node_type).dereference() | |
889 | self.node = elt['_M_nxt'] | |
890 | valptr = elt['_M_storage'].address | |
891 | valptr = valptr.cast(elt.type.template_argument(0).pointer()) | |
892 | return valptr.dereference() | |
893 | ||
b1986f6e | 894 | class Tr1UnorderedSetPrinter: |
895 | "Print a tr1::unordered_set" | |
896 | ||
897 | def __init__ (self, typename, val): | |
d813c3cd | 898 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 899 | self.val = val |
900 | ||
ded5331d | 901 | def hashtable (self): |
902 | if self.typename.startswith('std::tr1'): | |
903 | return self.val | |
904 | return self.val['_M_h'] | |
905 | ||
b1986f6e | 906 | def to_string (self): |
ee6bf894 | 907 | count = self.hashtable()['_M_element_count'] |
908 | return '%s with %s' % (self.typename, num_elements(count)) | |
b1986f6e | 909 | |
910 | @staticmethod | |
911 | def format_count (i): | |
912 | return '[%d]' % i | |
913 | ||
914 | def children (self): | |
b0a6074c | 915 | counter = imap (self.format_count, itertools.count()) |
611894d1 | 916 | if self.typename.startswith('std::tr1'): |
b0a6074c | 917 | return izip (counter, Tr1HashtableIterator (self.hashtable())) |
918 | return izip (counter, StdHashtableIterator (self.hashtable())) | |
b1986f6e | 919 | |
920 | class Tr1UnorderedMapPrinter: | |
921 | "Print a tr1::unordered_map" | |
922 | ||
923 | def __init__ (self, typename, val): | |
d813c3cd | 924 | self.typename = strip_versioned_namespace(typename) |
b1986f6e | 925 | self.val = val |
926 | ||
ded5331d | 927 | def hashtable (self): |
928 | if self.typename.startswith('std::tr1'): | |
929 | return self.val | |
930 | return self.val['_M_h'] | |
931 | ||
b1986f6e | 932 | def to_string (self): |
ee6bf894 | 933 | count = self.hashtable()['_M_element_count'] |
934 | return '%s with %s' % (self.typename, num_elements(count)) | |
b1986f6e | 935 | |
936 | @staticmethod | |
937 | def flatten (list): | |
938 | for elt in list: | |
939 | for i in elt: | |
940 | yield i | |
941 | ||
942 | @staticmethod | |
943 | def format_one (elt): | |
944 | return (elt['first'], elt['second']) | |
945 | ||
946 | @staticmethod | |
947 | def format_count (i): | |
948 | return '[%d]' % i | |
949 | ||
950 | def children (self): | |
b0a6074c | 951 | counter = imap (self.format_count, itertools.count()) |
b1986f6e | 952 | # Map over the hash table and flatten the result. |
611894d1 | 953 | if self.typename.startswith('std::tr1'): |
b0a6074c | 954 | data = self.flatten (imap (self.format_one, Tr1HashtableIterator (self.hashtable()))) |
611894d1 | 955 | # Zip the two iterators together. |
b0a6074c | 956 | return izip (counter, data) |
957 | data = self.flatten (imap (self.format_one, StdHashtableIterator (self.hashtable()))) | |
b1986f6e | 958 | # Zip the two iterators together. |
b0a6074c | 959 | return izip (counter, data) |
b1986f6e | 960 | |
961 | def display_hint (self): | |
962 | return 'map' | |
963 | ||
3c80034b | 964 | class StdForwardListPrinter: |
965 | "Print a std::forward_list" | |
966 | ||
b0a6074c | 967 | class _iterator(Iterator): |
3c80034b | 968 | def __init__(self, nodetype, head): |
969 | self.nodetype = nodetype | |
970 | self.base = head['_M_next'] | |
971 | self.count = 0 | |
972 | ||
973 | def __iter__(self): | |
974 | return self | |
975 | ||
b0a6074c | 976 | def __next__(self): |
3c80034b | 977 | if self.base == 0: |
978 | raise StopIteration | |
979 | elt = self.base.cast(self.nodetype).dereference() | |
980 | self.base = elt['_M_next'] | |
981 | count = self.count | |
982 | self.count = self.count + 1 | |
bf1e1356 | 983 | valptr = elt['_M_storage'].address |
984 | valptr = valptr.cast(elt.type.template_argument(0).pointer()) | |
985 | return ('[%d]' % count, valptr.dereference()) | |
3c80034b | 986 | |
987 | def __init__(self, typename, val): | |
988 | self.val = val | |
d813c3cd | 989 | self.typename = strip_versioned_namespace(typename) |
3c80034b | 990 | |
991 | def children(self): | |
cd587d4d | 992 | nodetype = find_type(self.val.type, '_Node') |
993 | nodetype = nodetype.strip_typedefs().pointer() | |
3c80034b | 994 | return self._iterator(nodetype, self.val['_M_impl']['_M_head']) |
995 | ||
996 | def to_string(self): | |
997 | if self.val['_M_impl']['_M_head']['_M_next'] == 0: | |
1dc84a99 | 998 | return 'empty %s' % self.typename |
999 | return '%s' % self.typename | |
3c80034b | 1000 | |
f29d6b5d | 1001 | class SingleObjContainerPrinter(object): |
1002 | "Base class for printers of containers of single objects" | |
1003 | ||
bd4dc25f | 1004 | def __init__ (self, val, viz, hint = None): |
f29d6b5d | 1005 | self.contained_value = val |
1006 | self.visualizer = viz | |
bd4dc25f | 1007 | self.hint = hint |
f29d6b5d | 1008 | |
1009 | def _recognize(self, type): | |
1010 | """Return TYPE as a string after applying type printers""" | |
dacf2aec | 1011 | global _use_type_printing |
1012 | if not _use_type_printing: | |
1013 | return str(type) | |
f29d6b5d | 1014 | return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(), |
1015 | type) or str(type) | |
1016 | ||
fffc4f5a | 1017 | class _contained(Iterator): |
f29d6b5d | 1018 | def __init__ (self, val): |
1019 | self.val = val | |
1020 | ||
1021 | def __iter__ (self): | |
1022 | return self | |
1023 | ||
fffc4f5a | 1024 | def __next__(self): |
f29d6b5d | 1025 | if self.val is None: |
1026 | raise StopIteration | |
1027 | retval = self.val | |
1028 | self.val = None | |
1029 | return ('[contained value]', retval) | |
1030 | ||
1031 | def children (self): | |
1032 | if self.contained_value is None: | |
1033 | return self._contained (None) | |
1034 | if hasattr (self.visualizer, 'children'): | |
1035 | return self.visualizer.children () | |
1036 | return self._contained (self.contained_value) | |
1037 | ||
1038 | def display_hint (self): | |
1039 | # if contained value is a map we want to display in the same way | |
1040 | if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'): | |
1041 | return self.visualizer.display_hint () | |
bd4dc25f | 1042 | return self.hint |
f29d6b5d | 1043 | |
f29d6b5d | 1044 | class StdExpAnyPrinter(SingleObjContainerPrinter): |
e11be3ea | 1045 | "Print a std::any or std::experimental::any" |
f29d6b5d | 1046 | |
1047 | def __init__ (self, typename, val): | |
c730c800 | 1048 | self.typename = strip_versioned_namespace(typename) |
1049 | self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', self.typename, 1) | |
f29d6b5d | 1050 | self.val = val |
1051 | self.contained_type = None | |
1052 | contained_value = None | |
1053 | visualizer = None | |
1054 | mgr = self.val['_M_manager'] | |
1055 | if mgr != 0: | |
1056 | func = gdb.block_for_pc(int(mgr.cast(gdb.lookup_type('intptr_t')))) | |
1057 | if not func: | |
e11be3ea | 1058 | raise ValueError("Invalid function pointer in %s" % self.typename) |
fb75ff45 | 1059 | rx = r"""({0}::_Manager_\w+<.*>)::_S_manage\((enum )?{0}::_Op, (const {0}|{0} const) ?\*, (union )?{0}::_Arg ?\*\)""".format(typename) |
f29d6b5d | 1060 | m = re.match(rx, func.function.name) |
1061 | if not m: | |
e11be3ea | 1062 | raise ValueError("Unknown manager function in %s" % self.typename) |
f29d6b5d | 1063 | |
d813c3cd | 1064 | mgrname = m.group(1) |
f29d6b5d | 1065 | # FIXME need to expand 'std::string' so that gdb.lookup_type works |
d813c3cd | 1066 | if 'std::string' in mgrname: |
1067 | mgrname = re.sub("std::string(?!\w)", str(gdb.lookup_type('std::string').strip_typedefs()), m.group(1)) | |
1068 | ||
f29d6b5d | 1069 | mgrtype = gdb.lookup_type(mgrname) |
1070 | self.contained_type = mgrtype.template_argument(0) | |
1071 | valptr = None | |
1072 | if '::_Manager_internal' in mgrname: | |
1073 | valptr = self.val['_M_storage']['_M_buffer'].address | |
1074 | elif '::_Manager_external' in mgrname: | |
1075 | valptr = self.val['_M_storage']['_M_ptr'] | |
f29d6b5d | 1076 | else: |
e11be3ea | 1077 | raise ValueError("Unknown manager function in %s" % self.typename) |
f29d6b5d | 1078 | contained_value = valptr.cast(self.contained_type.pointer()).dereference() |
1079 | visualizer = gdb.default_visualizer(contained_value) | |
1080 | super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer) | |
1081 | ||
1082 | def to_string (self): | |
1083 | if self.contained_type is None: | |
1084 | return '%s [no contained value]' % self.typename | |
1085 | desc = "%s containing " % self.typename | |
1086 | if hasattr (self.visualizer, 'children'): | |
1087 | return desc + self.visualizer.to_string () | |
1088 | valtype = self._recognize (self.contained_type) | |
d813c3cd | 1089 | return desc + strip_versioned_namespace(str(valtype)) |
f29d6b5d | 1090 | |
1091 | class StdExpOptionalPrinter(SingleObjContainerPrinter): | |
e11be3ea | 1092 | "Print a std::optional or std::experimental::optional" |
f29d6b5d | 1093 | |
1094 | def __init__ (self, typename, val): | |
1095 | valtype = self._recognize (val.type.template_argument(0)) | |
c730c800 | 1096 | self.typename = strip_versioned_namespace(typename) |
1097 | self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, self.typename, 1) | |
87da5170 | 1098 | if not self.typename.startswith('std::experimental'): |
1099 | val = val['_M_payload'] | |
f29d6b5d | 1100 | self.val = val |
1101 | contained_value = val['_M_payload'] if self.val['_M_engaged'] else None | |
1102 | visualizer = gdb.default_visualizer (val['_M_payload']) | |
1103 | super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer) | |
1104 | ||
1105 | def to_string (self): | |
1106 | if self.contained_value is None: | |
1dc84a99 | 1107 | return "%s [no contained value]" % self.typename |
f29d6b5d | 1108 | if hasattr (self.visualizer, 'children'): |
1dc84a99 | 1109 | return "%s containing %s" % (self.typename, |
1110 | self.visualizer.to_string()) | |
f29d6b5d | 1111 | return self.typename |
1112 | ||
e11be3ea | 1113 | class StdVariantPrinter(SingleObjContainerPrinter): |
1114 | "Print a std::variant" | |
1115 | ||
1116 | def __init__(self, typename, val): | |
d4f6ff2a | 1117 | alternatives = get_template_arg_list(val.type) |
c730c800 | 1118 | self.typename = strip_versioned_namespace(typename) |
1119 | self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives])) | |
e11be3ea | 1120 | self.index = val['_M_index'] |
1121 | if self.index >= len(alternatives): | |
1122 | self.contained_type = None | |
1123 | contained_value = None | |
1124 | visualizer = None | |
1125 | else: | |
1126 | self.contained_type = alternatives[int(self.index)] | |
d80f17d7 | 1127 | addr = val['_M_u']['_M_first']['_M_storage'].address |
e11be3ea | 1128 | contained_value = addr.cast(self.contained_type.pointer()).dereference() |
1129 | visualizer = gdb.default_visualizer(contained_value) | |
bd4dc25f | 1130 | super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array') |
e11be3ea | 1131 | |
e11be3ea | 1132 | def to_string(self): |
1133 | if self.contained_value is None: | |
bd4dc25f | 1134 | return "%s [no contained value]" % self.typename |
e11be3ea | 1135 | if hasattr(self.visualizer, 'children'): |
1dc84a99 | 1136 | return "%s [index %d] containing %s" % (self.typename, self.index, |
1137 | self.visualizer.to_string()) | |
bd4dc25f | 1138 | return "%s [index %d]" % (self.typename, self.index) |
e11be3ea | 1139 | |
67218f06 | 1140 | class StdNodeHandlePrinter(SingleObjContainerPrinter): |
1141 | "Print a container node handle" | |
1142 | ||
1143 | def __init__(self, typename, val): | |
1144 | self.value_type = val.type.template_argument(1) | |
1145 | nodetype = val.type.template_argument(2).template_argument(0) | |
d813c3cd | 1146 | self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node') |
67218f06 | 1147 | self.is_map_node = val.type.template_argument(0) != self.value_type |
1148 | nodeptr = val['_M_ptr'] | |
1149 | if nodeptr: | |
1150 | if self.is_rb_tree_node: | |
1151 | contained_value = get_value_from_Rb_tree_node(nodeptr.dereference()) | |
1152 | else: | |
1153 | contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'], | |
1154 | self.value_type) | |
1155 | visualizer = gdb.default_visualizer(contained_value) | |
1156 | else: | |
1157 | contained_value = None | |
1158 | visualizer = None | |
1159 | optalloc = val['_M_alloc'] | |
1160 | self.alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None | |
1161 | super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer, | |
1162 | 'array') | |
1163 | ||
1164 | def to_string(self): | |
67218f06 | 1165 | desc = 'node handle for ' |
1166 | if not self.is_rb_tree_node: | |
1167 | desc += 'unordered ' | |
1168 | if self.is_map_node: | |
1169 | desc += 'map'; | |
1170 | else: | |
1171 | desc += 'set'; | |
1172 | ||
1173 | if self.contained_value: | |
1174 | desc += ' with element' | |
1175 | if hasattr(self.visualizer, 'children'): | |
1176 | return "%s = %s" % (desc, self.visualizer.to_string()) | |
1177 | return desc | |
1178 | else: | |
1179 | return 'empty %s' % desc | |
1180 | ||
f29d6b5d | 1181 | class StdExpStringViewPrinter: |
e11be3ea | 1182 | "Print a std::basic_string_view or std::experimental::basic_string_view" |
f29d6b5d | 1183 | |
1184 | def __init__ (self, typename, val): | |
1185 | self.val = val | |
1186 | ||
1187 | def to_string (self): | |
1188 | ptr = self.val['_M_str'] | |
1189 | len = self.val['_M_len'] | |
1190 | if hasattr (ptr, "lazy_string"): | |
1191 | return ptr.lazy_string (length = len) | |
1192 | return ptr.string (length = len) | |
1193 | ||
1194 | def display_hint (self): | |
1195 | return 'string' | |
3c80034b | 1196 | |
5924b28e | 1197 | class StdExpPathPrinter: |
1198 | "Print a std::experimental::filesystem::path" | |
1199 | ||
1200 | def __init__ (self, typename, val): | |
1201 | self.val = val | |
d1eff9de | 1202 | start = self.val['_M_cmpts']['_M_impl']['_M_start'] |
1203 | finish = self.val['_M_cmpts']['_M_impl']['_M_finish'] | |
1204 | self.num_cmpts = int (finish - start) | |
1205 | ||
1206 | def _path_type(self): | |
1207 | t = str(self.val['_M_type']) | |
1208 | if t[-9:] == '_Root_dir': | |
1209 | return "root-directory" | |
1210 | if t[-10:] == '_Root_name': | |
1211 | return "root-name" | |
1212 | return None | |
5924b28e | 1213 | |
1214 | def to_string (self): | |
d1eff9de | 1215 | path = "%s" % self.val ['_M_pathname'] |
1216 | if self.num_cmpts == 0: | |
1217 | t = self._path_type() | |
1218 | if t: | |
1219 | path = '%s [%s]' % (path, t) | |
1220 | return "filesystem::path %s" % path | |
1221 | ||
1222 | class _iterator(Iterator): | |
1223 | def __init__(self, cmpts): | |
1224 | self.item = cmpts['_M_impl']['_M_start'] | |
1225 | self.finish = cmpts['_M_impl']['_M_finish'] | |
1226 | self.count = 0 | |
1227 | ||
1228 | def __iter__(self): | |
1229 | return self | |
1230 | ||
1231 | def __next__(self): | |
1232 | if self.item == self.finish: | |
1233 | raise StopIteration | |
1234 | item = self.item.dereference() | |
1235 | count = self.count | |
1236 | self.count = self.count + 1 | |
1237 | self.item = self.item + 1 | |
1238 | path = item['_M_pathname'] | |
1239 | t = StdExpPathPrinter(item.type.name, item)._path_type() | |
1240 | if not t: | |
1241 | t = count | |
1242 | return ('[%s]' % t, path) | |
1243 | ||
1244 | def children(self): | |
1245 | return self._iterator(self.val['_M_cmpts']) | |
1246 | ||
6bec006a | 1247 | class StdPathPrinter: |
1248 | "Print a std::filesystem::path" | |
1249 | ||
1250 | def __init__ (self, typename, val): | |
1251 | self.val = val | |
1252 | self.typename = typename | |
1253 | impl = self.val['_M_cmpts']['_M_impl']['_M_t']['_M_t']['_M_head_impl'] | |
1254 | self.type = impl.cast(gdb.lookup_type('uintptr_t')) & 3 | |
1255 | if self.type == 0: | |
1256 | self.impl = impl | |
1257 | else: | |
1258 | self.impl = None | |
1259 | ||
1260 | def _path_type(self): | |
1261 | t = str(self.type.cast(gdb.lookup_type(self.typename + '::_Type'))) | |
1262 | if t[-9:] == '_Root_dir': | |
1263 | return "root-directory" | |
1264 | if t[-10:] == '_Root_name': | |
1265 | return "root-name" | |
1266 | return None | |
1267 | ||
1268 | def to_string (self): | |
1269 | path = "%s" % self.val ['_M_pathname'] | |
1270 | if self.type != 0: | |
1271 | t = self._path_type() | |
1272 | if t: | |
1273 | path = '%s [%s]' % (path, t) | |
1274 | return "filesystem::path %s" % path | |
1275 | ||
1276 | class _iterator(Iterator): | |
1277 | def __init__(self, impl, pathtype): | |
1278 | if impl: | |
1279 | # We can't access _Impl::_M_size because _Impl is incomplete | |
1280 | # so cast to int* to access the _M_size member at offset zero, | |
1281 | int_type = gdb.lookup_type('int') | |
1282 | cmpt_type = gdb.lookup_type(pathtype+'::_Cmpt') | |
1283 | char_type = gdb.lookup_type('char') | |
1284 | impl = impl.cast(int_type.pointer()) | |
1285 | size = impl.dereference() | |
1286 | #self.capacity = (impl + 1).dereference() | |
1287 | if hasattr(gdb.Type, 'alignof'): | |
1288 | sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof) | |
1289 | else: | |
1290 | sizeof_Impl = 2 * int_type.sizeof | |
1291 | begin = impl.cast(char_type.pointer()) + sizeof_Impl | |
1292 | self.item = begin.cast(cmpt_type.pointer()) | |
1293 | self.finish = self.item + size | |
1294 | self.count = 0 | |
1295 | else: | |
1296 | self.item = None | |
1297 | self.finish = None | |
1298 | ||
1299 | def __iter__(self): | |
1300 | return self | |
1301 | ||
1302 | def __next__(self): | |
1303 | if self.item == self.finish: | |
1304 | raise StopIteration | |
1305 | item = self.item.dereference() | |
1306 | count = self.count | |
1307 | self.count = self.count + 1 | |
1308 | self.item = self.item + 1 | |
1309 | path = item['_M_pathname'] | |
1310 | t = StdPathPrinter(item.type.name, item)._path_type() | |
1311 | if not t: | |
1312 | t = count | |
1313 | return ('[%s]' % t, path) | |
1314 | ||
1315 | def children(self): | |
1316 | return self._iterator(self.impl, self.typename) | |
1317 | ||
5924b28e | 1318 | |
785c6c31 | 1319 | class StdPairPrinter: |
1320 | "Print a std::pair object, with 'first' and 'second' as children" | |
1321 | ||
1322 | def __init__(self, typename, val): | |
1323 | self.val = val | |
1324 | ||
1325 | class _iter(Iterator): | |
1326 | "An iterator for std::pair types. Returns 'first' then 'second'." | |
1327 | ||
1328 | def __init__(self, val): | |
1329 | self.val = val | |
1330 | self.which = 'first' | |
1331 | ||
1332 | def __iter__(self): | |
1333 | return self | |
1334 | ||
1335 | def __next__(self): | |
1336 | if self.which is None: | |
1337 | raise StopIteration | |
1338 | which = self.which | |
1339 | if which == 'first': | |
1340 | self.which = 'second' | |
1341 | else: | |
1342 | self.which = None | |
1343 | return (which, self.val[which]) | |
1344 | ||
1345 | def children(self): | |
1346 | return self._iter(self.val) | |
1347 | ||
1348 | def to_string(self): | |
1349 | return None | |
1350 | ||
1351 | ||
510f22a9 | 1352 | # A "regular expression" printer which conforms to the |
1353 | # "SubPrettyPrinter" protocol from gdb.printing. | |
1354 | class RxPrinter(object): | |
1355 | def __init__(self, name, function): | |
1356 | super(RxPrinter, self).__init__() | |
1357 | self.name = name | |
1358 | self.function = function | |
1359 | self.enabled = True | |
1360 | ||
1361 | def invoke(self, value): | |
1362 | if not self.enabled: | |
1363 | return None | |
df1ac917 | 1364 | |
1365 | if value.type.code == gdb.TYPE_CODE_REF: | |
1366 | if hasattr(gdb.Value,"referenced_value"): | |
1367 | value = value.referenced_value() | |
1368 | ||
510f22a9 | 1369 | return self.function(self.name, value) |
1370 | ||
1371 | # A pretty-printer that conforms to the "PrettyPrinter" protocol from | |
1372 | # gdb.printing. It can also be used directly as an old-style printer. | |
1373 | class Printer(object): | |
1374 | def __init__(self, name): | |
1375 | super(Printer, self).__init__() | |
1376 | self.name = name | |
1377 | self.subprinters = [] | |
1378 | self.lookup = {} | |
1379 | self.enabled = True | |
f29d6b5d | 1380 | self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$') |
510f22a9 | 1381 | |
1382 | def add(self, name, function): | |
1383 | # A small sanity check. | |
1384 | # FIXME | |
f29d6b5d | 1385 | if not self.compiled_rx.match(name): |
3a30bda9 | 1386 | raise ValueError('libstdc++ programming error: "%s" does not match' % name) |
510f22a9 | 1387 | printer = RxPrinter(name, function) |
1388 | self.subprinters.append(printer) | |
1389 | self.lookup[name] = printer | |
b1986f6e | 1390 | |
cd587d4d | 1391 | # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION. |
1392 | def add_version(self, base, name, function): | |
1393 | self.add(base + name, function) | |
d813c3cd | 1394 | if _versioned_namespace: |
c730c800 | 1395 | vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % _versioned_namespace, base) |
1396 | self.add(vbase + name, function) | |
cd587d4d | 1397 | |
1398 | # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER. | |
1399 | def add_container(self, base, name, function): | |
1400 | self.add_version(base, name, function) | |
1401 | self.add_version(base + '__cxx1998::', name, function) | |
1402 | ||
510f22a9 | 1403 | @staticmethod |
1404 | def get_basic_type(type): | |
1405 | # If it points to a reference, get the reference. | |
1406 | if type.code == gdb.TYPE_CODE_REF: | |
1407 | type = type.target () | |
b1986f6e | 1408 | |
510f22a9 | 1409 | # Get the unqualified type, stripped of typedefs. |
1410 | type = type.unqualified ().strip_typedefs () | |
b1986f6e | 1411 | |
510f22a9 | 1412 | return type.tag |
b1986f6e | 1413 | |
510f22a9 | 1414 | def __call__(self, val): |
1415 | typename = self.get_basic_type(val.type) | |
1416 | if not typename: | |
1417 | return None | |
b1986f6e | 1418 | |
510f22a9 | 1419 | # All the types we match are template types, so we can use a |
1420 | # dictionary. | |
1421 | match = self.compiled_rx.match(typename) | |
1422 | if not match: | |
1423 | return None | |
b1986f6e | 1424 | |
510f22a9 | 1425 | basename = match.group(1) |
df1ac917 | 1426 | |
1427 | if val.type.code == gdb.TYPE_CODE_REF: | |
1428 | if hasattr(gdb.Value,"referenced_value"): | |
1429 | val = val.referenced_value() | |
1430 | ||
510f22a9 | 1431 | if basename in self.lookup: |
1432 | return self.lookup[basename].invoke(val) | |
b1986f6e | 1433 | |
510f22a9 | 1434 | # Cannot find a pretty printer. Return None. |
b1986f6e | 1435 | return None |
1436 | ||
510f22a9 | 1437 | libstdcxx_printer = None |
1438 | ||
a29af167 | 1439 | class TemplateTypePrinter(object): |
1dc84a99 | 1440 | r""" |
d4f6ff2a | 1441 | A type printer for class templates with default template arguments. |
a29af167 | 1442 | |
d4f6ff2a | 1443 | Recognizes specializations of class templates and prints them without |
1444 | any template arguments that use a default template argument. | |
1445 | Type printers are recursively applied to the template arguments. | |
a29af167 | 1446 | |
d4f6ff2a | 1447 | e.g. replace "std::vector<T, std::allocator<T> >" with "std::vector<T>". |
a29af167 | 1448 | """ |
1449 | ||
d4f6ff2a | 1450 | def __init__(self, name, defargs): |
a29af167 | 1451 | self.name = name |
d4f6ff2a | 1452 | self.defargs = defargs |
a29af167 | 1453 | self.enabled = True |
1454 | ||
1455 | class _recognizer(object): | |
d4f6ff2a | 1456 | "The recognizer class for TemplateTypePrinter." |
1457 | ||
1458 | def __init__(self, name, defargs): | |
1459 | self.name = name | |
1460 | self.defargs = defargs | |
1461 | # self.type_obj = None | |
a29af167 | 1462 | |
1463 | def recognize(self, type_obj): | |
d4f6ff2a | 1464 | """ |
1465 | If type_obj is a specialization of self.name that uses all the | |
1466 | default template arguments for the class template, then return | |
1467 | a string representation of the type without default arguments. | |
1468 | Otherwise, return None. | |
1469 | """ | |
1470 | ||
a29af167 | 1471 | if type_obj.tag is None: |
1472 | return None | |
1473 | ||
d4f6ff2a | 1474 | if not type_obj.tag.startswith(self.name): |
1475 | return None | |
1476 | ||
1477 | template_args = get_template_arg_list(type_obj) | |
1478 | displayed_args = [] | |
1479 | require_defaulted = False | |
1480 | for n in range(len(template_args)): | |
1481 | # The actual template argument in the type: | |
1482 | targ = template_args[n] | |
1483 | # The default template argument for the class template: | |
1484 | defarg = self.defargs.get(n) | |
1485 | if defarg is not None: | |
1486 | # Substitute other template arguments into the default: | |
1487 | defarg = defarg.format(*template_args) | |
1488 | # Fail to recognize the type (by returning None) | |
1489 | # unless the actual argument is the same as the default. | |
1490 | try: | |
1491 | if targ != gdb.lookup_type(defarg): | |
1492 | return None | |
1493 | except gdb.error: | |
1494 | # Type lookup failed, just use string comparison: | |
1495 | if targ.tag != defarg: | |
1496 | return None | |
1497 | # All subsequent args must have defaults: | |
1498 | require_defaulted = True | |
1499 | elif require_defaulted: | |
1500 | return None | |
1501 | else: | |
1502 | # Recursively apply recognizers to the template argument | |
1503 | # and add it to the arguments that will be displayed: | |
1504 | displayed_args.append(self._recognize_subtype(targ)) | |
1505 | ||
1506 | # This assumes no class templates in the nested-name-specifier: | |
1507 | template_name = type_obj.tag[0:type_obj.tag.find('<')] | |
1508 | template_name = strip_inline_namespaces(template_name) | |
1509 | ||
1510 | return template_name + '<' + ', '.join(displayed_args) + '>' | |
1511 | ||
1512 | def _recognize_subtype(self, type_obj): | |
1513 | """Convert a gdb.Type to a string by applying recognizers, | |
1514 | or if that fails then simply converting to a string.""" | |
1515 | ||
1516 | if type_obj.code == gdb.TYPE_CODE_PTR: | |
1517 | return self._recognize_subtype(type_obj.target()) + '*' | |
1518 | if type_obj.code == gdb.TYPE_CODE_ARRAY: | |
1519 | type_str = self._recognize_subtype(type_obj.target()) | |
1520 | if str(type_obj.strip_typedefs()).endswith('[]'): | |
1521 | return type_str + '[]' # array of unknown bound | |
1522 | return "%s[%d]" % (type_str, type_obj.range()[1] + 1) | |
1523 | if type_obj.code == gdb.TYPE_CODE_REF: | |
1524 | return self._recognize_subtype(type_obj.target()) + '&' | |
1525 | if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'): | |
1526 | if type_obj.code == gdb.TYPE_CODE_RVALUE_REF: | |
1527 | return self._recognize_subtype(type_obj.target()) + '&&' | |
1528 | ||
1529 | type_str = gdb.types.apply_type_recognizers( | |
1530 | gdb.types.get_type_recognizers(), type_obj) | |
1531 | if type_str: | |
1532 | return type_str | |
1533 | return str(type_obj) | |
a29af167 | 1534 | |
1535 | def instantiate(self): | |
d4f6ff2a | 1536 | "Return a recognizer object for this type printer." |
1537 | return self._recognizer(self.name, self.defargs) | |
a29af167 | 1538 | |
d4f6ff2a | 1539 | def add_one_template_type_printer(obj, name, defargs): |
1540 | r""" | |
1541 | Add a type printer for a class template with default template arguments. | |
1542 | ||
1543 | Args: | |
1544 | name (str): The template-name of the class template. | |
1545 | defargs (dict int:string) The default template arguments. | |
1546 | ||
1547 | Types in defargs can refer to the Nth template-argument using {N} | |
1548 | (with zero-based indices). | |
1549 | ||
1550 | e.g. 'unordered_map' has these defargs: | |
1551 | { 2: 'std::hash<{0}>', | |
1552 | 3: 'std::equal_to<{0}>', | |
1553 | 4: 'std::allocator<std::pair<const {0}, {1}> >' } | |
1554 | ||
1555 | """ | |
1556 | printer = TemplateTypePrinter('std::'+name, defargs) | |
a29af167 | 1557 | gdb.types.register_type_printer(obj, printer) |
d813c3cd | 1558 | if _versioned_namespace: |
1559 | # Add second type printer for same type in versioned namespace: | |
d4f6ff2a | 1560 | ns = 'std::' + _versioned_namespace |
63d7b064 | 1561 | # PR 86112 Cannot use dict comprehension here: |
1562 | defargs = dict((n, d.replace('std::', ns)) for (n,d) in defargs.items()) | |
d4f6ff2a | 1563 | printer = TemplateTypePrinter(ns+name, defargs) |
d813c3cd | 1564 | gdb.types.register_type_printer(obj, printer) |
a29af167 | 1565 | |
0ed3336a | 1566 | class FilteringTypePrinter(object): |
d4f6ff2a | 1567 | r""" |
1568 | A type printer that uses typedef names for common template specializations. | |
1569 | ||
1570 | Args: | |
1571 | match (str): The class template to recognize. | |
1572 | name (str): The typedef-name that will be used instead. | |
1573 | ||
1574 | Checks if a specialization of the class template 'match' is the same type | |
1575 | as the typedef 'name', and prints it as 'name' instead. | |
1576 | ||
1577 | e.g. if an instantiation of std::basic_istream<C, T> is the same type as | |
1578 | std::istream then print it as std::istream. | |
1579 | """ | |
1580 | ||
0ed3336a | 1581 | def __init__(self, match, name): |
1582 | self.match = match | |
1583 | self.name = name | |
1584 | self.enabled = True | |
1585 | ||
1586 | class _recognizer(object): | |
d4f6ff2a | 1587 | "The recognizer class for TemplateTypePrinter." |
1588 | ||
0ed3336a | 1589 | def __init__(self, match, name): |
1590 | self.match = match | |
1591 | self.name = name | |
1592 | self.type_obj = None | |
1593 | ||
1594 | def recognize(self, type_obj): | |
d4f6ff2a | 1595 | """ |
1596 | If type_obj starts with self.match and is the same type as | |
1597 | self.name then return self.name, otherwise None. | |
1598 | """ | |
0ed3336a | 1599 | if type_obj.tag is None: |
1600 | return None | |
1601 | ||
1602 | if self.type_obj is None: | |
d4f6ff2a | 1603 | if not type_obj.tag.startswith(self.match): |
0ed3336a | 1604 | # Filter didn't match. |
1605 | return None | |
1606 | try: | |
1607 | self.type_obj = gdb.lookup_type(self.name).strip_typedefs() | |
1608 | except: | |
1609 | pass | |
1610 | if self.type_obj == type_obj: | |
d4f6ff2a | 1611 | return strip_inline_namespaces(self.name) |
0ed3336a | 1612 | return None |
1613 | ||
1614 | def instantiate(self): | |
d4f6ff2a | 1615 | "Return a recognizer object for this type printer." |
0ed3336a | 1616 | return self._recognizer(self.match, self.name) |
1617 | ||
1618 | def add_one_type_printer(obj, match, name): | |
d4f6ff2a | 1619 | printer = FilteringTypePrinter('std::' + match, 'std::' + name) |
0ed3336a | 1620 | gdb.types.register_type_printer(obj, printer) |
d813c3cd | 1621 | if _versioned_namespace: |
d4f6ff2a | 1622 | ns = 'std::' + _versioned_namespace |
1623 | printer = FilteringTypePrinter(ns + match, ns + name) | |
d813c3cd | 1624 | gdb.types.register_type_printer(obj, printer) |
0ed3336a | 1625 | |
1626 | def register_type_printers(obj): | |
1627 | global _use_type_printing | |
1628 | ||
1629 | if not _use_type_printing: | |
1630 | return | |
1631 | ||
d4f6ff2a | 1632 | # Add type printers for typedefs std::string, std::wstring etc. |
1633 | for ch in ('', 'w', 'u16', 'u32'): | |
1634 | add_one_type_printer(obj, 'basic_string', ch + 'string') | |
6cfbd82f | 1635 | add_one_type_printer(obj, '__cxx11::basic_string', ch + 'string') |
1636 | # Typedefs for __cxx11::basic_string used to be in namespace __cxx11: | |
d4f6ff2a | 1637 | add_one_type_printer(obj, '__cxx11::basic_string', |
1638 | '__cxx11::' + ch + 'string') | |
1639 | add_one_type_printer(obj, 'basic_string_view', ch + 'string_view') | |
1640 | ||
1641 | # Add type printers for typedefs std::istream, std::wistream etc. | |
1642 | for ch in ('', 'w'): | |
1643 | for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream', | |
1644 | 'filebuf', 'ifstream', 'ofstream', 'fstream'): | |
1645 | add_one_type_printer(obj, 'basic_' + x, ch + x) | |
1646 | for x in ('stringbuf', 'istringstream', 'ostringstream', | |
1647 | 'stringstream'): | |
1648 | add_one_type_printer(obj, 'basic_' + x, ch + x) | |
6cfbd82f | 1649 | # <sstream> types are in __cxx11 namespace, but typedefs aren't: |
d4f6ff2a | 1650 | add_one_type_printer(obj, '__cxx11::basic_' + x, ch + x) |
1651 | ||
1652 | # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc. | |
1653 | for abi in ('', '__cxx11::'): | |
1654 | for ch in ('', 'w'): | |
1655 | add_one_type_printer(obj, abi + 'basic_regex', abi + ch + 'regex') | |
1656 | for ch in ('c', 's', 'wc', 'ws'): | |
1657 | add_one_type_printer(obj, abi + 'match_results', abi + ch + 'match') | |
1658 | for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'): | |
1659 | add_one_type_printer(obj, abi + x, abi + ch + x) | |
0ed3336a | 1660 | |
1661 | # Note that we can't have a printer for std::wstreampos, because | |
d4f6ff2a | 1662 | # it is the same type as std::streampos. |
0ed3336a | 1663 | add_one_type_printer(obj, 'fpos', 'streampos') |
d813c3cd | 1664 | |
d4f6ff2a | 1665 | # Add type printers for <chrono> typedefs. |
0ed3336a | 1666 | for dur in ('nanoseconds', 'microseconds', 'milliseconds', |
1667 | 'seconds', 'minutes', 'hours'): | |
1668 | add_one_type_printer(obj, 'duration', dur) | |
1669 | ||
d4f6ff2a | 1670 | # Add type printers for <random> typedefs. |
0ed3336a | 1671 | add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0') |
1672 | add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand') | |
1673 | add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937') | |
1674 | add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64') | |
1675 | add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base') | |
1676 | add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base') | |
1677 | add_one_type_printer(obj, 'discard_block_engine', 'ranlux24') | |
1678 | add_one_type_printer(obj, 'discard_block_engine', 'ranlux48') | |
1679 | add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b') | |
1680 | ||
d4f6ff2a | 1681 | # Add type printers for experimental::basic_string_view typedefs. |
1682 | ns = 'experimental::fundamentals_v1::' | |
1683 | for ch in ('', 'w', 'u16', 'u32'): | |
1684 | add_one_type_printer(obj, ns + 'basic_string_view', | |
1685 | ns + ch + 'string_view') | |
1686 | ||
1687 | # Do not show defaulted template arguments in class templates. | |
1688 | add_one_template_type_printer(obj, 'unique_ptr', | |
1689 | { 1: 'std::default_delete<{0}>' }) | |
1690 | add_one_template_type_printer(obj, 'deque', { 1: 'std::allocator<{0}>'}) | |
1691 | add_one_template_type_printer(obj, 'forward_list', { 1: 'std::allocator<{0}>'}) | |
1692 | add_one_template_type_printer(obj, 'list', { 1: 'std::allocator<{0}>'}) | |
1693 | add_one_template_type_printer(obj, '__cxx11::list', { 1: 'std::allocator<{0}>'}) | |
1694 | add_one_template_type_printer(obj, 'vector', { 1: 'std::allocator<{0}>'}) | |
1695 | add_one_template_type_printer(obj, 'map', | |
1696 | { 2: 'std::less<{0}>', | |
1697 | 3: 'std::allocator<std::pair<{0} const, {1}>>' }) | |
1698 | add_one_template_type_printer(obj, 'multimap', | |
1699 | { 2: 'std::less<{0}>', | |
1700 | 3: 'std::allocator<std::pair<{0} const, {1}>>' }) | |
1701 | add_one_template_type_printer(obj, 'set', | |
1702 | { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' }) | |
1703 | add_one_template_type_printer(obj, 'multiset', | |
1704 | { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' }) | |
1705 | add_one_template_type_printer(obj, 'unordered_map', | |
1706 | { 2: 'std::hash<{0}>', | |
1707 | 3: 'std::equal_to<{0}>', | |
1708 | 4: 'std::allocator<std::pair<{0} const, {1}>>'}) | |
1709 | add_one_template_type_printer(obj, 'unordered_multimap', | |
1710 | { 2: 'std::hash<{0}>', | |
1711 | 3: 'std::equal_to<{0}>', | |
1712 | 4: 'std::allocator<std::pair<{0} const, {1}>>'}) | |
1713 | add_one_template_type_printer(obj, 'unordered_set', | |
1714 | { 1: 'std::hash<{0}>', | |
1715 | 2: 'std::equal_to<{0}>', | |
1716 | 3: 'std::allocator<{0}>'}) | |
1717 | add_one_template_type_printer(obj, 'unordered_multiset', | |
1718 | { 1: 'std::hash<{0}>', | |
1719 | 2: 'std::equal_to<{0}>', | |
1720 | 3: 'std::allocator<{0}>'}) | |
a29af167 | 1721 | |
510f22a9 | 1722 | def register_libstdcxx_printers (obj): |
1723 | "Register libstdc++ pretty-printers with objfile Obj." | |
1724 | ||
1725 | global _use_gdb_pp | |
1726 | global libstdcxx_printer | |
1727 | ||
1728 | if _use_gdb_pp: | |
1729 | gdb.printing.register_pretty_printer(obj, libstdcxx_printer) | |
1730 | else: | |
1731 | if obj is None: | |
1732 | obj = gdb | |
1733 | obj.pretty_printers.append(libstdcxx_printer) | |
b1986f6e | 1734 | |
0ed3336a | 1735 | register_type_printers(obj) |
1736 | ||
b1986f6e | 1737 | def build_libstdcxx_dictionary (): |
510f22a9 | 1738 | global libstdcxx_printer |
1739 | ||
1740 | libstdcxx_printer = Printer("libstdc++-v6") | |
1741 | ||
b1986f6e | 1742 | # libstdc++ objects requiring pretty-printing. |
1743 | # In order from: | |
1744 | # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html | |
cd587d4d | 1745 | libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter) |
c730c800 | 1746 | libstdcxx_printer.add_version('std::__cxx11::', 'basic_string', StdStringPrinter) |
cd587d4d | 1747 | libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter) |
1748 | libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter) | |
1749 | libstdcxx_printer.add_container('std::', 'list', StdListPrinter) | |
0a9343a8 | 1750 | libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter) |
cd587d4d | 1751 | libstdcxx_printer.add_container('std::', 'map', StdMapPrinter) |
1752 | libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter) | |
1753 | libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter) | |
785c6c31 | 1754 | libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter) |
cd587d4d | 1755 | libstdcxx_printer.add_version('std::', 'priority_queue', |
1756 | StdStackOrQueuePrinter) | |
1757 | libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter) | |
1758 | libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter) | |
1759 | libstdcxx_printer.add_container('std::', 'set', StdSetPrinter) | |
1760 | libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter) | |
1761 | libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter) | |
1762 | libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter) | |
b1986f6e | 1763 | # vector<bool> |
1764 | ||
19791f4a | 1765 | # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG. |
510f22a9 | 1766 | libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter) |
1767 | libstdcxx_printer.add('std::__debug::deque', StdDequePrinter) | |
1768 | libstdcxx_printer.add('std::__debug::list', StdListPrinter) | |
1769 | libstdcxx_printer.add('std::__debug::map', StdMapPrinter) | |
1770 | libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter) | |
1771 | libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter) | |
1772 | libstdcxx_printer.add('std::__debug::priority_queue', | |
1773 | StdStackOrQueuePrinter) | |
1774 | libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter) | |
1775 | libstdcxx_printer.add('std::__debug::set', StdSetPrinter) | |
1776 | libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter) | |
1777 | libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter) | |
1778 | libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter) | |
19791f4a | 1779 | |
e11be3ea | 1780 | # These are the TR1 and C++11 printers. |
b1986f6e | 1781 | # For array - the default GDB pretty-printer seems reasonable. |
6c2e05ff | 1782 | libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter) |
1783 | libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter) | |
cd587d4d | 1784 | libstdcxx_printer.add_container('std::', 'unordered_map', |
1785 | Tr1UnorderedMapPrinter) | |
1786 | libstdcxx_printer.add_container('std::', 'unordered_set', | |
1787 | Tr1UnorderedSetPrinter) | |
1788 | libstdcxx_printer.add_container('std::', 'unordered_multimap', | |
1789 | Tr1UnorderedMapPrinter) | |
1790 | libstdcxx_printer.add_container('std::', 'unordered_multiset', | |
1791 | Tr1UnorderedSetPrinter) | |
1792 | libstdcxx_printer.add_container('std::', 'forward_list', | |
1793 | StdForwardListPrinter) | |
1794 | ||
c730c800 | 1795 | libstdcxx_printer.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter) |
1796 | libstdcxx_printer.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter) | |
1797 | libstdcxx_printer.add_version('std::tr1::', 'unordered_map', | |
cd587d4d | 1798 | Tr1UnorderedMapPrinter) |
c730c800 | 1799 | libstdcxx_printer.add_version('std::tr1::', 'unordered_set', |
cd587d4d | 1800 | Tr1UnorderedSetPrinter) |
c730c800 | 1801 | libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap', |
cd587d4d | 1802 | Tr1UnorderedMapPrinter) |
c730c800 | 1803 | libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset', |
cd587d4d | 1804 | Tr1UnorderedSetPrinter) |
b1986f6e | 1805 | |
e11be3ea | 1806 | # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases. |
cbd50187 | 1807 | # The tr1 namespace containers do not have any debug equivalents, |
1808 | # so do not register printers for them. | |
510f22a9 | 1809 | libstdcxx_printer.add('std::__debug::unordered_map', |
1810 | Tr1UnorderedMapPrinter) | |
1811 | libstdcxx_printer.add('std::__debug::unordered_set', | |
1812 | Tr1UnorderedSetPrinter) | |
1813 | libstdcxx_printer.add('std::__debug::unordered_multimap', | |
1814 | Tr1UnorderedMapPrinter) | |
1815 | libstdcxx_printer.add('std::__debug::unordered_multiset', | |
1816 | Tr1UnorderedSetPrinter) | |
3c80034b | 1817 | libstdcxx_printer.add('std::__debug::forward_list', |
1818 | StdForwardListPrinter) | |
19791f4a | 1819 | |
f29d6b5d | 1820 | # Library Fundamentals TS components |
1821 | libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', | |
1822 | 'any', StdExpAnyPrinter) | |
1823 | libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', | |
1824 | 'optional', StdExpOptionalPrinter) | |
1825 | libstdcxx_printer.add_version('std::experimental::fundamentals_v1::', | |
1826 | 'basic_string_view', StdExpStringViewPrinter) | |
5924b28e | 1827 | # Filesystem TS components |
1828 | libstdcxx_printer.add_version('std::experimental::filesystem::v1::', | |
1829 | 'path', StdExpPathPrinter) | |
d1eff9de | 1830 | libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::', |
5924b28e | 1831 | 'path', StdExpPathPrinter) |
3b90ed62 | 1832 | libstdcxx_printer.add_version('std::filesystem::', |
6bec006a | 1833 | 'path', StdPathPrinter) |
3b90ed62 | 1834 | libstdcxx_printer.add_version('std::filesystem::__cxx11::', |
6bec006a | 1835 | 'path', StdPathPrinter) |
b1986f6e | 1836 | |
e11be3ea | 1837 | # C++17 components |
1838 | libstdcxx_printer.add_version('std::', | |
1839 | 'any', StdExpAnyPrinter) | |
1840 | libstdcxx_printer.add_version('std::', | |
1841 | 'optional', StdExpOptionalPrinter) | |
1842 | libstdcxx_printer.add_version('std::', | |
1843 | 'basic_string_view', StdExpStringViewPrinter) | |
1844 | libstdcxx_printer.add_version('std::', | |
1845 | 'variant', StdVariantPrinter) | |
67218f06 | 1846 | libstdcxx_printer.add_version('std::', |
1847 | '_Node_handle', StdNodeHandlePrinter) | |
e11be3ea | 1848 | |
b1986f6e | 1849 | # Extensions. |
cd587d4d | 1850 | libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter) |
b1986f6e | 1851 | |
1852 | if True: | |
1853 | # These shouldn't be necessary, if GDB "print *i" worked. | |
1854 | # But it often doesn't, so here they are. | |
cd587d4d | 1855 | libstdcxx_printer.add_container('std::', '_List_iterator', |
1856 | StdListIteratorPrinter) | |
1857 | libstdcxx_printer.add_container('std::', '_List_const_iterator', | |
1858 | StdListIteratorPrinter) | |
1859 | libstdcxx_printer.add_version('std::', '_Rb_tree_iterator', | |
1860 | StdRbtreeIteratorPrinter) | |
1861 | libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator', | |
1862 | StdRbtreeIteratorPrinter) | |
1863 | libstdcxx_printer.add_container('std::', '_Deque_iterator', | |
1864 | StdDequeIteratorPrinter) | |
1865 | libstdcxx_printer.add_container('std::', '_Deque_const_iterator', | |
1866 | StdDequeIteratorPrinter) | |
1867 | libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator', | |
1868 | StdVectorIteratorPrinter) | |
1869 | libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator', | |
1870 | StdSlistIteratorPrinter) | |
8c1baff7 | 1871 | libstdcxx_printer.add_container('std::', '_Fwd_list_iterator', |
1872 | StdFwdListIteratorPrinter) | |
1873 | libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator', | |
1874 | StdFwdListIteratorPrinter) | |
510f22a9 | 1875 | |
1876 | # Debug (compiled with -D_GLIBCXX_DEBUG) printer | |
db4f7f88 | 1877 | # registrations. |
510f22a9 | 1878 | libstdcxx_printer.add('__gnu_debug::_Safe_iterator', |
1879 | StdDebugIteratorPrinter) | |
b1986f6e | 1880 | |
1881 | build_libstdcxx_dictionary () |