Skip to content

Commit

Permalink
[Dwarf] Support __ptrauth qualifier in metadata nodes (#83862)
Browse files Browse the repository at this point in the history
Reland #82363 after fixing build failure
https://lab.llvm.org/buildbot/#/builders/5/builds/41428.

Memory sanitizer detects usage of `RawData` union member which is not
filled directly. Instead, the code relies on filling `Data` union
member, which is a struct consisting of signing schema parameters.

According to https://en.cppreference.com/w/cpp/language/union, this is
UB:
"It is undefined behavior to read from the member of the union that
wasn't most recently written".

Instead of relying on compiler allowing us to do dirty things, do not
use union and only store `RawData`. Particular ptrauth parameters are
obtained on demand via bit operations.

Original PR description below.

Emit `__ptrauth`-qualified types as `DIDerivedType` metadata nodes in IR
with tag `DW_TAG_LLVM_ptrauth_type`, baseType referring to the type
which has the qualifier applied, and the following parameters
representing the signing schema:

- `ptrAuthKey` (integer)
- `ptrAuthIsAddressDiscriminated` (boolean)
- `ptrAuthExtraDiscriminator` (integer)
- `ptrAuthIsaPointer` (boolean)
- `ptrAuthAuthenticatesNullValues` (boolean)

Co-authored-by: Ahmed Bougacha <ahmed@bougacha.org>
  • Loading branch information
kovdan01 and ahmedbougacha committed Mar 19, 2024
1 parent e04dd68 commit 924a1dc
Show file tree
Hide file tree
Showing 16 changed files with 358 additions and 100 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 @@ -270,6 +270,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
98 changes: 75 additions & 23 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ class DIType : public DIScope {

unsigned getLine() const { return Line; }
uint64_t getSizeInBits() const { return SizeInBits; }
uint32_t getAlignInBits() const { return SubclassData32; }
uint32_t getAlignInBits() const;
uint32_t getAlignInBytes() const { return getAlignInBits() / CHAR_BIT; }
uint64_t getOffsetInBits() const { return OffsetInBits; }
DIFlags getFlags() const { return Flags; }
Expand Down Expand Up @@ -972,6 +972,35 @@ class DIStringType : public DIType {
///
/// TODO: Split out members (inheritance, fields, methods, etc.).
class DIDerivedType : public DIType {
public:
/// Pointer authentication (__ptrauth) metadata.
struct PtrAuthData {
// RawData layout:
// - Bits 0..3: Key
// - Bit 4: IsAddressDiscriminated
// - Bits 5..20: ExtraDiscriminator
// - Bit 21: IsaPointer
// - Bit 22: AuthenticatesNullValues
unsigned RawData;

PtrAuthData(unsigned FromRawData) : RawData(FromRawData) {}
PtrAuthData(unsigned Key, bool IsDiscr, unsigned Discriminator,
bool IsaPointer, bool AuthenticatesNullValues) {
assert(Key < 16);
assert(Discriminator <= 0xffff);
RawData = (Key << 0) | (IsDiscr ? (1 << 4) : 0) | (Discriminator << 5) |
(IsaPointer ? (1 << 21) : 0) |
(AuthenticatesNullValues ? (1 << 22) : 0);
}

unsigned key() { return (RawData >> 0) & 0b1111; }
bool isAddressDiscriminated() { return (RawData >> 4) & 1; }
unsigned extraDiscriminator() { return (RawData >> 5) & 0xffff; }
bool isaPointer() { return (RawData >> 21) & 1; }
bool authenticatesNullValues() { return (RawData >> 22) & 1; }
};

private:
friend class LLVMContextImpl;
friend class MDNode;

Expand All @@ -982,59 +1011,70 @@ 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->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());
return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(),
getScope(), getBaseType(), getSizeInBits(),
getAlignInBits(), getOffsetInBits(),
getDWARFAddressSpace(), getPtrAuthData(), getFlags(),
getExtraData(), getAnnotations());
}

public:
DEFINE_MDNODE_GET(
DIDerivedType,
(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,
Metadata *ExtraData = nullptr, Metadata *Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits,
OffsetInBits, DWARFAddressSpace, Flags, ExtraData, Annotations))
DEFINE_MDNODE_GET(DIDerivedType,
(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,
std::optional<PtrAuthData> PtrAuthData, DIFlags Flags,
Metadata *ExtraData = nullptr,
Metadata *Annotations = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, 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 @@ -1048,6 +1088,8 @@ class DIDerivedType : public DIType {
return DWARFAddressSpace;
}

std::optional<PtrAuthData> getPtrAuthData() const;

/// Get extra data associated with this derived type.
///
/// Class type for pointer-to-members, objective-c property node for ivars,
Expand Down Expand Up @@ -1087,6 +1129,16 @@ class DIDerivedType : public DIType {
}
};

inline bool operator==(DIDerivedType::PtrAuthData Lhs,
DIDerivedType::PtrAuthData Rhs) {
return Lhs.RawData == Rhs.RawData;
}

inline bool operator!=(DIDerivedType::PtrAuthData Lhs,
DIDerivedType::PtrAuthData Rhs) {
return !(Lhs == Rhs);
}

/// Composite types.
///
/// TODO: Detach from DerivedTypeBase (split out MDEnumType?).
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 @@ -5184,7 +5184,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 @@ -5199,19 +5203,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.emplace(
(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
17 changes: 13 additions & 4 deletions llvm/lib/Bitcode/Reader/MetadataLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1556,7 +1556,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 @@ -1566,8 +1566,17 @@ 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.emplace(Record[14]);
}

IsDistinct = Record[0];
DINode::DIFlags Flags = static_cast<DINode::DIFlags>(Record[10]);
Expand All @@ -1577,7 +1586,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
5 changes: 5 additions & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,11 @@ void ModuleBitcodeWriter::writeDIDerivedType(const DIDerivedType *N,

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

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

Stream.EmitRecord(bitc::METADATA_DERIVED_TYPE, Record, Abbrev);
Record.clear();
}
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,18 @@ 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 PtrAuthData = DTy->getPtrAuthData()) {
addUInt(Buffer, dwarf::DW_AT_LLVM_ptrauth_key, dwarf::DW_FORM_data1,
PtrAuthData->key());
if (PtrAuthData->isAddressDiscriminated())
addFlag(Buffer, dwarf::DW_AT_LLVM_ptrauth_address_discriminated);
addUInt(Buffer, dwarf::DW_AT_LLVM_ptrauth_extra_discriminator,
dwarf::DW_FORM_data2, PtrAuthData->extraDiscriminator());
if (PtrAuthData->isaPointer())
addFlag(Buffer, dwarf::DW_AT_LLVM_ptrauth_isa_pointer);
if (PtrAuthData->authenticatesNullValues())
addFlag(Buffer, dwarf::DW_AT_LLVM_ptrauth_authenticates_null_values);
}
}

void DwarfUnit::constructSubprogramArguments(DIE &Buffer, DITypeRefArray Args) {
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2141,6 +2141,16 @@ static void writeDIDerivedType(raw_ostream &Out, const DIDerivedType *N,
Printer.printInt("dwarfAddressSpace", *DWARFAddressSpace,
/* ShouldSkipZero */ false);
Printer.printMetadata("annotations", N->getRawAnnotations());
if (auto PtrAuthData = N->getPtrAuthData()) {
Printer.printInt("ptrAuthKey", PtrAuthData->key());
Printer.printBool("ptrAuthIsAddressDiscriminated",
PtrAuthData->isAddressDiscriminated());
Printer.printInt("ptrAuthExtraDiscriminator",
PtrAuthData->extraDiscriminator());
Printer.printBool("ptrAuthIsaPointer", PtrAuthData->isaPointer());
Printer.printBool("ptrAuthAuthenticatesNullValues",
PtrAuthData->authenticatesNullValues());
}
Out << ")";
}

Expand Down

0 comments on commit 924a1dc

Please sign in to comment.