Skip to content

Commit

Permalink
[DWARF] Support __ptrauth type qualifier.
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedbougacha committed Sep 19, 2023
1 parent 306f70f commit f28e8db
Show file tree
Hide file tree
Showing 15 changed files with 356 additions and 80 deletions.
7 changes: 7 additions & 0 deletions llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,13 @@ namespace llvm {
std::optional<unsigned> DWARFAddressSpace = std::nullopt,
StringRef Name = "", DINodeArray Annotations = nullptr);

/// Create a __ptrauth qualifier.
DIDerivedType *createPtrAuthQualifiedType(DIType *FromTy, unsigned Key,
bool IsAddressDiscriminated,
unsigned ExtraDiscriminator,
bool IsaPointer,
bool authenticatesNullValues);

/// Create debugging information entry for a pointer to member.
/// \param PointeeTy Type pointed to by this pointer.
/// \param SizeInBits Size.
Expand Down
108 changes: 96 additions & 12 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/PseudoProbe.h"
Expand Down Expand Up @@ -962,6 +963,40 @@ class DIStringType : public DIType {
///
/// TODO: Split out members (inheritance, fields, methods, etc.).
class DIDerivedType : public DIType {
public:
/// Pointer authentication (__ptrauth) metadata.
struct PtrAuthData {
union {
struct {
unsigned Key : 4;
unsigned IsAddressDiscriminated : 1;
unsigned ExtraDiscriminator : 16;
unsigned IsaPointer : 1;
unsigned AuthenticatesNullValues : 1;
} Data;
unsigned RawData;
} Payload;

PtrAuthData(unsigned FromRawData) { Payload.RawData = FromRawData; }
PtrAuthData(unsigned Key, bool IsDiscr, unsigned Discriminator,
bool IsaPointer, bool AuthenticatesNullValues) {
assert(Key < 16);
assert(Discriminator <= 0xffff);
Payload.Data.Key = Key;
Payload.Data.IsAddressDiscriminated = IsDiscr;
Payload.Data.ExtraDiscriminator = Discriminator;
Payload.Data.IsaPointer = IsaPointer;
Payload.Data.AuthenticatesNullValues = AuthenticatesNullValues;
}
bool operator==(struct PtrAuthData Other) const {
return Payload.RawData == Other.Payload.RawData;
}
bool operator!=(struct PtrAuthData Other) const {
return !(*this == Other);
}
};

private:
friend class LLVMContextImpl;
friend class MDNode;

Expand All @@ -972,37 +1007,44 @@ class DIDerivedType : public DIType {
DIDerivedType(LLVMContext &C, StorageType Storage, unsigned Tag,
unsigned Line, uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
ArrayRef<Metadata *> Ops)
: DIType(C, DIDerivedTypeKind, Storage, Tag, Line, SizeInBits,
AlignInBits, OffsetInBits, Flags, Ops),
DWARFAddressSpace(DWARFAddressSpace) {}
DWARFAddressSpace(DWARFAddressSpace) {
if (PtrAuthData)
SubclassData32 = PtrAuthData->Payload.RawData;
}
~DIDerivedType() = default;
static DIDerivedType *
getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, DIFile *File,
unsigned Line, DIScope *Scope, DIType *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
Metadata *ExtraData, DINodeArray Annotations, StorageType Storage,
bool ShouldCreate = true) {
return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File,
Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits,
DWARFAddressSpace, Flags, ExtraData, Annotations.get(),
Storage, ShouldCreate);
DWARFAddressSpace, PtrAuthData, Flags, ExtraData,
Annotations.get(), Storage, ShouldCreate);
}
static DIDerivedType *
getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
Metadata *ExtraData, Metadata *Annotations, StorageType Storage,
bool ShouldCreate = true);

TempDIDerivedType cloneImpl() const {
return getTemporary(
getContext(), getTag(), getName(), getFile(), getLine(), getScope(),
getBaseType(), getSizeInBits(), getAlignInBits(), getOffsetInBits(),
getDWARFAddressSpace(), getFlags(), getExtraData(), getAnnotations());
getDWARFAddressSpace(), getPtrAuthData(), getFlags(), getExtraData(),
getAnnotations());
}

public:
Expand All @@ -1011,20 +1053,23 @@ class DIDerivedType : public DIType {
(unsigned Tag, MDString *Name, Metadata *File, unsigned Line,
Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
Metadata *ExtraData = nullptr, Metadata *Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits,
OffsetInBits, DWARFAddressSpace, Flags, ExtraData, Annotations))
OffsetInBits, DWARFAddressSpace, PtrAuthData, Flags, ExtraData,
Annotations))
DEFINE_MDNODE_GET(DIDerivedType,
(unsigned Tag, StringRef Name, DIFile *File, unsigned Line,
DIScope *Scope, DIType *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
std::optional<unsigned> DWARFAddressSpace, DIFlags Flags,
std::optional<unsigned> DWARFAddressSpace,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
Metadata *ExtraData = nullptr,
DINodeArray Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, DWARFAddressSpace, Flags,
ExtraData, Annotations))
AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData,
Flags, ExtraData, Annotations))

