Author: Daniil Kovalev Date: 2024-04-30T11:15:35+03:00 New Revision: 64248d7dee09fef4900058ba98a67feb68eb617c
URL: https://github.com/llvm/llvm-project/commit/64248d7dee09fef4900058ba98a67feb68eb617c DIFF: https://github.com/llvm/llvm-project/commit/64248d7dee09fef4900058ba98a67feb68eb617c.diff LOG: [PAC][lldb][Dwarf] Support `__ptrauth`-qualified types in user expressions (#84387) Depends on #84384 and #90329 This adds support for `DW_TAG_LLVM_ptrauth_type` entries corresponding to explicitly signed types (e.g. free function pointers) in lldb user expressions. Applies PR https://github.com/apple/llvm-project/pull/8239 from Apple's downstream and also adds tests and related code. --------- Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com> Added: Modified: lldb/include/lldb/Symbol/CompilerType.h lldb/include/lldb/Symbol/Type.h lldb/include/lldb/Symbol/TypeSystem.h lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h lldb/source/Symbol/CompilerType.cpp lldb/source/Symbol/Type.cpp lldb/source/Symbol/TypeSystem.cpp lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index 9e889a53086b2a..28c723abf27948 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -262,6 +262,12 @@ class CompilerType { size_t GetPointerByteSize() const; /// \} + unsigned GetPtrAuthKey() const; + + unsigned GetPtrAuthDiscriminator() const; + + bool GetPtrAuthAddressDiversity() const; + /// Accessors. /// \{ @@ -369,6 +375,12 @@ 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 from the given 32-bit + /// opaque payload 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(uint32_t payload) const; /// \} /// Exploring the type. diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index b5eac5fa732d67..1c4f7b5601b0c3 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -401,7 +401,9 @@ class Type : public std::enable_shared_from_this<Type>, 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 0924e21a6b54a4..7bcb8d69387a02 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -221,6 +221,14 @@ class TypeSystem : public PluginInterface, virtual uint32_t GetPointerByteSize() = 0; + 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, @@ -285,6 +293,9 @@ class TypeSystem : public PluginInterface, virtual CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type); + virtual CompilerType AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload); + /// \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 12dafd3f5d5d51..bea11e0e3840af 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -570,6 +570,39 @@ ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value, return memberOffset.ResolveValue(nullptr).UInt(); } +static TypePayloadClang GetPtrAuthMofidierPayload(const DWARFDIE &die) { + auto getAttr = [&](llvm::dwarf::Attribute Attr, unsigned defaultValue = 0) { + return die.GetAttributeValueAsUnsigned(Attr, defaultValue); + }; + const unsigned key = getAttr(DW_AT_LLVM_ptrauth_key); + const bool addr_disc = getAttr(DW_AT_LLVM_ptrauth_address_discriminated); + const unsigned extra = getAttr(DW_AT_LLVM_ptrauth_extra_discriminator); + const bool isapointer = getAttr(DW_AT_LLVM_ptrauth_isa_pointer); + const bool authenticates_null_values = + getAttr(DW_AT_LLVM_ptrauth_authenticates_null_values); + const unsigned authentication_mode_int = getAttr( + DW_AT_LLVM_ptrauth_authentication_mode, + static_cast<unsigned>(clang::PointerAuthenticationMode::SignAndAuth)); + clang::PointerAuthenticationMode authentication_mode = + clang::PointerAuthenticationMode::SignAndAuth; + if (authentication_mode_int >= + static_cast<unsigned>(clang::PointerAuthenticationMode::None) && + authentication_mode_int <= + static_cast<unsigned>( + clang::PointerAuthenticationMode::SignAndAuth)) { + authentication_mode = + static_cast<clang::PointerAuthenticationMode>(authentication_mode_int); + } else { + die.GetDWARF()->GetObjectFile()->GetModule()->ReportError( + "[{0:x16}]: invalid pointer authentication mode method {1:x4}", + die.GetOffset(), authentication_mode_int); + } + auto ptr_auth = clang::PointerAuthQualifier::Create( + key, addr_disc, extra, authentication_mode, isapointer, + authenticates_null_values); + return TypePayloadClang(ptr_auth.getAsOpaqueValue()); +} + lldb::TypeSP DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, const DWARFDIE &die, @@ -580,6 +613,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU()); Type::ResolveState resolve_state = Type::ResolveState::Unresolved; Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + TypePayloadClang payload(GetOwningClangModule(die)); TypeSP type_sp; CompilerType clang_type; @@ -677,6 +711,10 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, case DW_TAG_volatile_type: encoding_data_type = Type::eEncodingIsVolatileUID; break; + case DW_TAG_LLVM_ptrauth_type: + encoding_data_type = Type::eEncodingIsLLVMPtrAuthUID; + payload = GetPtrAuthMofidierPayload(die); + break; case DW_TAG_atomic_type: encoding_data_type = Type::eEncodingIsAtomicUID; break; @@ -786,8 +824,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, type_sp = dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr, attrs.type.Reference().GetID(), encoding_data_type, - &attrs.decl, clang_type, resolve_state, - TypePayloadClang(GetOwningClangModule(die))); + &attrs.decl, clang_type, resolve_state, payload); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index ec005ac46b34f3..3bdb288e97dd6a 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2923,6 +2923,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(); @@ -4511,6 +4540,19 @@ TypeSystemClang::AddConstModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType +TypeSystemClang::AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload) { + if (type) { + clang::ASTContext &clang_ast = getASTContext(); + auto pauth = PointerAuthQualifier::fromOpaqueValue(payload); + 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 8a7d45254bcf52..59ca69622d9e82 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -67,11 +67,13 @@ class OptionalClangModuleID { /// The implementation of lldb::Type's m_payload field for TypeSystemClang. class TypePayloadClang { - /// The Layout is as follows: + /// The payload is used for typedefs and ptrauth types. + /// For typedefs, the Layout is as follows: /// \verbatim /// bit 0..30 ... Owning Module ID. /// bit 31 ...... IsCompleteObjCClass. /// \endverbatim + /// For ptrauth types, we store the PointerAuthQualifier as an opaque value. Type::Payload m_payload = 0; public: @@ -653,6 +655,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, @@ -793,6 +799,9 @@ class TypeSystemClang : public TypeSystem { CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override; + CompilerType AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload) 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 9523fb6ea77c20..072dbccec44fba 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::IsFunctionType() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) @@ -664,6 +685,13 @@ CompilerType CompilerType::GetPointerType() const { return CompilerType(); } +CompilerType CompilerType::AddPtrAuthModifier(uint32_t payload) const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->AddPtrAuthModifier(m_type, payload); + 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 dcfd1238f6d789..b85c38097ebe28 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -355,6 +355,9 @@ void Type::GetDescription(Stream *s, lldb::DescriptionLevel level, case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break; + case eEncodingIsLLVMPtrAuthUID: + s->PutCString(" (ptrauth type)"); + break; } } } @@ -416,6 +419,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)"); } } @@ -477,7 +482,8 @@ std::optional<uint64_t> 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: { + case eEncodingIsRValueReferenceUID: + case eEncodingIsLLVMPtrAuthUID: { if (ArchSpec arch = m_symbol_file->GetObjectFile()->GetArchitecture()) { m_byte_size = arch.GetAddressByteSize(); m_byte_size_has_value = true; @@ -621,6 +627,12 @@ bool Type::ResolveCompilerType(ResolveState compiler_type_resolve_state) { encoding_type->GetForwardCompilerType().GetRValueReferenceType(); break; + case eEncodingIsLLVMPtrAuthUID: + m_compiler_type = + encoding_type->GetForwardCompilerType().AddPtrAuthModifier( + m_payload); + break; + default: llvm_unreachable("Unhandled encoding_data_type."); } @@ -676,6 +688,10 @@ bool Type::ResolveCompilerType(ResolveState compiler_type_resolve_state) { m_compiler_type = void_compiler_type.GetRValueReferenceType(); break; + case eEncodingIsLLVMPtrAuthUID: + llvm_unreachable("Cannot handle eEncodingIsLLVMPtrAuthUID without " + "valid encoding_type"); + default: llvm_unreachable("Unhandled encoding_data_type."); } diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 59b1b39e635ac5..3665771b188906 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -93,6 +93,11 @@ CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType TypeSystem::AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload) { + 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 0c2a0d735dc837..f7a4b8f1ac59be 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp @@ -287,6 +287,141 @@ 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<clang_utils::TypeSystemClangHolder>("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_sp = + ast_parser.ParseTypeFromDWARF(sc, ptrauth_type, &new_type); + CompilerType compiler_type = type_sp->GetForwardCompilerType(); + ASSERT_EQ(compiler_type.GetPtrAuthKey(), 0); + ASSERT_EQ(compiler_type.GetPtrAuthAddressDiversity(), false); + ASSERT_EQ(compiler_type.GetPtrAuthDiscriminator(), 42); +} + struct ExtractIntFromFormValueTest : public testing::Test { SubsystemRAII<FileSystem, HostInfo> subsystems; clang_utils::TypeSystemClangHolder holder; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits