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