TempDIDerivedType clone() const { return cloneImpl(); }

Expand All @@ -1038,6 +1083,45 @@ class DIDerivedType : public DIType {
return DWARFAddressSpace;
}

std::optional<PtrAuthData> getPtrAuthData() const {
return getTag() == dwarf::DW_TAG_LLVM_ptrauth_type
? std::optional<PtrAuthData>(PtrAuthData(SubclassData32))
: std::nullopt;
}

/// \returns The PointerAuth key.
std::optional<unsigned> getPtrAuthKey() const {
if (auto PtrAuthData = getPtrAuthData())
return (unsigned)PtrAuthData->Payload.Data.Key;
else return std::nullopt;
}
/// \returns The PointerAuth address discrimination bit.
std::optional<bool> isPtrAuthAddressDiscriminated() const {
if (auto PtrAuthData = getPtrAuthData())
return (bool)PtrAuthData->Payload.Data.IsAddressDiscriminated;
else return std::nullopt;
}
/// \returns The PointerAuth extra discriminator.
std::optional<unsigned> getPtrAuthExtraDiscriminator() const {
if (auto PtrAuthData = getPtrAuthData())
return (unsigned)PtrAuthData->Payload.Data.ExtraDiscriminator;
else return std::nullopt;
}
/// \returns The PointerAuth IsaPointer bit.
std::optional<bool> isPtrAuthIsaPointer() const {
if (auto PtrAuthData = getPtrAuthData())
return (bool)PtrAuthData->Payload.Data.IsaPointer;
else
return std::nullopt;
}
/// \returns The PointerAuth authenticates null values bit.
std::optional<bool> getPtrAuthAuthenticatesNullValues() const {
if (auto PtrAuthData = getPtrAuthData())
return (bool)PtrAuthData->Payload.Data.AuthenticatesNullValues;
else
return std::nullopt;
}

