[llvm] [llvm][formatters] Add LLDB data-formatter for llvm::PointerIntPair (PR #173261)

Michael Buch via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 23 00:48:47 PST 2025


https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/173261

>From 95dc640d094b64ca091ec0b153cb136fa5f046b0 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 22 Dec 2025 10:14:35 +0000
Subject: [PATCH 1/7] [cross-project] Add tests for LLDB data-formatters for
 llvm::ArrayRef

This patch bare-minimum tests for the LLDB `llvm::ArrayRef` formatters.
I wanted to keep the test itself minimal and mainly set up/agree on the
infrastructure (i.e., CMake machinery, etc.).

The setup mimicks that of GDB. The main difference is that the GDB
formatter tests put all the test cases in one monolithic test file,
whereas I'm planning on having one test-file per LLVM container.

Note, the tests currently only get run if LLVM was built with
debug-info. Not sure we have any buildbots out there runing this
configuration. Though that's what the GDB formatters do too. We could
probably get away with relying on just the debug-info from the LLVM
headers. We could do that in a follow-up patch, or part of this PR,
depending on how reviewers feel.
---
 cross-project-tests/CMakeLists.txt            |  6 +++++
 .../llvm-prettyprinters/lldb/arrayref.cpp     | 10 +++++++
 .../llvm-prettyprinters/lldb/arrayref.test    | 26 +++++++++++++++++++
 .../llvm-prettyprinters/lldb/lit.local.cfg    |  6 +++++
 4 files changed, 48 insertions(+)
 create mode 100644 cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
 create mode 100644 cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test
 create mode 100644 cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/lit.local.cfg

diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt
index 3f932b8c7fd22..f7d2fabfc1cea 100644
--- a/cross-project-tests/CMakeLists.txt
+++ b/cross-project-tests/CMakeLists.txt
@@ -12,12 +12,18 @@ add_llvm_executable(check-gdb-llvm-support
 )
 target_link_libraries(check-gdb-llvm-support PRIVATE LLVMSupport)
 
+add_llvm_executable(check-lldb-llvm-support-arrayref
+        debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
+)
+target_link_libraries(check-lldb-llvm-support-arrayref PRIVATE LLVMSupport)
+
 set(CROSS_PROJECT_TESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(CROSS_PROJECT_TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 
 set(CROSS_PROJECT_TEST_DEPS
   FileCheck
   check-gdb-llvm-support
+  check-lldb-llvm-support-arrayref
   count
   llvm-ar
   llvm-config
diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
new file mode 100644
index 0000000000000..96d253437761f
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
@@ -0,0 +1,10 @@
+#include "llvm/ADT/ArrayRef.h"
+
+int Array[] = {1, 2, 3};
+
+llvm::ArrayRef<int> ArrayRef(Array);
+llvm::MutableArrayRef<int> MutableArrayRef(Array);
+
+int main() {
+  return 0;
+}
diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test
new file mode 100644
index 0000000000000..a5d2a2472304e
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test
@@ -0,0 +1,26 @@
+# REQUIRES: debug-info
+# RUN: split-file %s %t
+# RUN: lldb -b -x -o 'command script import %llvm_src_root/utils/lldbDataFormatters.py' -s %t/commands.input %llvm_tools_dir/check-lldb-llvm-support-arrayref | FileCheck %t/checks
+
+#--- commands.input
+b main
+run
+p ArrayRef
+p MutableArrayRef
+
+#--- checks
+# CHECK:      (lldb) p ArrayRef
+# CHECK-NEXT: (llvm::ArrayRef<int>) size=3 {
+# CHECK-NEXT:  [0] = 1
+# CHECK-NEXT:  [1] = 2
+# CHECK-NEXT:  [2] = 3
+# CHECK-NEXT: }
+
+# CHECK:      (lldb) p MutableArrayRef
+# CHECK-NEXT: (llvm::MutableArrayRef<int>) {
+# CHECK-NEXT:   llvm::ArrayRef<int> = size=3 {
+# CHECK-NEXT:    [0] = 1
+# CHECK-NEXT:    [1] = 2
+# CHECK-NEXT:    [2] = 3
+# CHECK-NEXT:   }
+# CHECK-NEXT: }
diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/lit.local.cfg b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/lit.local.cfg
new file mode 100644
index 0000000000000..7d787e012756b
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/lit.local.cfg
@@ -0,0 +1,6 @@
+import lit.util
+
+if "native" not in config.available_features or lit.util.which("lldb") is None:
+    config.unsupported = True
+
+config.suffixes = [".test"]

>From 32fb68b34f4bc367192886803ce58ff6bb0ed651 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 22 Dec 2025 10:21:48 +0000
Subject: [PATCH 2/7] fixup! clang-format

---
 .../debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp     | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
index 96d253437761f..7f93aa08615d1 100644
--- a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
@@ -5,6 +5,4 @@ int Array[] = {1, 2, 3};
 llvm::ArrayRef<int> ArrayRef(Array);
 llvm::MutableArrayRef<int> MutableArrayRef(Array);
 
-int main() {
-  return 0;
-}
+int main() { return 0; }

>From 841e2e58a190347d696ad29620a1cc386410fa11 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 22 Dec 2025 10:37:04 +0000
Subject: [PATCH 3/7] fixup! don't require debug-info LLVM build

---
 cross-project-tests/CMakeLists.txt                             | 3 ++-
 .../debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test     | 1 -
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt
index f7d2fabfc1cea..e83d374f025d7 100644
--- a/cross-project-tests/CMakeLists.txt
+++ b/cross-project-tests/CMakeLists.txt
@@ -12,10 +12,11 @@ add_llvm_executable(check-gdb-llvm-support
 )
 target_link_libraries(check-gdb-llvm-support PRIVATE LLVMSupport)
 
-add_llvm_executable(check-lldb-llvm-support-arrayref
+add_executable(check-lldb-llvm-support-arrayref
         debuginfo-tests/llvm-prettyprinters/lldb/arrayref.cpp
 )
 target_link_libraries(check-lldb-llvm-support-arrayref PRIVATE LLVMSupport)
+target_compile_options(check-lldb-llvm-support-arrayref PRIVATE -g -O0)
 
 set(CROSS_PROJECT_TESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(CROSS_PROJECT_TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test
index a5d2a2472304e..0ee3b38ed3f39 100644
--- a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/arrayref.test
@@ -1,4 +1,3 @@
-# REQUIRES: debug-info
 # RUN: split-file %s %t
 # RUN: lldb -b -x -o 'command script import %llvm_src_root/utils/lldbDataFormatters.py' -s %t/commands.input %llvm_tools_dir/check-lldb-llvm-support-arrayref | FileCheck %t/checks
 

>From dd56bd7bd9ef4aadc21d17b900139c11e6129944 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 22 Dec 2025 13:50:27 +0000
Subject: [PATCH 4/7] [llvm][formatters] Add LLDB data-formatter for
 llvm::PointerIntPair

---
 cross-project-tests/CMakeLists.txt            |   7 +
 .../lldb/pointer-int-pair.cpp                 |  30 ++++
 .../lldb/pointer-int-pair.test                |  64 ++++++++
 llvm/utils/lldbDataFormatters.py              | 155 ++++++++----------
 4 files changed, 172 insertions(+), 84 deletions(-)
 create mode 100644 cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp
 create mode 100644 cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test

diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt
index e83d374f025d7..14e2f65059ed4 100644
--- a/cross-project-tests/CMakeLists.txt
+++ b/cross-project-tests/CMakeLists.txt
@@ -18,6 +18,12 @@ add_executable(check-lldb-llvm-support-arrayref
 target_link_libraries(check-lldb-llvm-support-arrayref PRIVATE LLVMSupport)
 target_compile_options(check-lldb-llvm-support-arrayref PRIVATE -g -O0)
 
+add_executable(check-lldb-llvm-support-pointer-int-pair
+        debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp
+)
+target_link_libraries(check-lldb-llvm-support-pointer-int-pair PRIVATE LLVMSupport)
+target_compile_options(check-lldb-llvm-support-pointer-int-pair PRIVATE -g -O0)
+
 set(CROSS_PROJECT_TESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(CROSS_PROJECT_TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
 
@@ -25,6 +31,7 @@ set(CROSS_PROJECT_TEST_DEPS
   FileCheck
   check-gdb-llvm-support
   check-lldb-llvm-support-arrayref
+  check-lldb-llvm-support-pointer-int-pair
   count
   llvm-ar
   llvm-config
diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp
new file mode 100644
index 0000000000000..55596c6aaf866
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp
@@ -0,0 +1,30 @@
+#include "llvm/ADT/PointerIntPair.h"
+
+int main() {
+  float a = 5;
+  llvm::PointerIntPair<float *, 1, bool> float_pair(&a, true);
+  llvm::PointerIntPair<void *, 1, bool> void_pair(&a, false);
+  llvm::PointerIntPair<llvm::PointerIntPair<void *, 1, bool>, 1, bool> nested(
+      void_pair, true);
+
+  struct S {
+    int i;
+  };
+  S s;
+
+  enum class E : unsigned {
+    Case1,
+    Case2,
+    Case3,
+    Case4,
+  };
+  llvm::PointerIntPair<S *, 2, E> enum_pair(&s, E::Case2);
+
+  S s2;
+
+  __builtin_debugtrap();
+
+  enum_pair.setPointerAndInt(&s2, E::Case3);
+
+  __builtin_debugtrap();
+}
diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test
new file mode 100644
index 0000000000000..2af064eba8af1
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test
@@ -0,0 +1,64 @@
+# RUN: split-file %s %t
+# RUN: lldb -x \
+# RUN:   -o 'command script import %llvm_src_root/utils/lldbDataFormatters.py' \
+# RUN:   -s %t/commands.input %llvm_tools_dir/check-lldb-llvm-support-pointer-int-pair \
+# RUN:   -o quit \
+# RUN:   | FileCheck %t/checks
+
+#--- commands.input
+run
+
+p &a
+p float_pair
+p nested
+p &s
+p enum_pair
+
+continue
+
+p &s2
+p enum_pair
+p enum_pair.Pointer
+p enum_pair.Int
+
+#--- checks
+# CHECK:      (lldb) p &a
+# CHECK-NEXT: (float *) [[PTR_A:0x[0-9a-zA-Z]+]]
+
+# CHECK:      (lldb) p float_pair
+# CHECK-NEXT: (llvm::PointerIntPair<float *, 1, bool>) {
+# CHECK-NEXT:   Pointer = [[PTR_A]]
+# CHECK-NEXT:   Int = true
+# CHECK-NEXT: }
+
+# CHECK:      (lldb) p nested
+# CHECK-NEXT: (llvm::PointerIntPair<llvm::PointerIntPair<void *, 1, bool>, 1, bool>) {
+# CHECK-NEXT:   Pointer = (Pointer = [[PTR_A]], Int = false)
+# CHECK-NEXT:   Int = true
+# CHECK-NEXT: }
+
+# CHECK:      (lldb) p &s
+# CHECK-NEXT: (S *) [[PTR_S:0x[0-9a-zA-Z]+]]
+
+# CHECK:      (lldb) p enum_pair
+# CHECK-NEXT: (llvm::PointerIntPair<S *, 2, E>) {
+# CHECK-NEXT:   Pointer = [[PTR_S]]
+# CHECK-NEXT:   Int = Case2
+# CHECK-NEXT: }
+
+# CHECK:      (lldb) continue
+
+# CHECK:      (lldb) p &s2
+# CHECK-NEXT: (S *) [[PTR_S2:0x[0-9a-zA-Z]+]]
+
+# CHECK:      (lldb) p enum_pair
+# CHECK-NEXT: (llvm::PointerIntPair<S *, 2, E>) {
+# CHECK-NEXT:   Pointer = [[PTR_S2]]
+# CHECK-NEXT:   Int = Case3
+# CHECK-NEXT: }
+
+# CHECK:      (lldb) p enum_pair.Pointer
+# CHECK-NEXT: (S *) [[PTR_S2]]
+
+# CHECK:      (lldb) p enum_pair.Int
+# CHECK-NEXT: (E) Case3
diff --git a/llvm/utils/lldbDataFormatters.py b/llvm/utils/lldbDataFormatters.py
index a3e4ae15930d9..046b3b1aee324 100644
--- a/llvm/utils/lldbDataFormatters.py
+++ b/llvm/utils/lldbDataFormatters.py
@@ -57,21 +57,11 @@ def __lldb_init_module(debugger, internal_dict):
         f"-F {__name__}.ConstStringSummaryProvider "
         "lldb_private::ConstString"
     )
-
-    # The synthetic providers for PointerIntPair and PointerUnion are disabled
-    # because of a few issues. One example is template arguments that are
-    # non-pointer types that instead specialize PointerLikeTypeTraits.
-    # debugger.HandleCommand(
-    #     "type synthetic add -w llvm "
-    #     f"-l {__name__}.PointerIntPairSynthProvider "
-    #     '-x "^llvm::PointerIntPair<.+>$"'
-    # )
-    # debugger.HandleCommand(
-    #     "type synthetic add -w llvm "
-    #     f"-l {__name__}.PointerUnionSynthProvider "
-    #     '-x "^llvm::PointerUnion<.+>$"'
-    # )
-
+    debugger.HandleCommand(
+        "type synthetic add -w llvm "
+        f"-l {__name__}.PointerIntPairSynthProvider "
+        '-x "^llvm::PointerIntPair<.+>$"'
+    )
     debugger.HandleCommand(
         "type summary add -w llvm "
         f"-e -F {__name__}.DenseMapSummary "
@@ -217,13 +207,6 @@ def ConstStringSummaryProvider(valobj, internal_dict):
     return ""
 
 
-def get_expression_path(val):
-    stream = lldb.SBStream()
-    if not val.GetExpressionPath(stream):
-        return None
-    return stream.GetData()
-
-
 class PointerIntPairSynthProvider:
     def __init__(self, valobj, internal_dict):
         self.valobj = valobj
@@ -239,81 +222,85 @@ def get_child_index(self, name):
             return 1
         return None
 
-    def get_child_at_index(self, index):
-        expr_path = get_expression_path(self.valobj)
-        if index == 0:
-            return self.valobj.CreateValueFromExpression(
-                "Pointer", f"({self.pointer_ty.name}){expr_path}.getPointer()"
-            )
-        if index == 1:
-            return self.valobj.CreateValueFromExpression(
-                "Int", f"({self.int_ty.name}){expr_path}.getInt()"
-            )
-        return None
-
-    def update(self):
-        self.pointer_ty = self.valobj.GetType().GetTemplateArgumentType(0)
-        self.int_ty = self.valobj.GetType().GetTemplateArgumentType(2)
-
+    def _is_valid(self) -> bool:
+        return (
+            self.value
+            and self.pointer_ty
+            and self.int_ty
+            and self.pointer_bit_mask
+            and self.int_shift
+            and self.int_mask
+        )
 
-def parse_template_parameters(typename):
-    """
-    LLDB doesn't support template parameter packs, so let's parse them manually.
-    """
-    result = []
-    start = typename.find("<")
-    end = typename.rfind(">")
-    if start < 1 or end < 2 or end - start < 2:
-        return result
+    def _get_pointer(self):
+        data: SBData = self.value.GetData()
+        error = lldb.SBError()
+        raw_bytes = data.ReadRawData(error, 0, self.ptr_size)
+        if error.Fail():
+            return None
 
-    nesting_level = 0
-    current_parameter_start = start + 1
+        unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder)
+        return unmasked_pointer & self.pointer_bit_mask.GetValueAsUnsigned()
 
-    for i in range(start + 1, end + 1):
-        c = typename[i]
-        if c == "<":
-            nesting_level += 1
-        elif c == ">":
-            nesting_level -= 1
-        elif c == "," and nesting_level == 0:
-            result.append(typename[current_parameter_start:i].strip())
-            current_parameter_start = i + 1
+    def _get_int(self):
+        data: SBData = self.value.GetData()
+        error = lldb.SBError()
+        raw_bytes = data.ReadRawData(error, 0, self.ptr_size)
+        if error.Fail():
+            return None
 
-    result.append(typename[current_parameter_start:i].strip())
+        unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder)
+        return (
+            unmasked_pointer >> self.int_shift.GetValueAsUnsigned()
+        ) & self.int_mask.GetValueAsUnsigned()
 
-    return result
+    def get_child_at_index(self, index):
+        if not self._is_valid():
+            return None
 
+        if index == 0:
+            pointer_value = self._get_pointer()
+            if pointer_value is None:
+                return None
 
-class PointerUnionSynthProvider:
-    def __init__(self, valobj, internal_dict):
-        self.valobj = valobj
-        self.update()
+            data = lldb.SBData()
+            data.SetDataFromUInt64Array([pointer_value])
+            return self.valobj.CreateValueFromData("Pointer", data, self.pointer_ty)
+        if index == 1:
+            int_value = self._get_int()
+            if int_value is None:
+                return None
 
-    def num_children(self):
-        return 1
+            data = lldb.SBData()
+            data.SetDataFromUInt64Array([int_value])
+            return self.valobj.CreateValueFromData("Int", data, self.int_ty)
 
-    def get_child_index(self, name):
-        if name == "Ptr":
-            return 0
         return None
 
-    def get_child_at_index(self, index):
-        if index != 0:
-            return None
-        ptr_type_name = self.template_args[self.active_type_tag]
-        return self.valobj.CreateValueFromExpression(
-            "Ptr", f"({ptr_type_name}){self.val_expr_path}.getPointer()"
-        )
-
     def update(self):
-        self.pointer_int_pair = self.valobj.GetChildMemberWithName("Val")
-        self.val_expr_path = get_expression_path(
-            self.valobj.GetChildMemberWithName("Val")
+        self.byteorder = (
+            "big"
+            if self.valobj.target.GetByteOrder() == lldb.eByteOrderBig
+            else "little"
+        )
+        self.ptr_size = self.valobj.target.GetAddressByteSize()
+        self.value: SBValue = self.valobj.GetChildMemberWithName("Value")
+        self.pointer_ty: SBType = self.valobj.GetType().GetTemplateArgumentType(0)
+        self.int_ty: SBType = self.valobj.GetType().GetTemplateArgumentType(2)
+
+        pointer_info = self.valobj.GetType().GetTemplateArgumentType(4)
+        mask_and_shift_constants = pointer_info.FindDirectNestedType(
+            "MaskAndShiftConstants"
+        ).GetEnumMembers()
+        self.pointer_bit_mask: SBTypeEnumMember = (
+            mask_and_shift_constants.GetTypeEnumMemberAtIndex(0)
+        )
+        self.int_shift: SBTypeEnumMember = (
+            mask_and_shift_constants.GetTypeEnumMemberAtIndex(1)
+        )
+        self.int_mask: SBTypeEnumMember = (
+            mask_and_shift_constants.GetTypeEnumMemberAtIndex(2)
         )
-        self.active_type_tag = self.valobj.CreateValueFromExpression(
-            "", f"(int){self.val_expr_path}.getInt()"
-        ).GetValueAsSigned()
-        self.template_args = parse_template_parameters(self.valobj.GetType().name)
 
 
 def DenseMapSummary(valobj: lldb.SBValue, _) -> str:

>From 2f46d5707a39f11565ccaf528c10c6ca34c33fe8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Mon, 22 Dec 2025 20:40:00 +0100
Subject: [PATCH 5/7] fixup! add types to test cases

---
 .../lldb/pointer-int-pair.test                | 31 ++++++++++---------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test
index 2af064eba8af1..e7b3e1c05dc74 100644
--- a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test
+++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test
@@ -9,10 +9,10 @@
 run
 
 p &a
-p float_pair
-p nested
+v -T float_pair
+v -T nested
 p &s
-p enum_pair
+v -T enum_pair
 
 continue
 
@@ -25,25 +25,28 @@ p enum_pair.Int
 # CHECK:      (lldb) p &a
 # CHECK-NEXT: (float *) [[PTR_A:0x[0-9a-zA-Z]+]]
 
-# CHECK:      (lldb) p float_pair
-# CHECK-NEXT: (llvm::PointerIntPair<float *, 1, bool>) {
-# CHECK-NEXT:   Pointer = [[PTR_A]]
-# CHECK-NEXT:   Int = true
+# CHECK:      (lldb) v -T float_pair
+# CHECK-NEXT: (llvm::PointerIntPair<float *, 1, bool>) float_pair = {
+# CHECK-NEXT:   (float *) Pointer = [[PTR_A]]
+# CHECK-NEXT:   (bool) Int = true
 # CHECK-NEXT: }
 
-# CHECK:      (lldb) p nested
-# CHECK-NEXT: (llvm::PointerIntPair<llvm::PointerIntPair<void *, 1, bool>, 1, bool>) {
-# CHECK-NEXT:   Pointer = (Pointer = [[PTR_A]], Int = false)
+# CHECK:      (lldb) v -T nested
+# CHECK-NEXT: (llvm::PointerIntPair<llvm::PointerIntPair<void *, 1, bool>, 1, bool>) nested = {
+# CHECK-NEXT:   (llvm::PointerIntPair<void *, 1, bool>) Pointer = {
+# CHECK-NEXT:     (void *) Pointer = [[PTR_A]]
+# CHECK-NEXT:     (bool) Int = false
+# CHECK-NEXT:   }
 # CHECK-NEXT:   Int = true
 # CHECK-NEXT: }
 
 # CHECK:      (lldb) p &s
 # CHECK-NEXT: (S *) [[PTR_S:0x[0-9a-zA-Z]+]]
 
-# CHECK:      (lldb) p enum_pair
-# CHECK-NEXT: (llvm::PointerIntPair<S *, 2, E>) {
-# CHECK-NEXT:   Pointer = [[PTR_S]]
-# CHECK-NEXT:   Int = Case2
+# CHECK:      (lldb) v -T enum_pair
+# CHECK-NEXT: (llvm::PointerIntPair<S *, 2, E>) enum_pair = {
+# CHECK-NEXT:   (S *) Pointer = [[PTR_S]]
+# CHECK-NEXT:   (E) Int = Case2
 # CHECK-NEXT: }
 
 # CHECK:      (lldb) continue

>From b710c5196c6df4a00641e6e15abdfe3fe27261b8 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 23 Dec 2025 09:20:32 +0100
Subject: [PATCH 6/7] fixup! add assertion on enum name

---
 llvm/utils/lldbDataFormatters.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/llvm/utils/lldbDataFormatters.py b/llvm/utils/lldbDataFormatters.py
index 046b3b1aee324..89045bbd82a90 100644
--- a/llvm/utils/lldbDataFormatters.py
+++ b/llvm/utils/lldbDataFormatters.py
@@ -292,15 +292,23 @@ def update(self):
         mask_and_shift_constants = pointer_info.FindDirectNestedType(
             "MaskAndShiftConstants"
         ).GetEnumMembers()
+
+        # FIXME: SBAPI should provide a way to retrieve an enum member
+        # by name.
         self.pointer_bit_mask: SBTypeEnumMember = (
             mask_and_shift_constants.GetTypeEnumMemberAtIndex(0)
         )
+        assert self.pointer_bit_mask.name == "PointerBitMask"
+
         self.int_shift: SBTypeEnumMember = (
             mask_and_shift_constants.GetTypeEnumMemberAtIndex(1)
         )
+        assert self.int_shift.name == "IntShift"
+
         self.int_mask: SBTypeEnumMember = (
             mask_and_shift_constants.GetTypeEnumMemberAtIndex(2)
         )
+        assert self.int_mask.name == "IntMask"
 
 
 def DenseMapSummary(valobj: lldb.SBValue, _) -> str:

>From 14c99e1167e611d0e8254e52c6f966fbc0ec98c7 Mon Sep 17 00:00:00 2001
From: Michael Buch <michaelbuch12 at gmail.com>
Date: Tue, 23 Dec 2025 09:48:33 +0100
Subject: [PATCH 7/7] fixup! move logic out of get_child_at_index

---
 llvm/utils/lldbDataFormatters.py | 108 +++++++++++++++++--------------
 1 file changed, 58 insertions(+), 50 deletions(-)

diff --git a/llvm/utils/lldbDataFormatters.py b/llvm/utils/lldbDataFormatters.py
index 89045bbd82a90..36a4a63474b36 100644
--- a/llvm/utils/lldbDataFormatters.py
+++ b/llvm/utils/lldbDataFormatters.py
@@ -222,59 +222,44 @@ def get_child_index(self, name):
             return 1
         return None
 
-    def _is_valid(self) -> bool:
-        return (
-            self.value
-            and self.pointer_ty
-            and self.int_ty
-            and self.pointer_bit_mask
-            and self.int_shift
-            and self.int_mask
-        )
-
-    def _get_pointer(self):
+    def _get_raw_value(self):
         data: SBData = self.value.GetData()
         error = lldb.SBError()
         raw_bytes = data.ReadRawData(error, 0, self.ptr_size)
         if error.Fail():
             return None
 
-        unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder)
-        return unmasked_pointer & self.pointer_bit_mask.GetValueAsUnsigned()
+        return raw_bytes
 
-    def _get_int(self):
-        data: SBData = self.value.GetData()
-        error = lldb.SBError()
-        raw_bytes = data.ReadRawData(error, 0, self.ptr_size)
-        if error.Fail():
-            return None
+    def _get_pointer(self, pointer_bit_mask: int, pointer_ty: SBType):
+        raw_bytes = self._get_raw_value()
+        if raw_bytes is None:
+            return
 
         unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder)
-        return (
-            unmasked_pointer >> self.int_shift.GetValueAsUnsigned()
-        ) & self.int_mask.GetValueAsUnsigned()
+        pointer_value = unmasked_pointer & pointer_bit_mask
 
-    def get_child_at_index(self, index):
-        if not self._is_valid():
-            return None
+        data = lldb.SBData()
+        data.SetDataFromUInt64Array([pointer_value])
+        return self.valobj.CreateValueFromData("Pointer", data, pointer_ty)
 
-        if index == 0:
-            pointer_value = self._get_pointer()
-            if pointer_value is None:
-                return None
+    def _get_int(self, int_shift: int, int_mask: int, int_ty: SBType):
+        raw_bytes = self._get_raw_value()
+        if raw_bytes is None:
+            return
 
-            data = lldb.SBData()
-            data.SetDataFromUInt64Array([pointer_value])
-            return self.valobj.CreateValueFromData("Pointer", data, self.pointer_ty)
-        if index == 1:
-            int_value = self._get_int()
-            if int_value is None:
-                return None
+        unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder)
+        int_value = (unmasked_pointer >> int_shift) & int_mask
 
-            data = lldb.SBData()
-            data.SetDataFromUInt64Array([int_value])
-            return self.valobj.CreateValueFromData("Int", data, self.int_ty)
+        data = lldb.SBData()
+        data.SetDataFromUInt64Array([int_value])
+        return self.valobj.CreateValueFromData("Int", data, int_ty)
 
+    def get_child_at_index(self, index):
+        if index == 0:
+            return self.pointer_valobj
+        if index == 1:
+            return self.int_valobj
         return None
 
     def update(self):
@@ -285,30 +270,53 @@ def update(self):
         )
         self.ptr_size = self.valobj.target.GetAddressByteSize()
         self.value: SBValue = self.valobj.GetChildMemberWithName("Value")
-        self.pointer_ty: SBType = self.valobj.GetType().GetTemplateArgumentType(0)
-        self.int_ty: SBType = self.valobj.GetType().GetTemplateArgumentType(2)
+        if not self.value:
+            return
+
+        valobj_type = self.valobj.GetType()
+
+        pointer_ty: SBType = valobj_type.GetTemplateArgumentType(0)
+        if not pointer_ty:
+            return
+
+        int_ty: SBType = valobj_type.GetTemplateArgumentType(2)
+        if not int_ty:
+            return
+
+        pointer_info = valobj_type.GetTemplateArgumentType(4)
+        if not pointer_info:
+            return
 
-        pointer_info = self.valobj.GetType().GetTemplateArgumentType(4)
         mask_and_shift_constants = pointer_info.FindDirectNestedType(
             "MaskAndShiftConstants"
         ).GetEnumMembers()
 
         # FIXME: SBAPI should provide a way to retrieve an enum member
         # by name.
-        self.pointer_bit_mask: SBTypeEnumMember = (
+        pointer_bit_mask: SBTypeEnumMember = (
             mask_and_shift_constants.GetTypeEnumMemberAtIndex(0)
         )
-        assert self.pointer_bit_mask.name == "PointerBitMask"
+        if pointer_bit_mask.name != "PointerBitMask":
+            return
+
+        int_shift: SBTypeEnumMember = mask_and_shift_constants.GetTypeEnumMemberAtIndex(
+            1
+        )
+        if int_shift.name != "IntShift":
+            return
 
-        self.int_shift: SBTypeEnumMember = (
-            mask_and_shift_constants.GetTypeEnumMemberAtIndex(1)
+        int_mask: SBTypeEnumMember = mask_and_shift_constants.GetTypeEnumMemberAtIndex(
+            2
         )
-        assert self.int_shift.name == "IntShift"
+        if int_mask.name != "IntMask":
+            return
 
-        self.int_mask: SBTypeEnumMember = (
-            mask_and_shift_constants.GetTypeEnumMemberAtIndex(2)
+        self.pointer_valobj = self._get_pointer(
+            pointer_bit_mask.GetValueAsUnsigned(), pointer_ty
+        )
+        self.int_valobj = self._get_int(
+            int_shift.GetValueAsUnsigned(), int_mask.GetValueAsUnsigned(), int_ty
         )
-        assert self.int_mask.name == "IntMask"
 
 
 def DenseMapSummary(valobj: lldb.SBValue, _) -> str:



More information about the llvm-commits mailing list