//===--- MetadataReader.h - Abstract access to remote metadata --*- 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 operations for reading metadata from a remote process. // //===----------------------------------------------------------------------===// #ifndef SWIFT_REMOTE_METADATAREADER_H #define SWIFT_REMOTE_METADATAREADER_H #include "swift/Runtime/Metadata.h" #include "swift/Remote/MemoryReader.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/TypeDecoder.h" #include "swift/Basic/Defer.h" #include "swift/Basic/ExternalUnion.h" #include "swift/Basic/Range.h" #include "swift/Basic/LLVM.h" #include "swift/ABI/TypeIdentity.h" #include "swift/Runtime/ExistentialContainer.h" #include "swift/Runtime/HeapObject.h" #include "swift/Basic/Unreachable.h" #include #include #include namespace swift { namespace remote { template using FunctionParam = swift::Demangle::FunctionParam; template using TypeDecoder = swift::Demangle::TypeDecoder; /// The kind of mangled name to read. enum class MangledNameKind { Type, Symbol, }; /// A pointer to the local buffer of an object that also remembers the /// address at which it was stored remotely. template class RemoteRef { private: uint64_t Address; const T *LocalBuffer; public: RemoteRef() : Address(0), LocalBuffer(nullptr) {} /*implicit*/ RemoteRef(std::nullptr_t _) : RemoteRef() {} template explicit RemoteRef(StoredPointer address, const T *localBuffer) : Address((uint64_t)address), LocalBuffer(localBuffer) {} uint64_t getAddressData() const { return Address; } const T *getLocalBuffer() const { return LocalBuffer; } explicit operator bool() const { return LocalBuffer != nullptr; } const T *operator->() const { assert(LocalBuffer); return LocalBuffer; } bool operator==(RemoteRef other) const { return Address == other.Address; } bool operator!=(RemoteRef other) const { return !operator==(other); } /// Project a reference for a field. The field must be projected from the same /// LocalBuffer pointer as this RemoteRef. template RemoteRef getField(U &field) const { auto offset = (intptr_t)&field - (intptr_t)LocalBuffer; return RemoteRef((uint64_t)(Address + (int64_t)offset), &field); } /// Resolve the remote address of a relative offset stored at the remote address. uint64_t resolveRelativeAddressData() const { int32_t offset; memcpy(&offset, LocalBuffer, sizeof(int32_t)); if (offset == 0) return 0; return Address + (int64_t)offset; } template uint64_t resolveRelativeFieldData(U &field) const { return getField(field).resolveRelativeAddressData(); } RemoteRef atByteOffset(int64_t Offset) const { return RemoteRef(Address + Offset, (const T *)((intptr_t)LocalBuffer + Offset)); } }; /// A structure, designed for use with std::unique_ptr, which destroys /// a pointer by calling free on it (and not trying to call a destructor). struct delete_with_free { void operator()(const void *memory) { free(const_cast(memory)); } }; /// A structure representing an opened existential type. struct RemoteExistential { /// The payload's concrete type metadata. RemoteAddress MetadataAddress; /// The address of the payload value. RemoteAddress PayloadAddress; /// True if this is an NSError instance transparently bridged to an Error /// existential. bool IsBridgedError; RemoteExistential(RemoteAddress MetadataAddress, RemoteAddress PayloadAddress, bool IsBridgedError=false) : MetadataAddress(MetadataAddress), PayloadAddress(PayloadAddress), IsBridgedError(IsBridgedError) {} }; /// A generic reader of metadata. /// /// BuilderType must implement a particular interface which is currently /// too fluid to allow useful documentation; consult the actual /// implementations. The chief thing is that it provides several member /// types which should obey the following constraints: /// - T() yields a value which is false when contextually converted to bool /// - a false value signals that an error occurred when building a value template class MetadataReader { public: using BuiltType = typename BuilderType::BuiltType; using BuiltTypeDecl = typename BuilderType::BuiltTypeDecl; using BuiltProtocolDecl = typename BuilderType::BuiltProtocolDecl; using BuiltRequirement = typename BuilderType::BuiltRequirement; using StoredPointer = typename Runtime::StoredPointer; using StoredSignedPointer = typename Runtime::StoredSignedPointer; using StoredSize = typename Runtime::StoredSize; private: /// The maximum number of bytes to read when reading metadata. Anything larger /// will automatically return failure. This prevents us from reading absurd /// amounts of data when we encounter corrupt values for sizes/counts. static const uint64_t MaxMetadataSize = 1048576; // 1MB /// A cache of built types, keyed by the address of the type. std::unordered_map TypeCache; using MetadataRef = RemoteRef>; using OwnedMetadataRef = MemoryReader::ReadBytesResult; /// A cache of read type metadata, keyed by the address of the metadata. std::unordered_map MetadataCache; using ContextDescriptorRef = RemoteRef>; using OwnedContextDescriptorRef = MemoryReader::ReadBytesResult; /// A reference to a context descriptor that may be in an unloaded image. class ParentContextDescriptorRef { bool IsResolved; using Payloads = ExternalUnionMembers; static typename Payloads::Index getPayloadIndex(bool IsResolved) { return IsResolved ? Payloads::template indexOf() : Payloads::template indexOf(); } ExternalUnion Payload; public: explicit ParentContextDescriptorRef(StringRef Symbol) : IsResolved(false) { Payload.template emplace(IsResolved, Symbol); } explicit ParentContextDescriptorRef(ContextDescriptorRef Resolved) : IsResolved(true) { Payload.template emplace(IsResolved, Resolved); } ParentContextDescriptorRef() : ParentContextDescriptorRef(ContextDescriptorRef()) {} ParentContextDescriptorRef(const ParentContextDescriptorRef &o) : IsResolved(o.IsResolved) { Payload.copyConstruct(IsResolved, o.Payload); } ParentContextDescriptorRef(ParentContextDescriptorRef &&o) : IsResolved(o.IsResolved) { Payload.moveConstruct(IsResolved, std::move(o.Payload)); } ~ParentContextDescriptorRef() { Payload.destruct(IsResolved); } ParentContextDescriptorRef &operator=(const ParentContextDescriptorRef &o) { Payload.copyAssign(IsResolved, o.IsResolved, o.Payload); IsResolved = o.isResolved(); return *this; } ParentContextDescriptorRef &operator=(ParentContextDescriptorRef &&o) { Payload.moveAssign(IsResolved, o.IsResolved, std::move(o.Payload)); IsResolved = o.isResolved(); return *this; } bool isResolved() const { return IsResolved; } StringRef getSymbol() const { return Payload.template get(IsResolved); } ContextDescriptorRef getResolved() const { return Payload.template get(IsResolved); } explicit operator bool() const { return !isResolved() || getResolved(); } }; /// A cache of read nominal type descriptors, keyed by the address of the /// nominal type descriptor. std::unordered_map ContextDescriptorCache; using OwnedProtocolDescriptorRef = std::unique_ptr, delete_with_free>; enum class IsaEncodingKind { /// We haven't checked yet. Unknown, /// There was an error trying to find out the isa encoding. Error, /// There's no special isa encoding. None, /// There's an unconditional mask to apply to the isa pointer. /// - IsaMask stores the mask. Masked, /// Isa pointers are indexed. If applying a mask yields a magic value, /// applying a different mask and shifting yields an index into a global /// array of class pointers. Otherwise, the isa pointer is just a raw /// class pointer. /// - IsaIndexMask stores the index mask. /// - IsaIndexShift stores the index shift. /// - IsaMagicMask stores the magic value mask. /// - IsaMagicValue stores the magic value. /// - IndexedClassesPointer stores the pointer to the start of the /// indexed classes array; this is constant throughout the program. /// - IndexedClassesCountPointer stores a pointer to the number /// of elements in the indexed classes array. Indexed }; IsaEncodingKind IsaEncoding = IsaEncodingKind::Unknown; union { StoredPointer IsaMask; StoredPointer IsaIndexMask; }; StoredPointer IsaIndexShift; StoredPointer IsaMagicMask; StoredPointer IsaMagicValue; StoredPointer IndexedClassesPointer; StoredPointer IndexedClassesCountPointer; StoredPointer LastIndexedClassesCount = 0; enum class TaggedPointerEncodingKind { /// We haven't checked yet. Unknown, /// There was an error trying to find out the tagged pointer encoding. Error, /// The "extended" encoding. /// /// 1 bit: is-tagged /// 3 bits: class index (for objc_debug_taggedpointer_classes[]) /// 60 bits: payload /// /// Class index 0b111 represents 256 additional classes: /// /// 1 bit: is-tagged /// 3 bits: 0b111 /// 8 bits: extended class index (for objc_debug_taggedpointer_ext_classes[]) /// 54 bits: payload Extended }; TaggedPointerEncodingKind TaggedPointerEncoding = TaggedPointerEncodingKind::Unknown; StoredPointer TaggedPointerMask; StoredPointer TaggedPointerSlotShift; StoredPointer TaggedPointerSlotMask; StoredPointer TaggedPointerClasses; StoredPointer TaggedPointerExtendedMask; StoredPointer TaggedPointerExtendedSlotShift; StoredPointer TaggedPointerExtendedSlotMask; StoredPointer TaggedPointerExtendedClasses; StoredPointer TaggedPointerObfuscator; Demangle::NodeFactory Factory; Demangle::NodeFactory &getNodeFactory() { return Factory; } public: BuilderType Builder; BuilderType &getBuilder() { return this->Builder; } std::shared_ptr Reader; StoredPointer PtrAuthMask; StoredPointer stripSignedPointer(StoredSignedPointer P) { return P.SignedValue & PtrAuthMask; } RemoteAbsolutePointer stripSignedPointer(const RemoteAbsolutePointer &P) { if (P.isResolved()) { return RemoteAbsolutePointer("", P.getResolvedAddress().getAddressData() & PtrAuthMask); } return P; } StoredPointer queryPtrAuthMask() { StoredPointer QueryResult; if (Reader->queryDataLayout(DataLayoutQueryType::DLQ_GetPtrAuthMask, nullptr, &QueryResult)) { return QueryResult; } return ~StoredPointer(0); } template MetadataReader(std::shared_ptr reader, T &&... args) : Builder(std::forward(args)...), Reader(std::move(reader)), PtrAuthMask(queryPtrAuthMask()) { } MetadataReader(const MetadataReader &other) = delete; MetadataReader &operator=(const MetadataReader &other) = delete; /// Clear all of the caches in this reader. void clear() { TypeCache.clear(); MetadataCache.clear(); ContextDescriptorCache.clear(); } /// Demangle a mangled name that was read from the given remote address. Demangle::NodePointer demangle(RemoteRef mangledName, MangledNameKind kind, Demangler &dem, bool useOpaqueTypeSymbolicReferences = false) { // Symbolic reference resolver for the demangle operation below. auto symbolicReferenceResolver = [&](SymbolicReferenceKind kind, Directness directness, int32_t offset, const void *base) -> swift::Demangle::NodePointer { // Resolve the reference to a remote address. auto offsetInMangledName = (const char *)base - mangledName.getLocalBuffer(); auto remoteAddress = mangledName.getAddressData() + offsetInMangledName + offset; RemoteAbsolutePointer resolved; if (directness == Directness::Indirect) { if (auto indirectAddress = readPointer(remoteAddress)) { resolved = stripSignedPointer(*indirectAddress); } else { return nullptr; } } else { resolved = RemoteAbsolutePointer("", remoteAddress); } switch (kind) { case Demangle::SymbolicReferenceKind::Context: { auto context = readContextDescriptor(resolved); if (!context) return nullptr; // Try to preserve a reference to an OpaqueTypeDescriptor // symbolically, since we'd like to read out and resolve the type ref // to the underlying type if available. if (useOpaqueTypeSymbolicReferences && context.isResolved() && context.getResolved()->getKind() == ContextDescriptorKind::OpaqueType){ return dem.createNode( Node::Kind::OpaqueTypeDescriptorSymbolicReference, context.getResolved().getAddressData()); } return buildContextMangling(context, dem); } case Demangle::SymbolicReferenceKind::AccessorFunctionReference: { // The symbolic reference points at a resolver function, but we can't // execute code in the target process to resolve it from here. return nullptr; } } return nullptr; }; auto mangledNameStr = Demangle::makeSymbolicMangledNameStringRef(mangledName.getLocalBuffer()); swift::Demangle::NodePointer result; switch (kind) { case MangledNameKind::Type: result = dem.demangleType(mangledNameStr, symbolicReferenceResolver); break; case MangledNameKind::Symbol: result = dem.demangleSymbol(mangledNameStr, symbolicReferenceResolver); break; } return result; } /// Given a demangle tree, attempt to turn it into a type. TypeLookupErrorOr decodeMangledType(NodePointer Node) { return swift::Demangle::decodeMangledType(Builder, Node); } /// Get the remote process's swift_isaMask. llvm::Optional readIsaMask() { auto encoding = getIsaEncoding(); if (encoding != IsaEncodingKind::Masked) { // Still return success if there's no isa encoding at all. if (encoding == IsaEncodingKind::None) return 0; else return None; } return IsaMask; } /// Given a remote pointer to metadata, attempt to discover its MetadataKind. llvm::Optional readKindFromMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta) return None; return meta->getKind(); } /// Given a remote pointer to class metadata, attempt to read its superclass. StoredPointer readSuperClassFromClassMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::Class) return StoredPointer(); auto classMeta = cast>(meta); return stripSignedPointer(classMeta->Superclass); } /// Given a remote pointer to class metadata, attempt to discover its class /// instance size and whether fields should use the resilient layout strategy. llvm::Optional readInstanceStartAndAlignmentFromClassMetadata( StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::Class) return None; #if SWIFT_OBJC_INTEROP // The following algorithm only works on the non-fragile Apple runtime. // Grab the RO-data pointer. This part is not ABI. StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress); if (!roDataPtr) return None; // Get the address of the InstanceStart field. auto address = roDataPtr + sizeof(uint32_t) * 1; unsigned start; if (!Reader->readInteger(RemoteAddress(address), &start)) return None; return start; #else // All swift class instances start with an isa pointer, // followed by the retain counts (which are the size of a long long). size_t isaAndRetainCountSize = sizeof(StoredSize) + sizeof(long long); size_t start = isaAndRetainCountSize; auto classMeta = cast>(meta); while (stripSignedPointer(classMeta->Superclass)) { classMeta = cast>( readMetadata(stripSignedPointer(classMeta->Superclass))); // Subtract the size contribution of the isa and retain counts from // the super class. start += classMeta->InstanceSize - isaAndRetainCountSize; } return start; #endif } /// Given a pointer to the metadata, attempt to read the value /// witness table. Note that it's not safe to access any non-mandatory /// members of the value witness table, like extra inhabitants or enum members. llvm::Optional> readValueWitnessTable(StoredPointer MetadataAddress) { // The value witness table pointer is at offset -1 from the metadata // pointer, that is, the pointer-sized word immediately before the // pointer's referenced address. TargetValueWitnessTable VWT; auto ValueWitnessTableAddrAddr = MetadataAddress - sizeof(StoredPointer); StoredPointer ValueWitnessTableAddr; if (!Reader->readInteger(RemoteAddress(ValueWitnessTableAddrAddr), &ValueWitnessTableAddr)) return None; if (!Reader->readBytes(RemoteAddress(ValueWitnessTableAddr), (uint8_t *)&VWT, sizeof(VWT))) return None; return VWT; } /// Given a pointer to a known-error existential, attempt to discover the /// pointer to its metadata address, its value address, and whether this /// is a toll-free-bridged NSError or an actual Error existential wrapper /// around a native Swift value. llvm::Optional readMetadataAndValueErrorExistential(RemoteAddress ExistentialAddress) { // An pointer to an error existential is always an heap object. auto MetadataAddress = readMetadataFromInstance(ExistentialAddress.getAddressData()); if (!MetadataAddress) return None; bool isObjC = false; bool isBridged = false; auto Meta = readMetadata(*MetadataAddress); if (!Meta) return None; if (auto ClassMeta = dyn_cast>(Meta)) { if (ClassMeta->isPureObjC()) { // If we can determine the Objective-C class name, this is probably an // error existential with NSError-compatible layout. std::string ObjCClassName; if (readObjCClassName(*MetadataAddress, ObjCClassName)) { if (ObjCClassName == "__SwiftNativeNSError") isObjC = true; else isBridged = true; } } else { isBridged = true; } } if (isBridged) { // NSError instances don't need to be unwrapped. return RemoteExistential(RemoteAddress(*MetadataAddress), ExistentialAddress, isBridged); } // In addition to the isa pointer and two 32-bit reference counts, if the // error existential is layout-compatible with NSError, we also need to // skip over its three word-sized fields: the error code, the domain, // and userInfo. StoredPointer InstanceMetadataAddressAddress = ExistentialAddress.getAddressData() + (isObjC ? 5 : 2) * sizeof(StoredPointer); // We need to get the instance's alignment info so we can get the exact // offset of the start of its data in the class. auto InstanceMetadataAddress = readMetadataFromInstance(InstanceMetadataAddressAddress); if (!InstanceMetadataAddress) return None; // Read the value witness table. auto VWT = readValueWitnessTable(*InstanceMetadataAddress); if (!VWT) return None; // Now we need to skip over the instance metadata pointer and instance's // conformance pointer for Swift.Error. StoredPointer InstanceAddress = InstanceMetadataAddressAddress + 2 * sizeof(StoredPointer); // When built with Objective-C interop, the runtime also stores a conformance // to Hashable and the base type introducing the Hashable conformance. if (isObjC) InstanceAddress += 2 * sizeof(StoredPointer); // Round up to alignment, and we have the start address of the // instance payload. auto AlignmentMask = VWT->getAlignmentMask(); InstanceAddress = (InstanceAddress + AlignmentMask) & ~AlignmentMask; return RemoteExistential( RemoteAddress(*InstanceMetadataAddress), RemoteAddress(InstanceAddress), isBridged); } /// Given a known-opaque existential, attemp to discover the pointer to its /// metadata address and its value. llvm::Optional readMetadataAndValueOpaqueExistential(RemoteAddress ExistentialAddress) { // OpaqueExistentialContainer is the layout of an opaque existential. // `Type` is the pointer to the metadata. TargetOpaqueExistentialContainer Container; if (!Reader->readBytes(RemoteAddress(ExistentialAddress), (uint8_t *)&Container, sizeof(Container))) return None; auto MetadataAddress = static_cast(Container.Type); auto Metadata = readMetadata(MetadataAddress); if (!Metadata) return None; auto VWT = readValueWitnessTable(MetadataAddress); if (!VWT) return None; // Inline representation (the value fits in the existential container). // So, the value starts at the first word of the container. if (VWT->isValueInline()) return RemoteExistential(RemoteAddress(MetadataAddress), ExistentialAddress); // Non-inline (box'ed) representation. // The first word of the container stores the address to the box. StoredPointer BoxAddress; if (!Reader->readInteger(ExistentialAddress, &BoxAddress)) return None; auto AlignmentMask = VWT->getAlignmentMask(); auto Offset = (sizeof(HeapObject) + AlignmentMask) & ~AlignmentMask; auto StartOfValue = BoxAddress + Offset; return RemoteExistential(RemoteAddress(MetadataAddress), RemoteAddress(StartOfValue)); } /// Given a known-opaque existential, discover if its value is inlined in /// the existential container. llvm::Optional isValueInlinedInExistentialContainer(RemoteAddress ExistentialAddress) { // OpaqueExistentialContainer is the layout of an opaque existential. // `Type` is the pointer to the metadata. TargetOpaqueExistentialContainer Container; if (!Reader->readBytes(RemoteAddress(ExistentialAddress), (uint8_t *)&Container, sizeof(Container))) return None; auto MetadataAddress = static_cast(Container.Type); auto Metadata = readMetadata(MetadataAddress); if (!Metadata) return None; auto VWT = readValueWitnessTable(MetadataAddress); if (!VWT) return None; return VWT->isValueInline(); } /// Read a protocol from a reference to said protocol. template typename Resolver::Result readProtocol( const TargetProtocolDescriptorRef &ProtocolAddress, Demangler &dem, Resolver resolver) { #if SWIFT_OBJC_INTEROP // Check whether we have an Objective-C protocol. if (ProtocolAddress.isObjC()) { auto Name = readObjCProtocolName(ProtocolAddress.getObjCProtocol()); StringRef NameStr(Name); // If this is a Swift-defined protocol, demangle it. if (NameStr.startswith("_TtP")) { auto Demangled = dem.demangleSymbol(NameStr); if (!Demangled) return resolver.failure(); // FIXME: This appears in _swift_buildDemanglingForMetadata(). while (Demangled->getKind() == Node::Kind::Global || Demangled->getKind() == Node::Kind::TypeMangling || Demangled->getKind() == Node::Kind::Type || Demangled->getKind() == Node::Kind::ProtocolList || Demangled->getKind() == Node::Kind::TypeList || Demangled->getKind() == Node::Kind::Type) { if (Demangled->getNumChildren() != 1) return resolver.failure(); Demangled = Demangled->getFirstChild(); } return resolver.swiftProtocol(Demangled); } // Otherwise, this is an imported protocol. return resolver.objcProtocol(NameStr); } #endif // Swift-native protocol. auto Demangled = readDemanglingForContextDescriptor( stripSignedPointer({ProtocolAddress.getSwiftProtocol()}), dem); if (!Demangled) return resolver.failure(); return resolver.swiftProtocol(Demangled); } /// Given a remote pointer to metadata, attempt to turn it into a type. BuiltType readTypeFromMetadata(StoredPointer MetadataAddress, bool skipArtificialSubclasses = false) { auto Cached = TypeCache.find(MetadataAddress); if (Cached != TypeCache.end()) return Cached->second; // If we see garbage data in the process of building a BuiltType, and get // the same metadata address again, we will hit an infinite loop. // Insert a negative result into the cache now so that, if we recur with // the same address, we will return the negative result with the check // just above. TypeCache.insert({MetadataAddress, BuiltType()}); auto Meta = readMetadata(MetadataAddress); if (!Meta) return BuiltType(); switch (Meta->getKind()) { case MetadataKind::Class: return readNominalTypeFromClassMetadata(Meta, skipArtificialSubclasses); case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: return readNominalTypeFromMetadata(Meta); case MetadataKind::Tuple: { auto tupleMeta = cast>(Meta); std::vector elementTypes; elementTypes.reserve(tupleMeta->NumElements); for (unsigned i = 0, n = tupleMeta->NumElements; i != n; ++i) { auto &element = tupleMeta->getElement(i); if (auto elementType = readTypeFromMetadata(element.Type)) elementTypes.push_back(elementType); else return BuiltType(); } // Read the labels string. std::string labels; if (tupleMeta->Labels && !Reader->readString(RemoteAddress(tupleMeta->Labels), labels)) return BuiltType(); auto BuiltTuple = Builder.createTupleType(elementTypes, std::move(labels)); TypeCache[MetadataAddress] = BuiltTuple; return BuiltTuple; } case MetadataKind::Function: { auto Function = cast>(Meta); std::vector> Parameters; for (unsigned i = 0, n = Function->getNumParameters(); i != n; ++i) { auto ParamTypeRef = readTypeFromMetadata(Function->getParameter(i)); if (!ParamTypeRef) return BuiltType(); FunctionParam Param; Param.setType(ParamTypeRef); Param.setFlags(Function->getParameterFlags(i)); Parameters.push_back(std::move(Param)); } auto Result = readTypeFromMetadata(Function->ResultType); if (!Result) return BuiltType(); auto flags = FunctionTypeFlags() .withConvention(Function->getConvention()) .withAsync(Function->isAsync()) .withThrows(Function->isThrowing()) .withParameterFlags(Function->hasParameterFlags()) .withEscaping(Function->isEscaping()) .withDifferentiable(Function->isDifferentiable()); BuiltType globalActor = BuiltType(); if (Function->hasGlobalActor()) { globalActor = readTypeFromMetadata(Function->getGlobalActor()); if (globalActor) flags = flags.withGlobalActor(true); } FunctionMetadataDifferentiabilityKind diffKind; switch (Function->getDifferentiabilityKind().Value) { #define CASE(X) \ case TargetFunctionMetadataDifferentiabilityKind< \ typename Runtime::StoredSize>::X: \ diffKind = FunctionMetadataDifferentiabilityKind::X; \ break; CASE(NonDifferentiable) CASE(Forward) CASE(Reverse) CASE(Normal) CASE(Linear) #undef CASE } auto BuiltFunction = Builder.createFunctionType( Parameters, Result, flags, diffKind, globalActor); TypeCache[MetadataAddress] = BuiltFunction; return BuiltFunction; } case MetadataKind::Existential: { auto Exist = cast>(Meta); bool HasExplicitAnyObject = false; if (Exist->isClassBounded()) HasExplicitAnyObject = true; BuiltType SuperclassType = BuiltType(); if (Exist->Flags.hasSuperclassConstraint()) { // The superclass is stored after the list of protocols. SuperclassType = readTypeFromMetadata(Exist->getSuperclassConstraint()); if (!SuperclassType) return BuiltType(); HasExplicitAnyObject = true; } /// Resolver to turn a protocol reference into a protocol declaration. struct ProtocolResolver { using Result = BuiltProtocolDecl; BuilderType &builder; BuiltProtocolDecl failure() const { return BuiltProtocolDecl(); } BuiltProtocolDecl swiftProtocol(Demangle::Node *node) { return builder.createProtocolDecl(node); } #if SWIFT_OBJC_INTEROP BuiltProtocolDecl objcProtocol(StringRef name) { return builder.createObjCProtocolDecl(name.str()); } #endif } resolver{Builder}; Demangler dem; std::vector Protocols; for (auto ProtocolAddress : Exist->getProtocols()) { if (auto Protocol = readProtocol(ProtocolAddress, dem, resolver)) Protocols.push_back(Protocol); else return BuiltType(); } auto BuiltExist = Builder.createProtocolCompositionType( Protocols, SuperclassType, HasExplicitAnyObject); TypeCache[MetadataAddress] = BuiltExist; return BuiltExist; } case MetadataKind::Metatype: { auto Metatype = cast>(Meta); auto Instance = readTypeFromMetadata(Metatype->InstanceType); if (!Instance) return BuiltType(); auto BuiltMetatype = Builder.createMetatypeType(Instance); TypeCache[MetadataAddress] = BuiltMetatype; return BuiltMetatype; } case MetadataKind::ObjCClassWrapper: { auto objcWrapper = cast>(Meta); auto classAddress = objcWrapper->Class; std::string className; if (!readObjCClassName(classAddress, className)) return BuiltType(); auto BuiltObjCClass = Builder.createObjCClassType(std::move(className)); TypeCache[MetadataAddress] = BuiltObjCClass; return BuiltObjCClass; } case MetadataKind::ExistentialMetatype: { auto Exist = cast>(Meta); auto Instance = readTypeFromMetadata(Exist->InstanceType); if (!Instance) return BuiltType(); auto BuiltExist = Builder.createExistentialMetatypeType(Instance); TypeCache[MetadataAddress] = BuiltExist; return BuiltExist; } case MetadataKind::ForeignClass: { auto descriptorAddr = readAddressOfNominalTypeDescriptor(Meta); if (!descriptorAddr) return BuiltType(); auto descriptor = readContextDescriptor(descriptorAddr); if (!descriptor) return BuiltType(); // Build the demangling tree from the context tree. Demangler dem; auto node = buildContextMangling(descriptor, dem); if (!node || node->getKind() != Node::Kind::Type) return BuiltType(); auto mangling = Demangle::mangleNode(node); if (!mangling.isSuccess()) return BuiltType(); auto name = mangling.result(); auto BuiltForeign = Builder.createForeignClassType(std::move(name)); TypeCache[MetadataAddress] = BuiltForeign; return BuiltForeign; } case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: // Treat these all as Builtin.NativeObject for type lowering purposes. return Builder.createBuiltinType("Builtin.NativeObject", "Bo"); case MetadataKind::Opaque: default: { auto BuiltOpaque = Builder.getOpaqueType(); TypeCache[MetadataAddress] = BuiltOpaque; return BuiltOpaque; } } swift_unreachable("Unhandled MetadataKind in switch"); } TypeLookupErrorOr readTypeFromMangledName(const char *MangledTypeName, size_t Length) { Demangle::Demangler Dem; Demangle::NodePointer Demangled = Dem.demangleSymbol(StringRef(MangledTypeName, Length)); return decodeMangledType(Demangled); } /// Given the address of a context descriptor, attempt to read it, or /// represent it symbolically. ParentContextDescriptorRef readContextDescriptor(const RemoteAbsolutePointer &address) { // Map an unresolved pointer to an unresolved context ref. if (!address.isResolved()) { // We can only handle references to a symbol without an offset currently. if (address.getOffset() != 0) { return ParentContextDescriptorRef(); } return ParentContextDescriptorRef(address.getSymbol()); } return ParentContextDescriptorRef( readContextDescriptor(address.getResolvedAddress().getAddressData())); } /// Given the address of a context descriptor, attempt to read it. ContextDescriptorRef readContextDescriptor(StoredPointer address) { if (address == 0) return nullptr; auto cached = ContextDescriptorCache.find(address); if (cached != ContextDescriptorCache.end()) return ContextDescriptorRef( address, reinterpret_cast *>( cached->second.get())); // Read the flags to figure out how much space we should read. ContextDescriptorFlags flags; if (!Reader->readBytes(RemoteAddress(address), (uint8_t*)&flags, sizeof(flags))) return nullptr; TypeContextDescriptorFlags typeFlags(flags.getKindSpecificFlags()); uint64_t baseSize = 0; uint64_t genericHeaderSize = sizeof(GenericContextDescriptorHeader); uint64_t metadataInitSize = 0; bool hasVTable = false; auto readMetadataInitSize = [&]() -> unsigned { switch (typeFlags.getMetadataInitialization()) { case TypeContextDescriptorFlags::NoMetadataInitialization: return 0; case TypeContextDescriptorFlags::SingletonMetadataInitialization: // FIXME: classes return sizeof(TargetSingletonMetadataInitialization); case TypeContextDescriptorFlags::ForeignMetadataInitialization: return sizeof(TargetForeignMetadataInitialization); } return 0; }; switch (auto kind = flags.getKind()) { case ContextDescriptorKind::Module: baseSize = sizeof(TargetModuleContextDescriptor); break; // TODO: Should we include trailing generic arguments in this load? case ContextDescriptorKind::Extension: baseSize = sizeof(TargetExtensionContextDescriptor); break; case ContextDescriptorKind::Anonymous: baseSize = sizeof(TargetAnonymousContextDescriptor); if (AnonymousContextDescriptorFlags(flags.getKindSpecificFlags()) .hasMangledName()) { metadataInitSize = sizeof(TargetMangledContextName); } break; case ContextDescriptorKind::Class: baseSize = sizeof(TargetClassDescriptor); genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); hasVTable = typeFlags.class_hasVTable(); metadataInitSize = readMetadataInitSize(); break; case ContextDescriptorKind::Enum: baseSize = sizeof(TargetEnumDescriptor); genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); metadataInitSize = readMetadataInitSize(); break; case ContextDescriptorKind::Struct: baseSize = sizeof(TargetStructDescriptor); genericHeaderSize = sizeof(TypeGenericContextDescriptorHeader); metadataInitSize = readMetadataInitSize(); break; case ContextDescriptorKind::Protocol: baseSize = sizeof(TargetProtocolDescriptor); break; case ContextDescriptorKind::OpaqueType: baseSize = sizeof(TargetOpaqueTypeDescriptor); metadataInitSize = sizeof(typename Runtime::template RelativeDirectPointer) * flags.getKindSpecificFlags(); break; default: // We don't know about this kind of context. return nullptr; } // Determine the full size of the descriptor. This is reimplementing a fair // bit of TrailingObjects but for out-of-process; maybe there's a way to // factor the layout stuff out... uint64_t genericsSize = 0; if (flags.isGeneric()) { GenericContextDescriptorHeader header; auto headerAddr = address + baseSize + genericHeaderSize - sizeof(header); if (!Reader->readBytes(RemoteAddress(headerAddr), (uint8_t*)&header, sizeof(header))) return nullptr; genericsSize = genericHeaderSize + (header.NumParams + 3u & ~3u) + header.NumRequirements * sizeof(TargetGenericRequirementDescriptor); } uint64_t vtableSize = 0; if (hasVTable) { TargetVTableDescriptorHeader header; auto headerAddr = address + baseSize + genericsSize + metadataInitSize; if (!Reader->readBytes(RemoteAddress(headerAddr), (uint8_t*)&header, sizeof(header))) return nullptr; vtableSize = sizeof(header) + header.VTableSize * sizeof(TargetMethodDescriptor); } uint64_t size = baseSize + genericsSize + metadataInitSize + vtableSize; if (size > MaxMetadataSize) return nullptr; auto readResult = Reader->readBytes(RemoteAddress(address), size); if (!readResult) return nullptr; auto descriptor = reinterpret_cast *>( readResult.get()); ContextDescriptorCache.insert( std::make_pair(address, std::move(readResult))); return ContextDescriptorRef(address, descriptor); } /// Demangle the entity represented by a symbolic reference to a given symbol name. Demangle::NodePointer buildContextManglingForSymbol(StringRef symbol, Demangler &dem) { auto demangledSymbol = dem.demangleSymbol(symbol); if (demangledSymbol->getKind() == Demangle::Node::Kind::Global) { demangledSymbol = demangledSymbol->getChild(0); } switch (demangledSymbol->getKind()) { // Pointers to nominal type or protocol descriptors would demangle to // the type they represent. case Demangle::Node::Kind::NominalTypeDescriptor: case Demangle::Node::Kind::ProtocolDescriptor: demangledSymbol = demangledSymbol->getChild(0); assert(demangledSymbol->getKind() == Demangle::Node::Kind::Type); break; // Pointers to opaque type descriptors demangle to the name of the opaque // type declaration. case Demangle::Node::Kind::OpaqueTypeDescriptor: demangledSymbol = demangledSymbol->getChild(0); break; // We don't handle pointers to other symbols yet. default: return nullptr; } return demangledSymbol; } /// Given a read context descriptor, attempt to build a demangling tree /// for it. Demangle::NodePointer buildContextMangling(const ParentContextDescriptorRef &descriptor, Demangler &dem) { if (descriptor.isResolved()) { return buildContextMangling(descriptor.getResolved(), dem); } // Try to demangle the symbol name to figure out what context it would // point to. return buildContextManglingForSymbol(descriptor.getSymbol(), dem); } /// Given a read context descriptor, attempt to build a demangling tree /// for it. Demangle::NodePointer buildContextMangling(ContextDescriptorRef descriptor, Demangler &dem) { auto demangling = buildContextDescriptorMangling(descriptor, dem, 50); if (!demangling) return nullptr; Demangle::NodePointer top; // References to type nodes behave as types in the mangling. if (isa>(descriptor.getLocalBuffer()) || isa>(descriptor.getLocalBuffer())) { top = dem.createNode(Node::Kind::Type); top->addChild(demangling, dem); } else { top = demangling; } return top; } /// Read a context descriptor from the given address and build a mangling /// tree representing it. Demangle::NodePointer readDemanglingForContextDescriptor(StoredPointer contextAddress, Demangler &Dem) { auto context = readContextDescriptor(contextAddress); if (!context) return nullptr; return buildContextMangling(context, Dem); } /// Read the mangled underlying type from an opaque type descriptor. Demangle::NodePointer readUnderlyingTypeManglingForOpaqueTypeDescriptor(StoredPointer contextAddr, unsigned ordinal, Demangler &Dem) { auto context = readContextDescriptor(contextAddr); if (!context) return nullptr; if (context->getKind() != ContextDescriptorKind::OpaqueType) return nullptr; auto opaqueType = reinterpret_cast *>( context.getLocalBuffer()); if (ordinal >= opaqueType->getNumUnderlyingTypeArguments()) return nullptr; auto nameAddr = resolveRelativeField(context, opaqueType->getUnderlyingTypeArgumentMangledName(ordinal)); return readMangledName(RemoteAddress(nameAddr), MangledNameKind::Type, Dem); } TypeLookupErrorOr readUnderlyingTypeForOpaqueTypeDescriptor(StoredPointer contextAddr, unsigned ordinal) { Demangle::Demangler Dem; auto node = readUnderlyingTypeManglingForOpaqueTypeDescriptor(contextAddr, ordinal, Dem); if (!node) return TypeLookupError("Failed to read type mangling for descriptor."); return decodeMangledType(node); } bool isTaggedPointer(StoredPointer objectAddress) { if (getTaggedPointerEncoding() != TaggedPointerEncodingKind::Extended) return false; return (objectAddress ^ TaggedPointerObfuscator) & TaggedPointerMask; } /// Read the isa pointer of an Object-C tagged pointer value. llvm::Optional readMetadataFromTaggedPointer(StoredPointer objectAddress) { auto readArrayElement = [&](StoredPointer base, StoredPointer tag) -> llvm::Optional { StoredPointer addr = base + tag * sizeof(StoredPointer); StoredPointer isa; if (!Reader->readInteger(RemoteAddress(addr), &isa)) return None; return isa; }; // Extended pointers have a tag of 0b111, using 8 additional bits // to specify the class. if (TaggedPointerExtendedMask != 0 && (((objectAddress ^ TaggedPointerObfuscator) & TaggedPointerExtendedMask) == TaggedPointerExtendedMask)) { auto tag = ((objectAddress >> TaggedPointerExtendedSlotShift) & TaggedPointerExtendedSlotMask); return readArrayElement(TaggedPointerExtendedClasses, tag); } // Basic tagged pointers use a 3 bit tag to specify the class. auto tag = ((objectAddress >> TaggedPointerSlotShift) & TaggedPointerSlotMask); return readArrayElement(TaggedPointerClasses, tag); } /// Read the isa pointer of a class or closure context instance and apply /// the isa mask. llvm::Optional readMetadataFromInstance(StoredPointer objectAddress) { if (isTaggedPointer(objectAddress)) return readMetadataFromTaggedPointer(objectAddress); StoredPointer isa; if (!Reader->readInteger(RemoteAddress(objectAddress), &isa)) return None; switch (getIsaEncoding()) { case IsaEncodingKind::Unknown: case IsaEncodingKind::Error: return None; case IsaEncodingKind::None: return isa; case IsaEncodingKind::Masked: return isa & IsaMask; case IsaEncodingKind::Indexed: { // If applying the magic mask doesn't give us the magic value, // it's not an indexed isa. if ((isa & IsaMagicMask) != IsaMagicValue) return isa; // Extract the index. auto classIndex = (isa & IsaIndexMask) >> IsaIndexShift; // 0 is never a valid index. if (classIndex == 0) { return None; // If the index is out of range, it's an error; but check for an // update first. (This will also trigger the first time because // we initialize LastIndexedClassesCount to 0). } else if (classIndex >= LastIndexedClassesCount) { StoredPointer count; if (!Reader->readInteger(RemoteAddress(IndexedClassesCountPointer), &count)) { return None; } LastIndexedClassesCount = count; if (classIndex >= count) { return None; } } // Find the address of the appropriate array element. RemoteAddress eltPointer = RemoteAddress(IndexedClassesPointer + classIndex * sizeof(StoredPointer)); StoredPointer metadataPointer; if (!Reader->readInteger(eltPointer, &metadataPointer)) { return None; } return metadataPointer; } } swift_unreachable("Unhandled IsaEncodingKind in switch."); } /// Read the offset of the generic parameters of a class from the nominal /// type descriptor. If the class has a resilient superclass, we also /// have to read the superclass size and add that to the offset. /// /// The offset is in units of words, from the start of the class's /// metadata. llvm::Optional readGenericArgsOffset(MetadataRef metadata, ContextDescriptorRef descriptor) { switch (descriptor->getKind()) { case ContextDescriptorKind::Class: { auto type = cast>(descriptor); if (!type->hasResilientSuperclass()) return type->getNonResilientGenericArgumentOffset(); auto bounds = readMetadataBoundsOfSuperclass(descriptor); if (!bounds) return None; bounds->adjustForSubclass(type->areImmediateMembersNegative(), type->NumImmediateMembers); return bounds->ImmediateMembersOffset / sizeof(StoredPointer); } case ContextDescriptorKind::Enum: { auto type = cast>(descriptor); return type->getGenericArgumentOffset(); } case ContextDescriptorKind::Struct: { auto type = cast>(descriptor); return type->getGenericArgumentOffset(); } default: return None; } } using ClassMetadataBounds = TargetClassMetadataBounds; // This follows computeMetadataBoundsForSuperclass. llvm::Optional readMetadataBoundsOfSuperclass(ContextDescriptorRef subclassRef) { auto subclass = cast>(subclassRef); if (!subclass->hasResilientSuperclass()) return ClassMetadataBounds::forSwiftRootClass(); auto rawSuperclass = resolveRelativeField(subclassRef, subclass->getResilientSuperclass()); if (!rawSuperclass) { return ClassMetadataBounds::forSwiftRootClass(); } return forTypeReference( subclass->getResilientSuperclassReferenceKind(), rawSuperclass, [&](ContextDescriptorRef superclass) -> llvm::Optional { if (!isa>(superclass)) return None; return readMetadataBoundsOfSuperclass(superclass); }, [&](MetadataRef metadata) -> llvm::Optional { auto cls = dyn_cast>(metadata); if (!cls) return None; return cls->getClassBoundsAsSwiftSuperclass(); }, [](StoredPointer objcClassName) -> llvm::Optional { // We have no ability to look up an ObjC class by name. // FIXME: add a query for this; clients may have a way to do it. return None; }); } template llvm::Optional forTypeReference(TypeReferenceKind refKind, StoredPointer ref, const DescriptorFn &descriptorFn, const MetadataFn &metadataFn, const ClassNameFn &classNameFn) { switch (refKind) { case TypeReferenceKind::IndirectTypeDescriptor: { StoredPointer descriptorAddress = 0; if (!Reader->readInteger(RemoteAddress(ref), &descriptorAddress)) return None; ref = descriptorAddress; LLVM_FALLTHROUGH; } case TypeReferenceKind::DirectTypeDescriptor: { auto descriptor = readContextDescriptor(ref); if (!descriptor) return None; return descriptorFn(descriptor); } case TypeReferenceKind::DirectObjCClassName: return classNameFn(ref); case TypeReferenceKind::IndirectObjCClass: { StoredPointer classRef = 0; if (!Reader->readInteger(RemoteAddress(ref), &classRef)) return None; auto metadata = readMetadata(classRef); if (!metadata) return None; return metadataFn(metadata); } } return None; } /// Read a single generic type argument from a bound generic type /// metadata. llvm::Optional readGenericArgFromMetadata(StoredPointer metadata, unsigned index) { auto Meta = readMetadata(metadata); if (!Meta) return None; auto descriptorAddress = readAddressOfNominalTypeDescriptor(Meta); if (!descriptorAddress) return None; // Read the nominal type descriptor. auto descriptor = readContextDescriptor(descriptorAddress); if (!descriptor) return None; auto generics = descriptor->getGenericContext(); if (!generics) return None; auto offsetToGenericArgs = readGenericArgsOffset(Meta, descriptor); if (!offsetToGenericArgs) return None; auto addressOfGenericArgAddress = (getAddress(Meta) + *offsetToGenericArgs * sizeof(StoredPointer) + index * sizeof(StoredPointer)); if (index >= generics->getGenericContextHeader().getNumArguments()) return None; StoredPointer genericArgAddress; if (!Reader->readInteger(RemoteAddress(addressOfGenericArgAddress), &genericArgAddress)) return None; return genericArgAddress; } /// Given the address of a nominal type descriptor, attempt to resolve /// its nominal type declaration. BuiltTypeDecl readNominalTypeFromDescriptor(StoredPointer address) { auto descriptor = readContextDescriptor(address); if (!descriptor) return BuiltTypeDecl(); return buildNominalTypeDecl(descriptor); } /// Try to read the offset of a tuple element from a tuple metadata. bool readTupleElementOffset(StoredPointer metadataAddress, unsigned eltIndex, StoredSize *offset) { // Read the metadata. auto metadata = readMetadata(metadataAddress); if (!metadata) return false; // Ensure that the metadata actually is tuple metadata. auto tupleMetadata = dyn_cast>(metadata); if (!tupleMetadata) return false; // Ensure that the element is in-bounds. if (eltIndex >= tupleMetadata->NumElements) return false; // Read the offset. const auto &element = tupleMetadata->getElement(eltIndex); *offset = element.Offset; return true; } /// Given a remote pointer to class metadata, attempt to read its superclass. llvm::Optional readOffsetToFirstCaptureFromMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) return None; auto heapMeta = cast>(meta); return heapMeta->OffsetToFirstCapture; } llvm::Optional readPointer(StoredPointer address) { return Reader->readPointer(RemoteAddress(address), sizeof(StoredPointer)); } llvm::Optional readResolvedPointerValue(StoredPointer address) { if (auto pointer = readPointer(address)) { if (!pointer->isResolved()) return None; return (StoredPointer)pointer->getResolvedAddress().getAddressData(); } return None; } template RemoteAbsolutePointer resolvePointerField(RemoteRef base, const U &field) { auto pointerRef = base.getField(field); return Reader->resolvePointer(RemoteAddress(getAddress(pointerRef)), *pointerRef.getLocalBuffer()); } /// Given a remote pointer to class metadata, attempt to read its superclass. llvm::Optional readCaptureDescriptorFromMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) return None; auto heapMeta = cast>(meta); return resolvePointerField(meta, heapMeta->CaptureDescription); } protected: template StoredPointer getAddress(RemoteRef base) { return (StoredPointer)base.getAddressData(); } template StoredPointer resolveRelativeField( RemoteRef base, const Field &field) { return (StoredPointer)base.resolveRelativeFieldData(field); } template llvm::Optional resolveRelativeIndirectableField(RemoteRef base, const Field &field) { auto fieldRef = base.getField(field); int32_t offset; memcpy(&offset, fieldRef.getLocalBuffer(), sizeof(int32_t)); if (offset == 0) return llvm::Optional(nullptr); bool indirect = offset & 1; offset &= ~1u; using SignedPointer = typename std::make_signed::type; StoredPointer resultAddress = getAddress(fieldRef) + (SignedPointer)offset; // Low bit set in the offset indicates that the offset leads to the absolute // address in memory. if (indirect) { if (auto ptr = readPointer(resultAddress)) { return stripSignedPointer(*ptr); } return None; } return RemoteAbsolutePointer("", resultAddress); } /// Given a pointer to an Objective-C class, try to read its class name. bool readObjCClassName(StoredPointer classAddress, std::string &className) { // The following algorithm only works on the non-fragile Apple runtime. // Grab the RO-data pointer. This part is not ABI. StoredPointer roDataPtr = readObjCRODataPtr(classAddress); if (!roDataPtr) return false; // This is ABI. static constexpr auto OffsetToName = roundUpToAlignment(size_t(12), sizeof(StoredPointer)) + sizeof(StoredPointer); // Read the name pointer. StoredPointer namePtr; if (!Reader->readInteger(RemoteAddress(roDataPtr + OffsetToName), &namePtr)) return false; // If the name pointer is null, treat that as an error. if (!namePtr) return false; return Reader->readString(RemoteAddress(namePtr), className); } MetadataRef readMetadata(StoredPointer address) { auto cached = MetadataCache.find(address); if (cached != MetadataCache.end()) return MetadataRef(address, reinterpret_cast *>( cached->second.get())); StoredPointer KindValue = 0; if (!Reader->readInteger(RemoteAddress(address), &KindValue)) return nullptr; switch (getEnumeratedMetadataKind(KindValue)) { case MetadataKind::Class: return _readMetadata(address); case MetadataKind::Enum: return _readMetadata(address); case MetadataKind::ErrorObject: return _readMetadata(address); case MetadataKind::Existential: { StoredPointer flagsAddress = address + sizeof(StoredPointer); ExistentialTypeFlags::int_type flagsData; if (!Reader->readInteger(RemoteAddress(flagsAddress), &flagsData)) return nullptr; ExistentialTypeFlags flags(flagsData); StoredPointer numProtocolsAddress = flagsAddress + sizeof(flagsData); uint32_t numProtocols; if (!Reader->readInteger(RemoteAddress(numProtocolsAddress), &numProtocols)) return nullptr; // Make sure the number of protocols is reasonable if (numProtocols >= 256) return nullptr; auto totalSize = sizeof(TargetExistentialTypeMetadata) + numProtocols * sizeof(ConstTargetMetadataPointer); if (flags.hasSuperclassConstraint()) totalSize += sizeof(StoredPointer); return _readMetadata(address, totalSize); } case MetadataKind::ExistentialMetatype: return _readMetadata(address); case MetadataKind::ForeignClass: return _readMetadata(address); case MetadataKind::Function: { StoredSize flagsValue; auto flagsAddr = address + TargetFunctionTypeMetadata::OffsetToFlags; if (!Reader->readInteger(RemoteAddress(flagsAddr), &flagsValue)) return nullptr; auto flags = TargetFunctionTypeFlags::fromIntValue(flagsValue); auto totalSize = sizeof(TargetFunctionTypeMetadata) + flags.getNumParameters() * sizeof(FunctionTypeMetadata::Parameter); if (flags.hasParameterFlags()) totalSize += flags.getNumParameters() * sizeof(uint32_t); if (flags.isDifferentiable()) totalSize = roundUpToAlignment(totalSize, sizeof(void *)) + sizeof(TargetFunctionMetadataDifferentiabilityKind< typename Runtime::StoredSize>); return _readMetadata(address, roundUpToAlignment(totalSize, sizeof(void *))); } case MetadataKind::HeapGenericLocalVariable: return _readMetadata(address); case MetadataKind::HeapLocalVariable: return _readMetadata(address); case MetadataKind::Metatype: return _readMetadata(address); case MetadataKind::ObjCClassWrapper: return _readMetadata(address); case MetadataKind::Optional: return _readMetadata(address); case MetadataKind::Struct: return _readMetadata(address); case MetadataKind::Tuple: { auto numElementsAddress = address + TargetTupleTypeMetadata::getOffsetToNumElements(); StoredSize numElements; if (!Reader->readInteger(RemoteAddress(numElementsAddress), &numElements)) return nullptr; auto totalSize = sizeof(TargetTupleTypeMetadata) + numElements * sizeof(TupleTypeMetadata::Element); // Make sure the number of elements is reasonable if (numElements >= 256) return nullptr; return _readMetadata(address, totalSize); } case MetadataKind::Opaque: default: return _readMetadata(address); } // We can fall out here if the value wasn't actually a valid // MetadataKind. return nullptr; } StoredPointer readAddressOfNominalTypeDescriptor(MetadataRef &metadata, bool skipArtificialSubclasses = false) { switch (metadata->getKind()) { case MetadataKind::Class: { auto classMeta = cast>(metadata); while (true) { if (!classMeta->isTypeMetadata()) return 0; StoredSignedPointer descriptorAddressSigned = classMeta->getDescriptionAsSignedPointer(); StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); // If this class has a null descriptor, it's artificial, // and we need to skip it upon request. Otherwise, we're done. if (descriptorAddress || !skipArtificialSubclasses) return static_cast(descriptorAddress); auto superclassMetadataAddress = stripSignedPointer(classMeta->Superclass); if (!superclassMetadataAddress) return 0; auto superMeta = readMetadata(superclassMetadataAddress); if (!superMeta) return 0; auto superclassMeta = dyn_cast>(superMeta); if (!superclassMeta) return 0; classMeta = superclassMeta; metadata = superMeta; } } case MetadataKind::Struct: case MetadataKind::Optional: case MetadataKind::Enum: { auto valueMeta = cast>(metadata); StoredSignedPointer descriptorAddressSigned = valueMeta->getDescriptionAsSignedPointer(); StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); return descriptorAddress; } case MetadataKind::ForeignClass: { auto foreignMeta = cast>(metadata); StoredSignedPointer descriptorAddressSigned = foreignMeta->getDescriptionAsSignedPointer(); StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned); return descriptorAddress; } default: return 0; } } private: template