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