[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 <jonas@devlieghere.com>
This commit is contained in:
Daniil Kovalev
2024-04-30 11:15:35 +03:00
committed by GitHub
parent a413c563bd
commit 64248d7dee
10 changed files with 302 additions and 5 deletions

View File

@@ -262,6 +262,12 @@ public:
size_t GetPointerByteSize() const;
/// \}
unsigned GetPtrAuthKey() const;
unsigned GetPtrAuthDiscriminator() const;
bool GetPtrAuthAddressDiversity() const;
/// Accessors.
/// \{
@@ -369,6 +375,12 @@ public:
/// 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.

View File

@@ -401,7 +401,9 @@ public:
/// 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 {

View File

@@ -221,6 +221,14 @@ public:
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 @@ public:
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,

View File

@@ -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;

View File

@@ -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) {

View File

@@ -67,11 +67,13 @@ public:
/// 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 @@ public:
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 @@ public:
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;

View File

@@ -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())

View File

@@ -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.");
}

View File

@@ -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();

View File

@@ -287,6 +287,141 @@ DWARF:
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;