From 8e62fa862afe823d56ae59380ff6c180b11f550e Mon Sep 17 00:00:00 2001 From: Daniil Kovalev Date: Mon, 12 Feb 2024 13:02:54 +0300 Subject: [PATCH] [AArch64][PAC][lldb][Dwarf] Support `__ptrauth`-qualified types This adds support for `DW_TAG_LLVM_ptrauth_type` entries corresponding to explicitly signed free function pointers in lldb user expressions. In this patch, as a temporary solution pointer auth schema corresponding to `-mbranch-protection=pauthabi` is enabled unconditionally. This also brings support for all kinds of implicitly signed pointers, including member function pointers, virtual function pointers, etc. --- lldb/include/lldb/Symbol/CompilerType.h | 13 ++ lldb/include/lldb/Symbol/Type.h | 4 +- lldb/include/lldb/Symbol/TypeSystem.h | 17 +++ .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 31 ++++ .../SymbolFile/DWARF/DWARFASTParserClang.h | 4 + .../TypeSystem/Clang/TypeSystemClang.cpp | 47 ++++++ .../TypeSystem/Clang/TypeSystemClang.h | 8 ++ lldb/source/Symbol/CompilerType.cpp | 32 +++++ lldb/source/Symbol/Type.cpp | 18 ++- lldb/source/Symbol/TypeSystem.cpp | 7 + .../DWARF/DWARFASTParserClangTests.cpp | 134 ++++++++++++++++++ 11 files changed, 308 insertions(+), 7 deletions(-) diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index 2d7092d2c93f..4e5b4b76d459 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -215,6 +215,12 @@ class CompilerType { size_t GetPointerByteSize() const; /// \} + unsigned GetPtrAuthKey() const; + + unsigned GetPtrAuthDiscriminator() const; + + bool GetPtrAuthAddressDiversity() const; + /// Accessors. /// \{ @@ -322,6 +328,13 @@ class CompilerType { /// Create related types using the current type's AST CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) const; + + /// Return a new CompilerType adds a ptrauth modifier with given parameters to + /// this type if this type is valid and the type system supports ptrauth + /// modifiers, else return an invalid type. Note that this does not check if + /// this type is a pointer. + CompilerType AddPtrAuthModifier(unsigned key, bool isAddressDiscriminated, + unsigned extraDiscriminator) const; /// \} /// Exploring the type. diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 046501931d21..5dcd98387c90 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -92,7 +92,9 @@ class Type : public std::enable_shared_from_this, public UserID { /// This type is the type whose UID is m_encoding_uid as an atomic type. eEncodingIsAtomicUID, /// This type is the synthetic type whose UID is m_encoding_uid. - eEncodingIsSyntheticUID + eEncodingIsSyntheticUID, + /// This type is a signed pointer. + eEncodingIsLLVMPtrAuthUID }; enum class ResolveState : unsigned char { diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index eb6e453e1aec..52313c86a558 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -215,6 +215,16 @@ class TypeSystem : public PluginInterface, virtual uint32_t GetPointerByteSize() = 0; + // TODO: are we allowed to insert virtual functions in the middle of the class + // interface and break ABI? + virtual unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) = 0; + + virtual unsigned + GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) = 0; + + virtual bool + GetPtrAuthAddressDiversity(lldb::opaque_compiler_type_t type) = 0; + // Accessors virtual ConstString GetTypeName(lldb::opaque_compiler_type_t type, @@ -279,6 +289,13 @@ class TypeSystem : public PluginInterface, virtual CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type); + // TODO: are we allowed to insert virtual functions in the middle of the class + // interface and break ABI? + virtual CompilerType AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + unsigned key, + bool isAddressDiscriminated, + unsigned extraDiscriminator); + /// \param opaque_payload The m_payload field of Type, which may /// carry TypeSystem-specific extra information. virtual CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 37fb16d4e035..21fdeff1a27e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -504,6 +504,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, type_sp = ParsePointerToMemberType(die, attrs); break; } + case DW_TAG_LLVM_ptrauth_type: { + type_sp = ParsePtrAuthQualifiedType(die, attrs); + break; + } default: dwarf->GetObjectFile()->GetModule()->ReportError( "[{0:x16}]: unhandled type tag {1:x4} ({2}), " @@ -1375,6 +1379,33 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType( return nullptr; } +TypeSP DWARFASTParserClang::ParsePtrAuthQualifiedType( + const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs) { + SymbolFileDWARF *dwarf = die.GetDWARF(); + Type *pointer_type = dwarf->ResolveTypeUID(attrs.type.Reference(), true); + + if (pointer_type == nullptr) + return nullptr; + + CompilerType pointer_clang_type = pointer_type->GetForwardCompilerType(); + + unsigned key = die.GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_key, 0); + bool has_addr_discr = die.GetAttributeValueAsUnsigned( + DW_AT_LLVM_ptrauth_address_discriminated, false); + unsigned extra_discr = die.GetAttributeValueAsUnsigned( + DW_AT_LLVM_ptrauth_extra_discriminator, 0); + CompilerType clang_type = m_ast.AddPtrAuthModifier( + pointer_clang_type.GetOpaqueQualType(), key, has_addr_discr, extra_discr); + + TypeSP type_sp = dwarf->MakeType( + die.GetID(), attrs.name, pointer_type->GetByteSize(nullptr), nullptr, + attrs.type.Reference().GetID(), Type::eEncodingIsLLVMPtrAuthUID, + &attrs.decl, clang_type, Type::ResolveState::Forward); + + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + return type_sp; +} + void DWARFASTParserClang::ParseInheritance( const DWARFDIE &die, const DWARFDIE &parent_die, const CompilerType class_clang_type, const AccessType default_accessibility, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 88bfc490e890..15f8d44c2434 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -296,6 +296,10 @@ class DWARFASTParserClang : public DWARFASTParser { lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); + lldb::TypeSP + ParsePtrAuthQualifiedType(const DWARFDIE &die, + const ParsedDWARFTypeAttributes &attrs); + /// Parses a DW_TAG_inheritance DIE into a base/super class. /// /// \param die The DW_TAG_inheritance DIE to parse. diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 69cff0f35ae4..df863c9920a8 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -3048,6 +3048,35 @@ bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type, return false; } +unsigned TypeSystemClang::GetPtrAuthKey(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + if (auto pointer_auth = qual_type.getPointerAuth()) + return pointer_auth.getKey(); + } + return 0; +} + +unsigned +TypeSystemClang::GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + if (auto pointer_auth = qual_type.getPointerAuth()) + return pointer_auth.getExtraDiscriminator(); + } + return 0; +} + +bool TypeSystemClang::GetPtrAuthAddressDiversity( + lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + if (auto pointer_auth = qual_type.getPointerAuth()) + return pointer_auth.isAddressDiscriminated(); + } + return false; +} + bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type) { auto isFunctionType = [&](clang::QualType qual_type) { return qual_type->isFunctionType(); @@ -4622,6 +4651,24 @@ TypeSystemClang::AddConstModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType +TypeSystemClang::AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + unsigned key, bool isAddressDiscriminated, + unsigned extraDiscriminator) { + if (type) { + clang::ASTContext &clang_ast = getASTContext(); + auto pauth = PointerAuthQualifier::Create( + key, isAddressDiscriminated, extraDiscriminator, + PointerAuthenticationMode::SignAndAuth, + /* isIsaPointer */ false, + /* authenticatesNullValues */ false); + clang::QualType result = + clang_ast.getPointerAuthType(GetQualType(type), pauth); + return GetType(result); + } + return CompilerType(); +} + CompilerType TypeSystemClang::AddVolatileModifier(lldb::opaque_compiler_type_t type) { if (type) { diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 0544de3cd33b..e9f41ff880bc 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -642,6 +642,10 @@ class TypeSystemClang : public TypeSystem { bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) override; + unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) override; + unsigned GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) override; + bool GetPtrAuthAddressDiversity(lldb::opaque_compiler_type_t type) override; + bool IsFunctionType(lldb::opaque_compiler_type_t type) override; uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, @@ -782,6 +786,10 @@ class TypeSystemClang : public TypeSystem { CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override; + CompilerType AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + unsigned key, bool isAddressDiscriminated, + unsigned extraDiscriminator) override; + CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type) override; CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override; diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 33f7e63d9be4..5cd33a9ed4c1 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -108,6 +108,27 @@ bool CompilerType::IsConst() const { return false; } +unsigned CompilerType::GetPtrAuthKey() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetPtrAuthKey(m_type); + return 0; +} + +unsigned CompilerType::GetPtrAuthDiscriminator() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetPtrAuthDiscriminator(m_type); + return 0; +} + +bool CompilerType::GetPtrAuthAddressDiversity() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetPtrAuthAddressDiversity(m_type); + return false; +} + bool CompilerType::IsCStringType(uint32_t &length) const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) @@ -485,6 +506,17 @@ CompilerType CompilerType::GetPointerType() const { return CompilerType(); } +CompilerType +CompilerType::AddPtrAuthModifier(unsigned key, bool isAddressDiscriminated, + unsigned extraDiscriminator) const { + if (IsValid()) { + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->AddPtrAuthModifier( + m_type, key, isAddressDiscriminated, extraDiscriminator); + } + return CompilerType(); +} + CompilerType CompilerType::GetLValueReferenceType() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 66284eb73cad..e27642a84157 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -230,6 +230,9 @@ void Type::GetDescription(Stream *s, lldb::DescriptionLevel level, case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break; + case eEncodingIsLLVMPtrAuthUID: + s->PutCString(" (ptrauth type)"); + break; } } } @@ -291,6 +294,8 @@ void Type::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) { case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break; + case eEncodingIsLLVMPtrAuthUID: + s->PutCString(" (ptrauth type)"); } } @@ -376,12 +381,13 @@ std::optional Type::GetByteSize(ExecutionContextScope *exe_scope) { // If we are a pointer or reference, then this is just a pointer size; case eEncodingIsPointerUID: case eEncodingIsLValueReferenceUID: - case eEncodingIsRValueReferenceUID: { - if (ArchSpec arch = m_symbol_file->GetObjectFile()->GetArchitecture()) { - m_byte_size = arch.GetAddressByteSize(); - m_byte_size_has_value = true; - return static_cast(m_byte_size); - } + case eEncodingIsRValueReferenceUID: + case eEncodingIsLLVMPtrAuthUID: { + if (ArchSpec arch = m_symbol_file->GetObjectFile()->GetArchitecture()) { + m_byte_size = arch.GetAddressByteSize(); + m_byte_size_has_value = true; + return static_cast(m_byte_size); + } } break; } return {}; diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 24f202930565..47949518f7c6 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -93,6 +93,13 @@ CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType TypeSystem::AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + unsigned key, + bool isAddressDiscriminated, + unsigned extraDiscriminator) { + return CompilerType(); +} + CompilerType TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp index 20a085741f73..5d9d386430d4 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp @@ -286,6 +286,140 @@ TEST_F(DWARFASTParserClangTests, TestCallingConventionParsing) { ASSERT_EQ(found_function_types, expected_function_types); } +TEST_F(DWARFASTParserClangTests, TestPtrAuthParsing) { + // Tests parsing values with type DW_TAG_LLVM_ptrauth_type corresponding to + // explicitly signed raw function pointers + + // This is Dwarf for the following C code: + // ``` + // void (*__ptrauth(0, 0, 42) a)(); + // ``` + + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_AARCH64 +DWARF: + debug_str: + - a + debug_abbrev: + - ID: 0 + Table: + - Code: 0x01 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x02 + Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Attribute: DW_AT_external + Form: DW_FORM_flag_present + - Code: 0x03 + Tag: DW_TAG_LLVM_ptrauth_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Attribute: DW_AT_LLVM_ptrauth_key + Form: DW_FORM_data1 + - Attribute: DW_AT_LLVM_ptrauth_extra_discriminator + Form: DW_FORM_data2 + - Code: 0x04 + Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Code: 0x05 + Tag: DW_TAG_subroutine_type + Children: DW_CHILDREN_yes + - Code: 0x06 + Tag: DW_TAG_unspecified_parameters + Children: DW_CHILDREN_no + + debug_info: + - Version: 5 + UnitType: DW_UT_compile + AddrSize: 8 + Entries: +# 0x0c: DW_TAG_compile_unit +# DW_AT_language [DW_FORM_data2] (DW_LANG_C99) + - AbbrCode: 0x01 + Values: + - Value: 0x0c + +# 0x0f: DW_TAG_variable +# DW_AT_name [DW_FORM_strp] (\"a\") +# DW_AT_type [DW_FORM_ref4] (0x00000018 \"void (*__ptrauth(0, 0, 0x02a)\") +# DW_AT_external [DW_FORM_flag_present] (true) + - AbbrCode: 0x02 + Values: + - Value: 0x00 + - Value: 0x18 + +# 0x18: DW_TAG_LLVM_ptrauth_type +# DW_AT_type [DW_FORM_ref4] (0x00000020 \"void (*)(...)\") +# DW_AT_LLVM_ptrauth_key [DW_FORM_data1] (0x00) +# DW_AT_LLVM_ptrauth_extra_discriminator [DW_FORM_data2] (0x002a) + - AbbrCode: 0x03 + Values: + - Value: 0x20 + - Value: 0x00 + - Value: 0x2a + +# 0x20: DW_TAG_pointer_type +# DW_AT_type [DW_AT_type [DW_FORM_ref4] (0x00000025 \"void (...)\") + - AbbrCode: 0x04 + Values: + - Value: 0x25 + +# 0x25: DW_TAG_subroutine_type + - AbbrCode: 0x05 + +# 0x26: DW_TAG_unspecified_parameters + - AbbrCode: 0x06 + + - AbbrCode: 0x00 # end of child tags of 0x25 + - AbbrCode: 0x00 # end of child tags of 0x0c +... +)"; + YAMLModuleTester t(yamldata); + + DWARFUnit *unit = t.GetDwarfUnit(); + ASSERT_NE(unit, nullptr); + const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); + ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); + DWARFDIE cu_die(unit, cu_entry); + + auto holder = std::make_unique("ast"); + auto &ast_ctx = *holder->GetAST(); + DWARFASTParserClangStub ast_parser(ast_ctx); + + DWARFDIE ptrauth_variable = cu_die.GetFirstChild(); + ASSERT_EQ(ptrauth_variable.Tag(), DW_TAG_variable); + DWARFDIE ptrauth_type = + ptrauth_variable.GetAttributeValueAsReferenceDIE(DW_AT_type); + ASSERT_EQ(ptrauth_type.Tag(), DW_TAG_LLVM_ptrauth_type); + + SymbolContext sc; + bool new_type = false; + lldb::TypeSP type = + ast_parser.ParseTypeFromDWARF(sc, ptrauth_type, &new_type); + std::string type_as_string = + type->GetForwardCompilerType().GetTypeName().AsCString(); + ASSERT_EQ(type_as_string, "void (*__ptrauth(0,0,42))(...)"); +} + struct ExtractIntFromFormValueTest : public testing::Test { SubsystemRAII subsystems; clang_utils::TypeSystemClangHolder holder;