https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/187611

>From 35e207f6e5566eac6d5421069ca0a2888f0b5e53 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Thu, 19 Mar 2026 16:42:30 -0700
Subject: [PATCH 1/4] [lldb] Support arm64e C++ vtable pointer signing

When targeting arm64e, vtable pointers are signed with a discriminator
that incorporates the object's address (PointerAuthVTPtrAddressDiscrimination)
and class type (PointerAuthVTPtrTypeDiscrimination).

I had to make a small change to clang, specifically in
getPointerAuthDeclDiscriminator(). Previously, that was computing the
discriminator based on getMangledName(). The latter returns the
AsmLabelAttr, which for functions imported by lldb, is prefixed with
`$__lldb_func`, causing a different discriminator to be generated.
---
 clang/lib/CodeGen/CGPointerAuth.cpp           | 18 ++++++-
 .../Clang/ClangExpressionParser.cpp           |  2 +
 .../expression/ptrauth-vtable/Makefile        |  8 ++++
 .../TestPtrAuthVTableExpressions.py           | 48 +++++++++++++++++++
 .../expression/ptrauth-vtable/main.cpp        | 27 +++++++++++
 5 files changed, 101 insertions(+), 2 deletions(-)
 create mode 100644 lldb/test/API/commands/expression/ptrauth-vtable/Makefile
 create mode 100644 
lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
 create mode 100644 lldb/test/API/commands/expression/ptrauth-vtable/main.cpp

diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index 84b5c86e69a57..a083d10e9dbec 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -11,6 +11,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#include "CGCXXABI.h"
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "clang/CodeGen/CodeGenABITypes.h"
@@ -62,8 +63,21 @@ CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl 
Declaration) {
   uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration];
 
   if (EntityHash == 0) {
-    StringRef Name = getMangledName(Declaration);
-    EntityHash = llvm::getPointerAuthStableSipHash(Name);
+    const auto *ND = cast<NamedDecl>(Declaration.getDecl());
+    // If the declaration has an AsmLabelAttr (e.g., LLDB expression evaluator
+    // attaches one to map imported decls to debuggee symbols), the asm label
+    // would be used as the mangled name, producing a wrong discriminator.
+    // Compute the real C++ mangled name instead so the discriminator matches
+    // what the original translation unit used.
+    if (ND->hasAttr<AsmLabelAttr>()) {
+      SmallString<256> Buffer;
+      llvm::raw_svector_ostream Out(Buffer);
+      getCXXABI().getMangleContext().mangleCXXName(Declaration, Out);
+      EntityHash = llvm::getPointerAuthStableSipHash(Out.str());
+    } else {
+      StringRef Name = getMangledName(Declaration);
+      EntityHash = llvm::getPointerAuthStableSipHash(Name);
+    }
   }
 
   return EntityHash;
