| //===--- GenPointerAuth.h - IRGen for pointer authentication ----*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the basic interface for generating LLVM IR for pointer |
| // authentication. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_IRGEN_GENPOINTERAUTH_H |
| #define SWIFT_IRGEN_GENPOINTERAUTH_H |
| |
| #include "swift/IRGen/ValueWitness.h" |
| #include "swift/Basic/ExternalUnion.h" |
| #include "swift/AST/IRGenOptions.h" |
| #include "swift/AST/ProtocolAssociations.h" |
| #include "swift/AST/Types.h" |
| #include "swift/SIL/SILDeclRef.h" |
| |
| namespace llvm { |
| class ConstantInt; |
| class Value; |
| } |
| |
| namespace clang { |
| class PointerAuthSchema; |
| } |
| |
| namespace swift { |
| namespace irgen { |
| class FunctionPointer; |
| class IRGenFunction; |
| class IRGenModule; |
| class PointerAuthInfo; |
| |
| /// Additional information about the source of a function pointer. |
| class PointerAuthEntity { |
| public: |
| enum class Special { |
| BlockCopyHelper, |
| BlockDisposeHelper, |
| HeapDestructor, |
| PartialApplyCapture, |
| TypeDescriptor, |
| TypeDescriptorAsArgument, |
| KeyPathDestroy, |
| KeyPathCopy, |
| KeyPathEquals, |
| KeyPathHash, |
| KeyPathGetter, |
| KeyPathNonmutatingSetter, |
| KeyPathMutatingSetter, |
| KeyPathGetLayout, |
| KeyPathInitializer, |
| KeyPathMetadataAccessor, |
| DynamicReplacementKey, |
| ProtocolConformanceDescriptor, |
| ProtocolConformanceDescriptorAsArgument, |
| }; |
| |
| private: |
| enum class Kind { |
| None, |
| Special, |
| ValueWitness, |
| AssociatedType, |
| AssociatedConformance, |
| CanSILFunctionType, |
| CoroutineYieldTypes, |
| SILDeclRef, |
| SILFunction, |
| } StoredKind; |
| |
| using Members = ExternalUnionMembers<void, |
| Special, |
| ValueWitness, |
| AssociatedType, |
| AssociatedConformance, |
| CanSILFunctionType, |
| SILDeclRef, |
| SILFunction *>; |
| static Members::Index getStorageIndexForKind(Kind kind) { |
| switch (kind) { |
| case Kind::None: |
| return Members::indexOf<void>(); |
| case Kind::Special: |
| return Members::indexOf<Special>(); |
| case Kind::ValueWitness: |
| return Members::indexOf<ValueWitness>(); |
| case Kind::CoroutineYieldTypes: |
| case Kind::CanSILFunctionType: |
| return Members::indexOf<CanSILFunctionType>(); |
| case Kind::SILDeclRef: |
| return Members::indexOf<SILDeclRef>(); |
| case Kind::AssociatedType: |
| return Members::indexOf<AssociatedType>(); |
| case Kind::AssociatedConformance: |
| return Members::indexOf<AssociatedConformance>(); |
| case Kind::SILFunction: |
| return Members::indexOf<SILFunction *>(); |
| } |
| llvm_unreachable("bad kind"); |
| } |
| ExternalUnion<Kind, Members, getStorageIndexForKind> Storage; |
| |
| static_assert(decltype(Storage)::union_is_trivially_copyable, |
| "please add copy/move/dtor if you need a non-trivial type"); |
| |
| public: |
| PointerAuthEntity() |
| : StoredKind(Kind::None) { |
| } |
| PointerAuthEntity(Special specialKind) |
| : StoredKind(Kind::Special) { |
| Storage.emplace<Special>(StoredKind, specialKind); |
| } |
| PointerAuthEntity(CanSILFunctionType type) |
| : StoredKind(Kind::CanSILFunctionType) { |
| Storage.emplace<CanSILFunctionType>(StoredKind, type); |
| } |
| PointerAuthEntity(SILDeclRef decl) |
| : StoredKind(Kind::SILDeclRef) { |
| Storage.emplace<SILDeclRef>(StoredKind, decl); |
| } |
| PointerAuthEntity(ValueWitness witness) |
| : StoredKind(Kind::ValueWitness) { |
| assert(isValueWitnessFunction(witness)); |
| Storage.emplace<ValueWitness>(StoredKind, witness); |
| } |
| PointerAuthEntity(AssociatedType association) |
| : StoredKind(Kind::AssociatedType) { |
| Storage.emplaceAggregate<AssociatedType>(StoredKind, association); |
| } |
| PointerAuthEntity(const AssociatedConformance &association) |
| : StoredKind(Kind::AssociatedConformance) { |
| Storage.emplaceAggregate<AssociatedConformance>(StoredKind, association); |
| } |
| PointerAuthEntity(SILFunction *f) |
| : StoredKind(Kind::SILFunction) { |
| Storage.emplace<SILFunction *>(StoredKind, f); |
| } |
| |
| static PointerAuthEntity forYieldTypes(CanSILFunctionType fnType) { |
| assert(fnType->isCoroutine()); |
| PointerAuthEntity result; |
| result.StoredKind = Kind::CoroutineYieldTypes; |
| result.Storage.emplace<CanSILFunctionType>(result.StoredKind, fnType); |
| return result; |
| } |
| |
| llvm::ConstantInt *getDeclDiscriminator(IRGenModule &IGM) const; |
| llvm::ConstantInt *getTypeDiscriminator(IRGenModule &IGM) const; |
| }; |
| |
| std::pair<clang::PointerAuthSchema, PointerAuthEntity> |
| getCoroutineResumeFunctionPointerAuth(IRGenModule &IGM, |
| CanSILFunctionType coroutineFnType); |
| |
| /// Blend a small integer discriminator with the given address value |
| /// in a way that is assumed to maximally preserve entropy from both. |
| llvm::Value *emitPointerAuthBlend(IRGenFunction &IGF, |
| llvm::Value *address, |
| llvm::Value *discriminator); |
| |
| /// Strip the signature of a signed pointer value. |
| /// The return value has the same type as the input. |
| llvm::Value *emitPointerAuthStrip(IRGenFunction &IGF, llvm::Value *fnPtr, |
| unsigned Key); |
| |
| /// Sign the given pointer value, which is assumed to be unsigned. |
| /// The return value has the same type as the input. This is a no-op if |
| /// the target auth info has disabled signing. |
| llvm::Value *emitPointerAuthSign(IRGenFunction &IGF, llvm::Value *fnPtr, |
| const PointerAuthInfo &newAuth); |
| |
| /// Authenticate the given pointer value and return an unsigned value. |
| llvm::Value *emitPointerAuthAuth(IRGenFunction &IGF, llvm::Value *fnPtr, |
| const PointerAuthInfo &oldAuth); |
| |
| /// Resign the given function pointer. |
| FunctionPointer emitPointerAuthResign(IRGenFunction &IGF, |
| const FunctionPointer &fn, |
| const PointerAuthInfo &newAuth); |
| |
| /// Resign the given pointer value. This function does the right thing |
| /// for unsigned input and result schemas. The result will have the same |
| /// type as the input. |
| llvm::Value *emitPointerAuthResign(IRGenFunction &IGF, |
| llvm::Value *fnPtr, |
| const PointerAuthInfo &oldAuth, |
| const PointerAuthInfo &newAuth); |
| |
| /// The (non-ABI) discriminator used for non-constant captures of |
| /// partial apply functions. |
| const uint16_t PointerAuthDiscriminator_PartialApplyCapture = 7185; |
| |
| } // end namespace irgen |
| } // end namespace swift |
| |
| #endif |