gcc/gcc11-libstdc++-prettyprinter-update-16.patch
Siddhesh Poyarekar 62cd20ee1a Update libstdc++ pretty printers from GCC 16 GTS
Add incremental prettyprinter update patches from GTS 15 to GTS 16.

Resolves: RHEL-169098

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-09 15:25:59 -04:00

292 lines
11 KiB
Diff

libstdc++-v3/python/libstdcxx/v6/__init__.py | 2 +-
libstdc++-v3/python/libstdcxx/v6/printers.py | 119 ++++++++++++++++++++++++---
libstdc++-v3/python/libstdcxx/v6/xmethods.py | 9 +-
3 files changed, 110 insertions(+), 20 deletions(-)
diff --git a/libstdc++-v3/python/libstdcxx/v6/__init__.py b/libstdc++-v3/python/libstdcxx/v6/__init__.py
index 5a8f2de195d..c46c92739bb 100644
--- a/libstdc++-v3/python/libstdcxx/v6/__init__.py
+++ b/libstdc++-v3/python/libstdcxx/v6/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2014-2025 Free Software Foundation, Inc.
+# Copyright (C) 2014-2026 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 052a99a28ed..be7e7a25606 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -1,6 +1,6 @@
# Pretty-printers for libstdc++.
-# Copyright (C) 2008-2025 Free Software Foundation, Inc.
+# Copyright (C) 2008-2026 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -291,7 +291,17 @@ class SharedPointerPrinter(printer_base):
def _get_refcounts(self):
if self._typename == 'std::atomic':
# A tagged pointer is stored as uintptr_t.
- ptr_val = self._val['_M_refcount']['_M_val']['_M_i']
+ val = self._val['_M_refcount']['_M_val']
+ # GCC 16 stores it directly as uintptr_t
+ # GCC 12-15 stores std::atomic<uintptr_t>
+ if hasattr(val.type, 'is_scalar'): # Added in GDB 12.1
+ val_is_uintptr = val.type.is_scalar
+ else:
+ val_is_uintptr = val.type.tag is None
+ if val_is_uintptr:
+ ptr_val = val
+ else:
+ ptr_val = val['_M_i']
ptr_val = ptr_val - (ptr_val % 2) # clear lock bit
ptr_type = find_type(self._val['_M_refcount'].type, 'pointer')
return ptr_val.cast(ptr_type)
@@ -572,7 +582,10 @@ class StdVectorPrinter(printer_base):
self._val['_M_impl']['_M_finish'],
self._is_bool)
- def to_string(self):
+ # Helper to compute the bounds of the vector.
+ # Returns a tuple: (length, capacity, suffix)
+ # SUFFIX is a type-name suffix to print.
+ def _bounds(self):
start = self._val['_M_impl']['_M_start']
finish = self._val['_M_impl']['_M_finish']
end = self._val['_M_impl']['_M_end_of_storage']
@@ -582,13 +595,27 @@ class StdVectorPrinter(printer_base):
fo = self._val['_M_impl']['_M_finish']['_M_offset']
itype = start.dereference().type
bl = 8 * itype.sizeof
- length = bl * (finish - start) + fo
- capacity = bl * (end - start)
- return ('%s<bool> of length %d, capacity %d'
- % (self._typename, int(length), int(capacity)))
+ length = int(bl * (finish - start) + fo)
+ capacity = int(bl * (end - start))
+ suffix = '<bool>'
else:
- return ('%s of length %d, capacity %d'
- % (self._typename, int(finish - start), int(end - start)))
+ length = int(finish - start)
+ capacity = int(end - start)
+ suffix = ''
+ if length < 0:
+ # Probably uninitialized.
+ length = 0
+ capacity = 0
+ return (length, capacity, suffix)
+
+ def to_string(self):
+ (length, capacity, suffix) = self._bounds()
+ return ('%s%s of length %d, capacity %d'
+ % (self._typename, suffix, length, capacity))
+
+ def num_children(self):
+ (length, capacity, suffix) = self._bounds()
+ return length
def display_hint(self):
return 'array'
@@ -733,6 +760,11 @@ class StdStackOrQueuePrinter(printer_base):
return '%s wrapping: %s' % (self._typename,
self._visualizer.to_string())
+ def num_children(self):
+ if hasattr(self._visualizer, 'num_children'):
+ return self._visualizer.num_children()
+ return None
+
def display_hint(self):
if hasattr(self._visualizer, 'display_hint'):
return self._visualizer.display_hint()
@@ -876,6 +908,9 @@ class StdMapPrinter(printer_base):
node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
return self._iter(RbtreeIterator(self._val), node)
+ def num_children(slf):
+ return len(RbtreeIterator(self._val))
+
def display_hint(self):
return 'map'
@@ -915,6 +950,8 @@ class StdSetPrinter(printer_base):
node = lookup_node_type('_Rb_tree_node', self._val.type).pointer()
return self._iter(RbtreeIterator(self._val), node)
+ def num_children(slf):
+ return len(RbtreeIterator(self._val))
class StdBitsetPrinter(printer_base):
"""Print a std::bitset."""
@@ -1006,7 +1043,8 @@ class StdDequePrinter(printer_base):
else:
self._buffer_size = 1
- def to_string(self):
+ # Helper to compute the size.
+ def _size(self):
start = self._val['_M_impl']['_M_start']
end = self._val['_M_impl']['_M_finish']
@@ -1014,9 +1052,11 @@ class StdDequePrinter(printer_base):
delta_s = start['_M_last'] - start['_M_cur']
delta_e = end['_M_cur'] - end['_M_first']
- size = self._buffer_size * delta_n + delta_s + delta_e
+ return long(self._buffer_size * delta_n + delta_s + delta_e)
- return '%s with %s' % (self._typename, num_elements(long(size)))
+ def to_string(self):
+ size = self._size()
+ return '%s with %s' % (self._typename, num_elements(size))
def children(self):
start = self._val['_M_impl']['_M_start']
@@ -1024,6 +1064,9 @@ class StdDequePrinter(printer_base):
return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
end['_M_cur'], self._buffer_size)
+ def num_children(self):
+ return self._size()
+
def display_hint(self):
return 'array'
@@ -1210,6 +1253,9 @@ class Tr1UnorderedSetPrinter(printer_base):
return izip(counter, Tr1HashtableIterator(self._hashtable()))
return izip(counter, StdHashtableIterator(self._hashtable()))
+ def num_children(self):
+ return int(self._hashtable()['_M_element_count'])
+
class Tr1UnorderedMapPrinter(printer_base):
"""Print a std::unordered_map or tr1::unordered_map."""
@@ -1254,6 +1300,9 @@ class Tr1UnorderedMapPrinter(printer_base):
# Zip the two iterators together.
return izip(counter, data)
+ def num_children(self):
+ return int(self._hashtable()['_M_element_count'])
+
def display_hint(self):
return 'map'
@@ -1753,7 +1802,11 @@ class StdCmpCatPrinter(printer_base):
if self._typename == 'strong_ordering' and self._val == 0:
name = 'equal'
else:
- names = {2: 'unordered', -1: 'less', 0: 'equivalent', 1: 'greater'}
+ names = {
+ -1: 'less', 0: 'equivalent', 1: 'greater',
+ # GCC 10-15 used 2 for unordered
+ -128: 'unordered', 2: 'unordered'
+ }
name = names[int(self._val)]
return 'std::{}::{}'.format(self._typename, name)
@@ -1945,6 +1998,9 @@ class StdSpanPrinter(printer_base):
def children(self):
return self._iterator(self._val['_M_ptr'], self._size)
+ def num_children(self):
+ return int(self._size)
+
def display_hint(self):
return 'array'
@@ -2353,6 +2409,37 @@ class StdTextEncodingPrinter(printer_base):
return 'unknown'
return rep['_M_name']
+class StdStacktraceEntryPrinter(printer_base):
+ """Print a std::stacktrace_entry."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+
+ def to_string(self):
+ block = gdb.current_progspace().block_for_pc(self._val['_M_pc'])
+ if block is None or block.function is None:
+ return "<unknown>"
+ sym = block.function
+ return "{{{} at {}:{}}}".format(sym.print_name, sym.symtab.filename, sym.line)
+
+class StdStacktracePrinter(printer_base):
+ """Print a std::stacktrace."""
+
+ def __init__(self, typename, val):
+ self._val = val
+ self._typename = typename
+ self._size = self._val['_M_impl']['_M_size']
+
+ def to_string(self):
+ return '%s of length %d' % (self._typename, self._size)
+
+ def children(self):
+ return StdSpanPrinter._iterator(self._val['_M_impl']['_M_frames'], self._size)
+
+ def display_hint(self):
+ return 'array'
+
# A "regular expression" printer which conforms to the
# "SubPrettyPrinter" protocol from gdb.printing.
class RxPrinter(object):
@@ -2973,6 +3060,12 @@ def build_libstdcxx_dictionary():
# libstdcxx_printer.add_version('std::chrono::(anonymous namespace)', 'Rule',
# StdChronoTimeZoneRulePrinter)
+ # C++23 components
+ libstdcxx_printer.add_version('std::', 'stacktrace_entry',
+ StdStacktraceEntryPrinter)
+ libstdcxx_printer.add_version('std::', 'basic_stacktrace',
+ StdStacktracePrinter)
+
# C++26 components
libstdcxx_printer.add_version('std::', 'text_encoding',
StdTextEncodingPrinter)
diff --git a/libstdc++-v3/python/libstdcxx/v6/xmethods.py b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
index 109ca10956a..5d1eb375dc3 100644
--- a/libstdc++-v3/python/libstdcxx/v6/xmethods.py
+++ b/libstdc++-v3/python/libstdcxx/v6/xmethods.py
@@ -1,6 +1,6 @@
# Xmethods for libstdc++.
-# Copyright (C) 2014-2025 Free Software Foundation, Inc.
+# Copyright (C) 2014-2026 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -28,8 +28,6 @@ def get_bool_type():
def get_std_size_type():
return gdb.lookup_type('std::size_t')
-_versioned_namespace = '__8::'
-
def is_specialization_of(x, template_name):
"""
Test whether a type is a specialization of the named class template.
@@ -39,8 +37,7 @@ def is_specialization_of(x, template_name):
"""
if isinstance(x, gdb.Type):
x = x.tag
- template_name = '(%s)?%s' % (_versioned_namespace, template_name)
- return re.match(r'^std::(__\d::)?%s<.*>$' % template_name, x) is not None
+ return re.match(r'^std::(__\d::|__debug::)?%s<.*>$' % template_name, x) is not None
class LibStdCxxXMethod(gdb.xmethod.XMethod):
def __init__(self, name, worker_class):
@@ -445,7 +442,7 @@ class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
if method is None or not method.enabled:
return None
val_type = class_type.template_argument(0)
- node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
+ node_type = gdb.lookup_type(str(class_type) + '::_Node_ptr')
return method.worker_class(val_type, node_type)
# Xmethods for std::vector