diff --git 
a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp 
b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 38e5298f9cc93..a69a4ec3d5294 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -731,6 +731,8 @@ static void SetPointerAuthOptionsForArm64e(LangOptions 
&lang_opts) {
   lang_opts.PointerAuthReturns = true;
   lang_opts.PointerAuthAuthTraps = true;
   lang_opts.PointerAuthIndirectGotos = true;
+  lang_opts.PointerAuthVTPtrAddressDiscrimination = true;
+  lang_opts.PointerAuthVTPtrTypeDiscrimination = true;
   lang_opts.PointerAuthObjcIsa = true;
   lang_opts.PointerAuthObjcClassROPointers = true;
   lang_opts.PointerAuthObjcInterfaceSel = true;
diff --git a/lldb/test/API/commands/expression/ptrauth-vtable/Makefile 
b/lldb/test/API/commands/expression/ptrauth-vtable/Makefile
new file mode 100644
index 0000000000000..3c6bc2dd007e1
--- /dev/null
+++ b/lldb/test/API/commands/expression/ptrauth-vtable/Makefile
@@ -0,0 +1,8 @@
+CXX_SOURCES := main.cpp
+
+override ARCH := arm64e
+
+# We need an arm64e stblib.
+USE_SYSTEM_STDLIB := 1
+
+include Makefile.rules
diff --git 
a/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
 
b/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
new file mode 100644
index 0000000000000..07a806dd53355
--- /dev/null
+++ 
b/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
@@ -0,0 +1,48 @@
+"""
+VTable pointers are signed with a discriminator that incorporates the object's
+address (PointerAuthVTPtrAddressDiscrimination) and class type (
+PointerAuthVTPtrTypeDiscrimination).
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestPtrAuthVTableExpressions(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessArm64eSupported
+    def test_virtual_call_on_debuggee_object(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp", False)
+        )
+
+        self.expect_expr("d.value()", result_type="int", result_value="20")
+        self.expect_expr("od.value()", result_type="int", result_value="30")
+
+    @skipUnlessArm64eSupported
+    def test_virtual_call_through_base_pointer(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp", False)
+        )
+
+        self.expect_expr(
+            "base_ptr->value()", result_type="int", result_value="20"
+        )
+
+    @skipUnlessArm64eSupported
+    def test_virtual_call_via_helper(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp", False)
+        )
+
+        self.expect_expr("call_value(&d)", result_type="int", 
result_value="20")
+        self.expect_expr("call_value(&od)", result_type="int", 
result_value="30")
+        self.expect_expr(
+            "call_value(base_ptr)", result_type="int", result_value="20"
+        )
diff --git a/lldb/test/API/commands/expression/ptrauth-vtable/main.cpp 
b/lldb/test/API/commands/expression/ptrauth-vtable/main.cpp
new file mode 100644
index 0000000000000..d9dec9b9a6a41
--- /dev/null
+++ b/lldb/test/API/commands/expression/ptrauth-vtable/main.cpp
@@ -0,0 +1,27 @@
+#include <cstdio>
+
+class Base {
+public:
+  virtual int value() { return 10; }
+  virtual ~Base() = default;
+};
+
+class Derived : public Base {
+public:
+  int value() override { return 20; }
+};
+
+class OtherDerived : public Base {
+public:
+  int value() override { return 30; }
+};
+
+int call_value(Base *obj) { return obj->value(); }
+
+int main() {
+  Derived d;
+  OtherDerived od;
+  Base *base_ptr = &d;
+  printf("%d %d %d\n", d.value(), od.value(), base_ptr->value());
+  return 0; // break here
+}

>From 015c13b8b4b18c63f5d29912d4cc0ed81c75e4c2 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Thu, 19 Mar 2026 17:12:57 -0700
Subject: [PATCH 2/4] Formatting

---
 .../ptrauth-vtable/TestPtrAuthVTableExpressions.py        | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git 
a/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
 
b/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
index 07a806dd53355..92a30b6e6548f 100644
--- 
a/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
+++ 
b/lldb/test/API/commands/expression/ptrauth-vtable/TestPtrAuthVTableExpressions.py
@@ -30,9 +30,7 @@ def test_virtual_call_through_base_pointer(self):
             self, "// break here", lldb.SBFileSpec("main.cpp", False)
         )
 
-        self.expect_expr(
-            "base_ptr->value()", result_type="int", result_value="20"
-        )
+        self.expect_expr("base_ptr->value()", result_type="int", 
result_value="20")
 
     @skipUnlessArm64eSupported
     def test_virtual_call_via_helper(self):
@@ -43,6 +41,4 @@ def test_virtual_call_via_helper(self):
 
         self.expect_expr("call_value(&d)", result_type="int", 
result_value="20")
         self.expect_expr("call_value(&od)", result_type="int", 
result_value="30")
-        self.expect_expr(
-            "call_value(base_ptr)", result_type="int", result_value="20"
-        )
+        self.expect_expr("call_value(base_ptr)", result_type="int", 
result_value="20")

>From 11d8ba5dfb44a004256aa62a822cc71f7c67ac8c Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Fri, 20 Mar 2026 07:42:33 -0700
Subject: [PATCH 3/4] Implement Michael's suggestion of checking the prefix

---
 clang/lib/CodeGen/CGPointerAuth.cpp | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index a083d10e9dbec..5e0ef91f51ffb 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -64,12 +64,13 @@ CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl 
Declaration) {
 
   if (EntityHash == 0) {
     const auto *ND = cast<NamedDecl>(Declaration.getDecl());
-    // If the declaration has an AsmLabelAttr (e.g., LLDB expression evaluator
-    // attaches one to map imported decls to debuggee symbols), the asm label
-    // would be used as the mangled name, producing a wrong discriminator.
-    // Compute the real C++ mangled name instead so the discriminator matches
-    // what the original translation unit used.
-    if (ND->hasAttr<AsmLabelAttr>()) {
+    constexpr static llvm::StringLiteral LLDBLabelPrefix = "$__lldb_func:";
+    if (ND->hasAttr<AsmLabelAttr>() &&
+        ND->getAttr<AsmLabelAttr>()->getLabel().starts_with(LLDBLabelPrefix)) {
+      // If the declaration comes from LLDB, the asm label has a prefix that
+      // would producing a different discriminator. Compute the real C++ 
mangled
+      // name instead so the discriminator matches what the original 
translation
+      // unit used.
       SmallString<256> Buffer;
       llvm::raw_svector_ostream Out(Buffer);
       getCXXABI().getMangleContext().mangleCXXName(Declaration, Out);

>From fb2c8502546d0137788f8827748f6ab926ab2819 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Tue, 24 Mar 2026 08:29:20 -0700
Subject: [PATCH 4/4] [lldb] Move prefix into Mangle.h so it can be shared

---
 clang/include/clang/AST/Mangle.h    |  5 +++++
 clang/lib/AST/Mangle.cpp            | 10 ++++------
 clang/lib/CodeGen/CGPointerAuth.cpp |  4 ++--
 3 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index ca72dcfd4483d..13fa0d1c880bc 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -317,6 +317,11 @@ class ASTNameGenerator {
   class Implementation;
   std::unique_ptr<Implementation> Impl;
 };
+
+/// Constants used by LLDB for mangling.
+struct LLDBManglingABI {
+  static constexpr llvm::StringLiteral FunctionLabelPrefix = "$__lldb_func:";
+};
 } // namespace clang
 
 #endif
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 780b2c585c810..58216667116a8 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -152,8 +152,6 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl 
*D) {
   return shouldMangleCXXName(D);
 }
 
-static llvm::StringRef g_lldb_func_call_label_prefix = "$__lldb_func:";
-
 /// Given an LLDB function call label, this function prints the label
 /// into \c Out, together with the structor type of \c GD (if the
 /// decl is a constructor/destructor). LLDB knows how to handle mangled
@@ -167,9 +165,9 @@ static llvm::StringRef g_lldb_func_call_label_prefix = 
"$__lldb_func:";
 ///
 static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD,
                              llvm::raw_ostream &Out) {
-  assert(label.starts_with(g_lldb_func_call_label_prefix));
+  assert(label.starts_with(LLDBManglingABI::FunctionLabelPrefix));
 
-  Out << g_lldb_func_call_label_prefix;
+  Out << LLDBManglingABI::FunctionLabelPrefix;
 
   if (auto *Ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(GD.getDecl())) {
     Out << "C";
@@ -180,7 +178,7 @@ static void emitLLDBAsmLabel(llvm::StringRef label, 
GlobalDecl GD,
     Out << "D" << GD.getDtorType();
   }
 
-  Out << label.substr(g_lldb_func_call_label_prefix.size());
+  Out << label.substr(LLDBManglingABI::FunctionLabelPrefix.size());
 }
 
 void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
@@ -216,7 +214,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream 
&Out) {
     if (!UserLabelPrefix.empty())
       Out << '\01'; // LLVM IR Marker for __asm("foo")
 
-    if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
+    if (ALA->getLabel().starts_with(LLDBManglingABI::FunctionLabelPrefix))
       emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
     else
       Out << ALA->getLabel();
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp 
b/clang/lib/CodeGen/CGPointerAuth.cpp
index 5e0ef91f51ffb..28d3289dfe04f 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -64,9 +64,9 @@ CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl 
Declaration) {
 
   if (EntityHash == 0) {
     const auto *ND = cast<NamedDecl>(Declaration.getDecl());
-    constexpr static llvm::StringLiteral LLDBLabelPrefix = "$__lldb_func:";
     if (ND->hasAttr<AsmLabelAttr>() &&
-        ND->getAttr<AsmLabelAttr>()->getLabel().starts_with(LLDBLabelPrefix)) {
+        ND->getAttr<AsmLabelAttr>()->getLabel().starts_with(
+            LLDBManglingABI::FunctionLabelPrefix)) {
       // If the declaration comes from LLDB, the asm label has a prefix that
       // would producing a different discriminator. Compute the real C++ 
mangled
       // name instead so the discriminator matches what the original 
translation

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to