From 0e3c7fa84e6754ac304d84d0205899cff90f003d Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 11 Dec 2023 12:00:48 +0300 Subject: [PATCH] [WIP][PAC] Emit IR debug info metadata nodes for implicitly signed pointers Emit debug metadata nodes with `DW_TAG_LLVM_ptrauth_type` tag containing signing scheme info for the following types of implicitly (without `__ptrauth` specifier) signed pointers: - virtual table pointers; - free function pointers; - member function pointers. --- clang/lib/CodeGen/CGDebugInfo.cpp | 46 +++++++- .../CodeGen/ptrauth-debuginfo-implicit.cpp | 104 ++++++++++++++++++ clang/test/CodeGen/ptrauth-debuginfo.c | 11 ++ 3 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGen/ptrauth-debuginfo-implicit.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 44757b8ebb05..d2726fb25021 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1058,8 +1058,25 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit) { - return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, - Ty->getPointeeType(), Unit); + llvm::DIType *DIPointerTy = CreatePointerLikeType( + llvm::dwarf::DW_TAG_pointer_type, Ty, Ty->getPointeeType(), Unit); + + if (!Ty->getPointeeType()->isFunctionType()) + return DIPointerTy; + + CGPointerAuthInfo SignSchema = + CGM.getFunctionPointerAuthInfo(QualType(Ty, 0)); + if (!SignSchema) + return DIPointerTy; + + llvm::ConstantInt *Discr = + cast_or_null(SignSchema.getDiscriminator()); + // See CodeGenModule::getMemberFunctionPointer in CGPointerAuth.cpp - we + // do not use address discrimination + return DBuilder.createPtrAuthQualifiedType( + DIPointerTy, SignSchema.getKey(), false, + Discr ? Discr->getValue().getZExtValue() : 0, SignSchema.isIsaPointer(), + SignSchema.authenticatesNullValues()); } /// \return whether a C++ mangling exists for the type defined by TD. @@ -2432,6 +2449,14 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, if (!VPtrTy) VPtrTy = getOrCreateVTablePtrType(Unit); + if (std::optional VTAuth = + CGM.getVTablePointerAuthentication(RD)) { + VPtrTy = DBuilder.createPtrAuthQualifiedType( + VPtrTy, VTAuth->getKey(), VTAuth->isAddressDiscriminated(), + VTAuth->getExtraDiscriminator(), VTAuth->isIsaPointer(), + VTAuth->authenticatesNullValues()); + } + unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); llvm::DIType *VPtrMember = DBuilder.createMemberType(Unit, getVTableName(RD), Unit, 0, Size, 0, 0, @@ -3311,11 +3336,26 @@ llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty, const FunctionProtoType *FPT = Ty->getPointeeType()->castAs(); - return DBuilder.createMemberPointerType( + + llvm::DIType *DIPointerTy = DBuilder.createMemberPointerType( getOrCreateInstanceMethodType( CXXMethodDecl::getThisType(FPT, Ty->getMostRecentCXXRecordDecl()), FPT, U), ClassType, Size, /*Align=*/0, Flags); + + CGPointerAuthInfo SignSchema = + CGM.getMemberFunctionPointerAuthInfo(QualType(Ty, 0)); + if (!SignSchema) + return DIPointerTy; + + llvm::ConstantInt *Discr = + cast_or_null(SignSchema.getDiscriminator()); + // See CodeGenModule::getFunctionPointer in CGPointerAuth.cpp - we do not + // use address discrimination + return DBuilder.createPtrAuthQualifiedType( + DIPointerTy, SignSchema.getKey(), false, + Discr ? Discr->getValue().getZExtValue() : 0, SignSchema.isIsaPointer(), + SignSchema.authenticatesNullValues()); } llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { diff --git a/clang/test/CodeGen/ptrauth-debuginfo-implicit.cpp b/clang/test/CodeGen/ptrauth-debuginfo-implicit.cpp new file mode 100644 index 000000000000..17daf8554628 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-debuginfo-implicit.cpp @@ -0,0 +1,104 @@ +// RUN: split-file %s %t && cd %t + +//--- vtptr.cpp + +// RUN: %clang -g -target aarch64-elf -mbranch-protection=pauthabi \ +// RUN: -S -emit-llvm vtptr.cpp -o - | FileCheck vtptr.cpp + +// CHECK: !DIDerivedType(tag: DW_TAG_member +// CHECK-SAME: name: "_vptr$A" +// CHECK-SAME: baseType: [[BASE1:![0-9]+]] + +// CHECK: [[BASE1]] = !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type +// CHECK-SAME: baseType: [[BASE2:![0-9]+]] +// CHECK-SAME: ptrAuthKey: 2 +// CHECK-SAME: ptrAuthIsAddressDiscriminated: true +// CHECK-SAME: ptrAuthExtraDiscriminator: 62866 +// CHECK-SAME: ptrAuthIsaPointer: false +// CHECK-SAME: ptrAuthAuthenticatesNullValues: false + +// CHECK: [[BASE2]] = !DIDerivedType(tag: DW_TAG_pointer_type +// CHECK-SAME: baseType: [[BASE3:![0-9]+]] + +// CHECK: [[BASE3]] = !DIDerivedType(tag: DW_TAG_pointer_type +// CHECK-SAME: name: "__vtbl_ptr_type" +// CHECK-SAME: baseType: [[BASE4:![0-9]+]] + +// CHECK: [[BASE4]] = !DISubroutineType + +struct A { + virtual void foo() {}; +}; + +void bar(A& a) { + a.foo(); +} + +void test() { + A a; + bar(a); +} + +//--- fptr.c + +// RUN: %clang -g -target aarch64-elf -mbranch-protection=pauthabi \ +// RUN: -S -emit-llvm fptr.c -o - | FileCheck fptr.c + +// CHECK: !DIGlobalVariable(name: "y" +// CHECK-SAME: type: [[TYPE:![0-9]+]] + +/* IA key and zero extra discriminator are not emitted in IR metadata nodes + * but are still present in Dwarf output generated. */ + +// CHECK: [[TYPE]] = !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type +// CHECK-SAME: baseType: [[BASE1:![0-9]+]] +// CHECK-SAME: ptrAuthIsAddressDiscriminated: false +// CHECK-SAME: ptrAuthIsaPointer: false +// CHECK-SAME: ptrAuthAuthenticatesNullValues: false + +// CHECK: [[BASE1]] = !DIDerivedType(tag: DW_TAG_pointer_type +// CHECK-SAME: baseType: [[BASE2:![0-9]+]] + +// CHECK: [[BASE2]] = !DIDerivedType(tag: DW_TAG_typedef +// CHECK-SAME: name: "fptr" + +typedef void fptr(); + +fptr x; + +fptr *y = &x; + +//--- member-fptr.cpp + +// RUN: %clang -g -target aarch64-elf -mbranch-protection=pauthabi \ +// RUN: -S -emit-llvm member-fptr.cpp -o - | FileCheck member-fptr.cpp + +// CHECK: !DIGlobalVariable(name: "x" +// CHECK-SAME: type: [[TYPEDEF:![0-9]+]] + +// CHECK: [[TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef +// CHECK-SAME: name: "fptr", +// CHECK-SAME: baseType: [[TYPE:![0-9]+]] + +/* IA key is not emitted in IR metadata nodes but is still present + * in Dwarf output generated. */ + +// CHECK: [[TYPE]] = !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type +// CHECK-SAME: baseType: [[BASE1:![0-9]+]] +// CHECK-SAME: ptrAuthIsAddressDiscriminated: false +// CHECK-SAME: ptrAuthExtraDiscriminator: 15253 +// CHECK-SAME: ptrAuthIsaPointer: false +// CHECK-SAME: ptrAuthAuthenticatesNullValues: false + +// CHECK: [[BASE1]] = !DIDerivedType(tag: DW_TAG_ptr_to_member_type +// CHECK-SAME: baseType: [[BASE2:![0-9]+]] + +// CHECK: [[BASE2]] = !DISubroutineType + +struct A { + void foo() {}; +}; + +typedef void (A::*fptr)(); + +fptr x = &A::foo; diff --git a/clang/test/CodeGen/ptrauth-debuginfo.c b/clang/test/CodeGen/ptrauth-debuginfo.c index 02137a1b512a..5614f48ca99c 100644 --- a/clang/test/CodeGen/ptrauth-debuginfo.c +++ b/clang/test/CodeGen/ptrauth-debuginfo.c @@ -39,6 +39,17 @@ void f() { // CHECK-SAME: ptrAuthIsaPointer: false, // CHECK-SAME: ptrAuthAuthenticatesNullValues: false) +/* Block descriptor signed function type. The same is used for further block + * descriptors, so checking only once. */ + +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__FuncPtr", +// CHECK-SAME: baseType: [[BASE1:![0-9]+]], + +// CHECK: [[BASE1]] = !DIDerivedType(tag: DW_TAG_LLVM_ptrauth_type, +// CHECK-SAME: ptrAuthIsAddressDiscriminated: false, +// CHECK-SAME: ptrAuthIsaPointer: false, +// CHECK-SAME: ptrAuthAuthenticatesNullValues: false) + void f2() { __block struct A *__ptrauth(1, 1, 1237, "isa-pointer") ptr = createA(); ^{