]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/python/libstdcxx/v6/printers.py
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / python / libstdcxx / v6 / printers.py
CommitLineData
cdd1ba62 1# Pretty-printers for libstdc++.
41850419 2
83ffe9cd 3# Copyright (C) 2008-2023 Free Software Foundation, Inc.
41850419
TT
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
d1f736a2 18import gdb
41850419
TT
19import itertools
20import re
2db38d9f 21import sys, os, errno
80ff207d 22import datetime
cdd1ba62
SB
23
24### Python 2 + Python 3 compatibility code
25
26# Resources about compatibility:
27#
28# * <http://pythonhosted.org/six/>: Documentation of the "six" module
29
30# FIXME: The handling of e.g. std::basic_string (at least on char)
31# probably needs updating to work with Python 3's new string rules.
32#
33# In particular, Python 3 has a separate type (called byte) for
34# bytestrings, and a special b"" syntax for the byte literals; the old
35# str() type has been redefined to always store Unicode text.
36#
37# We probably can't do much about this until this GDB PR is addressed:
38# <https://sourceware.org/bugzilla/show_bug.cgi?id=17138>
39
40if sys.version_info[0] > 2:
41 ### Python 3 stuff
42 Iterator = object
43 # Python 3 folds these into the normal functions.
44 imap = map
45 izip = zip
46 # Also, int subsumes long
47 long = int
80ff207d 48 _utc_timezone = datetime.timezone.utc
cdd1ba62
SB
49else:
50 ### Python 2 stuff
51 class Iterator:
52 """Compatibility mixin for iterators
53
54 Instead of writing next() methods for iterators, write
55 __next__() methods and use this mixin to make them work in
56 Python 2 as well as Python 3.
57
58 Idea stolen from the "six" documentation:
59 <http://pythonhosted.org/six/#six.Iterator>
60 """
61
62 def next(self):
63 return self.__next__()
64
65 # In Python 2, we still need these from itertools
66 from itertools import imap, izip
41850419 67
80ff207d
JW
68 # Python 2 does not provide the datetime.UTC singleton.
69 class UTC(datetime.tzinfo):
70 """Concrete tzinfo class representing the UTC time zone"""
71
72 def utcoffset(self, dt):
73 return datetime.timedelta(0)
74
75 def tzname(self, dt):
76 return "UTC"
77
78 def dst(self, dt):
79 return datetime.timedelta(0)
80 _utc_timezone = UTC()
81
d63c53cc
TT
82# Try to use the new-style pretty-printing if available.
83_use_gdb_pp = True
84try:
85 import gdb.printing
86except ImportError:
87 _use_gdb_pp = False
88
50605a7f
TT
89# Try to install type-printers.
90_use_type_printing = False
91try:
92 import gdb.types
93 if hasattr(gdb.types, 'TypePrinter'):
94 _use_type_printing = True
95except ImportError:
96 pass
97
3efe2bf7
TT
98# Starting with the type ORIG, search for the member type NAME. This
99# handles searching upward through superclasses. This is needed to
100# work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
101def find_type(orig, name):
102 typ = orig.strip_typedefs()
103 while True:
9dacc828
JW
104 # Use Type.tag to ignore cv-qualifiers. PR 67440.
105 search = '%s::%s' % (typ.tag, name)
3efe2bf7
TT
106 try:
107 return gdb.lookup_type(search)
108 except RuntimeError:
109 pass
110 # The type was not found, so try the superclass. We only need
111 # to check the first superclass, so we don't bother with
112 # anything fancier here.
9d50a6a7
JW
113 fields = typ.fields()
114 if len(fields) and fields[0].is_base_class:
115 typ = fields[0].type
116 else:
47059228 117 raise ValueError("Cannot find type %s::%s" % (str(orig), name))
3efe2bf7 118
87c7063d 119_versioned_namespace = '__8::'
f9a27859 120
9d50a6a7
JW
121def lookup_templ_spec(templ, *args):
122 """
123 Lookup template specialization templ<args...>
124 """
125 t = '{}<{}>'.format(templ, ', '.join([str(a) for a in args]))
126 try:
127 return gdb.lookup_type(t)
128 except gdb.error as e:
129 # Type not found, try again in versioned namespace.
130 global _versioned_namespace
131 if _versioned_namespace and _versioned_namespace not in templ:
132 t = t.replace('::', '::' + _versioned_namespace, 1)
133 try:
134 return gdb.lookup_type(t)
135 except gdb.error:
136 # If that also fails, rethrow the original exception
137 pass
138 raise e
139
140# Use this to find container node types instead of find_type,
141# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91997 for details.
142def lookup_node_type(nodename, containertype):
143 """
144 Lookup specialization of template NODENAME corresponding to CONTAINERTYPE.
145 e.g. if NODENAME is '_List_node' and CONTAINERTYPE is std::list<int>
146 then return the type std::_List_node<int>.
147 Returns None if not found.
148 """
149 # If nodename is unqualified, assume it's in namespace std.
150 if '::' not in nodename:
151 nodename = 'std::' + nodename
152 try:
153 valtype = find_type(containertype, 'value_type')
154 except:
155 valtype = containertype.template_argument(0)
156 valtype = valtype.strip_typedefs()
157 try:
158 return lookup_templ_spec(nodename, valtype)
159 except gdb.error as e:
160 # For debug mode containers the node is in std::__cxx1998.
161 if is_member_of_namespace(nodename, 'std'):
162 if is_member_of_namespace(containertype, 'std::__cxx1998',
163 'std::__debug', '__gnu_debug'):
164 nodename = nodename.replace('::', '::__cxx1998::', 1)
9d50a6a7
JW
165 try:
166 return lookup_templ_spec(nodename, valtype)
167 except gdb.error:
168 pass
169 return None
170
171def is_member_of_namespace(typ, *namespaces):
172 """
173 Test whether a type is a member of one of the specified namespaces.
174 The type can be specified as a string or a gdb.Type object.
175 """
176 if type(typ) is gdb.Type:
177 typ = str(typ)
178 typ = strip_versioned_namespace(typ)
179 for namespace in namespaces:
180 if typ.startswith(namespace + '::'):
181 return True
182 return False
183
478490f6 184def is_specialization_of(x, template_name):
92281622
JW
185 """
186 Test whether a type is a specialization of the named class template.
187 The type can be specified as a string or a gdb.Type object.
188 The template should be the name of a class template as a string,
189 without any 'std' qualification.
190 """
f9a27859 191 global _versioned_namespace
478490f6
JW
192 if type(x) is gdb.Type:
193 x = x.tag
f9a27859 194 if _versioned_namespace:
478490f6
JW
195 return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None
196 return re.match('^std::%s<.*>$' % template_name, x) is not None
f9a27859
FD
197
198def strip_versioned_namespace(typename):
199 global _versioned_namespace
200 if _versioned_namespace:
201 return typename.replace(_versioned_namespace, '')
202 return typename
203
bab0a26d
JW
204def strip_inline_namespaces(type_str):
205 "Remove known inline namespaces from the canonical name of a type."
206 type_str = strip_versioned_namespace(type_str)
207 type_str = type_str.replace('std::__cxx11::', 'std::')
208 expt_ns = 'std::experimental::'
209 for lfts_ns in ('fundamentals_v1', 'fundamentals_v2'):
210 type_str = type_str.replace(expt_ns+lfts_ns+'::', expt_ns)
211 fs_ns = expt_ns + 'filesystem::'
212 type_str = type_str.replace(fs_ns+'v1::', fs_ns)
213 return type_str
214
215def get_template_arg_list(type_obj):
216 "Return a type's template arguments as a list"
217 n = 0
218 template_args = []
219 while True:
220 try:
221 template_args.append(type_obj.template_argument(n))
222 except:
223 return template_args
224 n += 1
225
d2dfcf82
JO
226class SmartPtrIterator(Iterator):
227 "An iterator for smart pointer types with a single 'child' value"
228
229 def __init__(self, val):
230 self.val = val
231
232 def __iter__(self):
233 return self
234
235 def __next__(self):
236 if self.val is None:
237 raise StopIteration
238 self.val, val = None, self.val
239 return ('get()', val)
240
a1527f2f 241class SharedPointerPrinter:
a8495845 242 "Print a shared_ptr, weak_ptr, atomic<shared_ptr>, or atomic<weak_ptr>"
41850419
TT
243
244 def __init__ (self, typename, val):
f9a27859 245 self.typename = strip_versioned_namespace(typename)
41850419 246 self.val = val
d2dfcf82
JO
247 self.pointer = val['_M_ptr']
248
249 def children (self):
250 return SmartPtrIterator(self.pointer)
41850419 251
a8495845
JW
252 # Return the _Sp_counted_base<>* that holds the refcounts.
253 def _get_refcounts (self):
254 if self.typename == 'std::atomic':
255 # A tagged pointer is stored as uintptr_t.
256 ptr_val = self.val['_M_refcount']['_M_val']['_M_i']
257 ptr_val = ptr_val - (ptr_val % 2) # clear lock bit
258 ptr_type = find_type(self.val['_M_refcount'].type, 'pointer')
259 return ptr_val.cast(ptr_type)
260 return self.val['_M_refcount']['_M_pi']
261
41850419 262 def to_string (self):
a1527f2f 263 state = 'empty'
a8495845
JW
264 refcounts = self._get_refcounts()
265 targ = self.val.type.template_argument(0)
634b0089 266 targ = strip_versioned_namespace(str(targ))
a8495845 267
a1527f2f
JW
268 if refcounts != 0:
269 usecount = refcounts['_M_use_count']
270 weakcount = refcounts['_M_weak_count']
271 if usecount == 0:
d2dfcf82 272 state = 'expired, weak count %d' % weakcount
a1527f2f 273 else:
d2dfcf82 274 state = 'use count %d, weak count %d' % (usecount, weakcount - 1)
634b0089 275 return '%s<%s> (%s)' % (self.typename, targ, state)
41850419 276
a634928f
JW
277def _tuple_impl_get(val):
278 "Return the tuple element stored in a _Tuple_impl<N, T> base class."
279 bases = val.type.fields()
280 if not bases[-1].is_base_class:
281 raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type))
282 # Get the _Head_base<N, T> base class:
283 head_base = val.cast(bases[-1].type)
284 fields = head_base.type.fields()
285 if len(fields) == 0:
286 raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type))
287 if fields[0].name == '_M_head_impl':
288 # The tuple element is the _Head_base::_M_head_impl data member.
289 return head_base['_M_head_impl']
290 elif fields[0].is_base_class:
291 # The tuple element is an empty base class of _Head_base.
292 # Cast to that empty base class.
293 return head_base.cast(fields[0].type)
294 else:
295 raise ValueError("Unsupported implementation for std::tuple: %s" % str(val.type))
296
297def tuple_get(n, val):
298 "Return the result of std::get<n>(val) on a std::tuple"
299 tuple_size = len(get_template_arg_list(val.type))
300 if n > tuple_size:
301 raise ValueError("Out of range index for std::get<N> on std::tuple")
302 # Get the first _Tuple_impl<0, T...> base class:
303 node = val.cast(val.type.fields()[0].type)
304 while n > 0:
305 # Descend through the base classes until the Nth one.
306 node = node.cast(node.type.fields()[0].type)
307 n -= 1
308 return _tuple_impl_get(node)
309
310def unique_ptr_get(val):
311 "Return the result of val.get() on a std::unique_ptr"
312 # std::unique_ptr<T, D> contains a std::tuple<D::pointer, D>,
313 # either as a direct data member _M_t (the old implementation)
314 # or within a data member of type __uniq_ptr_data.
315 impl_type = val.type.fields()[0].type.strip_typedefs()
316 # Check for new implementations first:
317 if is_specialization_of(impl_type, '__uniq_ptr_data') \
318 or is_specialization_of(impl_type, '__uniq_ptr_impl'):
319 tuple_member = val['_M_t']['_M_t']
320 elif is_specialization_of(impl_type, 'tuple'):
321 tuple_member = val['_M_t']
322 else:
323 raise ValueError("Unsupported implementation for unique_ptr: %s" % str(impl_type))
324 return tuple_get(0, tuple_member)
325
41850419
TT
326class UniquePointerPrinter:
327 "Print a unique_ptr"
328
d63c53cc 329 def __init__ (self, typename, val):
41850419 330 self.val = val
d2dfcf82
JO
331
332 def children (self):
a634928f 333 return SmartPtrIterator(unique_ptr_get(self.val))
d2dfcf82
JO
334
335 def to_string (self):
8273aa77 336 return ('std::unique_ptr<%s>' % (str(self.val.type.template_argument(0))))
41850419 337
2dbe56bd
JW
338def get_value_from_aligned_membuf(buf, valtype):
339 """Returns the value held in a __gnu_cxx::__aligned_membuf."""
340 return buf['_M_storage'].address.cast(valtype.pointer()).dereference()
341
cc7f3d0e
JW
342def get_value_from_list_node(node):
343 """Returns the value held in an _List_node<_Val>"""
344 try:
345 member = node.type.fields()[1].name
346 if member == '_M_data':
347 # C++03 implementation, node contains the value as a member
348 return node['_M_data']
349 elif member == '_M_storage':
350 # C++11 implementation, node stores value in __aligned_membuf
2dbe56bd
JW
351 valtype = node.type.template_argument(0)
352 return get_value_from_aligned_membuf(node['_M_storage'], valtype)
cc7f3d0e
JW
353 except:
354 pass
355 raise ValueError("Unsupported implementation for %s" % str(node.type))
356
41850419
TT
357class StdListPrinter:
358 "Print a std::list"
359
cdd1ba62 360 class _iterator(Iterator):
41850419
TT
361 def __init__(self, nodetype, head):
362 self.nodetype = nodetype
363 self.base = head['_M_next']
364 self.head = head.address
365 self.count = 0
366
367 def __iter__(self):
368 return self
369
cdd1ba62 370 def __next__(self):
41850419
TT
371 if self.base == self.head:
372 raise StopIteration
373 elt = self.base.cast(self.nodetype).dereference()
374 self.base = elt['_M_next']
375 count = self.count
376 self.count = self.count + 1
cc7f3d0e
JW
377 val = get_value_from_list_node(elt)
378 return ('[%d]' % count, val)
41850419 379
cd0961a5 380 def __init__(self, typename, val):
f9a27859 381 self.typename = strip_versioned_namespace(typename)
41850419
TT
382 self.val = val
383
384 def children(self):
9d50a6a7 385 nodetype = lookup_node_type('_List_node', self.val.type).pointer()
41850419
TT
386 return self._iterator(nodetype, self.val['_M_impl']['_M_node'])
387
388 def to_string(self):
9d50a6a7
JW
389 headnode = self.val['_M_impl']['_M_node']
390 if headnode['_M_next'] == headnode.address:
cd0961a5
PM
391 return 'empty %s' % (self.typename)
392 return '%s' % (self.typename)
41850419 393
fe6bd21a 394class NodeIteratorPrinter:
9d50a6a7 395 def __init__(self, typename, val, contname, nodename):
41850419 396 self.val = val
cd0961a5 397 self.typename = typename
fe6bd21a 398 self.contname = contname
9d50a6a7 399 self.nodetype = lookup_node_type(nodename, val.type)
41850419
TT
400
401 def to_string(self):
bdfc9f5c 402 if not self.val['_M_node']:
fe6bd21a 403 return 'non-dereferenceable iterator for std::%s' % (self.contname)
9d50a6a7 404 node = self.val['_M_node'].cast(self.nodetype.pointer()).dereference()
50a8a941 405 return str(get_value_from_list_node(node))
41850419 406
fe6bd21a
FD
407class StdListIteratorPrinter(NodeIteratorPrinter):
408 "Print std::list::iterator"
409
410 def __init__(self, typename, val):
9d50a6a7 411 NodeIteratorPrinter.__init__(self, typename, val, 'list', '_List_node')
fe6bd21a
FD
412
413class StdFwdListIteratorPrinter(NodeIteratorPrinter):
414 "Print std::forward_list::iterator"
415
416 def __init__(self, typename, val):
9d50a6a7
JW
417 NodeIteratorPrinter.__init__(self, typename, val, 'forward_list',
418 '_Fwd_list_node')
fe6bd21a 419
41850419
TT
420class StdSlistPrinter:
421 "Print a __gnu_cxx::slist"
422
cdd1ba62 423 class _iterator(Iterator):
41850419
TT
424 def __init__(self, nodetype, head):
425 self.nodetype = nodetype
426 self.base = head['_M_head']['_M_next']
427 self.count = 0
428
429 def __iter__(self):
430 return self
431
cdd1ba62 432 def __next__(self):
41850419
TT
433 if self.base == 0:
434 raise StopIteration
435 elt = self.base.cast(self.nodetype).dereference()
436 self.base = elt['_M_next']
437 count = self.count
438 self.count = self.count + 1
439 return ('[%d]' % count, elt['_M_data'])
440
d63c53cc 441 def __init__(self, typename, val):
41850419
TT
442 self.val = val
443
444 def children(self):
9d50a6a7
JW
445 nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self.val.type)
446 return self._iterator(nodetype.pointer(), self.val)
41850419
TT
447
448 def to_string(self):
449 if self.val['_M_head']['_M_next'] == 0:
450 return 'empty __gnu_cxx::slist'
451 return '__gnu_cxx::slist'
452
453class StdSlistIteratorPrinter:
454 "Print __gnu_cxx::slist::iterator"
455
d63c53cc 456 def __init__(self, typename, val):
41850419
TT
457 self.val = val
458
459 def to_string(self):
bdfc9f5c
JW
460 if not self.val['_M_node']:
461 return 'non-dereferenceable iterator for __gnu_cxx::slist'
9d50a6a7 462 nodetype = lookup_node_type('__gnu_cxx::_Slist_node', self.val.type).pointer()
50a8a941 463 return str(self.val['_M_node'].cast(nodetype).dereference()['_M_data'])
41850419
TT
464
465class StdVectorPrinter:
466 "Print a std::vector"
467
cdd1ba62 468 class _iterator(Iterator):
7bf7b578
CM
469 def __init__ (self, start, finish, bitvec):
470 self.bitvec = bitvec
471 if bitvec:
472 self.item = start['_M_p']
6f00ccba 473 self.so = 0
7bf7b578
CM
474 self.finish = finish['_M_p']
475 self.fo = finish['_M_offset']
476 itype = self.item.dereference().type
477 self.isize = 8 * itype.sizeof
478 else:
479 self.item = start
480 self.finish = finish
41850419
TT
481 self.count = 0
482
483 def __iter__(self):
484 return self
485
cdd1ba62 486 def __next__(self):
41850419
TT
487 count = self.count
488 self.count = self.count + 1
7bf7b578
CM
489 if self.bitvec:
490 if self.item == self.finish and self.so >= self.fo:
491 raise StopIteration
36d0dada 492 elt = bool(self.item.dereference() & (1 << self.so))
7bf7b578
CM
493 self.so = self.so + 1
494 if self.so >= self.isize:
495 self.item = self.item + 1
496 self.so = 0
36d0dada 497 return ('[%d]' % count, elt)
7bf7b578
CM
498 else:
499 if self.item == self.finish:
500 raise StopIteration
501 elt = self.item.dereference()
502 self.item = self.item + 1
503 return ('[%d]' % count, elt)
41850419 504
cd0961a5 505 def __init__(self, typename, val):
f9a27859 506 self.typename = strip_versioned_namespace(typename)
41850419 507 self.val = val
36d0dada 508 self.is_bool = val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL
41850419
TT
509
510 def children(self):
511 return self._iterator(self.val['_M_impl']['_M_start'],
7bf7b578
CM
512 self.val['_M_impl']['_M_finish'],
513 self.is_bool)
41850419
TT
514
515 def to_string(self):
516 start = self.val['_M_impl']['_M_start']
517 finish = self.val['_M_impl']['_M_finish']
518 end = self.val['_M_impl']['_M_end_of_storage']
7bf7b578
CM
519 if self.is_bool:
520 start = self.val['_M_impl']['_M_start']['_M_p']
7bf7b578
CM
521 finish = self.val['_M_impl']['_M_finish']['_M_p']
522 fo = self.val['_M_impl']['_M_finish']['_M_offset']
523 itype = start.dereference().type
524 bl = 8 * itype.sizeof
6f00ccba 525 length = bl * (finish - start) + fo
7bf7b578
CM
526 capacity = bl * (end - start)
527 return ('%s<bool> of length %d, capacity %d'
528 % (self.typename, int (length), int (capacity)))
529 else:
530 return ('%s of length %d, capacity %d'
531 % (self.typename, int (finish - start), int (end - start)))
41850419
TT
532
533 def display_hint(self):
534 return 'array'
535
536class StdVectorIteratorPrinter:
537 "Print std::vector::iterator"
538
d63c53cc 539 def __init__(self, typename, val):
41850419
TT
540 self.val = val
541
542 def to_string(self):
bdfc9f5c
JW
543 if not self.val['_M_current']:
544 return 'non-dereferenceable iterator for std::vector'
50a8a941 545 return str(self.val['_M_current'].dereference())
41850419 546
39836f83
MW
547class StdBitIteratorPrinter:
548 "Print std::vector<bool>'s _Bit_iterator and _Bit_const_iterator"
549
550 def __init__(self, typename, val):
551 self.val = val
552
553 def to_string(self):
554 if not self.val['_M_p']:
555 return 'non-dereferenceable iterator for std::vector<bool>'
556 return bool(self.val['_M_p'].dereference() & (1 << self.val['_M_offset']))
557
558class StdBitReferencePrinter:
c883d1dc 559 "Print std::vector<bool>::reference"
39836f83
MW
560
561 def __init__(self, typename, val):
562 self.val = val
563
564 def to_string(self):
565 if not self.val['_M_p']:
c883d1dc 566 return 'invalid std::vector<bool>::reference'
39836f83 567 return bool(self.val['_M_p'].dereference() & (self.val['_M_mask']))
36d0dada 568
8345c8e4
PM
569class StdTuplePrinter:
570 "Print a std::tuple"
571
cdd1ba62 572 class _iterator(Iterator):
478490f6
JW
573 @staticmethod
574 def _is_nonempty_tuple (nodes):
575 if len (nodes) == 2:
576 if is_specialization_of (nodes[1].type, '__tuple_base'):
577 return True
578 elif len (nodes) == 1:
579 return True
580 elif len (nodes) == 0:
581 return False
582 raise ValueError("Top of tuple tree does not consist of a single node.")
583
8345c8e4
PM
584 def __init__ (self, head):
585 self.head = head
586
587 # Set the base class as the initial head of the
588 # tuple.
589 nodes = self.head.type.fields ()
478490f6 590 if self._is_nonempty_tuple (nodes):
9dacb44b
JW
591 # Set the actual head to the first pair.
592 self.head = self.head.cast (nodes[0].type)
8345c8e4
PM
593 self.count = 0
594
595 def __iter__ (self):
596 return self
597
cdd1ba62 598 def __next__ (self):
8345c8e4 599 # Check for further recursions in the inheritance tree.
deaa1ccb
JW
600 # For a GCC 5+ tuple self.head is None after visiting all nodes:
601 if not self.head:
602 raise StopIteration
603 nodes = self.head.type.fields ()
604 # For a GCC 4.x tuple there is a final node with no fields:
8345c8e4
PM
605 if len (nodes) == 0:
606 raise StopIteration
607 # Check that this iteration has an expected structure.
deaa1ccb 608 if len (nodes) > 2:
47059228 609 raise ValueError("Cannot parse more than 2 nodes in a tuple tree.")
8345c8e4 610
deaa1ccb
JW
611 if len (nodes) == 1:
612 # This is the last node of a GCC 5+ std::tuple.
613 impl = self.head.cast (nodes[0].type)
614 self.head = None
615 else:
616 # Either a node before the last node, or the last node of
617 # a GCC 4.x tuple (which has an empty parent).
618
619 # - Left node is the next recursion parent.
620 # - Right node is the actual class contained in the tuple.
8345c8e4 621
deaa1ccb
JW
622 # Process right node.
623 impl = self.head.cast (nodes[1].type)
624
625 # Process left node and set it as head.
626 self.head = self.head.cast (nodes[0].type)
8345c8e4 627
8345c8e4
PM
628 self.count = self.count + 1
629
630 # Finally, check the implementation. If it is
631 # wrapped in _M_head_impl return that, otherwise return
632 # the value "as is".
633 fields = impl.type.fields ()
634 if len (fields) < 1 or fields[0].name != "_M_head_impl":
07568376 635 return ('[%d]' % (self.count - 1), impl)
8345c8e4 636 else:
07568376 637 return ('[%d]' % (self.count - 1), impl['_M_head_impl'])
8345c8e4
PM
638
639 def __init__ (self, typename, val):
f9a27859 640 self.typename = strip_versioned_namespace(typename)
8345c8e4
PM
641 self.val = val;
642
643 def children (self):
644 return self._iterator (self.val)
645
646 def to_string (self):
9dacb44b
JW
647 if len (self.val.type.fields ()) == 0:
648 return 'empty %s' % (self.typename)
8345c8e4
PM
649 return '%s containing' % (self.typename)
650
41850419
TT
651class StdStackOrQueuePrinter:
652 "Print a std::stack or std::queue"
653
654 def __init__ (self, typename, val):
f9a27859 655 self.typename = strip_versioned_namespace(typename)
41850419
TT
656 self.visualizer = gdb.default_visualizer(val['c'])
657
658 def children (self):
659 return self.visualizer.children()
660
661 def to_string (self):
662 return '%s wrapping: %s' % (self.typename,
663 self.visualizer.to_string())
664
665 def display_hint (self):
666 if hasattr (self.visualizer, 'display_hint'):
667 return self.visualizer.display_hint ()
668 return None
669
cdd1ba62 670class RbtreeIterator(Iterator):
7224c6a9
JW
671 """
672 Turn an RB-tree-based container (std::map, std::set etc.) into
673 a Python iterable object.
674 """
675
41850419
TT
676 def __init__(self, rbtree):
677 self.size = rbtree['_M_t']['_M_impl']['_M_node_count']
678 self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
679 self.count = 0
680
681 def __iter__(self):
682 return self
683
684 def __len__(self):
685 return int (self.size)
686
cdd1ba62 687 def __next__(self):
41850419
TT
688 if self.count == self.size:
689 raise StopIteration
690 result = self.node
691 self.count = self.count + 1
692 if self.count < self.size:
693 # Compute the next node.
694 node = self.node
695 if node.dereference()['_M_right']:
696 node = node.dereference()['_M_right']
697 while node.dereference()['_M_left']:
698 node = node.dereference()['_M_left']
699 else:
700 parent = node.dereference()['_M_parent']
701 while node == parent.dereference()['_M_right']:
702 node = parent
703 parent = parent.dereference()['_M_parent']
704 if node.dereference()['_M_right'] != parent:
705 node = parent
706 self.node = node
707 return result
708
047f1cec
JW
709def get_value_from_Rb_tree_node(node):
710 """Returns the value held in an _Rb_tree_node<_Val>"""
711 try:
712 member = node.type.fields()[1].name
713 if member == '_M_value_field':
714 # C++03 implementation, node contains the value as a member
715 return node['_M_value_field']
716 elif member == '_M_storage':
cc7f3d0e 717 # C++11 implementation, node stores value in __aligned_membuf
2dbe56bd
JW
718 valtype = node.type.template_argument(0)
719 return get_value_from_aligned_membuf(node['_M_storage'], valtype)
047f1cec
JW
720 except:
721 pass
47059228 722 raise ValueError("Unsupported implementation for %s" % str(node.type))
047f1cec 723
41850419
TT
724# This is a pretty printer for std::_Rb_tree_iterator (which is
725# std::map::iterator), and has nothing to do with the RbtreeIterator
726# class above.
727class StdRbtreeIteratorPrinter:
7224c6a9 728 "Print std::map::iterator, std::set::iterator, etc."
41850419 729
d63c53cc 730 def __init__ (self, typename, val):
41850419 731 self.val = val
9d50a6a7
JW
732 nodetype = lookup_node_type('_Rb_tree_node', self.val.type)
733 self.link_type = nodetype.pointer()
41850419
TT
734
735 def to_string (self):
bdfc9f5c
JW
736 if not self.val['_M_node']:
737 return 'non-dereferenceable iterator for associative container'
2097b5b0 738 node = self.val['_M_node'].cast(self.link_type).dereference()
50a8a941 739 return str(get_value_from_Rb_tree_node(node))
41850419 740
cd0961a5
PM
741class StdDebugIteratorPrinter:
742 "Print a debug enabled version of an iterator"
743
d63c53cc 744 def __init__ (self, typename, val):
cd0961a5
PM
745 self.val = val
746
747 # Just strip away the encapsulating __gnu_debug::_Safe_iterator
748 # and return the wrapped iterator value.
749 def to_string (self):
3c760f4a 750 base_type = gdb.lookup_type('__gnu_debug::_Safe_iterator_base')
fe6bd21a 751 itype = self.val.type.template_argument(0)
3c760f4a 752 safe_seq = self.val.cast(base_type)['_M_sequence']
fe6bd21a
FD
753 if not safe_seq:
754 return str(self.val.cast(itype))
755 if self.val['_M_version'] != safe_seq['_M_version']:
3c760f4a 756 return "invalid iterator"
50a8a941 757 return str(self.val.cast(itype))
41850419 758
d33c00e1
JW
759def num_elements(num):
760 """Return either "1 element" or "N elements" depending on the argument."""
761 return '1 element' if num == 1 else '%d elements' % num
762
41850419
TT
763class StdMapPrinter:
764 "Print a std::map or std::multimap"
765
766 # Turn an RbtreeIterator into a pretty-print iterator.
cdd1ba62 767 class _iter(Iterator):
41850419
TT
768 def __init__(self, rbiter, type):
769 self.rbiter = rbiter
770 self.count = 0
771 self.type = type
772
773 def __iter__(self):
774 return self
775
cdd1ba62 776 def __next__(self):
41850419 777 if self.count % 2 == 0:
cdd1ba62 778 n = next(self.rbiter)
047f1cec
JW
779 n = n.cast(self.type).dereference()
780 n = get_value_from_Rb_tree_node(n)
41850419
TT
781 self.pair = n
782 item = n['first']
783 else:
784 item = self.pair['second']
785 result = ('[%d]' % self.count, item)
786 self.count = self.count + 1
787 return result
788
789 def __init__ (self, typename, val):
f9a27859 790 self.typename = strip_versioned_namespace(typename)
41850419 791 self.val = val
41850419
TT
792
793 def to_string (self):
d33c00e1
JW
794 return '%s with %s' % (self.typename,
795 num_elements(len(RbtreeIterator (self.val))))
41850419
TT
796
797 def children (self):
9d50a6a7 798 node = lookup_node_type('_Rb_tree_node', self.val.type).pointer()
3efe2bf7 799 return self._iter (RbtreeIterator (self.val), node)
41850419
TT
800
801 def display_hint (self):
802 return 'map'
803
804class StdSetPrinter:
805 "Print a std::set or std::multiset"
806
807 # Turn an RbtreeIterator into a pretty-print iterator.
cdd1ba62 808 class _iter(Iterator):
41850419
TT
809 def __init__(self, rbiter, type):
810 self.rbiter = rbiter
811 self.count = 0
812 self.type = type
813
814 def __iter__(self):
815 return self
816
cdd1ba62
SB
817 def __next__(self):
818 item = next(self.rbiter)
047f1cec
JW
819 item = item.cast(self.type).dereference()
820 item = get_value_from_Rb_tree_node(item)
41850419
TT
821 # FIXME: this is weird ... what to do?
822 # Maybe a 'set' display hint?
823 result = ('[%d]' % self.count, item)
824 self.count = self.count + 1
825 return result
826
827 def __init__ (self, typename, val):
f9a27859 828 self.typename = strip_versioned_namespace(typename)
41850419 829 self.val = val
41850419
TT
830
831 def to_string (self):
d33c00e1
JW
832 return '%s with %s' % (self.typename,
833 num_elements(len(RbtreeIterator (self.val))))
41850419
TT
834
835 def children (self):
9d50a6a7 836 node = lookup_node_type('_Rb_tree_node', self.val.type).pointer()
3efe2bf7 837 return self._iter (RbtreeIterator (self.val), node)
41850419
TT
838
839class StdBitsetPrinter:
840 "Print a std::bitset"
841
cd0961a5 842 def __init__(self, typename, val):
f9a27859 843 self.typename = strip_versioned_namespace(typename)
41850419
TT
844 self.val = val
845
846 def to_string (self):
847 # If template_argument handled values, we could print the
848 # size. Or we could use a regexp on the type.
cd0961a5 849 return '%s' % (self.typename)
41850419
TT
850
851 def children (self):
14a9206d
MS
852 try:
853 # An empty bitset may not have any members which will
854 # result in an exception being thrown.
855 words = self.val['_M_w']
856 except:
857 return []
858
41850419
TT
859 wtype = words.type
860
861 # The _M_w member can be either an unsigned long, or an
862 # array. This depends on the template specialization used.
863 # If it is a single long, convert to a single element list.
864 if wtype.code == gdb.TYPE_CODE_ARRAY:
865 tsize = wtype.target ().sizeof
866 else:
867 words = [words]
14a9206d 868 tsize = wtype.sizeof
41850419
TT
869
870 nwords = wtype.sizeof / tsize
871 result = []
872 byte = 0
873 while byte < nwords:
874 w = words[byte]
875 bit = 0
876 while w != 0:
877 if (w & 1) != 0:
878 # Another spot where we could use 'set'?
879 result.append(('[%d]' % (byte * tsize * 8 + bit), 1))
880 bit = bit + 1
881 w = w >> 1
882 byte = byte + 1
883 return result
884
885class StdDequePrinter:
886 "Print a std::deque"
887
cdd1ba62 888 class _iter(Iterator):
41850419
TT
889 def __init__(self, node, start, end, last, buffer_size):
890 self.node = node
891 self.p = start
892 self.end = end
893 self.last = last
894 self.buffer_size = buffer_size
895 self.count = 0
896
897 def __iter__(self):
898 return self
899
cdd1ba62 900 def __next__(self):
41850419
TT
901 if self.p == self.last:
902 raise StopIteration
903
904 result = ('[%d]' % self.count, self.p.dereference())
905 self.count = self.count + 1
906
907 # Advance the 'cur' pointer.
908 self.p = self.p + 1
909 if self.p == self.end:
910 # If we got to the end of this bucket, move to the
911 # next bucket.
912 self.node = self.node + 1
913 self.p = self.node[0]
914 self.end = self.p + self.buffer_size
915
916 return result
917
cd0961a5 918 def __init__(self, typename, val):
f9a27859 919 self.typename = strip_versioned_namespace(typename)
41850419
TT
920 self.val = val
921 self.elttype = val.type.template_argument(0)
922 size = self.elttype.sizeof
923 if size < 512:
924 self.buffer_size = int (512 / size)
925 else:
926 self.buffer_size = 1
927
928 def to_string(self):
929 start = self.val['_M_impl']['_M_start']
930 end = self.val['_M_impl']['_M_finish']
931
932 delta_n = end['_M_node'] - start['_M_node'] - 1
933 delta_s = start['_M_last'] - start['_M_cur']
934 delta_e = end['_M_cur'] - end['_M_first']
935
936 size = self.buffer_size * delta_n + delta_s + delta_e
937
d33c00e1 938 return '%s with %s' % (self.typename, num_elements(long(size)))
41850419
TT
939
940 def children(self):
941 start = self.val['_M_impl']['_M_start']
942 end = self.val['_M_impl']['_M_finish']
943 return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
944 end['_M_cur'], self.buffer_size)
945
946 def display_hint (self):
947 return 'array'
948
949class StdDequeIteratorPrinter:
950 "Print std::deque::iterator"
951
d63c53cc 952 def __init__(self, typename, val):
41850419
TT
953 self.val = val
954
955 def to_string(self):
bdfc9f5c
JW
956 if not self.val['_M_cur']:
957 return 'non-dereferenceable iterator for std::deque'
50a8a941 958 return str(self.val['_M_cur'].dereference())
41850419
TT
959
960class StdStringPrinter:
961 "Print a std::basic_string of some kind"
962
d63c53cc 963 def __init__(self, typename, val):
41850419 964 self.val = val
34a2b755 965 self.new_string = typename.find("::__cxx11::basic_string") != -1
41850419
TT
966
967 def to_string(self):
271167f1
PM
968 # Make sure &string works, too.
969 type = self.val.type
970 if type.code == gdb.TYPE_CODE_REF:
971 type = type.target ()
972
973 # Calculate the length of the string so that to_string returns
974 # the string according to length, not according to first null
975 # encountered.
976 ptr = self.val ['_M_dataplus']['_M_p']
34a2b755
JW
977 if self.new_string:
978 length = self.val['_M_string_length']
979 # https://sourceware.org/bugzilla/show_bug.cgi?id=17728
980 ptr = ptr.cast(ptr.type.strip_typedefs())
981 else:
982 realtype = type.unqualified ().strip_typedefs ()
983 reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer ()
984 header = ptr.cast(reptype) - 1
985 length = header.dereference ()['_M_length']
708f539d 986 if hasattr(ptr, "lazy_string"):
34a2b755
JW
987 return ptr.lazy_string (length = length)
988 return ptr.string (length = length)
41850419
TT
989
990 def display_hint (self):
991 return 'string'
992
93257ed6
PF
993def access_streambuf_ptrs(streambuf):
994 "Access the streambuf put area pointers"
995 pbase = streambuf['_M_out_beg']
996 pptr = streambuf['_M_out_cur']
997 egptr = streambuf['_M_in_end']
998 return pbase, pptr, egptr
999
1000class StdStringBufPrinter:
1001 "Print a std::basic_stringbuf"
1002
1003 def __init__(self, _, val):
1004 self.val = val
1005
1006 def to_string(self):
1007 (pbase, pptr, egptr) = access_streambuf_ptrs(self.val)
1008 # Logic from basic_stringbuf::_M_high_mark()
1009 if pptr:
1010 if not egptr or pptr > egptr:
1011 return pbase.string(length = pptr - pbase)
1012 else:
1013 return pbase.string(length = egptr - pbase)
1014 return self.val['_M_string']
1015
1016 def display_hint(self):
1017 return 'string'
1018
1019class StdStringStreamPrinter:
1020 "Print a std::basic_stringstream"
1021
1022 def __init__(self, typename, val):
1023 self.val = val
1024 self.typename = typename
1025
1026 # Check if the stream was redirected:
1027 # This is essentially: val['_M_streambuf'] == val['_M_stringbuf'].address
1028 # However, GDB can't resolve the virtual inheritance, so we do that manually
1029 basetype = [f.type for f in val.type.fields() if f.is_base_class][0]
1030 gdb.set_convenience_variable('__stream', val.cast(basetype).address)
1031 self.streambuf = gdb.parse_and_eval('$__stream->rdbuf()')
1032 self.was_redirected = self.streambuf != val['_M_stringbuf'].address
1033
1034 def to_string(self):
1035 if self.was_redirected:
1036 return "%s redirected to %s" % (self.typename, self.streambuf.dereference())
1037 return self.val['_M_stringbuf']
1038
1039 def display_hint(self):
1040 if self.was_redirected:
1041 return None
1042 return 'string'
1043
cdd1ba62 1044class Tr1HashtableIterator(Iterator):
9d50a6a7
JW
1045 def __init__ (self, hashtable):
1046 self.buckets = hashtable['_M_buckets']
4722d005 1047 self.bucket = 0
9d50a6a7
JW
1048 self.bucket_count = hashtable['_M_bucket_count']
1049 self.node_type = find_type(hashtable.type, '_Node').pointer()
4722d005
FD
1050 self.node = 0
1051 while self.bucket != self.bucket_count:
1052 self.node = self.buckets[self.bucket]
1053 if self.node:
1054 break
14a9206d 1055 self.bucket = self.bucket + 1
41850419
TT
1056
1057 def __iter__ (self):
1058 return self
1059
cdd1ba62 1060 def __next__ (self):
d25b1e3a 1061 if self.node == 0:
41850419 1062 raise StopIteration
d25b1e3a
TT
1063 node = self.node.cast(self.node_type)
1064 result = node.dereference()['_M_v']
4722d005
FD
1065 self.node = node.dereference()['_M_next'];
1066 if self.node == 0:
1067 self.bucket = self.bucket + 1
1068 while self.bucket != self.bucket_count:
1069 self.node = self.buckets[self.bucket]
1070 if self.node:
1071 break
1072 self.bucket = self.bucket + 1
41850419
TT
1073 return result
1074
cdd1ba62 1075class StdHashtableIterator(Iterator):
9d50a6a7
JW
1076 def __init__(self, hashtable):
1077 self.node = hashtable['_M_before_begin']['_M_nxt']
1078 valtype = hashtable.type.template_argument(1)
1079 cached = hashtable.type.template_argument(9).template_argument(0)
1080 node_type = lookup_templ_spec('std::__detail::_Hash_node', str(valtype),
1081 'true' if cached else 'false')
1082 self.node_type = node_type.pointer()
4722d005
FD
1083
1084 def __iter__(self):
1085 return self
1086
cdd1ba62 1087 def __next__(self):
4722d005
FD
1088 if self.node == 0:
1089 raise StopIteration
1090 elt = self.node.cast(self.node_type).dereference()
1091 self.node = elt['_M_nxt']
1092 valptr = elt['_M_storage'].address
1093 valptr = valptr.cast(elt.type.template_argument(0).pointer())
1094 return valptr.dereference()
1095
41850419 1096class Tr1UnorderedSetPrinter:
9d50a6a7 1097 "Print a std::unordered_set or tr1::unordered_set"
41850419
TT
1098
1099 def __init__ (self, typename, val):
f9a27859 1100 self.typename = strip_versioned_namespace(typename)
41850419
TT
1101 self.val = val
1102
937b190d
JW
1103 def hashtable (self):
1104 if self.typename.startswith('std::tr1'):
1105 return self.val
1106 return self.val['_M_h']
1107
41850419 1108 def to_string (self):
d33c00e1
JW
1109 count = self.hashtable()['_M_element_count']
1110 return '%s with %s' % (self.typename, num_elements(count))
41850419
TT
1111
1112 @staticmethod
1113 def format_count (i):
1114 return '[%d]' % i
1115
1116 def children (self):
cdd1ba62 1117 counter = imap (self.format_count, itertools.count())
4722d005 1118 if self.typename.startswith('std::tr1'):
cdd1ba62
SB
1119 return izip (counter, Tr1HashtableIterator (self.hashtable()))
1120 return izip (counter, StdHashtableIterator (self.hashtable()))
41850419
TT
1121
1122class Tr1UnorderedMapPrinter:
9d50a6a7 1123 "Print a std::unordered_map or tr1::unordered_map"
41850419
TT
1124
1125 def __init__ (self, typename, val):
f9a27859 1126 self.typename = strip_versioned_namespace(typename)
41850419
TT
1127 self.val = val
1128
937b190d
JW
1129 def hashtable (self):
1130 if self.typename.startswith('std::tr1'):
1131 return self.val
1132 return self.val['_M_h']
1133
41850419 1134 def to_string (self):
d33c00e1
JW
1135 count = self.hashtable()['_M_element_count']
1136 return '%s with %s' % (self.typename, num_elements(count))
41850419
TT
1137
1138 @staticmethod
1139 def flatten (list):
1140 for elt in list:
1141 for i in elt:
1142 yield i
1143
1144 @staticmethod
1145 def format_one (elt):
1146 return (elt['first'], elt['second'])
1147
1148 @staticmethod
1149 def format_count (i):
1150 return '[%d]' % i
1151
1152 def children (self):
cdd1ba62 1153 counter = imap (self.format_count, itertools.count())
41850419 1154 # Map over the hash table and flatten the result.
4722d005 1155 if self.typename.startswith('std::tr1'):
cdd1ba62 1156 data = self.flatten (imap (self.format_one, Tr1HashtableIterator (self.hashtable())))
4722d005 1157 # Zip the two iterators together.
cdd1ba62
SB
1158 return izip (counter, data)
1159 data = self.flatten (imap (self.format_one, StdHashtableIterator (self.hashtable())))
41850419 1160 # Zip the two iterators together.
cdd1ba62 1161 return izip (counter, data)
41850419
TT
1162
1163 def display_hint (self):
1164 return 'map'
1165
8dfb08ab
JW
1166class StdForwardListPrinter:
1167 "Print a std::forward_list"
1168
cdd1ba62 1169 class _iterator(Iterator):
8dfb08ab
JW
1170 def __init__(self, nodetype, head):
1171 self.nodetype = nodetype
1172 self.base = head['_M_next']
1173 self.count = 0
1174
1175 def __iter__(self):
1176 return self
1177
cdd1ba62 1178 def __next__(self):
8dfb08ab
JW
1179 if self.base == 0:
1180 raise StopIteration
1181 elt = self.base.cast(self.nodetype).dereference()
1182 self.base = elt['_M_next']
1183 count = self.count
1184 self.count = self.count + 1
073deae6
JW
1185 valptr = elt['_M_storage'].address
1186 valptr = valptr.cast(elt.type.template_argument(0).pointer())
1187 return ('[%d]' % count, valptr.dereference())
8dfb08ab
JW
1188
1189 def __init__(self, typename, val):
1190 self.val = val
f9a27859 1191 self.typename = strip_versioned_namespace(typename)
8dfb08ab
JW
1192
1193 def children(self):
9d50a6a7 1194 nodetype = lookup_node_type('_Fwd_list_node', self.val.type).pointer()
8dfb08ab
JW
1195 return self._iterator(nodetype, self.val['_M_impl']['_M_head'])
1196
1197 def to_string(self):
1198 if self.val['_M_impl']['_M_head']['_M_next'] == 0:
7224c6a9
JW
1199 return 'empty %s' % self.typename
1200 return '%s' % self.typename
8dfb08ab 1201
6f440cce
JW
1202class SingleObjContainerPrinter(object):
1203 "Base class for printers of containers of single objects"
1204
a0a1009a 1205 def __init__ (self, val, viz, hint = None):
6f440cce
JW
1206 self.contained_value = val
1207 self.visualizer = viz
a0a1009a 1208 self.hint = hint
6f440cce
JW
1209
1210 def _recognize(self, type):
1211 """Return TYPE as a string after applying type printers"""
faf7f829
JW
1212 global _use_type_printing
1213 if not _use_type_printing:
1214 return str(type)
6f440cce
JW
1215 return gdb.types.apply_type_recognizers(gdb.types.get_type_recognizers(),
1216 type) or str(type)
1217
3e5eda5b 1218 class _contained(Iterator):
6f440cce
JW
1219 def __init__ (self, val):
1220 self.val = val
1221
1222 def __iter__ (self):
1223 return self
1224
3e5eda5b 1225 def __next__(self):
6f440cce
JW
1226 if self.val is None:
1227 raise StopIteration
1228 retval = self.val
1229 self.val = None
1230 return ('[contained value]', retval)
1231
1232 def children (self):
1233 if self.contained_value is None:
1234 return self._contained (None)
1235 if hasattr (self.visualizer, 'children'):
1236 return self.visualizer.children ()
1237 return self._contained (self.contained_value)
1238
1239 def display_hint (self):
1240 # if contained value is a map we want to display in the same way
1241 if hasattr (self.visualizer, 'children') and hasattr (self.visualizer, 'display_hint'):
1242 return self.visualizer.display_hint ()
a0a1009a 1243 return self.hint
6f440cce 1244
dc2b372e
JW
1245def function_pointer_to_name(f):
1246 "Find the name of the function referred to by the gdb.Value f, "
1247 " which should contain a function pointer from the program."
1248
1249 # Turn the function pointer into an actual address.
1250 # This is needed to unpack ppc64 function descriptors.
1251 f = f.dereference().address
1252
1253 if sys.version_info[0] == 2:
1254 # Older versions of GDB need to use long for Python 2,
1255 # because int(f) on 64-bit big-endian values raises a
1256 # gdb.error saying "Cannot convert value to int."
1257 f = long(f)
1258 else:
1259 f = int(f)
1260
1261 try:
1262 # If the function can't be found older versions of GDB raise a
1263 # RuntimeError saying "Cannot locate object file for block."
1264 return gdb.block_for_pc(f).function.name
1265 except:
1266 return None
1267
6f440cce 1268class StdExpAnyPrinter(SingleObjContainerPrinter):
00895372 1269 "Print a std::any or std::experimental::any"
6f440cce
JW
1270
1271 def __init__ (self, typename, val):
86397ed1
FD
1272 self.typename = strip_versioned_namespace(typename)
1273 self.typename = re.sub('^std::experimental::fundamentals_v\d::', 'std::experimental::', self.typename, 1)
6f440cce
JW
1274 self.val = val
1275 self.contained_type = None
1276 contained_value = None
1277 visualizer = None
1278 mgr = self.val['_M_manager']
1279 if mgr != 0:
dc2b372e 1280 func = function_pointer_to_name(mgr)
6f440cce 1281 if not func:
dc2b372e 1282 raise ValueError("Invalid function pointer in %s" % (self.typename))
11aa881f 1283 rx = r"""({0}::_Manager_\w+<.*>)::_S_manage\((enum )?{0}::_Op, (const {0}|{0} const) ?\*, (union )?{0}::_Arg ?\*\)""".format(typename)
dc2b372e 1284 m = re.match(rx, func)
6f440cce 1285 if not m:
00895372 1286 raise ValueError("Unknown manager function in %s" % self.typename)
6f440cce 1287
f9a27859 1288 mgrname = m.group(1)
6f440cce 1289 # FIXME need to expand 'std::string' so that gdb.lookup_type works
f9a27859 1290 if 'std::string' in mgrname:
3c54805d
JW
1291 # This lookup for std::string might return the __cxx11 version,
1292 # but that's not necessarily the one used by the std::any
1293 # manager function we're trying to find.
1294 strings = {str(gdb.lookup_type('std::string').strip_typedefs())}
1295 # So also consider all the other possible std::string types!
1296 s = 'basic_string<char, std::char_traits<char>, std::allocator<char> >'
1297 quals = ['std::', 'std::__cxx11::', 'std::' + _versioned_namespace]
1298 strings |= {q+s for q in quals} # set of unique strings
1299 mgrtypes = []
1300 for s in strings:
1301 try:
1302 x = re.sub("std::string(?!\w)", s, m.group(1))
1303 # The following lookup might raise gdb.error if the
1304 # manager function was never instantiated for 's' in the
1305 # program, because there will be no such type.
1306 mgrtypes.append(gdb.lookup_type(x))
1307 except gdb.error:
1308 pass
1309 if len(mgrtypes) != 1:
1310 # FIXME: this is unlikely in practice, but possible for
1311 # programs that use both old and new string types with
1312 # std::any in a single program. Can we do better?
1313 # Maybe find the address of each type's _S_manage and
1314 # compare to the address stored in _M_manager?
1315 raise ValueError('Cannot uniquely determine std::string type used in std::any')
1316 mgrtype = mgrtypes[0]
1317 else:
1318 mgrtype = gdb.lookup_type(mgrname)
6f440cce
JW
1319 self.contained_type = mgrtype.template_argument(0)
1320 valptr = None
1321 if '::_Manager_internal' in mgrname:
1322 valptr = self.val['_M_storage']['_M_buffer'].address
1323 elif '::_Manager_external' in mgrname:
1324 valptr = self.val['_M_storage']['_M_ptr']
6f440cce 1325 else:
00895372 1326 raise ValueError("Unknown manager function in %s" % self.typename)
6f440cce
JW
1327 contained_value = valptr.cast(self.contained_type.pointer()).dereference()
1328 visualizer = gdb.default_visualizer(contained_value)
1329 super(StdExpAnyPrinter, self).__init__ (contained_value, visualizer)
1330
1331 def to_string (self):
1332 if self.contained_type is None:
1333 return '%s [no contained value]' % self.typename
1334 desc = "%s containing " % self.typename
1335 if hasattr (self.visualizer, 'children'):
1336 return desc + self.visualizer.to_string ()
1337 valtype = self._recognize (self.contained_type)
f9a27859 1338 return desc + strip_versioned_namespace(str(valtype))
6f440cce
JW
1339
1340class StdExpOptionalPrinter(SingleObjContainerPrinter):
00895372 1341 "Print a std::optional or std::experimental::optional"
6f440cce
JW
1342
1343 def __init__ (self, typename, val):
1344 valtype = self._recognize (val.type.template_argument(0))
d942bc80
JW
1345 typename = strip_versioned_namespace(typename)
1346 self.typename = re.sub('^std::(experimental::|)(fundamentals_v\d::|)(.*)', r'std::\1\3<%s>' % valtype, typename, 1)
1347 payload = val['_M_payload']
1348 if self.typename.startswith('std::experimental'):
1349 engaged = val['_M_engaged']
1350 contained_value = payload
1351 else:
1352 engaged = payload['_M_engaged']
1353 contained_value = payload['_M_payload']
1354 try:
1355 # Since GCC 9
1356 contained_value = contained_value['_M_value']
1357 except:
1358 pass
1359 visualizer = gdb.default_visualizer (contained_value)
1360 if not engaged:
1361 contained_value = None
6f440cce
JW
1362 super (StdExpOptionalPrinter, self).__init__ (contained_value, visualizer)
1363
1364 def to_string (self):
1365 if self.contained_value is None:
7224c6a9 1366 return "%s [no contained value]" % self.typename
6f440cce 1367 if hasattr (self.visualizer, 'children'):
7224c6a9
JW
1368 return "%s containing %s" % (self.typename,
1369 self.visualizer.to_string())
6f440cce
JW
1370 return self.typename
1371
00895372
JW
1372class StdVariantPrinter(SingleObjContainerPrinter):
1373 "Print a std::variant"
1374
1375 def __init__(self, typename, val):
bab0a26d 1376 alternatives = get_template_arg_list(val.type)
86397ed1
FD
1377 self.typename = strip_versioned_namespace(typename)
1378 self.typename = "%s<%s>" % (self.typename, ', '.join([self._recognize(alt) for alt in alternatives]))
00895372
JW
1379 self.index = val['_M_index']
1380 if self.index >= len(alternatives):
1381 self.contained_type = None
1382 contained_value = None
1383 visualizer = None
1384 else:
1385 self.contained_type = alternatives[int(self.index)]
449a4321 1386 addr = val['_M_u']['_M_first']['_M_storage'].address
00895372
JW
1387 contained_value = addr.cast(self.contained_type.pointer()).dereference()
1388 visualizer = gdb.default_visualizer(contained_value)
a0a1009a 1389 super (StdVariantPrinter, self).__init__(contained_value, visualizer, 'array')
00895372 1390
00895372
JW
1391 def to_string(self):
1392 if self.contained_value is None:
a0a1009a 1393 return "%s [no contained value]" % self.typename
00895372 1394 if hasattr(self.visualizer, 'children'):
7224c6a9
JW
1395 return "%s [index %d] containing %s" % (self.typename, self.index,
1396 self.visualizer.to_string())
a0a1009a 1397 return "%s [index %d]" % (self.typename, self.index)
00895372 1398
2dbe56bd
JW
1399class StdNodeHandlePrinter(SingleObjContainerPrinter):
1400 "Print a container node handle"
1401
1402 def __init__(self, typename, val):
1403 self.value_type = val.type.template_argument(1)
1404 nodetype = val.type.template_argument(2).template_argument(0)
f9a27859 1405 self.is_rb_tree_node = is_specialization_of(nodetype.name, '_Rb_tree_node')
2dbe56bd
JW
1406 self.is_map_node = val.type.template_argument(0) != self.value_type
1407 nodeptr = val['_M_ptr']
1408 if nodeptr:
1409 if self.is_rb_tree_node:
1410 contained_value = get_value_from_Rb_tree_node(nodeptr.dereference())
1411 else:
1412 contained_value = get_value_from_aligned_membuf(nodeptr['_M_storage'],
1413 self.value_type)
1414 visualizer = gdb.default_visualizer(contained_value)
1415 else:
1416 contained_value = None
1417 visualizer = None
1418 optalloc = val['_M_alloc']
1419 self.alloc = optalloc['_M_payload'] if optalloc['_M_engaged'] else None
1420 super(StdNodeHandlePrinter, self).__init__(contained_value, visualizer,
1421 'array')
1422
1423 def to_string(self):
2dbe56bd
JW
1424 desc = 'node handle for '
1425 if not self.is_rb_tree_node:
1426 desc += 'unordered '
1427 if self.is_map_node:
1428 desc += 'map';
1429 else:
1430 desc += 'set';
1431
1432 if self.contained_value:
1433 desc += ' with element'
1434 if hasattr(self.visualizer, 'children'):
1435 return "%s = %s" % (desc, self.visualizer.to_string())
1436 return desc
1437 else:
1438 return 'empty %s' % desc
1439
6f440cce 1440class StdExpStringViewPrinter:
00895372 1441 "Print a std::basic_string_view or std::experimental::basic_string_view"
6f440cce
JW
1442
1443 def __init__ (self, typename, val):
1444 self.val = val
1445
1446 def to_string (self):
1447 ptr = self.val['_M_str']
1448 len = self.val['_M_len']
1449 if hasattr (ptr, "lazy_string"):
1450 return ptr.lazy_string (length = len)
1451 return ptr.string (length = len)
1452
1453 def display_hint (self):
1454 return 'string'
8dfb08ab 1455
0ca7ba9a
JW
1456class StdExpPathPrinter:
1457 "Print a std::experimental::filesystem::path"
1458
1459 def __init__ (self, typename, val):
1460 self.val = val
a70384f9 1461 self.typename = typename
a00d74c4
JW
1462 start = self.val['_M_cmpts']['_M_impl']['_M_start']
1463 finish = self.val['_M_cmpts']['_M_impl']['_M_finish']
1464 self.num_cmpts = int (finish - start)
1465
1466 def _path_type(self):
1467 t = str(self.val['_M_type'])
1468 if t[-9:] == '_Root_dir':
1469 return "root-directory"
1470 if t[-10:] == '_Root_name':
1471 return "root-name"
1472 return None
0ca7ba9a
JW
1473
1474 def to_string (self):
a00d74c4
JW
1475 path = "%s" % self.val ['_M_pathname']
1476 if self.num_cmpts == 0:
1477 t = self._path_type()
1478 if t:
1479 path = '%s [%s]' % (path, t)
a70384f9 1480 return "experimental::filesystem::path %s" % path
a00d74c4
JW
1481
1482 class _iterator(Iterator):
a70384f9
JW
1483 def __init__(self, cmpts, pathtype):
1484 self.pathtype = pathtype
a00d74c4
JW
1485 self.item = cmpts['_M_impl']['_M_start']
1486 self.finish = cmpts['_M_impl']['_M_finish']
1487 self.count = 0
1488
1489 def __iter__(self):
1490 return self
1491
1492 def __next__(self):
1493 if self.item == self.finish:
1494 raise StopIteration
1495 item = self.item.dereference()
1496 count = self.count
1497 self.count = self.count + 1
1498 self.item = self.item + 1
1499 path = item['_M_pathname']
a70384f9 1500 t = StdExpPathPrinter(self.pathtype, item)._path_type()
a00d74c4
JW
1501 if not t:
1502 t = count
1503 return ('[%s]' % t, path)
1504
1505 def children(self):
a70384f9 1506 return self._iterator(self.val['_M_cmpts'], self.typename)
a00d74c4 1507
4f87bb8d
JW
1508class StdPathPrinter:
1509 "Print a std::filesystem::path"
1510
1511 def __init__ (self, typename, val):
1512 self.val = val
1513 self.typename = typename
a634928f 1514 impl = unique_ptr_get(self.val['_M_cmpts']['_M_impl'])
4f87bb8d
JW
1515 self.type = impl.cast(gdb.lookup_type('uintptr_t')) & 3
1516 if self.type == 0:
1517 self.impl = impl
1518 else:
1519 self.impl = None
1520
1521 def _path_type(self):
1522 t = str(self.type.cast(gdb.lookup_type(self.typename + '::_Type')))
1523 if t[-9:] == '_Root_dir':
1524 return "root-directory"
1525 if t[-10:] == '_Root_name':
1526 return "root-name"
1527 return None
1528
1529 def to_string (self):
1530 path = "%s" % self.val ['_M_pathname']
1531 if self.type != 0:
1532 t = self._path_type()
1533 if t:
1534 path = '%s [%s]' % (path, t)
1535 return "filesystem::path %s" % path
1536
1537 class _iterator(Iterator):
1538 def __init__(self, impl, pathtype):
a70384f9 1539 self.pathtype = pathtype
4f87bb8d
JW
1540 if impl:
1541 # We can't access _Impl::_M_size because _Impl is incomplete
1542 # so cast to int* to access the _M_size member at offset zero,
1543 int_type = gdb.lookup_type('int')
1544 cmpt_type = gdb.lookup_type(pathtype+'::_Cmpt')
1545 char_type = gdb.lookup_type('char')
1546 impl = impl.cast(int_type.pointer())
1547 size = impl.dereference()
1548 #self.capacity = (impl + 1).dereference()
1549 if hasattr(gdb.Type, 'alignof'):
1550 sizeof_Impl = max(2 * int_type.sizeof, cmpt_type.alignof)
1551 else:
1552 sizeof_Impl = 2 * int_type.sizeof
1553 begin = impl.cast(char_type.pointer()) + sizeof_Impl
1554 self.item = begin.cast(cmpt_type.pointer())
1555 self.finish = self.item + size
1556 self.count = 0
1557 else:
1558 self.item = None
1559 self.finish = None
1560
1561 def __iter__(self):
1562 return self
1563
1564 def __next__(self):
1565 if self.item == self.finish:
1566 raise StopIteration
1567 item = self.item.dereference()
1568 count = self.count
1569 self.count = self.count + 1
1570 self.item = self.item + 1
1571 path = item['_M_pathname']
a70384f9 1572 t = StdPathPrinter(self.pathtype, item)._path_type()
4f87bb8d
JW
1573 if not t:
1574 t = count
1575 return ('[%s]' % t, path)
1576
1577 def children(self):
1578 return self._iterator(self.impl, self.typename)
1579
0ca7ba9a 1580
e1821582
JW
1581class StdPairPrinter:
1582 "Print a std::pair object, with 'first' and 'second' as children"
1583
1584 def __init__(self, typename, val):
1585 self.val = val
1586
1587 class _iter(Iterator):
1588 "An iterator for std::pair types. Returns 'first' then 'second'."
1589
1590 def __init__(self, val):
1591 self.val = val
1592 self.which = 'first'
1593
1594 def __iter__(self):
1595 return self
1596
1597 def __next__(self):
1598 if self.which is None:
1599 raise StopIteration
1600 which = self.which
1601 if which == 'first':
1602 self.which = 'second'
1603 else:
1604 self.which = None
1605 return (which, self.val[which])
1606
1607 def children(self):
1608 return self._iter(self.val)
1609
1610 def to_string(self):
1611 return None
1612
a59c50bd
JW
1613class StdCmpCatPrinter:
1614 "Print a comparison category object"
1615
1616 def __init__ (self, typename, val):
1617 self.typename = typename[typename.rfind(':')+1:]
1618 self.val = val['_M_value']
1619
1620 def to_string (self):
1621 if self.typename == 'strong_ordering' and self.val == 0:
1622 name = 'equal'
1623 else:
4540ef78 1624 names = {2:'unordered', -1:'less', 0:'equivalent', 1:'greater'}
a59c50bd
JW
1625 name = names[int(self.val)]
1626 return 'std::{}::{}'.format(self.typename, name)
e1821582 1627
2db38d9f
JW
1628class StdErrorCodePrinter:
1629 "Print a std::error_code or std::error_condition"
1630
36100e0e 1631 _system_is_posix = None # Whether std::system_category() use errno values.
2db38d9f
JW
1632
1633 def __init__ (self, typename, val):
1634 self.val = val
1918067e 1635 self.typename = strip_versioned_namespace(typename)
2db38d9f 1636 # Do this only once ...
36100e0e 1637 if StdErrorCodePrinter._system_is_posix is None:
2db38d9f
JW
1638 try:
1639 import posix
36100e0e 1640 StdErrorCodePrinter._system_is_posix = True
2db38d9f 1641 except ImportError:
36100e0e
JW
1642 StdErrorCodePrinter._system_is_posix = False
1643
1644 @staticmethod
1645 def _find_errc_enum(name):
1646 typ = gdb.lookup_type(name)
1647 if typ is not None and typ.code == gdb.TYPE_CODE_ENUM:
1648 return typ
1649 return None
1650
11e1ee1b
JW
1651 @classmethod
1652 def _find_standard_errc_enum(cls, name):
1653 for ns in ['', _versioned_namespace]:
1654 try:
1655 qname = 'std::{}{}'.format(ns, name)
1656 return cls._find_errc_enum(qname)
1657 except RuntimeError:
1658 pass
1659
36100e0e
JW
1660 @classmethod
1661 def _match_net_ts_category(cls, cat):
1662 net_cats = ['stream', 'socket', 'ip::resolver']
1663 for c in net_cats:
1664 func = c + '_category()'
1665 for ns in ['', _versioned_namespace]:
1666 ns = 'std::{}experimental::net::v1'.format(ns)
1667 sym = gdb.lookup_symbol('{}::{}::__c'.format(ns, func))[0]
1668 if sym is not None:
1669 if cat == sym.value().address:
1670 name = 'net::' + func
1671 enum = cls._find_errc_enum('{}::{}_errc'.format(ns, c))
1672 return (name, enum)
1673 return (None, None)
1674
1675 @classmethod
1676 def _category_info(cls, cat):
1677 "Return details of a std::error_category"
1678
1679 name = None
1680 enum = None
1681 is_errno = False
1682
1683 # Try these first, or we get "warning: RTTI symbol not found" when
1684 # using cat.dynamic_type on the local class types for Net TS categories.
1685 func, enum = cls._match_net_ts_category(cat)
1686 if func is not None:
1687 return (None, func, enum, is_errno)
1688
1689 # This might give a warning for a program-defined category defined as
1690 # a local class, but there doesn't seem to be any way to avoid that.
1691 typ = cat.dynamic_type.target()
1692 # Shortcuts for the known categories defined by libstdc++.
1693 if typ.tag.endswith('::generic_error_category'):
1694 name = 'generic'
1695 is_errno = True
1696 if typ.tag.endswith('::system_error_category'):
1697 name = 'system'
1698 is_errno = cls._system_is_posix
1699 if typ.tag.endswith('::future_error_category'):
1700 name = 'future'
11e1ee1b 1701 enum = cls._find_standard_errc_enum('future_errc')
36100e0e
JW
1702 if typ.tag.endswith('::io_error_category'):
1703 name = 'io'
11e1ee1b 1704 enum = cls._find_standard_errc_enum('io_errc')
36100e0e
JW
1705
1706 if name is None:
1707 try:
1708 # Want to call std::error_category::name() override, but it's
1709 # unsafe: https://sourceware.org/bugzilla/show_bug.cgi?id=28856
1710 # gdb.set_convenience_variable('__cat', cat)
1711 # return '"%s"' % gdb.parse_and_eval('$__cat->name()').string()
1712 pass
1713 except:
2db38d9f 1714 pass
36100e0e 1715 return (name, typ.tag, enum, is_errno)
2db38d9f
JW
1716
1717 @staticmethod
36100e0e
JW
1718 def _unqualified_name(name):
1719 "Strip any nested-name-specifier from NAME to give an unqualified name"
1720 return name.split('::')[-1]
2db38d9f
JW
1721
1722 def to_string (self):
1723 value = self.val['_M_value']
36100e0e
JW
1724 cat = self.val['_M_cat']
1725 name, alt_name, enum, is_errno = self._category_info(cat)
2db38d9f 1726 if value == 0:
36100e0e
JW
1727 default_cats = { 'error_code' : 'system',
1728 'error_condition' : 'generic' }
1729 if name == default_cats[self._unqualified_name(self.typename)]:
2db38d9f 1730 return self.typename + ' = { }' # default-constructed value
36100e0e
JW
1731
1732 strval = str(value)
1733 if is_errno and value != 0:
2db38d9f
JW
1734 try:
1735 strval = errno.errorcode[int(value)]
1736 except:
1737 pass
36100e0e
JW
1738 elif enum is not None:
1739 strval = self._unqualified_name(str(value.cast(enum)))
1740
1741 if name is not None:
1742 name = '"%s"' % name
1743 else:
1744 name = alt_name
1745 return '%s = {%s: %s}' % (self.typename, name, strval)
1746
2db38d9f 1747
7a2f2d91
JW
1748class StdRegexStatePrinter:
1749 "Print a state node in the NFA for a std::regex"
1750
1751 def __init__ (self, typename, val):
1752 self.val = val
1753 self.typename = typename
1754
1755 def to_string (self):
1756 opcode = str(self.val['_M_opcode'])
1757 if opcode:
1758 opcode = opcode[25:]
1759 next_id = self.val['_M_next']
1760
1761 variants = {'repeat':'alt', 'alternative':'alt',
1762 'subexpr_begin':'subexpr', 'subexpr_end':'subexpr',
1763 'line_begin_assertion':None, 'line_end_assertion':None,
1764 'word_boundary':'neg', 'subexpr_lookahead':'neg',
1765 'backref':'backref_index',
1766 'match':None, 'accept':None,
1767 'dummy':None, 'unknown':None
1768 }
1769 v = variants[opcode]
1770
1771 s = "opcode={}, next={}".format(opcode, next_id)
1772 if v is not None and self.val['_M_' + v] is not None:
1773 s = "{}, {}={}".format(s, v, self.val['_M_' + v])
1774 return "{%s}" % (s)
1775
fdb3f82f
PF
1776class StdSpanPrinter:
1777 "Print a std::span"
1778
71999fde 1779 class iterator(Iterator):
fdb3f82f
PF
1780 def __init__(self, begin, size):
1781 self.count = 0
1782 self.begin = begin
1783 self.size = size
1784
1785 def __iter__ (self):
1786 return self
1787
1788 def __next__ (self):
1789 if self.count == self.size:
1790 raise StopIteration
1791
1792 count = self.count
1793 self.count = self.count + 1
1794 return '[%d]' % count, (self.begin + count).dereference()
1795
1796 def __init__(self, typename, val):
ace4b7f2 1797 self.typename = strip_versioned_namespace(typename)
fdb3f82f
PF
1798 self.val = val
1799 if val.type.template_argument(1) == gdb.parse_and_eval('static_cast<std::size_t>(-1)'):
1800 self.size = val['_M_extent']['_M_extent_value']
1801 else:
1802 self.size = val.type.template_argument(1)
1803
1804 def to_string(self):
1805 return '%s of length %d' % (self.typename, self.size)
1806
1807 def children(self):
71999fde
PF
1808 return self.iterator(self.val['_M_ptr'], self.size)
1809
1810 def display_hint(self):
1811 return 'array'
1812
1813class StdInitializerListPrinter:
1814 "Print a std::initializer_list"
1815
1816 def __init__(self, typename, val):
1817 self.typename = typename
1818 self.val = val
1819 self.size = val['_M_len']
1820
1821 def to_string(self):
1822 return '%s of length %d' % (self.typename, self.size)
1823
1824 def children(self):
1825 return StdSpanPrinter.iterator(self.val['_M_array'], self.size)
fdb3f82f
PF
1826
1827 def display_hint(self):
1828 return 'array'
1829
a8495845
JW
1830class StdAtomicPrinter:
1831 "Print a std:atomic"
1832
1833 def __init__(self, typename, val):
11e1ee1b 1834 self.typename = strip_versioned_namespace(typename)
a8495845
JW
1835 self.val = val
1836 self.shptr_printer = None
1837 self.value_type = self.val.type.template_argument(0)
1838 if self.value_type.tag is not None:
1839 typ = strip_versioned_namespace(self.value_type.tag)
1840 if typ.startswith('std::shared_ptr<') or typ.startswith('std::weak_ptr<'):
1841 impl = val['_M_impl']
1842 self.shptr_printer = SharedPointerPrinter(typename, impl)
1843 self.children = self._shptr_children
1844
1845 def _shptr_children(self):
1846 return SmartPtrIterator(self.shptr_printer.pointer)
1847
1848 def to_string(self):
1849 if self.shptr_printer is not None:
1850 return self.shptr_printer.to_string()
1851
1852 if self.value_type.code == gdb.TYPE_CODE_INT:
1853 val = self.val['_M_i']
1854 elif self.value_type.code == gdb.TYPE_CODE_FLT:
1855 val = self.val['_M_fp']
1856 elif self.value_type.code == gdb.TYPE_CODE_PTR:
1857 val = self.val['_M_b']['_M_p']
1858 elif self.value_type.code == gdb.TYPE_CODE_BOOL:
1859 val = self.val['_M_base']['_M_i']
1860 else:
1861 val = self.val['_M_i']
1862 return '%s<%s> = { %s }' % (self.typename, str(self.value_type), val)
1863
1d9454ab
JW
1864class StdFormatArgsPrinter:
1865 "Print a std::basic_format_args"
1866 # TODO: add printer for basic_format_arg<C> and print out children
1867 # TODO: add printer for basic_format_args<C>::_Store<Args...>
1868
1869 def __init__(self, typename, val):
1870 self.typename = strip_versioned_namespace(typename)
1871 self.val = val
1872
1873 def to_string(self):
1874 targs = get_template_arg_list(self.val.type)
1875 char_type = get_template_arg_list(targs[0])[1]
1876 if char_type == gdb.lookup_type('char'):
1877 typ = 'std::format_args'
1878 elif char_type == gdb.lookup_type('wchar_t'):
1879 typ = 'std::wformat_args'
1880 else:
1881 typ = 'std::basic_format_args'
1882
1883 size = self.val['_M_packed_size']
1884 if size == 1:
1885 return "%s with 1 argument" % (typ)
1886 if size == 0:
1887 size = self.val['_M_unpacked_size']
1888 return "%s with %d arguments" % (typ, size)
1889
d33a250f
JW
1890def std_ratio_t_tuple(ratio_type):
1891 # TODO use reduced period i.e. duration::period
1892 period = self.val.type.template_argument(1)
1893 num = period.template_argument(0)
1894 den = period.template_argument(1)
1895 return (num, den)
1896
1897class StdChronoDurationPrinter:
1898 "Print a std::chrono::duration"
1899
1900 def __init__(self, typename, val):
1901 self.typename = strip_versioned_namespace(typename)
1902 self.val = val
1903
1904 def _ratio(self):
1905 # TODO use reduced period i.e. duration::period
1906 period = self.val.type.template_argument(1)
1907 num = period.template_argument(0)
1908 den = period.template_argument(1)
1909 return (num, den)
1910
1911 def _suffix(self):
1912 num, den = self._ratio()
1913 if num == 1:
1914 if den == 1:
1915 return 's'
1916 if den == 1000:
1917 return 'ms'
1918 if den == 1000000:
1919 return 'us'
1920 if den == 1000000000:
1921 return 'ns'
1922 elif den == 1:
1923 if num == 60:
1924 return 'min'
1925 if num == 3600:
1926 return 'h'
1927 if num == 86400:
1928 return 'd'
1929 return '[{}]s'.format(num)
1930 return "[{}/{}]s".format(num, den)
1931
1932 def to_string(self):
1933 return "std::chrono::duration = { %d%s }" % (self.val['__r'], self._suffix())
1934
1935
1936class StdChronoTimePointPrinter:
1937 "Print a std::chrono::time_point"
1938
1939 def __init__(self, typename, val):
1940 self.typename = strip_versioned_namespace(typename)
1941 self.val = val
1942
1943 def _clock(self):
1944 clock = self.val.type.template_argument(0)
1945 name = strip_versioned_namespace(clock.name)
1946 if name == 'std::chrono::_V2::system_clock' \
1947 or name == 'std::chrono::system_clock':
1948 return ('std::chrono::sys_time', 0)
1949 # XXX need to remove leap seconds from utc, gps, and tai
1950 #if name == 'std::chrono::utc_clock':
1951 # return ('std::chrono::utc_time', 0)
1952 #if name == 'std::chrono::gps_clock':
1953 # return ('std::chrono::gps_clock time_point', 315964809)
1954 #if name == 'std::chrono::tai_clock':
1955 # return ('std::chrono::tai_clock time_point', -378691210)
1956 if name == 'std::filesystem::__file_clock':
1957 return ('std::chrono::file_time', 6437664000)
1958 if name == 'std::chrono::local_t':
1959 return ('std::chrono::local_time', 0)
1960 return ('{} time_point'.format(name), None)
1961
1962 def to_string(self):
1963 clock, offset = self._clock()
1964 d = self.val['__d']
1965 r = d['__r']
1966 printer = StdChronoDurationPrinter(d.type.name, d)
1967 suffix = printer._suffix()
1968 time = ''
1969 if offset is not None:
1970 num, den = printer._ratio()
1971 secs = (r * num / den) + offset
1972 try:
80ff207d 1973 dt = datetime.fromtimestamp(secs, _utc_timezone)
d33a250f
JW
1974 time = ' [{:%Y-%m-%d %H:%M:%S}]'.format(dt)
1975 except:
1976 pass
1977 return '%s = {%d%s%s}' % (clock, r, suffix, time)
1978
1979class StdChronoZonedTimePrinter:
1980 "Print a std::chrono::zoned_time"
1981
1982 def __init__(self, typename, val):
1983 self.typename = strip_versioned_namespace(typename)
1984 self.val = val
1985
1986 def to_string(self):
1987 zone = self.val['_M_zone'].dereference()
1988 time = self.val['_M_tp']
1989 return 'std::chrono::zoned_time = {{{} {}}}'.format(zone, time)
1990
1991
1992months = [None, 'January', 'February', 'March', 'April', 'May', 'June',
1993 'July', 'August', 'September', 'October', 'November', 'December']
1994
1995weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
1996 'Saturday', 'Sunday']
1997
1998class StdChronoCalendarPrinter:
1999 "Print a std::chrono::day, std::chrono::month, std::chrono::year etc."
2000
2001 def __init__(self, typename, val):
2002 self.typename = strip_versioned_namespace(typename)
2003 self.val = val
2004
2005 def to_string(self):
2006 val = self.val
2007 typ = self.typename
2008 if 'month' in typ and typ != 'std::chrono::year_month_day_last':
2009 m = val['_M_m']
2010 if typ.startswith('std::chrono::year'):
2011 y = val['_M_y']
2012
2013 if typ == 'std::chrono::day':
2014 return '{}'.format(int(val['_M_d']))
2015 if typ == 'std::chrono::month':
2016 return months[m]
2017 if typ == 'std::chrono::year':
2018 return '{}y'.format(y)
2019 if typ == 'std::chrono::weekday':
2020 return '{}'.format(weekdays[val['_M_wd']])
2021 if typ == 'std::chrono::weekday_indexed':
2022 return '{}[{}]'.format(val['_M_wd'], int(val['_M_index']))
2023 if typ == 'std::chrono::weekday_last':
2024 return '{}[last]'.format(val['_M_wd'])
2025 if typ == 'std::chrono::month_day':
2026 return '{}/{}'.format(m, val['_M_d'])
2027 if typ == 'std::chrono::month_day_last':
2028 return '{}/last'.format(m)
2029 if typ == 'std::chrono::month_weekday':
2030 return '{}/{}'.format(m, val['_M_wdi'])
2031 if typ == 'std::chrono::month_weekday_last':
2032 return '{}/{}'.format(m, val['_M_wdl'])
2033 if typ == 'std::chrono::year_month':
2034 return '{}/{}'.format(y, m)
2035 if typ == 'std::chrono::year_month_day':
2036 return '{}/{}/{}'.format(y, m, val['_M_d'])
2037 if typ == 'std::chrono::year_month_day_last':
2038 return '{}/{}'.format(y, val['_M_mdl'])
2039 if typ == 'std::chrono::year_month_weekday':
2040 return '{}/{}'.format(y, m, val['_M_wdi'])
2041 if typ == 'std::chrono::year_month_weekday_last':
2042 return '{}/{}'.format(y, m, val['_M_wdl'])
2043 if typ.startswith('std::chrono::hh_mm_ss'):
2044 fract = ''
2045 if val['fractional_width'] != 0:
2046 fract = '.{:0{}d}'.format(int(val['_M_ss']['__r']),
2047 int(val['fractional_width']))
2048 h = int(val['_M_h']['__r'])
2049 m = int(val['_M_m']['__r'])
2050 s = int(val['_M_s']['__r'])
2051 if val['_M_is_neg']:
2052 h = -h
2053 return '{:02}:{:02}:{:02}{}'.format(h, m, s, fract)
2054
2055class StdChronoTimeZonePrinter:
2056 "Print a chrono::time_zone or chrono::time_zone_link"
2057
2058 def __init__(self, typename, val):
2059 self.typename = strip_versioned_namespace(typename)
2060 self.val = val
2061
2062 def to_string(self):
2063 str = '%s %s' % (self.typename, self.val['_M_name'])
2064 if self.typename.endswith("_link"):
2065 str += ' -> %s' % (self.val['_M_target'])
2066 return str
2067
2068class StdChronoLeapSecondPrinter:
2069 "Print a chrono::leap_second"
2070
2071 def __init__(self, typename, val):
2072 self.typename = strip_versioned_namespace(typename)
2073 self.val = val
2074
2075 def to_string(self):
2076 date = self.val['_M_s']['__r']
2077 neg = '+-'[date < 0]
2078 return '%s %d (%c)' % (self.typename, abs(date), neg)
2079
2080class StdChronoTzdbPrinter:
2081 "Print a chrono::tzdb"
2082
2083 def __init__(self, typename, val):
2084 self.typename = strip_versioned_namespace(typename)
2085 self.val = val
2086
2087 def to_string(self):
2088 return '%s %s' % (self.typename, self.val['version'])
2089
2090class StdChronoTimeZoneRulePrinter:
2091 "Print a chrono::time_zone rule"
2092
2093 def __init__(self, typename, val):
2094 self.typename = strip_versioned_namespace(typename)
2095 self.val = val
2096
2097 def to_string(self):
2098 on = self.val['on']
2099 kind = on['kind']
2100 month = months[on['month']]
2101 suffixes = {1:'st', 2:'nd', 3:'rd', 21:'st', 22:'nd', 23:'rd', 31:'st'}
2102 day = on['day_of_month']
2103 ordinal_day = '{}{}'.format(day, suffixes.get(day, 'th'))
2104 if kind == 0: # DayOfMonth
2105 start = '{} {}{}'.format(month, ordinal_day)
2106 else:
2107 weekday = weekdays[on['day_of_week']]
2108 if kind == 1: # LastWeekDay
2109 start = 'last {} in {}'.format(weekday, month)
2110 else:
2111 if kind == 2: # LessEq
2112 direction = ('last', '<=')
2113 else:
2114 direction = ('first', '>=')
2115 day = on['day_of_month']
2116 start = '{} {} {} {} {}'.format(direction[0], weekday,
2117 direction[1], month,
2118 ordinal_day)
2119 return 'time_zone rule {} from {} to {} starting on {}'.format(
2120 self.val['name'], self.val['from'], self.val['to'], start)
2121
2122
d63c53cc
TT
2123# A "regular expression" printer which conforms to the
2124# "SubPrettyPrinter" protocol from gdb.printing.
2125class RxPrinter(object):
2126 def __init__(self, name, function):
2127 super(RxPrinter, self).__init__()
2128 self.name = name
2129 self.function = function
2130 self.enabled = True
2131
2132 def invoke(self, value):
2133 if not self.enabled:
2134 return None
c77efe8f
PM
2135
2136 if value.type.code == gdb.TYPE_CODE_REF:
2137 if hasattr(gdb.Value,"referenced_value"):
2138 value = value.referenced_value()
2139
d63c53cc
TT
2140 return self.function(self.name, value)
2141
2142# A pretty-printer that conforms to the "PrettyPrinter" protocol from
2143# gdb.printing. It can also be used directly as an old-style printer.
2144class Printer(object):
2145 def __init__(self, name):
2146 super(Printer, self).__init__()
2147 self.name = name
2148 self.subprinters = []
2149 self.lookup = {}
2150 self.enabled = True
6f440cce 2151 self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
d63c53cc
TT
2152
2153 def add(self, name, function):
2154 # A small sanity check.
2155 # FIXME
6f440cce 2156 if not self.compiled_rx.match(name):
47059228 2157 raise ValueError('libstdc++ programming error: "%s" does not match' % name)
d63c53cc
TT
2158 printer = RxPrinter(name, function)
2159 self.subprinters.append(printer)
2160 self.lookup[name] = printer
41850419 2161
3efe2bf7
TT
2162 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION.
2163 def add_version(self, base, name, function):
2164 self.add(base + name, function)
4347fea9 2165 if _versioned_namespace and not '__cxx11' in base:
86397ed1
FD
2166 vbase = re.sub('^(std|__gnu_cxx)::', r'\g<0>%s' % _versioned_namespace, base)
2167 self.add(vbase + name, function)
3efe2bf7
TT
2168
2169 # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER.
2170 def add_container(self, base, name, function):
2171 self.add_version(base, name, function)
2172 self.add_version(base + '__cxx1998::', name, function)
2173
d63c53cc
TT
2174 @staticmethod
2175 def get_basic_type(type):
2176 # If it points to a reference, get the reference.
2177 if type.code == gdb.TYPE_CODE_REF:
2178 type = type.target ()
41850419 2179
d63c53cc
TT
2180 # Get the unqualified type, stripped of typedefs.
2181 type = type.unqualified ().strip_typedefs ()
41850419 2182
d63c53cc 2183 return type.tag
41850419 2184
d63c53cc
TT
2185 def __call__(self, val):
2186 typename = self.get_basic_type(val.type)
2187 if not typename:
2188 return None
41850419 2189
d63c53cc
TT
2190 # All the types we match are template types, so we can use a
2191 # dictionary.
2192 match = self.compiled_rx.match(typename)
2193 if not match:
2194 return None
41850419 2195
d63c53cc 2196 basename = match.group(1)
c77efe8f
PM
2197
2198 if val.type.code == gdb.TYPE_CODE_REF:
2199 if hasattr(gdb.Value,"referenced_value"):
2200 val = val.referenced_value()
2201
d63c53cc
TT
2202 if basename in self.lookup:
2203 return self.lookup[basename].invoke(val)
41850419 2204
d63c53cc 2205 # Cannot find a pretty printer. Return None.
41850419
TT
2206 return None
2207
d63c53cc
TT
2208libstdcxx_printer = None
2209
077aa95e 2210class TemplateTypePrinter(object):
7224c6a9 2211 r"""
bab0a26d 2212 A type printer for class templates with default template arguments.
077aa95e 2213
bab0a26d
JW
2214 Recognizes specializations of class templates and prints them without
2215 any template arguments that use a default template argument.
2216 Type printers are recursively applied to the template arguments.
077aa95e 2217
bab0a26d 2218 e.g. replace "std::vector<T, std::allocator<T> >" with "std::vector<T>".
077aa95e
JW
2219 """
2220
bab0a26d 2221 def __init__(self, name, defargs):
077aa95e 2222 self.name = name
bab0a26d 2223 self.defargs = defargs
077aa95e
JW
2224 self.enabled = True
2225
2226 class _recognizer(object):
bab0a26d
JW
2227 "The recognizer class for TemplateTypePrinter."
2228
2229 def __init__(self, name, defargs):
2230 self.name = name
2231 self.defargs = defargs
2232 # self.type_obj = None
077aa95e
JW
2233
2234 def recognize(self, type_obj):
bab0a26d
JW
2235 """
2236 If type_obj is a specialization of self.name that uses all the
2237 default template arguments for the class template, then return
2238 a string representation of the type without default arguments.
2239 Otherwise, return None.
2240 """
2241
077aa95e
JW
2242 if type_obj.tag is None:
2243 return None
2244
bab0a26d
JW
2245 if not type_obj.tag.startswith(self.name):
2246 return None
2247
2248 template_args = get_template_arg_list(type_obj)
2249 displayed_args = []
2250 require_defaulted = False
2251 for n in range(len(template_args)):
2252 # The actual template argument in the type:
2253 targ = template_args[n]
2254 # The default template argument for the class template:
2255 defarg = self.defargs.get(n)
2256 if defarg is not None:
2257 # Substitute other template arguments into the default:
2258 defarg = defarg.format(*template_args)
2259 # Fail to recognize the type (by returning None)
2260 # unless the actual argument is the same as the default.
2261 try:
2262 if targ != gdb.lookup_type(defarg):
2263 return None
2264 except gdb.error:
2265 # Type lookup failed, just use string comparison:
2266 if targ.tag != defarg:
2267 return None
2268 # All subsequent args must have defaults:
2269 require_defaulted = True
2270 elif require_defaulted:
2271 return None
2272 else:
2273 # Recursively apply recognizers to the template argument
2274 # and add it to the arguments that will be displayed:
2275 displayed_args.append(self._recognize_subtype(targ))
2276
2277 # This assumes no class templates in the nested-name-specifier:
2278 template_name = type_obj.tag[0:type_obj.tag.find('<')]
2279 template_name = strip_inline_namespaces(template_name)
2280
2281 return template_name + '<' + ', '.join(displayed_args) + '>'
2282
2283 def _recognize_subtype(self, type_obj):
2284 """Convert a gdb.Type to a string by applying recognizers,
2285 or if that fails then simply converting to a string."""
2286
2287 if type_obj.code == gdb.TYPE_CODE_PTR:
2288 return self._recognize_subtype(type_obj.target()) + '*'
2289 if type_obj.code == gdb.TYPE_CODE_ARRAY:
2290 type_str = self._recognize_subtype(type_obj.target())
2291 if str(type_obj.strip_typedefs()).endswith('[]'):
2292 return type_str + '[]' # array of unknown bound
2293 return "%s[%d]" % (type_str, type_obj.range()[1] + 1)
2294 if type_obj.code == gdb.TYPE_CODE_REF:
2295 return self._recognize_subtype(type_obj.target()) + '&'
2296 if hasattr(gdb, 'TYPE_CODE_RVALUE_REF'):
2297 if type_obj.code == gdb.TYPE_CODE_RVALUE_REF:
2298 return self._recognize_subtype(type_obj.target()) + '&&'
2299
2300 type_str = gdb.types.apply_type_recognizers(
2301 gdb.types.get_type_recognizers(), type_obj)
2302 if type_str:
2303 return type_str
2304 return str(type_obj)
077aa95e
JW
2305
2306 def instantiate(self):
bab0a26d
JW
2307 "Return a recognizer object for this type printer."
2308 return self._recognizer(self.name, self.defargs)
077aa95e 2309
bab0a26d
JW
2310def add_one_template_type_printer(obj, name, defargs):
2311 r"""
2312 Add a type printer for a class template with default template arguments.
2313
2314 Args:
2315 name (str): The template-name of the class template.
2316 defargs (dict int:string) The default template arguments.
2317
2318 Types in defargs can refer to the Nth template-argument using {N}
2319 (with zero-based indices).
2320
2321 e.g. 'unordered_map' has these defargs:
2322 { 2: 'std::hash<{0}>',
2323 3: 'std::equal_to<{0}>',
2324 4: 'std::allocator<std::pair<const {0}, {1}> >' }
2325
2326 """
2327 printer = TemplateTypePrinter('std::'+name, defargs)
077aa95e 2328 gdb.types.register_type_printer(obj, printer)
3997383b
FD
2329
2330 # Add type printer for same type in debug namespace:
2331 printer = TemplateTypePrinter('std::__debug::'+name, defargs)
2332 gdb.types.register_type_printer(obj, printer)
2333
4347fea9 2334 if _versioned_namespace and not '__cxx11' in name:
f9a27859 2335 # Add second type printer for same type in versioned namespace:
bab0a26d 2336 ns = 'std::' + _versioned_namespace
4fdb6fb6
JW
2337 # PR 86112 Cannot use dict comprehension here:
2338 defargs = dict((n, d.replace('std::', ns)) for (n,d) in defargs.items())
bab0a26d 2339 printer = TemplateTypePrinter(ns+name, defargs)
f9a27859 2340 gdb.types.register_type_printer(obj, printer)
077aa95e 2341
13337ea9
FD
2342 # Add type printer for same type in debug namespace:
2343 printer = TemplateTypePrinter('std::__debug::'+name, defargs)
2344 gdb.types.register_type_printer(obj, printer)
2345
50605a7f 2346class FilteringTypePrinter(object):
bab0a26d
JW
2347 r"""
2348 A type printer that uses typedef names for common template specializations.
2349
2350 Args:
2b7f0378 2351 template (str): The class template to recognize.
bab0a26d 2352 name (str): The typedef-name that will be used instead.
92281622 2353 targ1 (str, optional): The first template argument. Defaults to None.
bab0a26d 2354
2b7f0378 2355 Checks if a specialization of the class template 'template' is the same type
bab0a26d
JW
2356 as the typedef 'name', and prints it as 'name' instead.
2357
2358 e.g. if an instantiation of std::basic_istream<C, T> is the same type as
2359 std::istream then print it as std::istream.
92281622
JW
2360
2361 If targ1 is provided (not None), match only template specializations with
2362 this type as the first template argument, e.g. if template='basic_string'
2363 and targ1='char' then only match 'basic_string<char,...>' and not
2364 'basic_string<wchar_t,...>'. This rejects non-matching specializations
2365 more quickly, without needing to do GDB type lookups.
bab0a26d
JW
2366 """
2367
92281622 2368 def __init__(self, template, name, targ1 = None):
2b7f0378 2369 self.template = template
50605a7f 2370 self.name = name
2b7f0378 2371 self.targ1 = targ1
50605a7f
TT
2372 self.enabled = True
2373
2374 class _recognizer(object):
ace4b7f2 2375 "The recognizer class for FilteringTypePrinter."
bab0a26d 2376
2b7f0378
FD
2377 def __init__(self, template, name, targ1):
2378 self.template = template
50605a7f 2379 self.name = name
2b7f0378 2380 self.targ1 = targ1
50605a7f
TT
2381 self.type_obj = None
2382
2383 def recognize(self, type_obj):
bab0a26d 2384 """
2b7f0378 2385 If type_obj starts with self.template and is the same type as
bab0a26d
JW
2386 self.name then return self.name, otherwise None.
2387 """
50605a7f
TT
2388 if type_obj.tag is None:
2389 return None
2390
2391 if self.type_obj is None:
2b7f0378
FD
2392 if self.targ1 is not None:
2393 if not type_obj.tag.startswith('{}<{}'.format(self.template, self.targ1)):
2394 # Filter didn't match.
2395 return None
2396 elif not type_obj.tag.startswith(self.template):
50605a7f
TT
2397 # Filter didn't match.
2398 return None
2b7f0378 2399
50605a7f
TT
2400 try:
2401 self.type_obj = gdb.lookup_type(self.name).strip_typedefs()
2402 except:
2403 pass
4347fea9
FD
2404
2405 if self.type_obj is None:
2406 return None
2407
2b7f0378
FD
2408 if gdb.types.get_basic_type(self.type_obj) == gdb.types.get_basic_type(type_obj):
2409 return strip_inline_namespaces(self.name)
4347fea9 2410
2b7f0378
FD
2411 # Workaround ambiguous typedefs matching both std:: and std::__cxx11:: symbols.
2412 if self.template.split('::')[-1] == 'basic_string':
4347fea9
FD
2413 if self.type_obj.tag.replace('__cxx11::', '') == type_obj.tag.replace('__cxx11::', ''):
2414 return strip_inline_namespaces(self.name)
2415
50605a7f
TT
2416 return None
2417
2418 def instantiate(self):
bab0a26d 2419 "Return a recognizer object for this type printer."
2b7f0378 2420 return self._recognizer(self.template, self.name, self.targ1)
50605a7f 2421
2b7f0378
FD
2422def add_one_type_printer(obj, template, name, targ1 = None):
2423 printer = FilteringTypePrinter('std::' + template, 'std::' + name, targ1)
50605a7f 2424 gdb.types.register_type_printer(obj, printer)
2b7f0378 2425 if _versioned_namespace and not '__cxx11' in template:
bab0a26d 2426 ns = 'std::' + _versioned_namespace
2b7f0378 2427 printer = FilteringTypePrinter(ns + template, ns + name, targ1)
f9a27859 2428 gdb.types.register_type_printer(obj, printer)
50605a7f
TT
2429
2430def register_type_printers(obj):
2431 global _use_type_printing
2432
2433 if not _use_type_printing:
2434 return
2435
bab0a26d 2436 # Add type printers for typedefs std::string, std::wstring etc.
2b7f0378
FD
2437 for ch in (('', 'char'),
2438 ('w', 'wchar_t'),
2439 ('u8', 'char8_t'),
2440 ('u16', 'char16_t'),
2441 ('u32', 'char32_t')):
2442 add_one_type_printer(obj, 'basic_string', ch[0] + 'string', ch[1])
2443 add_one_type_printer(obj, '__cxx11::basic_string', ch[0] + 'string', ch[1])
33b43b0d 2444 # Typedefs for __cxx11::basic_string used to be in namespace __cxx11:
bab0a26d 2445 add_one_type_printer(obj, '__cxx11::basic_string',
2b7f0378
FD
2446 '__cxx11::' + ch[0] + 'string', ch[1])
2447 add_one_type_printer(obj, 'basic_string_view', ch[0] + 'string_view', ch[1])
bab0a26d
JW
2448
2449 # Add type printers for typedefs std::istream, std::wistream etc.
2b7f0378 2450 for ch in (('', 'char'), ('w', 'wchar_t')):
bab0a26d
JW
2451 for x in ('ios', 'streambuf', 'istream', 'ostream', 'iostream',
2452 'filebuf', 'ifstream', 'ofstream', 'fstream'):
2b7f0378 2453 add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1])
bab0a26d
JW
2454 for x in ('stringbuf', 'istringstream', 'ostringstream',
2455 'stringstream'):
2b7f0378 2456 add_one_type_printer(obj, 'basic_' + x, ch[0] + x, ch[1])
33b43b0d 2457 # <sstream> types are in __cxx11 namespace, but typedefs aren't:
2b7f0378 2458 add_one_type_printer(obj, '__cxx11::basic_' + x, ch[0] + x, ch[1])
bab0a26d
JW
2459
2460 # Add type printers for typedefs regex, wregex, cmatch, wcmatch etc.
2461 for abi in ('', '__cxx11::'):
2b7f0378
FD
2462 for ch in (('', 'char'), ('w', 'wchar_t')):
2463 add_one_type_printer(obj, abi + 'basic_regex', abi + ch[0] + 'regex', ch[1])
bab0a26d
JW
2464 for ch in ('c', 's', 'wc', 'ws'):
2465 add_one_type_printer(obj, abi + 'match_results', abi + ch + 'match')
2466 for x in ('sub_match', 'regex_iterator', 'regex_token_iterator'):
2467 add_one_type_printer(obj, abi + x, abi + ch + x)
50605a7f
TT
2468
2469 # Note that we can't have a printer for std::wstreampos, because
bab0a26d 2470 # it is the same type as std::streampos.
50605a7f 2471 add_one_type_printer(obj, 'fpos', 'streampos')
f9a27859 2472
bab0a26d 2473 # Add type printers for <chrono> typedefs.
d33a250f
JW
2474 for dur in ('nanoseconds', 'microseconds', 'milliseconds', 'seconds',
2475 'minutes', 'hours', 'days', 'weeks', 'years', 'months'):
2476 add_one_type_printer(obj, 'chrono::duration', 'chrono::' + dur)
50605a7f 2477
bab0a26d 2478 # Add type printers for <random> typedefs.
50605a7f
TT
2479 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
2480 add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand')
2481 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937')
2482 add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64')
2483 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base')
2484 add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base')
2485 add_one_type_printer(obj, 'discard_block_engine', 'ranlux24')
2486 add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
2487 add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
2488
bab0a26d
JW
2489 # Add type printers for experimental::basic_string_view typedefs.
2490 ns = 'experimental::fundamentals_v1::'
2b7f0378
FD
2491 for ch in (('', 'char'),
2492 ('w', 'wchar_t'),
2493 ('u8', 'char8_t'),
2494 ('u16', 'char16_t'),
2495 ('u32', 'char32_t')):
bab0a26d 2496 add_one_type_printer(obj, ns + 'basic_string_view',
2b7f0378 2497 ns + ch[0] + 'string_view', ch[1])
bab0a26d
JW
2498
2499 # Do not show defaulted template arguments in class templates.
2500 add_one_template_type_printer(obj, 'unique_ptr',
2501 { 1: 'std::default_delete<{0}>' })
2502 add_one_template_type_printer(obj, 'deque', { 1: 'std::allocator<{0}>'})
2503 add_one_template_type_printer(obj, 'forward_list', { 1: 'std::allocator<{0}>'})
2504 add_one_template_type_printer(obj, 'list', { 1: 'std::allocator<{0}>'})
2505 add_one_template_type_printer(obj, '__cxx11::list', { 1: 'std::allocator<{0}>'})
2506 add_one_template_type_printer(obj, 'vector', { 1: 'std::allocator<{0}>'})
2507 add_one_template_type_printer(obj, 'map',
2508 { 2: 'std::less<{0}>',
2509 3: 'std::allocator<std::pair<{0} const, {1}>>' })
2510 add_one_template_type_printer(obj, 'multimap',
2511 { 2: 'std::less<{0}>',
2512 3: 'std::allocator<std::pair<{0} const, {1}>>' })
2513 add_one_template_type_printer(obj, 'set',
2514 { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
2515 add_one_template_type_printer(obj, 'multiset',
2516 { 1: 'std::less<{0}>', 2: 'std::allocator<{0}>' })
2517 add_one_template_type_printer(obj, 'unordered_map',
2518 { 2: 'std::hash<{0}>',
2519 3: 'std::equal_to<{0}>',
2520 4: 'std::allocator<std::pair<{0} const, {1}>>'})
2521 add_one_template_type_printer(obj, 'unordered_multimap',
2522 { 2: 'std::hash<{0}>',
2523 3: 'std::equal_to<{0}>',
2524 4: 'std::allocator<std::pair<{0} const, {1}>>'})
2525 add_one_template_type_printer(obj, 'unordered_set',
2526 { 1: 'std::hash<{0}>',
2527 2: 'std::equal_to<{0}>',
2528 3: 'std::allocator<{0}>'})
2529 add_one_template_type_printer(obj, 'unordered_multiset',
2530 { 1: 'std::hash<{0}>',
2531 2: 'std::equal_to<{0}>',
2532 3: 'std::allocator<{0}>'})
077aa95e 2533
d63c53cc
TT
2534def register_libstdcxx_printers (obj):
2535 "Register libstdc++ pretty-printers with objfile Obj."
2536
2537 global _use_gdb_pp
2538 global libstdcxx_printer
2539
2540 if _use_gdb_pp:
2541 gdb.printing.register_pretty_printer(obj, libstdcxx_printer)
2542 else:
2543 if obj is None:
2544 obj = gdb
2545 obj.pretty_printers.append(libstdcxx_printer)
41850419 2546
50605a7f
TT
2547 register_type_printers(obj)
2548
41850419 2549def build_libstdcxx_dictionary ():
d63c53cc
TT
2550 global libstdcxx_printer
2551
2552 libstdcxx_printer = Printer("libstdc++-v6")
2553
41850419
TT
2554 # libstdc++ objects requiring pretty-printing.
2555 # In order from:
2556 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
3efe2bf7 2557 libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter)
86397ed1 2558 libstdcxx_printer.add_version('std::__cxx11::', 'basic_string', StdStringPrinter)
3efe2bf7
TT
2559 libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter)
2560 libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter)
2561 libstdcxx_printer.add_container('std::', 'list', StdListPrinter)
bf1de1ac 2562 libstdcxx_printer.add_container('std::__cxx11::', 'list', StdListPrinter)
3efe2bf7
TT
2563 libstdcxx_printer.add_container('std::', 'map', StdMapPrinter)
2564 libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter)
2565 libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter)
e1821582 2566 libstdcxx_printer.add_version('std::', 'pair', StdPairPrinter)
3efe2bf7
TT
2567 libstdcxx_printer.add_version('std::', 'priority_queue',
2568 StdStackOrQueuePrinter)
2569 libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter)
2570 libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter)
2571 libstdcxx_printer.add_container('std::', 'set', StdSetPrinter)
2572 libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter)
2573 libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter)
2574 libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter)
41850419
TT
2575 # vector<bool>
2576
36100e0e
JW
2577 if hasattr(gdb.Value, 'dynamic_type'):
2578 libstdcxx_printer.add_version('std::', 'error_code',
2579 StdErrorCodePrinter)
2580 libstdcxx_printer.add_version('std::', 'error_condition',
2581 StdErrorCodePrinter)
2582
cd0961a5 2583 # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG.
d63c53cc
TT
2584 libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter)
2585 libstdcxx_printer.add('std::__debug::deque', StdDequePrinter)
2586 libstdcxx_printer.add('std::__debug::list', StdListPrinter)
2587 libstdcxx_printer.add('std::__debug::map', StdMapPrinter)
2588 libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter)
2589 libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter)
d63c53cc 2590 libstdcxx_printer.add('std::__debug::set', StdSetPrinter)
d63c53cc 2591 libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter)
cd0961a5 2592
00895372 2593 # These are the TR1 and C++11 printers.
41850419 2594 # For array - the default GDB pretty-printer seems reasonable.
a1527f2f
JW
2595 libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter)
2596 libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter)
3efe2bf7
TT
2597 libstdcxx_printer.add_container('std::', 'unordered_map',
2598 Tr1UnorderedMapPrinter)
2599 libstdcxx_printer.add_container('std::', 'unordered_set',
2600 Tr1UnorderedSetPrinter)
2601 libstdcxx_printer.add_container('std::', 'unordered_multimap',
2602 Tr1UnorderedMapPrinter)
2603 libstdcxx_printer.add_container('std::', 'unordered_multiset',
2604 Tr1UnorderedSetPrinter)
2605 libstdcxx_printer.add_container('std::', 'forward_list',
2606 StdForwardListPrinter)
2607
86397ed1
FD
2608 libstdcxx_printer.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter)
2609 libstdcxx_printer.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter)
2610 libstdcxx_printer.add_version('std::tr1::', 'unordered_map',
3efe2bf7 2611 Tr1UnorderedMapPrinter)
86397ed1 2612 libstdcxx_printer.add_version('std::tr1::', 'unordered_set',
3efe2bf7 2613 Tr1UnorderedSetPrinter)
86397ed1 2614 libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap',
3efe2bf7 2615 Tr1UnorderedMapPrinter)
86397ed1 2616 libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset',
3efe2bf7 2617 Tr1UnorderedSetPrinter)
41850419 2618
71999fde
PF
2619 libstdcxx_printer.add_version('std::', 'initializer_list',
2620 StdInitializerListPrinter)
a8495845 2621 libstdcxx_printer.add_version('std::', 'atomic', StdAtomicPrinter)
93257ed6
PF
2622 libstdcxx_printer.add_version('std::', 'basic_stringbuf', StdStringBufPrinter)
2623 libstdcxx_printer.add_version('std::__cxx11::', 'basic_stringbuf', StdStringBufPrinter)
2624 for sstream in ('istringstream', 'ostringstream', 'stringstream'):
2625 libstdcxx_printer.add_version('std::', 'basic_' + sstream, StdStringStreamPrinter)
2626 libstdcxx_printer.add_version('std::__cxx11::', 'basic_' + sstream, StdStringStreamPrinter)
71999fde 2627
d33a250f
JW
2628 libstdcxx_printer.add_version('std::chrono::', 'duration',
2629 StdChronoDurationPrinter)
2630 libstdcxx_printer.add_version('std::chrono::', 'time_point',
2631 StdChronoTimePointPrinter)
2632
7a2f2d91
JW
2633 # std::regex components
2634 libstdcxx_printer.add_version('std::__detail::', '_State',
2635 StdRegexStatePrinter)
2636
00895372 2637 # These are the C++11 printer registrations for -D_GLIBCXX_DEBUG cases.
3c760f4a
JW
2638 # The tr1 namespace containers do not have any debug equivalents,
2639 # so do not register printers for them.
d63c53cc
TT
2640 libstdcxx_printer.add('std::__debug::unordered_map',
2641 Tr1UnorderedMapPrinter)
2642 libstdcxx_printer.add('std::__debug::unordered_set',
2643 Tr1UnorderedSetPrinter)
2644 libstdcxx_printer.add('std::__debug::unordered_multimap',
2645 Tr1UnorderedMapPrinter)
2646 libstdcxx_printer.add('std::__debug::unordered_multiset',
2647 Tr1UnorderedSetPrinter)
8dfb08ab
JW
2648 libstdcxx_printer.add('std::__debug::forward_list',
2649 StdForwardListPrinter)
cd0961a5 2650
6f440cce
JW
2651 # Library Fundamentals TS components
2652 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
2653 'any', StdExpAnyPrinter)
2654 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
2655 'optional', StdExpOptionalPrinter)
2656 libstdcxx_printer.add_version('std::experimental::fundamentals_v1::',
2657 'basic_string_view', StdExpStringViewPrinter)
0ca7ba9a
JW
2658 # Filesystem TS components
2659 libstdcxx_printer.add_version('std::experimental::filesystem::v1::',
2660 'path', StdExpPathPrinter)
a00d74c4 2661 libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
0ca7ba9a 2662 'path', StdExpPathPrinter)
641cb5a6 2663 libstdcxx_printer.add_version('std::filesystem::',
4f87bb8d 2664 'path', StdPathPrinter)
641cb5a6 2665 libstdcxx_printer.add_version('std::filesystem::__cxx11::',
4f87bb8d 2666 'path', StdPathPrinter)
41850419 2667
00895372
JW
2668 # C++17 components
2669 libstdcxx_printer.add_version('std::',
2670 'any', StdExpAnyPrinter)
2671 libstdcxx_printer.add_version('std::',
2672 'optional', StdExpOptionalPrinter)
2673 libstdcxx_printer.add_version('std::',
2674 'basic_string_view', StdExpStringViewPrinter)
2675 libstdcxx_printer.add_version('std::',
2676 'variant', StdVariantPrinter)
2dbe56bd
JW
2677 libstdcxx_printer.add_version('std::',
2678 '_Node_handle', StdNodeHandlePrinter)
00895372 2679
a59c50bd
JW
2680 # C++20 components
2681 libstdcxx_printer.add_version('std::', 'partial_ordering', StdCmpCatPrinter)
2682 libstdcxx_printer.add_version('std::', 'weak_ordering', StdCmpCatPrinter)
2683 libstdcxx_printer.add_version('std::', 'strong_ordering', StdCmpCatPrinter)
fdb3f82f 2684 libstdcxx_printer.add_version('std::', 'span', StdSpanPrinter)
d33a250f
JW
2685 libstdcxx_printer.add_version('std::', 'basic_format_args',
2686 StdFormatArgsPrinter)
2687 for c in ['day','month','year','weekday','weekday_indexed','weekday_last',
2688 'month_day','month_day_last','month_weekday','month_weekday_last',
2689 'year_month','year_month_day','year_month_day_last',
2690 'year_month_weekday','year_month_weekday_last', 'hh_mm_ss']:
2691 libstdcxx_printer.add_version('std::chrono::', c,
2692 StdChronoCalendarPrinter)
2693 libstdcxx_printer.add_version('std::chrono::', 'time_zone',
2694 StdChronoTimeZonePrinter)
2695 libstdcxx_printer.add_version('std::chrono::', 'time_zone_link',
2696 StdChronoTimeZonePrinter)
2697 libstdcxx_printer.add_version('std::chrono::', 'zoned_time',
2698 StdChronoZonedTimePrinter)
2699 libstdcxx_printer.add_version('std::chrono::', 'leap_second',
2700 StdChronoLeapSecondPrinter)
2701 libstdcxx_printer.add_version('std::chrono::', 'tzdb', StdChronoTzdbPrinter)
2702 #libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule',
2703 # StdChronoTimeZoneRulePrinter)
a59c50bd 2704
41850419 2705 # Extensions.
3efe2bf7 2706 libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter)
41850419
TT
2707
2708 if True:
2709 # These shouldn't be necessary, if GDB "print *i" worked.
2710 # But it often doesn't, so here they are.
3efe2bf7
TT
2711 libstdcxx_printer.add_container('std::', '_List_iterator',
2712 StdListIteratorPrinter)
2713 libstdcxx_printer.add_container('std::', '_List_const_iterator',
2714 StdListIteratorPrinter)
2715 libstdcxx_printer.add_version('std::', '_Rb_tree_iterator',
2716 StdRbtreeIteratorPrinter)
2717 libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator',
2718 StdRbtreeIteratorPrinter)
2719 libstdcxx_printer.add_container('std::', '_Deque_iterator',
2720 StdDequeIteratorPrinter)
2721 libstdcxx_printer.add_container('std::', '_Deque_const_iterator',
2722 StdDequeIteratorPrinter)
2723 libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator',
2724 StdVectorIteratorPrinter)
c883d1dc 2725 libstdcxx_printer.add_container('std::', '_Bit_iterator',
39836f83 2726 StdBitIteratorPrinter)
c883d1dc 2727 libstdcxx_printer.add_container('std::', '_Bit_const_iterator',
39836f83 2728 StdBitIteratorPrinter)
c883d1dc 2729 libstdcxx_printer.add_container('std::', '_Bit_reference',
39836f83 2730 StdBitReferencePrinter)
3efe2bf7
TT
2731 libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator',
2732 StdSlistIteratorPrinter)
5da6b013
FD
2733 libstdcxx_printer.add_container('std::', '_Fwd_list_iterator',
2734 StdFwdListIteratorPrinter)
2735 libstdcxx_printer.add_container('std::', '_Fwd_list_const_iterator',
2736 StdFwdListIteratorPrinter)
d63c53cc
TT
2737
2738 # Debug (compiled with -D_GLIBCXX_DEBUG) printer
fe6bd21a 2739 # registrations.
d63c53cc
TT
2740 libstdcxx_printer.add('__gnu_debug::_Safe_iterator',
2741 StdDebugIteratorPrinter)
41850419
TT
2742
2743build_libstdcxx_dictionary ()