/// Get extra data associated with this derived type.
///
/// Class type for pointer-to-members, objective-c property node for ivars,
Expand Down
23 changes: 19 additions & 4 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5052,7 +5052,11 @@ bool LLParser::parseDIStringType(MDNode *&Result, bool IsDistinct) {
/// ::= !DIDerivedType(tag: DW_TAG_pointer_type, name: "int", file: !0,
/// line: 7, scope: !1, baseType: !2, size: 32,
/// align: 32, offset: 0, flags: 0, extraData: !3,
/// dwarfAddressSpace: 3)
/// dwarfAddressSpace: 3, ptrAuthKey: 1,
/// ptrAuthIsAddressDiscriminated: true,
/// ptrAuthExtraDiscriminator: 0x1234,
/// ptrAuthIsaPointer: 1, ptrAuthAuthenticatesNullValues:1
/// )
bool LLParser::parseDIDerivedType(MDNode *&Result, bool IsDistinct) {
#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \
REQUIRED(tag, DwarfTagField, ); \
Expand All @@ -5067,19 +5071,30 @@ bool LLParser::parseDIDerivedType(MDNode *&Result, bool IsDistinct) {
OPTIONAL(flags, DIFlagField, ); \
OPTIONAL(extraData, MDField, ); \
OPTIONAL(dwarfAddressSpace, MDUnsignedField, (UINT32_MAX, UINT32_MAX)); \
OPTIONAL(annotations, MDField, );
OPTIONAL(annotations, MDField, ); \
OPTIONAL(ptrAuthKey, MDUnsignedField, (0, 7)); \
OPTIONAL(ptrAuthIsAddressDiscriminated, MDBoolField, ); \
OPTIONAL(ptrAuthExtraDiscriminator, MDUnsignedField, (0, 0xffff)); \
OPTIONAL(ptrAuthIsaPointer, MDBoolField, ); \
OPTIONAL(ptrAuthAuthenticatesNullValues, MDBoolField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS

std::optional<unsigned> DWARFAddressSpace;
if (dwarfAddressSpace.Val != UINT32_MAX)
DWARFAddressSpace = dwarfAddressSpace.Val;
std::optional<DIDerivedType::PtrAuthData> PtrAuthData;
if (ptrAuthKey.Val)
PtrAuthData = DIDerivedType::PtrAuthData(
(unsigned)ptrAuthKey.Val, ptrAuthIsAddressDiscriminated.Val,
(unsigned)ptrAuthExtraDiscriminator.Val, ptrAuthIsaPointer.Val,
ptrAuthAuthenticatesNullValues.Val);

Result = GET_OR_DISTINCT(DIDerivedType,
(Context, tag.Val, name.Val, file.Val, line.Val,
scope.Val, baseType.Val, size.Val, align.Val,
offset.Val, DWARFAddressSpace, flags.Val,
extraData.Val, annotations.Val));
offset.Val, DWARFAddressSpace, PtrAuthData,
flags.Val, extraData.Val, annotations.Val));
return false;
}

Expand Down
18 changes: 14 additions & 4 deletions llvm/lib/Bitcode/Reader/MetadataLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
break;
}
case bitc::METADATA_DERIVED_TYPE: {
if (Record.size() < 12 || Record.size() > 14)
if (Record.size() < 12 || Record.size() > 15)
return error("Invalid record");

// DWARF address space is encoded as N->getDWARFAddressSpace() + 1. 0 means
Expand All @@ -1548,8 +1548,18 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
DWARFAddressSpace = Record[12] - 1;

Metadata *Annotations = nullptr;
if (Record.size() > 13 && Record[13])
Annotations = getMDOrNull(Record[13]);
std::optional<DIDerivedType::PtrAuthData> PtrAuthData;

// Only look for annotations/ptrauth if both are allocated.
// If not, we can't tell which was intended to be embedded, as both ptrauth
// and annotations have been expected at Record[13] at various times.
if (Record.size() > 14) {
if (Record[13])
Annotations = getMDOrNull(Record[13]);

if (Record[14])
PtrAuthData = DIDerivedType::PtrAuthData(Record[14]);
}

IsDistinct = Record[0];
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(Record[10]);
Expand All @@ -1559,7 +1569,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
getMDOrNull(Record[3]), Record[4],
getDITypeRefOrNull(Record[5]),
getDITypeRefOrNull(Record[6]), Record[7], Record[8],
Record[9], DWARFAddressSpace, Flags,
Record[9], DWARFAddressSpace, PtrAuthData, Flags,
getDITypeRefOrNull(Record[11]), Annotations)),
NextMetadataNo);
NextMetadataNo++;
Expand Down
6 changes: 5 additions & 1 deletion llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1753,9 +1753,13 @@ void ModuleBitcodeWriter::writeDIDerivedType(const DIDerivedType *N,
Record.push_back(*DWARFAddressSpace + 1);
else
Record.push_back(0);

Record.push_back(VE.getMetadataOrNullID(N->getAnnotations().get()));

if (auto PtrAuthData = N->getPtrAuthData())
Record.push_back(PtrAuthData->Payload.RawData);
else
Record.push_back(0);

Stream.EmitRecord(bitc::METADATA_DERIVED_TYPE, Record, Abbrev);
Record.clear();
}
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,20 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
if (DTy->getDWARFAddressSpace())
addUInt(Buffer, dwarf::DW_AT_address_class, dwarf::DW_FORM_data4,
*DTy->getDWARFAddressSpace());
if (auto Key = DTy->getPtrAuthKey())
addUInt(Buffer, dwarf::DW_AT_LLVM_ptrauth_key, dwarf::DW_FORM_data1, *Key);
if (auto AddrDisc = DTy->isPtrAuthAddressDiscriminated())
if (AddrDisc)
addFlag(Buffer, dwarf::DW_AT_LLVM_ptrauth_address_discriminated);
if (auto Disc = DTy->getPtrAuthExtraDiscriminator())
addUInt(Buffer, dwarf::DW_AT_LLVM_ptrauth_extra_discriminator,
dwarf::DW_FORM_data2, *Disc);
if (auto IsaPointer = DTy->isPtrAuthIsaPointer())
if (*IsaPointer)
addFlag(Buffer, dwarf::DW_AT_LLVM_ptrauth_isa_pointer);
if (auto AuthenticatesNullValues = DTy->getPtrAuthAuthenticatesNullValues())
if (*AuthenticatesNullValues)
addFlag(Buffer, dwarf::DW_AT_LLVM_ptrauth_authenticates_null_values);
}

void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2057,6 +2057,17 @@ static void writeDIDerivedType(raw_ostream &Out, const DIDerivedType *N,
Printer.printInt("dwarfAddressSpace", *DWARFAddressSpace,
/* ShouldSkipZero */ false);
Printer.printMetadata("annotations", N->getRawAnnotations());
if (auto Key = N->getPtrAuthKey())
Printer.printInt("ptrAuthKey", *Key);
if (auto AddrDisc = N->isPtrAuthAddressDiscriminated())
Printer.printBool("ptrAuthIsAddressDiscriminated", *AddrDisc);
if (auto Disc = N->getPtrAuthExtraDiscriminator())
Printer.printInt("ptrAuthExtraDiscriminator", *Disc);
if (auto IsaPointer = N->isPtrAuthIsaPointer())
Printer.printBool("ptrAuthIsaPointer", *IsaPointer);
if (auto AuthenticatesNullValues = N->getPtrAuthAuthenticatesNullValues())
Printer.printBool("ptrAuthAuthenticatesNullValues",
*AuthenticatesNullValues);
Out << ")";
}

Expand Down
Loading

0 comments on commit f28e8db

Please sign in to comment.