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
