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

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.

>From 0fcddd5e4a441fe4e1bf76f003d61025099f3bf1 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Thu, 19 Mar 2026 16:42:30 -0700
Subject: [PATCH] [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 0956406960b23..7955fffa26c5a 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -729,6 +729,8 @@ static void SetPointerAuthOptionsForArm64e(LangOptions 
&lang_opts) {
   lang_opts.PointerAuthIntrinsics = true;
   lang_opts.PointerAuthCalls = true;
   lang_opts.PointerAuthReturns = true;
+  lang_opts.PointerAuthVTPtrAddressDiscrimination = true;
+  lang_opts.PointerAuthVTPtrTypeDiscrimination = true;
 }
 
 ClangExpressionParser::ClangExpressionParser(
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
+}

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

Reply via email to