[clang] [PAC][clang] Define `PointerAuthQualifier` and `PointerAuthenticationMode` (PR #84384)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 7 14:06:14 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-modules
Author: Daniil Kovalev (kovdan01)
<details>
<summary>Changes</summary>
This brings declarations of `PointerAuthQualifier` class and
`PointerAuthenticationMode` enum and related functions required for PAuth
support in lldb (see #<!-- -->84387) from downstream Apple's code.
Co-authored-by: Ahmed Bougacha <ahmed@<!-- -->bougacha.org>
Co-authored-by: John McCall <rjmccall@<!-- -->apple.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/84384.diff
6 Files Affected:
- (modified) clang/include/clang/AST/ASTContext.h (+10)
- (modified) clang/include/clang/AST/AbstractBasicReader.h (+2-2)
- (modified) clang/include/clang/AST/AbstractBasicWriter.h (+2-2)
- (modified) clang/include/clang/AST/Type.h (+208-11)
- (modified) clang/include/clang/Basic/LangOptions.h (+7)
- (added) clang/include/clang/Basic/PointerAuthOptions.h (+23)
``````````diff
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index ff6b64c7f72d57..4fd214592d1f27 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -2182,6 +2182,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getQualifiedType(type.getUnqualifiedType(), Qs);
}
+ /// \brief Return a type with the given __ptrauth qualifier.
+ QualType getPointerAuthType(QualType type, PointerAuthQualifier pointerAuth) {
+ assert(!type.getPointerAuth());
+ assert(pointerAuth);
+
+ Qualifiers qs;
+ qs.setPointerAuth(pointerAuth);
+ return getQualifiedType(type, qs);
+ }
+
unsigned char getFixedPointScale(QualType Ty) const;
unsigned char getFixedPointIBits(QualType Ty) const;
llvm::FixedPointSemantics getFixedPointSemantics(QualType Ty) const;
diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h
index 1f2797cc701458..ab036f1d445acc 100644
--- a/clang/include/clang/AST/AbstractBasicReader.h
+++ b/clang/include/clang/AST/AbstractBasicReader.h
@@ -213,9 +213,9 @@ class DataStreamBasicReader : public BasicReaderBase<Impl> {
}
Qualifiers readQualifiers() {
- static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t),
+ static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint64_t),
"update this if the value size changes");
- uint32_t value = asImpl().readUInt32();
+ uint64_t value = asImpl().readUInt64();
return Qualifiers::fromOpaqueValue(value);
}
diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h
index 07afa388de2c17..8e42fcaad1d388 100644
--- a/clang/include/clang/AST/AbstractBasicWriter.h
+++ b/clang/include/clang/AST/AbstractBasicWriter.h
@@ -196,9 +196,9 @@ class DataStreamBasicWriter : public BasicWriterBase<Impl> {
}
void writeQualifiers(Qualifiers value) {
- static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
+ static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t),
"update this if the value size changes");
- asImpl().writeUInt32(value.getAsOpaqueValue());
+ asImpl().writeUInt64(value.getAsOpaqueValue());
}
void writeExceptionSpecInfo(
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 1942b0e67f65a3..48a51dd851ac36 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -25,8 +25,10 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/PointerAuthOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Visibility.h"
@@ -138,6 +140,165 @@ using CanQualType = CanQual<Type>;
#define TYPE(Class, Base) class Class##Type;
#include "clang/AST/TypeNodes.inc"
+/// Pointer-authentication qualifiers.
+class PointerAuthQualifier {
+ enum : uint32_t {
+ EnabledShift = 0,
+ EnabledBits = 1,
+ EnabledMask = 1 << EnabledShift,
+ AddressDiscriminatedShift = EnabledShift + EnabledBits,
+ AddressDiscriminatedBits = 1,
+ AddressDiscriminatedMask = 1 << AddressDiscriminatedShift,
+ AuthenticationModeShift =
+ AddressDiscriminatedShift + AddressDiscriminatedBits,
+ AuthenticationModeBits = 2,
+ AuthenticationModeMask = ((1 << AuthenticationModeBits) - 1)
+ << AuthenticationModeShift,
+ IsaPointerShift = AuthenticationModeShift + AuthenticationModeBits,
+ IsaPointerBits = 1,
+ IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift,
+ AuthenticatesNullValuesShift = IsaPointerShift + IsaPointerBits,
+ AuthenticatesNullValuesBits = 1,
+ AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1)
+ << AuthenticatesNullValuesShift,
+ KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
+ KeyBits = 10,
+ KeyMask = ((1 << KeyBits) - 1) << KeyShift,
+ DiscriminatorShift = KeyShift + KeyBits,
+ DiscriminatorBits = 16,
+ DiscriminatorMask = ((1u << DiscriminatorBits) - 1) << DiscriminatorShift,
+ };
+
+ // bits: |0 |1 |2..3 |4 |
+ // |Enabled|Address|AuthenticationMode|ISA pointer|
+ // bits: |5 |6..15| 16...31 |
+ // |AuthenticatesNull|Key |Discriminator|
+ uint32_t Data;
+
+ static_assert((EnabledBits + AddressDiscriminatedBits +
+ AuthenticationModeBits + IsaPointerBits +
+ AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) ==
+ 32,
+ "PointerAuthQualifier should be exactly 32 bits");
+ static_assert((EnabledMask + AddressDiscriminatedMask +
+ AuthenticationModeMask + IsaPointerMask +
+ AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) ==
+ 0xFFFFFFFF,
+ "All masks should cover the entire bits");
+ static_assert((EnabledMask ^ AddressDiscriminatedMask ^
+ AuthenticationModeMask ^ IsaPointerMask ^
+ AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) ==
+ 0xFFFFFFFF,
+ "All masks should cover the entire bits");
+
+ PointerAuthQualifier(unsigned key, bool isAddressDiscriminated,
+ unsigned extraDiscriminator,
+ PointerAuthenticationMode authenticationMode,
+ bool isIsaPointer, bool authenticatesNullValues)
+ : Data(EnabledMask |
+ (isAddressDiscriminated
+ ? static_cast<uint32_t>(AddressDiscriminatedMask)
+ : 0) |
+ (key << KeyShift) |
+ (unsigned(authenticationMode) << AuthenticationModeShift) |
+ (extraDiscriminator << DiscriminatorShift) |
+ (isIsaPointer << IsaPointerShift) |
+ (authenticatesNullValues << AuthenticatesNullValuesShift)) {
+ assert(key <= KeyNoneInternal);
+ assert(extraDiscriminator <= MaxDiscriminator);
+ }
+
+public:
+ enum {
+ KeyNoneInternal = (1u << KeyBits) - 1,
+
+ /// The maximum supported pointer-authentication key.
+ MaxKey = KeyNoneInternal - 1,
+
+ /// The maximum supported pointer-authentication discriminator.
+ MaxDiscriminator = (1u << DiscriminatorBits) - 1
+ };
+
+public:
+ PointerAuthQualifier() : Data(0) {}
+
+ static PointerAuthQualifier
+ Create(int key, bool isAddressDiscriminated, unsigned extraDiscriminator,
+ PointerAuthenticationMode authenticationMode, bool isIsaPointer,
+ bool authenticatesNullValues) {
+ if (key == PointerAuthKeyNone)
+ key = KeyNoneInternal;
+ assert((key >= 0 && key <= KeyNoneInternal) && "out-of-range key value");
+ return PointerAuthQualifier(key, isAddressDiscriminated, extraDiscriminator,
+ authenticationMode, isIsaPointer,
+ authenticatesNullValues);
+ }
+
+ bool isPresent() const {
+ return getAuthenticationMode() != PointerAuthenticationMode::None;
+ }
+
+ explicit operator bool() const { return isPresent(); }
+
+ unsigned getKey() const {
+ assert(isPresent());
+ return (Data & KeyMask) >> KeyShift;
+ }
+
+ bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; }
+
+ bool isAddressDiscriminated() const {
+ assert(isPresent());
+ return (Data & AddressDiscriminatedMask) >> AddressDiscriminatedShift;
+ }
+
+ unsigned getExtraDiscriminator() const {
+ assert(isPresent());
+ return (Data >> DiscriminatorShift);
+ }
+
+ PointerAuthenticationMode getAuthenticationMode() const {
+ return PointerAuthenticationMode((Data & AuthenticationModeMask) >>
+ AuthenticationModeShift);
+ }
+
+ bool isIsaPointer() const {
+ assert(isPresent());
+ return (Data & IsaPointerMask) >> IsaPointerShift;
+ }
+
+ bool authenticatesNullValues() const {
+ assert(isPresent());
+ return (Data & AuthenticatesNullValuesMask) >> AuthenticatesNullValuesShift;
+ }
+
+ PointerAuthQualifier withoutKeyNone() const {
+ return hasKeyNone() ? PointerAuthQualifier() : *this;
+ }
+
+ friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
+ return Lhs.Data == Rhs.Data;
+ }
+ friend bool operator!=(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
+ return Lhs.Data != Rhs.Data;
+ }
+
+ bool isEquivalent(PointerAuthQualifier Other) const {
+ return withoutKeyNone() == Other.withoutKeyNone();
+ }
+
+ uint32_t getAsOpaqueValue() const { return Data; }
+
+ // Deserialize pointer-auth qualifiers from an opaque representation.
+ static PointerAuthQualifier fromOpaqueValue(uint32_t opaque) {
+ PointerAuthQualifier result;
+ result.Data = opaque;
+ return result;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); }
+};
+
/// The collection of all-type qualifiers we support.
/// Clang supports five independent qualifiers:
/// * C99: const, volatile, and restrict
@@ -193,19 +354,27 @@ class Qualifiers {
FastMask = (1 << FastWidth) - 1
};
+ Qualifiers() : Mask(0), PtrAuth() {}
+
/// Returns the common set of qualifiers while removing them from
/// the given sets.
static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
+ Qualifiers Q;
+ if (L.getPointerAuth().isEquivalent(R.getPointerAuth())) {
+ Q.setPointerAuth(L.getPointerAuth().withoutKeyNone());
+ PointerAuthQualifier Empty;
+ L.setPointerAuth(Empty);
+ R.setPointerAuth(Empty);
+ }
+
// If both are only CVR-qualified, bit operations are sufficient.
if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) {
- Qualifiers Q;
Q.Mask = L.Mask & R.Mask;
L.Mask &= ~Q.Mask;
R.Mask &= ~Q.Mask;
return Q;
}
- Qualifiers Q;
unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers();
Q.addCVRQualifiers(CommonCRV);
L.removeCVRQualifiers(CommonCRV);
@@ -250,15 +419,16 @@ class Qualifiers {
}
// Deserialize qualifiers from an opaque representation.
- static Qualifiers fromOpaqueValue(unsigned opaque) {
+ static Qualifiers fromOpaqueValue(uint64_t opaque) {
Qualifiers Qs;
- Qs.Mask = opaque;
+ Qs.Mask = uint32_t(opaque);
+ Qs.PtrAuth = PointerAuthQualifier::fromOpaqueValue(uint32_t(opaque >> 32));
return Qs;
}
// Serialize these qualifiers into an opaque representation.
- unsigned getAsOpaqueValue() const {
- return Mask;
+ uint64_t getAsOpaqueValue() const {
+ return uint64_t(Mask) | (uint64_t(PtrAuth.getAsOpaqueValue()) << 32);
}
bool hasConst() const { return Mask & Const; }
@@ -406,6 +576,10 @@ class Qualifiers {
setAddressSpace(space);
}
+ PointerAuthQualifier getPointerAuth() const { return PtrAuth; }
+ void setPointerAuth(PointerAuthQualifier q) { PtrAuth = q; }
+ void removePtrAuth() { PtrAuth = PointerAuthQualifier(); }
+
// Fast qualifiers are those that can be allocated directly
// on a QualType object.
bool hasFastQualifiers() const { return getFastQualifiers(); }
@@ -428,7 +602,7 @@ class Qualifiers {
/// Return true if the set contains any qualifiers which require an ExtQuals
/// node to be allocated.
- bool hasNonFastQualifiers() const { return Mask & ~FastMask; }
+ bool hasNonFastQualifiers() const { return (Mask & ~FastMask) || PtrAuth; }
Qualifiers getNonFastQualifiers() const {
Qualifiers Quals = *this;
Quals.setFastQualifiers(0);
@@ -436,8 +610,8 @@ class Qualifiers {
}
/// Return true if the set contains any qualifiers.
- bool hasQualifiers() const { return Mask; }
- bool empty() const { return !Mask; }
+ bool hasQualifiers() const { return Mask || PtrAuth; }
+ bool empty() const { return !hasQualifiers(); }
/// Add the qualifiers from the given set to this set.
void addQualifiers(Qualifiers Q) {
@@ -454,6 +628,9 @@ class Qualifiers {
if (Q.hasObjCLifetime())
addObjCLifetime(Q.getObjCLifetime());
}
+
+ if (Q.PtrAuth)
+ PtrAuth = Q.PtrAuth;
}
/// Remove the qualifiers from the given set from this set.
@@ -471,6 +648,9 @@ class Qualifiers {
if (getAddressSpace() == Q.getAddressSpace())
removeAddressSpace();
}
+
+ if (PtrAuth == Q.PtrAuth)
+ PtrAuth = PointerAuthQualifier();
}
/// Add the qualifiers from the given set to this set, given that
@@ -482,7 +662,10 @@ class Qualifiers {
!hasObjCGCAttr() || !qs.hasObjCGCAttr());
assert(getObjCLifetime() == qs.getObjCLifetime() ||
!hasObjCLifetime() || !qs.hasObjCLifetime());
+ assert(!PtrAuth || !qs.PtrAuth || PtrAuth == qs.PtrAuth);
Mask |= qs.Mask;
+ if (qs.PtrAuth)
+ PtrAuth = qs.PtrAuth;
}
/// Returns true if address space A is equal to or a superset of B.
@@ -535,6 +718,8 @@ class Qualifiers {
// be changed.
(getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
!other.hasObjCGCAttr()) &&
+ // Pointer-auth qualifiers must match exactly.
+ PtrAuth == other.PtrAuth &&
// ObjC lifetime qualifiers must match exactly.
getObjCLifetime() == other.getObjCLifetime() &&
// CVR qualifiers may subset.
@@ -567,8 +752,12 @@ class Qualifiers {
/// another set of qualifiers, not considering qualifier compatibility.
bool isStrictSupersetOf(Qualifiers Other) const;
- bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
- bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
+ bool operator==(Qualifiers Other) const {
+ return Mask == Other.Mask && PtrAuth == Other.PtrAuth;
+ }
+ bool operator!=(Qualifiers Other) const {
+ return Mask != Other.Mask || PtrAuth != Other.PtrAuth;
+ }
explicit operator bool() const { return hasQualifiers(); }
@@ -606,6 +795,7 @@ class Qualifiers {
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Mask);
+ PtrAuth.Profile(ID);
}
private:
@@ -613,6 +803,9 @@ class Qualifiers {
// |C R V|U|GCAttr|Lifetime|AddressSpace|
uint32_t Mask = 0;
+ PointerAuthQualifier PtrAuth;
+ static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t),
+ "PointerAuthQualifier must be 32 bits");
static const uint32_t UMask = 0x8;
static const uint32_t UShift = 3;
static const uint32_t GCAttrMask = 0x30;
@@ -1241,6 +1434,10 @@ class QualType {
// true when Type is objc's weak and weak is enabled but ARC isn't.
bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
+ PointerAuthQualifier getPointerAuth() const {
+ return getQualifiers().getPointerAuth();
+ }
+
enum PrimitiveDefaultInitializeKind {
/// The type does not fall into any of the following categories. Note that
/// this case is zero-valued so that values of this enum can be used as a
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 862952d336ef31..6fe7472d8ad0ca 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -57,6 +57,13 @@ enum class ShaderStage {
Invalid,
};
+enum class PointerAuthenticationMode : unsigned {
+ None,
+ Strip,
+ SignAndStrip,
+ SignAndAuth
+};
+
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
/// this large collection of bitfields is a trivial class type.
class LangOptionsBase {
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
new file mode 100644
index 00000000000000..c69847ac704a41
--- /dev/null
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -0,0 +1,23 @@
+//===--- PointerAuthOptions.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines options for configuring pointer-auth technologies
+// like ARMv8.3.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
+#define LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
+
+namespace clang {
+
+constexpr int PointerAuthKeyNone = -1;
+
+} // end namespace clang
+
+#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/84384
More information about the cfe-commits
mailing list