[libcxx-commits] [libcxx] [libc++] Fix mi-mode in GDB pretty printers (PR #120951)

Sv. Lockal via libcxx-commits libcxx-commits at lists.llvm.org
Mon Dec 23 01:26:24 PST 2024


https://github.com/AngryLoki updated https://github.com/llvm/llvm-project/pull/120951

>From 39792aaef2219042e0985ccd2d3f0ab79896f373 Mon Sep 17 00:00:00 2001
From: "Sv. Lockal" <lockalsash at gmail.com>
Date: Mon, 23 Dec 2024 09:00:39 +0000
Subject: [PATCH] [libc++] Fix mi-mode in GDB pretty printers

GDB/MI requires unique names for each child, otherwise fails with "Duplicate variable object name".
Additionally wrapped containers printers were flattened for cleaner visualization in IDEs and CLI.

Fixes #62340
---
 libcxx/utils/gdb/libcxx/printers.py | 41 +++++++++++++++++------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/libcxx/utils/gdb/libcxx/printers.py b/libcxx/utils/gdb/libcxx/printers.py
index 8e74b93e7b121f..31c27a1959cb20 100644
--- a/libcxx/utils/gdb/libcxx/printers.py
+++ b/libcxx/utils/gdb/libcxx/printers.py
@@ -446,10 +446,13 @@ def _list_it(self):
         num_emitted = 0
         current_addr = self.start_ptr
         start_index = self.first_block_start_index
+        i = 0
         while num_emitted < self.size:
             end_index = min(start_index + self.size - num_emitted, self.block_size)
             for _, elem in self._bucket_it(current_addr, start_index, end_index):
-                yield "", elem
+                key_name = "[%d]" % i
+                i += 1
+                yield key_name, elem
             num_emitted += end_index - start_index
             current_addr = gdb.Value(addr_as_long(current_addr) + _pointer_size).cast(
                 self.node_type
@@ -494,8 +497,8 @@ def to_string(self):
 
     def _list_iter(self):
         current_node = self.first_node
-        for _ in range(self.size):
-            yield "", current_node.cast(self.nodetype).dereference()["__value_"]
+        for i in range(self.size):
+            yield "[%d]" % i, current_node.cast(self.nodetype).dereference()["__value_"]
             current_node = current_node.dereference()["__next_"]
 
     def __iter__(self):
@@ -512,15 +515,14 @@ class StdQueueOrStackPrinter(object):
     """Print a std::queue or std::stack."""
 
     def __init__(self, val):
-        self.val = val
-        self.underlying = val["c"]
+        self.typename = _remove_generics(_prettify_typename(val.type))
+        self.visualizer = gdb.default_visualizer(val["c"])
 
     def to_string(self):
-        typename = _remove_generics(_prettify_typename(self.val.type))
-        return "%s wrapping" % typename
+        return "%s wrapping: %s" % (self.typename, self.visualizer.to_string())
 
     def children(self):
-        return iter([("", self.underlying)])
+        return self.visualizer.children()
 
     def display_hint(self):
         return "array"
@@ -530,19 +532,18 @@ class StdPriorityQueuePrinter(object):
     """Print a std::priority_queue."""
 
     def __init__(self, val):
-        self.val = val
-        self.underlying = val["c"]
+        self.typename = _remove_generics(_prettify_typename(val.type))
+        self.visualizer = gdb.default_visualizer(val["c"])
 
     def to_string(self):
         # TODO(tamur): It would be nice to print the top element. The technical
         # difficulty is that, the implementation refers to the underlying
         # container, which is a generic class. libstdcxx pretty printers do not
         # print the top element.
-        typename = _remove_generics(_prettify_typename(self.val.type))
-        return "%s wrapping" % typename
+        return "%s wrapping: %s" % (self.typename, self.visualizer.to_string())
 
     def children(self):
-        return iter([("", self.underlying)])
+        return self.visualizer.children()
 
     def display_hint(self):
         return "array"
@@ -622,13 +623,16 @@ def _traverse(self):
         """Traverses the binary search tree in order."""
         current = self.util.root
         skip_left_child = False
+        i = 0
         while True:
             if not skip_left_child and self.util.left_child(current):
                 current = self.util.left_child(current)
                 continue
             skip_left_child = False
             for key_value in self._get_key_value(current):
-                yield "", key_value
+                key_name = "[%d]" % i
+                i += 1
+                yield key_name, key_value
             right_child = self.util.right_child(current)
             if right_child:
                 current = right_child
@@ -784,10 +788,13 @@ def __init__(self, val):
 
     def _list_it(self, sentinel_ptr):
         next_ptr = sentinel_ptr["__next_"]
+        i = 0
         while str(next_ptr.cast(_void_pointer_type)) != "0x0":
             next_val = next_ptr.cast(self.cast_type).dereference()
             for key_value in self._get_key_value(next_val):
-                yield "", key_value
+                key_name = "[%d]" % i
+                i += 1
+                yield key_name, key_value
             next_ptr = next_val["__next_"]
 
     def to_string(self):
@@ -851,8 +858,8 @@ def children(self):
         return self if self.addr else iter(())
 
     def __iter__(self):
-        for key_value in self._get_key_value():
-            yield "", key_value
+        for i, key_value in enumerate(self._get_key_value()):
+            yield "[%d]" % i, key_value
 
 
 class StdUnorderedSetIteratorPrinter(AbstractHashMapIteratorPrinter):



More information about the libcxx-commits mailing list