| //===--- 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/Basic/LLVM.h" |
| #include "swift/Runtime/Unreachable.h" |
| |
| #include <vector> |
| #include <unordered_map> |
| |
| namespace swift { |
| namespace remote { |
| |
| /// A utility class for constructing abstract types from |
| /// a textual mangling. |
| template <typename BuilderType> |
| class TypeDecoder { |
| using BuiltType = typename BuilderType::BuiltType; |
| using BuiltNominalTypeDecl = typename BuilderType::BuiltNominalTypeDecl; |
| using NodeKind = Demangle::Node::Kind; |
| |
| BuilderType &Builder; |
| |
| public: |
| explicit TypeDecoder(BuilderType &Builder) |
| : Builder(Builder) {} |
| |
| /// Given a demangle tree, attempt to turn it into a type. |
| BuiltType decodeMangledType(const Demangle::NodePointer &Node) { |
| if (!Node) return BuiltType(); |
| |
| using NodeKind = Demangle::Node::Kind; |
| switch (Node->getKind()) { |
| case NodeKind::Global: |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::TypeMangling: |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::Type: |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::Class: |
| case NodeKind::Enum: |
| case NodeKind::Structure: { |
| BuiltNominalTypeDecl typeDecl = BuiltNominalTypeDecl(); |
| BuiltType parent = BuiltType(); |
| if (!decodeMangledNominalType(Node, typeDecl, parent)) |
| return BuiltType(); |
| |
| return Builder.createNominalType(typeDecl, parent); |
| } |
| case NodeKind::BoundGenericClass: |
| case NodeKind::BoundGenericEnum: |
| case NodeKind::BoundGenericStructure: { |
| assert(Node->getNumChildren() == 2); |
| BuiltNominalTypeDecl typeDecl = BuiltNominalTypeDecl(); |
| BuiltType parent = BuiltType(); |
| if (!decodeMangledNominalType(Node->getChild(0), typeDecl, parent)) |
| return BuiltType(); |
| |
| std::vector<BuiltType> args; |
| |
| const auto &genericArgs = Node->getChild(1); |
| assert(genericArgs->getKind() == NodeKind::TypeList); |
| |
| for (auto genericArg : *genericArgs) { |
| auto paramType = decodeMangledType(genericArg); |
| if (!paramType) |
| return BuiltType(); |
| args.push_back(paramType); |
| } |
| |
| return Builder.createBoundGenericType(typeDecl, args, parent); |
| } |
| case NodeKind::BuiltinTypeName: { |
| auto mangledName = Demangle::mangleNode(Node); |
| return Builder.createBuiltinType(mangledName); |
| } |
| case NodeKind::Metatype: |
| case NodeKind::ExistentialMetatype: { |
| unsigned i = 0; |
| bool wasAbstract = false; |
| |
| // Handle lowered metatypes in a hackish way. If the representation |
| // was not thin, force the resulting typeref to have a non-empty |
| // representation. |
| if (Node->getNumChildren() == 2) { |
| auto repr = Node->getChild(i++); |
| if (repr->getKind() != NodeKind::MetatypeRepresentation || |
| !repr->hasText()) |
| return BuiltType(); |
| if (repr->getText() != "@thin") |
| wasAbstract = true; |
| } |
| auto instance = decodeMangledType(Node->getChild(i)); |
| if (!instance) |
| return BuiltType(); |
| if (Node->getKind() == NodeKind::Metatype) { |
| return Builder.createMetatypeType(instance, wasAbstract); |
| } else if (Node->getKind() == NodeKind::ExistentialMetatype) { |
| // FIXME: Ignore representation of existential metatype |
| // completely for now |
| return Builder.createExistentialMetatypeType(instance); |
| } else { |
| assert(false); |
| return nullptr; |
| } |
| } |
| case NodeKind::ProtocolList: { |
| std::vector<BuiltType> protocols; |
| auto TypeList = Node->getChild(0); |
| for (auto componentType : *TypeList) { |
| if (auto protocol = decodeMangledType(componentType)) |
| protocols.push_back(protocol); |
| else |
| return BuiltType(); |
| } |
| if (protocols.size() == 1) |
| return protocols.front(); |
| return Builder.createProtocolCompositionType( |
| protocols, |
| /*hasExplicitAnyObject=*/false); |
| } |
| case NodeKind::ProtocolListWithAnyObject: { |
| std::vector<BuiltType> protocols; |
| auto ProtocolList = Node->getChild(0); |
| auto TypeList = ProtocolList->getChild(0); |
| for (auto componentType : *TypeList) { |
| if (auto protocol = decodeMangledType(componentType)) |
| protocols.push_back(protocol); |
| else |
| return BuiltType(); |
| } |
| return Builder.createProtocolCompositionType( |
| protocols, |
| /*hasExplicitAnyObject=*/true); |
| } |
| case NodeKind::ProtocolListWithClass: { |
| std::vector<BuiltType> members; |
| auto ProtocolList = Node->getChild(0); |
| auto TypeList = ProtocolList->getChild(0); |
| for (auto componentType : *TypeList) { |
| if (auto protocol = decodeMangledType(componentType)) |
| members.push_back(protocol); |
| else |
| return BuiltType(); |
| } |
| |
| auto SuperclassNode = Node->getChild(1); |
| if (auto superclass = decodeMangledType(SuperclassNode)) |
| members.push_back(superclass); |
| |
| return Builder.createProtocolCompositionType( |
| members, |
| /*hasExplicitAnyObject=*/true); |
| } |
| case NodeKind::Protocol: { |
| auto moduleName = Node->getChild(0)->getText(); |
| auto nameNode = Node->getChild(1); |
| std::string privateDiscriminator, name; |
| if (nameNode->getKind() == NodeKind::PrivateDeclName) { |
| privateDiscriminator = nameNode->getChild(0)->getText(); |
| name = nameNode->getChild(1)->getText(); |
| } else if (nameNode->getKind() == NodeKind::Identifier) { |
| name = Node->getChild(1)->getText(); |
| } else { |
| return BuiltType(); |
| } |
| |
| // Consistent handling of protocols and protocol compositions |
| Demangle::Demangler Dem; |
| auto protocolList = Dem.createNode(NodeKind::ProtocolList); |
| auto typeList = Dem.createNode(NodeKind::TypeList); |
| auto type = Dem.createNode(NodeKind::Type); |
| type->addChild(Node, Dem); |
| typeList->addChild(type, Dem); |
| protocolList->addChild(typeList, Dem); |
| |
| auto mangledName = Demangle::mangleNode(protocolList); |
| return Builder.createProtocolType(mangledName, moduleName, |
| privateDiscriminator, name); |
| } |
| case NodeKind::DependentGenericParamType: { |
| auto depth = Node->getChild(0)->getIndex(); |
| auto index = Node->getChild(1)->getIndex(); |
| return Builder.createGenericTypeParameterType(depth, index); |
| } |
| case NodeKind::ObjCBlock: |
| case NodeKind::CFunctionPointer: |
| case NodeKind::ThinFunctionType: |
| case NodeKind::FunctionType: { |
| FunctionTypeFlags flags; |
| if (Node->getKind() == NodeKind::ObjCBlock) { |
| flags = flags.withConvention(FunctionMetadataConvention::Block); |
| } else if (Node->getKind() == NodeKind::CFunctionPointer) { |
| flags = |
| flags.withConvention(FunctionMetadataConvention::CFunctionPointer); |
| } else if (Node->getKind() == NodeKind::ThinFunctionType) { |
| flags = flags.withConvention(FunctionMetadataConvention::Thin); |
| } |
| |
| bool isThrow = |
| Node->getChild(0)->getKind() == NodeKind::ThrowsAnnotation; |
| flags = flags.withThrows(true); |
| |
| std::vector<BuiltType> arguments; |
| std::vector<bool> argsAreInOut; |
| if (!decodeMangledFunctionInputType(Node->getChild(isThrow ? 1 : 0), |
| arguments, argsAreInOut, flags)) |
| return BuiltType(); |
| |
| auto result = decodeMangledType(Node->getChild(isThrow ? 2 : 1)); |
| if (!result) return BuiltType(); |
| return Builder.createFunctionType(arguments, argsAreInOut, |
| result, flags); |
| } |
| case NodeKind::ImplFunctionType: { |
| // Minimal support for lowered function types. These come up in |
| // reflection as capture types. For the reflection library's |
| // purposes, the only part that matters is the convention. |
| FunctionTypeFlags flags; |
| |
| for (unsigned i = 0; i < Node->getNumChildren(); i++) { |
| auto child = Node->getChild(i); |
| |
| if (child->getKind() == NodeKind::ImplConvention) { |
| if (!child->hasText()) |
| return BuiltType(); |
| |
| if (child->getText() == "@convention(thin)") { |
| flags = |
| flags.withConvention(FunctionMetadataConvention::Thin); |
| } |
| } else if (child->getKind() == NodeKind::ImplFunctionAttribute) { |
| if (!child->hasText()) |
| return BuiltType(); |
| |
| StringRef text = child->getText(); |
| if (text == "@convention(c)") { |
| flags = |
| flags.withConvention(FunctionMetadataConvention::CFunctionPointer); |
| } else if (text == "@convention(block)") { |
| flags = |
| flags.withConvention(FunctionMetadataConvention::Block); |
| } |
| } |
| } |
| |
| // Completely punt on argument types and results. |
| std::vector<BuiltType> arguments; |
| std::vector<bool> argsAreInOut; |
| |
| std::vector<BuiltType> elements; |
| std::string labels; |
| auto result = Builder.createTupleType(elements, std::move(labels), false); |
| |
| return Builder.createFunctionType(arguments, argsAreInOut, |
| result, flags); |
| } |
| case NodeKind::ArgumentTuple: |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::ReturnType: |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::Tuple: { |
| std::vector<BuiltType> elements; |
| std::string labels; |
| bool variadic = false; |
| for (auto &element : *Node) { |
| if (element->getKind() != NodeKind::TupleElement) |
| return BuiltType(); |
| |
| // If the tuple element is labeled, add its label to 'labels'. |
| unsigned typeChildIndex = 0; |
| unsigned nameIdx = 0; |
| if (element->getChild(nameIdx)->getKind() == NodeKind::VariadicMarker) { |
| variadic = true; |
| nameIdx = 1; |
| typeChildIndex = 1; |
| } |
| if (element->getChild(nameIdx)->getKind() == NodeKind::TupleElementName) { |
| // Add spaces to terminate all the previous labels if this |
| // is the first we've seen. |
| if (labels.empty()) labels.append(elements.size(), ' '); |
| |
| // Add the label and its terminator. |
| labels += element->getChild(0)->getText(); |
| labels += ' '; |
| typeChildIndex++; |
| |
| // Otherwise, add a space if a previous element had a label. |
| } else if (!labels.empty()) { |
| labels += ' '; |
| } |
| |
| // Decode the element type. |
| BuiltType elementType = |
| decodeMangledType(element->getChild(typeChildIndex)); |
| if (!elementType) |
| return BuiltType(); |
| |
| elements.push_back(elementType); |
| } |
| return Builder.createTupleType(elements, std::move(labels), variadic); |
| } |
| case NodeKind::TupleElement: |
| if (Node->getChild(0)->getKind() == NodeKind::TupleElementName) |
| return decodeMangledType(Node->getChild(1)); |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::DependentGenericType: { |
| return decodeMangledType(Node->getChild(1)); |
| } |
| case NodeKind::DependentMemberType: { |
| auto base = decodeMangledType(Node->getChild(0)); |
| if (!base) |
| return BuiltType(); |
| auto member = Node->getChild(1)->getText(); |
| auto protocol = decodeMangledType(Node->getChild(1)); |
| if (!protocol) |
| return BuiltType(); |
| return Builder.createDependentMemberType(member, base, protocol); |
| } |
| case NodeKind::DependentAssociatedTypeRef: |
| return decodeMangledType(Node->getChild(0)); |
| case NodeKind::Unowned: { |
| auto base = decodeMangledType(Node->getChild(0)); |
| if (!base) |
| return BuiltType(); |
| return Builder.createUnownedStorageType(base); |
| } |
| case NodeKind::Unmanaged: { |
| auto base = decodeMangledType(Node->getChild(0)); |
| if (!base) |
| return BuiltType(); |
| return Builder.createUnmanagedStorageType(base); |
| } |
| case NodeKind::Weak: { |
| auto base = decodeMangledType(Node->getChild(0)); |
| if (!base) |
| return BuiltType(); |
| return Builder.createWeakStorageType(base); |
| } |
| case NodeKind::SILBoxType: { |
| auto base = decodeMangledType(Node->getChild(0)); |
| if (!base) |
| return BuiltType(); |
| return Builder.createSILBoxType(base); |
| } |
| case NodeKind::SILBoxTypeWithLayout: { |
| // TODO: Implement SILBoxTypeRefs with layout. As a stopgap, specify the |
| // NativeObject type ref. |
| return Builder.createBuiltinType("Bo"); |
| } |
| default: |
| return BuiltType(); |
| } |
| } |
| |
| private: |
| bool decodeMangledNominalType(const Demangle::NodePointer &node, |
| BuiltNominalTypeDecl &typeDecl, |
| BuiltType &parent) { |
| if (node->getKind() == NodeKind::Type) |
| return decodeMangledNominalType(node->getChild(0), typeDecl, parent); |
| |
| assert(node->getNumChildren() == 2); |
| auto moduleOrParentType = node->getChild(0); |
| |
| // Nested types are handled a bit funny here because a |
| // nominal typeref always stores its full mangled name, |
| // in addition to a reference to the parent type. The |
| // mangled name already includes the module and parent |
| // types, if any. |
| if (moduleOrParentType->getKind() != NodeKind::Module) { |
| parent = decodeMangledType(moduleOrParentType); |
| if (!parent) return false; |
| } |
| |
| typeDecl = Builder.createNominalTypeDecl(node); |
| if (!typeDecl) return false; |
| |
| return true; |
| } |
| |
| bool decodeMangledFunctionInputType(const Demangle::NodePointer &node, |
| std::vector<BuiltType> &args, |
| std::vector<bool> &argsAreInOut, |
| FunctionTypeFlags &flags) { |
| // Look through a couple of sugar nodes. |
| if (node->getKind() == NodeKind::Type || |
| node->getKind() == NodeKind::ArgumentTuple) { |
| return decodeMangledFunctionInputType(node->getFirstChild(), |
| args, argsAreInOut, flags); |
| } |
| |
| auto decodeSingleHelper = |
| [&](const Demangle::NodePointer &typeNode, bool argIsInOut) -> bool { |
| BuiltType argType = decodeMangledType(typeNode); |
| if (!argType) return false; |
| |
| args.push_back(argType); |
| argsAreInOut.push_back(argIsInOut); |
| return true; |
| }; |
| auto decodeSingle = |
| [&](const Demangle::NodePointer &typeNode) -> bool { |
| if (typeNode->getKind() == NodeKind::InOut) { |
| return decodeSingleHelper(typeNode->getFirstChild(), true); |
| } else { |
| return decodeSingleHelper(typeNode, false); |
| } |
| }; |
| |
| // Expand a single level of tuple. |
| if (node->getKind() == NodeKind::Tuple) { |
| // TODO: preserve variadic somewhere? |
| |
| // Decode all the elements as separate arguments. |
| for (const auto &elt : *node) { |
| if (elt->getKind() != NodeKind::TupleElement) |
| return false; |
| auto typeNode = elt->getChild(elt->getNumChildren() - 1); |
| if (typeNode->getKind() != NodeKind::Type) |
| return false; |
| if (!decodeSingle(typeNode->getFirstChild())) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // Otherwise, handle the type as a single argument. |
| return decodeSingle(node); |
| } |
| }; |
| |
| template<typename BuilderType> |
| static inline typename BuilderType::BuiltType |
| decodeMangledType(BuilderType &Builder, |
| const Demangle::NodePointer &Node) { |
| return TypeDecoder<BuilderType>(Builder).decodeMangledType(Node); |
| } |
| |
| /// A pointer to the local buffer of an object that also remembers the |
| /// address at which it was stored remotely. |
| template <typename Runtime, typename T> |
| class RemoteRef { |
| public: |
| using StoredPointer = typename Runtime::StoredPointer; |
| |
| private: |
| StoredPointer Address; |
| const T *LocalBuffer; |
| |
| public: |
| /*implicit*/ |
| RemoteRef(std::nullptr_t _) |
| : Address(0), LocalBuffer(nullptr) {} |
| |
| explicit RemoteRef(StoredPointer address, const T *localBuffer) |
| : Address(address), LocalBuffer(localBuffer) {} |
| |
| StoredPointer getAddress() const { |
| return Address; |
| } |
| |
| const T *getLocalBuffer() const { |
| return LocalBuffer; |
| } |
| |
| explicit operator bool() const { |
| return LocalBuffer != nullptr; |
| } |
| |
| const T *operator->() const { |
| assert(LocalBuffer); |
| return LocalBuffer; |
| } |
| }; |
| |
| /// 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<void*>(memory)); |
| } |
| }; |
| |
| /// 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 <typename Runtime, typename BuilderType> |
| class MetadataReader { |
| public: |
| using BuiltType = typename BuilderType::BuiltType; |
| using BuiltNominalTypeDecl = typename BuilderType::BuiltNominalTypeDecl; |
| using StoredPointer = typename Runtime::StoredPointer; |
| using StoredSize = typename Runtime::StoredSize; |
| |
| private: |
| /// A cache of built types, keyed by the address of the type. |
| std::unordered_map<StoredPointer, BuiltType> TypeCache; |
| |
| using MetadataRef = |
| RemoteRef<Runtime, TargetMetadata<Runtime>>; |
| using OwnedMetadataRef = |
| std::unique_ptr<const TargetMetadata<Runtime>, delete_with_free>; |
| |
| /// A cache of read type metadata, keyed by the address of the metadata. |
| std::unordered_map<StoredPointer, OwnedMetadataRef> |
| MetadataCache; |
| |
| using NominalTypeDescriptorRef = |
| RemoteRef<Runtime, TargetNominalTypeDescriptor<Runtime>>; |
| using OwnedNominalTypeDescriptorRef = |
| std::unique_ptr<const TargetNominalTypeDescriptor<Runtime>, |
| delete_with_free>; |
| |
| /// A cache of read nominal type descriptors, keyed by the address of the |
| /// nominal type descriptor. |
| std::unordered_map<StoredPointer, OwnedNominalTypeDescriptorRef> |
| NominalTypeDescriptorCache; |
| |
| using OwnedProtocolDescriptorRef = |
| std::unique_ptr<const TargetProtocolDescriptor<Runtime>, 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; |
| |
| public: |
| BuilderType Builder; |
| |
| BuilderType &getBuilder() { |
| return this->Builder; |
| } |
| |
| std::shared_ptr<MemoryReader> Reader; |
| |
| template <class... T> |
| MetadataReader(std::shared_ptr<MemoryReader> reader, T &&... args) |
| : Builder(std::forward<T>(args)...), |
| Reader(std::move(reader)) { |
| |
| } |
| |
| 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(); |
| NominalTypeDescriptorCache.clear(); |
| } |
| |
| /// Given a demangle tree, attempt to turn it into a type. |
| BuiltType decodeMangledType(const Demangle::NodePointer &Node) { |
| return swift::remote::decodeMangledType(Builder, Node); |
| } |
| |
| /// Get the remote process's swift_isaMask. |
| std::pair<bool, StoredPointer> readIsaMask() { |
| auto encoding = getIsaEncoding(); |
| if (encoding != IsaEncodingKind::Masked) |
| // Still return success if there's no isa encoding at all. |
| return {encoding == IsaEncodingKind::None, 0}; |
| |
| return {true, IsaMask}; |
| } |
| |
| /// Given a remote pointer to metadata, attempt to discover its MetadataKind. |
| std::pair<bool, MetadataKind> |
| readKindFromMetadata(StoredPointer MetadataAddress) { |
| auto meta = readMetadata(MetadataAddress); |
| if (!meta) return {false, MetadataKind::Opaque}; |
| |
| return {true, 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<TargetClassMetadata<Runtime>>(meta); |
| return 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. |
| std::pair<bool, unsigned> |
| readInstanceStartAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) { |
| auto meta = readMetadata(MetadataAddress); |
| if (!meta || meta->getKind() != MetadataKind::Class) |
| return std::make_pair(false, 0); |
| |
| // 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 std::make_pair(false, 0); |
| |
| // Get the address of the InstanceStart field. |
| auto address = roDataPtr + sizeof(uint32_t) * 1; |
| |
| unsigned start; |
| if (!Reader->readInteger(RemoteAddress(address), &start)) |
| return std::make_pair(false, 0); |
| |
| return std::make_pair(true, start); |
| } |
| |
| /// 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 readNominalTypeFromMetadata(Meta, skipArtificialSubclasses); |
| case MetadataKind::Struct: |
| return readNominalTypeFromMetadata(Meta); |
| case MetadataKind::Enum: |
| case MetadataKind::Optional: |
| return readNominalTypeFromMetadata(Meta); |
| case MetadataKind::Tuple: { |
| auto tupleMeta = cast<TargetTupleTypeMetadata<Runtime>>(Meta); |
| |
| std::vector<BuiltType> elementTypes; |
| elementTypes.reserve(tupleMeta->NumElements); |
| |
| StoredPointer elementAddress = MetadataAddress + |
| sizeof(TargetTupleTypeMetadata<Runtime>); |
| using Element = typename TargetTupleTypeMetadata<Runtime>::Element; |
| for (StoredPointer i = 0; i < tupleMeta->NumElements; ++i, |
| elementAddress += sizeof(Element)) { |
| Element element; |
| if (!Reader->readBytes(RemoteAddress(elementAddress), |
| (uint8_t*)&element, sizeof(Element))) |
| return BuiltType(); |
| |
| 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), |
| /*variadic*/ false); |
| TypeCache[MetadataAddress] = BuiltTuple; |
| return BuiltTuple; |
| } |
| case MetadataKind::Function: { |
| auto Function = cast<TargetFunctionTypeMetadata<Runtime>>(Meta); |
| |
| std::vector<BuiltType> Arguments; |
| std::vector<bool> ArgumentIsInOut; |
| StoredPointer ArgumentAddress = MetadataAddress + |
| sizeof(TargetFunctionTypeMetadata<Runtime>); |
| for (StoredPointer i = 0; i < Function->getNumArguments(); ++i, |
| ArgumentAddress += sizeof(StoredPointer)) { |
| StoredPointer FlaggedArgumentAddress; |
| if (!Reader->readInteger(RemoteAddress(ArgumentAddress), |
| &FlaggedArgumentAddress)) |
| return BuiltType(); |
| |
| // TODO: Use target-agnostic FlaggedPointer to mask this! |
| const auto InOutMask = (StoredPointer) 1; |
| ArgumentIsInOut.push_back((FlaggedArgumentAddress & InOutMask) != 0); |
| FlaggedArgumentAddress &= ~InOutMask; |
| |
| if (auto ArgumentTypeRef = readTypeFromMetadata(FlaggedArgumentAddress)) |
| Arguments.push_back(ArgumentTypeRef); |
| else |
| return BuiltType(); |
| } |
| |
| auto Result = readTypeFromMetadata(Function->ResultType); |
| if (!Result) |
| return BuiltType(); |
| |
| auto flags = FunctionTypeFlags().withConvention(Function->getConvention()) |
| .withThrows(Function->throws()); |
| auto BuiltFunction = Builder.createFunctionType(Arguments, |
| ArgumentIsInOut, |
| Result, flags); |
| TypeCache[MetadataAddress] = BuiltFunction; |
| return BuiltFunction; |
| } |
| case MetadataKind::Existential: { |
| auto Exist = cast<TargetExistentialTypeMetadata<Runtime>>(Meta); |
| std::vector<BuiltType> Members; |
| bool HasExplicitAnyObject = false; |
| |
| if (Exist->Flags.hasSuperclassConstraint()) { |
| // The superclass is stored after the list of protocols. |
| auto SuperclassType = readTypeFromMetadata( |
| Exist->Protocols[Exist->Protocols.NumProtocols]); |
| if (!SuperclassType) return BuiltType(); |
| Members.push_back(SuperclassType); |
| } |
| |
| if (Exist->isClassBounded()) |
| HasExplicitAnyObject = true; |
| |
| for (size_t i = 0; i < Exist->Protocols.NumProtocols; ++i) { |
| auto ProtocolAddress = Exist->Protocols[i]; |
| auto ProtocolDescriptor = readProtocolDescriptor(ProtocolAddress); |
| if (!ProtocolDescriptor) |
| return BuiltType(); |
| |
| std::string MangledName; |
| if (!Reader->readString(RemoteAddress(ProtocolDescriptor->Name), |
| MangledName)) |
| return BuiltType(); |
| Demangle::Context DCtx; |
| auto Demangled = DCtx.demangleSymbolAsNode(MangledName); |
| auto Protocol = decodeMangledType(Demangled); |
| if (!Protocol) |
| return BuiltType(); |
| |
| Members.push_back(Protocol); |
| } |
| auto BuiltExist = Builder.createProtocolCompositionType( |
| Members, HasExplicitAnyObject); |
| TypeCache[MetadataAddress] = BuiltExist; |
| return BuiltExist; |
| } |
| case MetadataKind::Metatype: { |
| auto Metatype = cast<TargetMetatypeMetadata<Runtime>>(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<TargetObjCClassWrapperMetadata<Runtime>>(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<TargetExistentialMetatypeMetadata<Runtime>>(Meta); |
| auto Instance = readTypeFromMetadata(Exist->InstanceType); |
| if (!Instance) return BuiltType(); |
| auto BuiltExist = Builder.createExistentialMetatypeType(Instance); |
| TypeCache[MetadataAddress] = BuiltExist; |
| return BuiltExist; |
| } |
| case MetadataKind::ForeignClass: { |
| auto namePtrAddress = |
| Meta.getAddress() + TargetForeignClassMetadata<Runtime>::OffsetToName; |
| StoredPointer namePtr; |
| if (!Reader->readInteger(RemoteAddress(namePtrAddress), &namePtr) || |
| namePtr == 0) |
| return BuiltType(); |
| std::string name; |
| if (!Reader->readString(RemoteAddress(namePtr), name)) |
| return BuiltType(); |
| 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("Bo"); |
| case MetadataKind::Opaque: { |
| auto BuiltOpaque = Builder.getOpaqueType(); |
| TypeCache[MetadataAddress] = BuiltOpaque; |
| return BuiltOpaque; |
| } |
| } |
| |
| swift_runtime_unreachable("Unhandled MetadataKind in switch"); |
| } |
| |
| BuiltType readTypeFromMangledName(const char *MangledTypeName, |
| size_t Length) { |
| Demangle::Demangler Dem; |
| Demangle::NodePointer Demangled = |
| Dem.demangleSymbol(StringRef(MangledTypeName, Length)); |
| return decodeMangledType(Demangled); |
| } |
| |
| /// Read the isa pointer of a class or closure context instance and apply |
| /// the isa mask. |
| std::pair<bool, StoredPointer> |
| readMetadataFromInstance(StoredPointer objectAddress) { |
| StoredPointer isa; |
| if (!Reader->readInteger(RemoteAddress(objectAddress), &isa)) |
| return {false, 0}; |
| |
| switch (getIsaEncoding()) { |
| case IsaEncodingKind::Unknown: |
| case IsaEncodingKind::Error: |
| return {false, 0}; |
| |
| case IsaEncodingKind::None: |
| return {true, isa}; |
| |
| case IsaEncodingKind::Masked: |
| return {true, 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 {true, isa}; |
| |
| // Extract the index. |
| auto classIndex = (isa & IsaIndexMask) >> IsaIndexShift; |
| |
| // 0 is never a valid index. |
| if (classIndex == 0) { |
| return {false, 0}; |
| |
| // 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 {false, 0}; |
| } |
| |
| LastIndexedClassesCount = count; |
| if (classIndex >= count) { |
| return {false, 0}; |
| } |
| } |
| |
| // Find the address of the appropriate array element. |
| RemoteAddress eltPointer = |
| RemoteAddress(IndexedClassesPointer |
| + classIndex * sizeof(StoredPointer)); |
| StoredPointer metadataPointer; |
| if (!Reader->readInteger(eltPointer, &metadataPointer)) { |
| return {false, 0}; |
| } |
| |
| return {true, metadataPointer}; |
| } |
| } |
| |
| swift_runtime_unreachable("Unhandled IsaEncodingKind in switch."); |
| } |
| |
| /// Read the parent type metadata from a nested nominal type metadata. |
| std::pair<bool, StoredPointer> |
| readParentFromMetadata(StoredPointer metadata) { |
| auto Meta = readMetadata(metadata); |
| if (!Meta) |
| return std::make_pair(false, 0); |
| |
| auto descriptorAddress = readAddressOfNominalTypeDescriptor(Meta); |
| if (!descriptorAddress) |
| return std::make_pair(false, 0); |
| |
| // Read the nominal type descriptor. |
| auto descriptor = readNominalTypeDescriptor(descriptorAddress); |
| if (!descriptor) |
| return std::make_pair(false, 0); |
| |
| // Read the parent type if the type has one. |
| if (descriptor->GenericParams.Flags.hasParent()) { |
| StoredPointer parentAddress = getNominalParent(Meta, descriptor); |
| if (!parentAddress) |
| return std::make_pair(false, 0); |
| return std::make_pair(true, parentAddress); |
| } |
| |
| return std::make_pair(false, 0); |
| } |
| |
| /// Read a single generic type argument from a bound generic type |
| /// metadata. |
| std::pair<bool, StoredPointer> |
| readGenericArgFromMetadata(StoredPointer metadata, unsigned index) { |
| auto Meta = readMetadata(metadata); |
| if (!Meta) |
| return std::make_pair(false, 0); |
| |
| auto descriptorAddress = readAddressOfNominalTypeDescriptor(Meta); |
| if (!descriptorAddress) |
| return std::make_pair(false, 0); |
| |
| // Read the nominal type descriptor. |
| auto descriptor = readNominalTypeDescriptor(descriptorAddress); |
| if (!descriptor) |
| return std::make_pair(false, 0); |
| |
| auto numGenericParams = descriptor->GenericParams.NumPrimaryParams; |
| auto offsetToGenericArgs = |
| sizeof(StoredPointer) * (descriptor->GenericParams.Offset); |
| auto addressOfGenericArgAddress = |
| Meta.getAddress() + offsetToGenericArgs + |
| index * sizeof(StoredPointer); |
| |
| if (index >= numGenericParams) |
| return std::make_pair(false, 0); |
| |
| StoredPointer genericArgAddress; |
| if (!Reader->readInteger(RemoteAddress(addressOfGenericArgAddress), |
| &genericArgAddress)) |
| return std::make_pair(false, 0); |
| |
| return std::make_pair(true, genericArgAddress); |
| } |
| |
| /// Given the address of a nominal type descriptor, attempt to resolve |
| /// its nominal type declaration. |
| BuiltNominalTypeDecl readNominalTypeFromDescriptor(StoredPointer address) { |
| auto descriptor = readNominalTypeDescriptor(address); |
| if (!descriptor) |
| return BuiltNominalTypeDecl(); |
| |
| 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<TargetTupleTypeMetadata<Runtime>>(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. |
| std::pair<bool, StoredPointer> |
| readOffsetToFirstCaptureFromMetadata(StoredPointer MetadataAddress) { |
| auto meta = readMetadata(MetadataAddress); |
| if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) |
| return std::make_pair(false, 0); |
| |
| auto heapMeta = cast<TargetHeapLocalVariableMetadata<Runtime>>(meta); |
| return std::make_pair(true, heapMeta->OffsetToFirstCapture); |
| } |
| |
| /// Given a remote pointer to class metadata, attempt to read its superclass. |
| std::pair<bool, StoredPointer> |
| readCaptureDescriptorFromMetadata(StoredPointer MetadataAddress) { |
| auto meta = readMetadata(MetadataAddress); |
| if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) |
| return std::make_pair(false, 0); |
| |
| auto heapMeta = cast<TargetHeapLocalVariableMetadata<Runtime>>(meta); |
| return std::make_pair(true, heapMeta->CaptureDescription); |
| } |
| |
| protected: |
| template<typename Offset> |
| StoredPointer resolveRelativeOffset(StoredPointer targetAddress) { |
| Offset relative; |
| if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) |
| return 0; |
| using SignedOffset = typename std::make_signed<Offset>::type; |
| using SignedPointer = typename std::make_signed<StoredPointer>::type; |
| auto signext = (SignedPointer)(SignedOffset)relative; |
| return targetAddress + signext; |
| } |
| |
| template<typename Offset> |
| llvm::Optional<StoredPointer> |
| resolveNullableRelativeOffset(StoredPointer targetAddress) { |
| Offset relative; |
| if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) |
| return llvm::None; |
| if (relative == 0) |
| return 0; |
| using SignedOffset = typename std::make_signed<Offset>::type; |
| using SignedPointer = typename std::make_signed<StoredPointer>::type; |
| auto signext = (SignedPointer)(SignedOffset)relative; |
| return targetAddress + signext; |
| } |
| |
| /// 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, cached->second.get()); |
| |
| StoredPointer KindValue = 0; |
| if (!Reader->readInteger(RemoteAddress(address), &KindValue)) |
| return nullptr; |
| |
| switch (getEnumeratedMetadataKind(KindValue)) { |
| case MetadataKind::Class: |
| return _readMetadata<TargetClassMetadata>(address); |
| case MetadataKind::Enum: |
| return _readMetadata<TargetEnumMetadata>(address); |
| case MetadataKind::ErrorObject: |
| return _readMetadata<TargetEnumMetadata>(address); |
| case MetadataKind::Existential: { |
| StoredPointer flagsAddress = address + |
| sizeof(StoredPointer); |
| |
| StoredPointer flags; |
| if (!Reader->readInteger(RemoteAddress(flagsAddress), |
| &flags)) |
| return nullptr; |
| |
| StoredPointer numProtocolsAddress = address + |
| TargetExistentialTypeMetadata<Runtime>::OffsetToNumProtocols; |
| StoredPointer 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<Runtime>) |
| + numProtocols * |
| sizeof(ConstTargetMetadataPointer<Runtime, TargetProtocolDescriptor>); |
| |
| if (ExistentialTypeFlags(flags).hasSuperclassConstraint()) |
| totalSize += sizeof(StoredPointer); |
| |
| return _readMetadata(address, totalSize); |
| } |
| case MetadataKind::ExistentialMetatype: |
| return _readMetadata<TargetExistentialMetatypeMetadata>(address); |
| case MetadataKind::ForeignClass: |
| return _readMetadata<TargetForeignClassMetadata>(address); |
| case MetadataKind::Function: |
| return _readMetadata<TargetFunctionTypeMetadata>(address); |
| case MetadataKind::HeapGenericLocalVariable: |
| return _readMetadata<TargetGenericBoxHeapMetadata>(address); |
| case MetadataKind::HeapLocalVariable: |
| return _readMetadata<TargetHeapLocalVariableMetadata>(address); |
| case MetadataKind::Metatype: |
| return _readMetadata<TargetMetatypeMetadata>(address); |
| case MetadataKind::ObjCClassWrapper: |
| return _readMetadata<TargetObjCClassWrapperMetadata>(address); |
| case MetadataKind::Opaque: |
| return _readMetadata<TargetOpaqueMetadata>(address); |
| case MetadataKind::Optional: |
| return _readMetadata<TargetEnumMetadata>(address); |
| case MetadataKind::Struct: |
| return _readMetadata<TargetStructMetadata>(address); |
| case MetadataKind::Tuple: { |
| auto numElementsAddress = address + |
| TargetTupleTypeMetadata<Runtime>::OffsetToNumElements; |
| StoredSize numElements; |
| if (!Reader->readInteger(RemoteAddress(numElementsAddress), |
| &numElements)) |
| return nullptr; |
| auto totalSize = sizeof(TargetTupleTypeMetadata<Runtime>) |
| + numElements * sizeof(StoredPointer); |
| |
| // Make sure the number of elements is reasonable |
| if (numElements >= 256) |
| return nullptr; |
| |
| return _readMetadata(address, totalSize); |
| } |
| } |
| |
| // We can fall out here if the value wasn't actually a valid |
| // MetadataKind. |
| return nullptr; |
| } |
| |
| private: |
| template <template <class R> class M> |
| MetadataRef _readMetadata(StoredPointer address) { |
| return _readMetadata(address, sizeof(M<Runtime>)); |
| } |
| |
| MetadataRef _readMetadata(StoredPointer address, size_t sizeAfter) { |
| auto size = sizeAfter; |
| uint8_t *buffer = (uint8_t *) malloc(size); |
| if (!Reader->readBytes(RemoteAddress(address), buffer, size)) { |
| free(buffer); |
| return nullptr; |
| } |
| |
| auto metadata = reinterpret_cast<TargetMetadata<Runtime>*>(buffer); |
| MetadataCache.insert(std::make_pair(address, OwnedMetadataRef(metadata))); |
| return MetadataRef(address, metadata); |
| } |
| |
| StoredPointer readAddressOfNominalTypeDescriptor(MetadataRef &metadata, |
| bool skipArtificialSubclasses = false) { |
| switch (metadata->getKind()) { |
| case MetadataKind::Class: { |
| auto classMeta = cast<TargetClassMetadata<Runtime>>(metadata); |
| while (true) { |
| auto descriptorAddress = |
| resolveNullableRelativeOffset<StoredPointer>(metadata.getAddress() + |
| classMeta->offsetToDescriptorOffset()); |
| |
| // Propagate errors reading the offset. |
| if (!descriptorAddress) return 0; |
| |
| // 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 *descriptorAddress; |
| |
| auto superclassMetadataAddress = classMeta->SuperClass; |
| if (!superclassMetadataAddress) |
| return 0; |
| |
| auto superMeta = readMetadata(superclassMetadataAddress); |
| if (!superMeta) |
| return 0; |
| auto superclassMeta = |
| dyn_cast<TargetClassMetadata<Runtime>>(superMeta); |
| if (!superclassMeta) |
| return 0; |
| |
| classMeta = superclassMeta; |
| metadata = superMeta; |
| } |
| } |
| |
| case MetadataKind::Struct: |
| case MetadataKind::Optional: |
| case MetadataKind::Enum: { |
| auto valueMeta = cast<TargetValueMetadata<Runtime>>(metadata); |
| return resolveRelativeOffset<StoredPointer>(metadata.getAddress() + |
| valueMeta->offsetToDescriptorOffset()); |
| } |
| |
| default: |
| return 0; |
| } |
| } |
| |
| /// Given the address of a nominal type descriptor, attempt to read it. |
| NominalTypeDescriptorRef |
| readNominalTypeDescriptor(StoredPointer address) { |
| auto cached = NominalTypeDescriptorCache.find(address); |
| if (cached != NominalTypeDescriptorCache.end()) |
| return NominalTypeDescriptorRef(address, cached->second.get()); |
| |
| auto size = sizeof(TargetNominalTypeDescriptor<Runtime>); |
| auto buffer = (uint8_t *)malloc(size); |
| if (!Reader->readBytes(RemoteAddress(address), buffer, size)) { |
| free(buffer); |
| return nullptr; |
| } |
| |
| auto descriptor |
| = reinterpret_cast<TargetNominalTypeDescriptor<Runtime> *>(buffer); |
| |
| NominalTypeDescriptorCache.insert( |
| std::make_pair(address, OwnedNominalTypeDescriptorRef(descriptor))); |
| return NominalTypeDescriptorRef(address, descriptor); |
| } |
| |
| /// Given a read nominal type descriptor, attempt to build a |
| /// nominal type decl from it. |
| BuiltNominalTypeDecl |
| buildNominalTypeDecl(NominalTypeDescriptorRef descriptor) { |
| auto nameAddress |
| = resolveRelativeOffset<int32_t>(descriptor.getAddress() + |
| descriptor->offsetToNameOffset()); |
| std::string mangledName; |
| if (!Reader->readString(RemoteAddress(nameAddress), mangledName)) |
| return BuiltNominalTypeDecl(); |
| |
| BuiltNominalTypeDecl decl = |
| Builder.createNominalTypeDecl(std::move(mangledName)); |
| return decl; |
| } |
| |
| OwnedProtocolDescriptorRef |
| readProtocolDescriptor(StoredPointer Address) { |
| auto Size = sizeof(TargetProtocolDescriptor<Runtime>); |
| auto Buffer = (uint8_t *)malloc(Size); |
| if (!Reader->readBytes(RemoteAddress(Address), Buffer, Size)) { |
| free(Buffer); |
| return nullptr; |
| } |
| auto Casted |
| = reinterpret_cast<TargetProtocolDescriptor<Runtime> *>(Buffer); |
| return OwnedProtocolDescriptorRef(Casted); |
| } |
| |
| StoredPointer getNominalParent(MetadataRef metadata, |
| NominalTypeDescriptorRef descriptor) { |
| // If this is metadata for some sort of value type, the parent type |
| // is at a fixed offset. |
| if (auto valueMetadata = dyn_cast<TargetValueMetadata<Runtime>>(metadata)) { |
| return valueMetadata->Parent; |
| } |
| |
| // If this is metadata for a class type, the parent type for the |
| // most-derived class is at an offset stored in the most-derived |
| // nominal type descriptor. |
| if (auto classMetadata = dyn_cast<TargetClassMetadata<Runtime>>(metadata)) { |
| // If it does, it's immediately before the generic parameters. |
| auto offsetToParent |
| = sizeof(StoredPointer) * (descriptor->GenericParams.Offset - 1); |
| RemoteAddress addressOfParent(metadata.getAddress() + offsetToParent); |
| StoredPointer parentAddress; |
| if (!Reader->readInteger(addressOfParent, &parentAddress)) |
| return StoredPointer(); |
| return parentAddress; |
| } |
| |
| // Otherwise, we don't know how to access its parent. This is a failure. |
| return StoredPointer(); |
| } |
| |
| std::vector<BuiltType> |
| getGenericSubst(MetadataRef metadata, NominalTypeDescriptorRef descriptor) { |
| std::vector<BuiltType> substitutions; |
| |
| auto numGenericParams = descriptor->GenericParams.NumPrimaryParams; |
| auto offsetToGenericArgs = |
| sizeof(StoredPointer) * (descriptor->GenericParams.Offset); |
| auto addressOfGenericArgAddress = |
| metadata.getAddress() + offsetToGenericArgs; |
| |
| using ArgIndex = decltype(descriptor->GenericParams.NumPrimaryParams); |
| for (ArgIndex i = 0; i < numGenericParams; |
| ++i, addressOfGenericArgAddress += sizeof(StoredPointer)) { |
| StoredPointer genericArgAddress; |
| if (!Reader->readInteger(RemoteAddress(addressOfGenericArgAddress), |
| &genericArgAddress)) |
| return {}; |
| if (auto genericArg = readTypeFromMetadata(genericArgAddress)) |
| substitutions.push_back(genericArg); |
| else |
| return {}; |
| } |
| return substitutions; |
| } |
| |
| BuiltType readNominalTypeFromMetadata(MetadataRef origMetadata, |
| bool skipArtificialSubclasses = false) { |
| auto metadata = origMetadata; |
| auto descriptorAddress = |
| readAddressOfNominalTypeDescriptor(metadata, |
| skipArtificialSubclasses); |
| if (!descriptorAddress) |
| return BuiltType(); |
| |
| // If we've skipped an artificial subclasses, check the cache at |
| // the superclass. (This also protects against recursion.) |
| if (skipArtificialSubclasses && |
| metadata.getAddress() != origMetadata.getAddress()) { |
| auto it = TypeCache.find(metadata.getAddress()); |
| if (it != TypeCache.end()) |
| return it->second; |
| } |
| |
| // Read the nominal type descriptor. |
| auto descriptor = readNominalTypeDescriptor(descriptorAddress); |
| if (!descriptor) |
| return BuiltType(); |
| |
| // From that, attempt to resolve a nominal type. |
| BuiltNominalTypeDecl typeDecl = buildNominalTypeDecl(descriptor); |
| if (!typeDecl) |
| return BuiltType(); |
| |
| // Read the parent type if the type has one. |
| BuiltType parent = BuiltType(); |
| if (descriptor->GenericParams.Flags.hasParent()) { |
| StoredPointer parentAddress = getNominalParent(metadata, descriptor); |
| if (!parentAddress) |
| return BuiltType(); |
| parent = readTypeFromMetadata(parentAddress); |
| if (!parent) return BuiltType(); |
| } |
| |
| BuiltType nominal; |
| if (descriptor->GenericParams.NumPrimaryParams) { |
| auto args = getGenericSubst(metadata, descriptor); |
| if (args.empty()) return BuiltType(); |
| nominal = Builder.createBoundGenericType(typeDecl, args, parent); |
| } else { |
| nominal = Builder.createNominalType(typeDecl, parent); |
| } |
| if (!nominal) return BuiltType(); |
| |
| TypeCache[metadata.getAddress()] = nominal; |
| |
| // If we've skipped an artificial subclass, remove the |
| // recursion-protection entry we made for it. |
| if (skipArtificialSubclasses && |
| metadata.getAddress() != origMetadata.getAddress()) { |
| TypeCache.erase(origMetadata.getAddress()); |
| } |
| |
| return nominal; |
| } |
| |
| /// Given that the remote process is running the non-fragile Apple runtime, |
| /// grab the ro-data from a class pointer. |
| StoredPointer readObjCRODataPtr(StoredPointer classAddress) { |
| // WARNING: the following algorithm works on current modern Apple |
| // runtimes but is not actually ABI. But it is pretty reliable. |
| |
| StoredPointer dataPtr; |
| if (!Reader->readInteger(RemoteAddress(classAddress + |
| TargetClassMetadata<Runtime>::offsetToData()), |
| &dataPtr)) |
| return StoredPointer(); |
| |
| // Apply the data-pointer mask. |
| // These values have been stolen from the runtime source. |
| static constexpr uint64_t DataPtrMask = |
| (Runtime::PointerSize == 8 ? 0x00007ffffffffff8ULL : 0xfffffffcULL); |
| dataPtr &= StoredPointer(DataPtrMask); |
| if (!dataPtr) |
| return StoredPointer(); |
| |
| // Read the flags, which is a 32-bit header on both formats. |
| uint32_t flags; |
| if (!Reader->readInteger(RemoteAddress(dataPtr), &flags)) |
| return StoredPointer(); |
| |
| // If the type is not realized, this is the RO-data. |
| static constexpr uint32_t RO_REALIZED = 0x80000000U; |
| if (!(flags & RO_REALIZED)) |
| return dataPtr; |
| |
| // Otherwise, it's the RW-data; read the RO-data pointer from a |
| // well-known position within the RW-data. |
| static constexpr uint32_t OffsetToROPtr = 8; |
| if (!Reader->readInteger(RemoteAddress(dataPtr + OffsetToROPtr), &dataPtr)) |
| return StoredPointer(); |
| |
| return dataPtr; |
| } |
| |
| IsaEncodingKind getIsaEncoding() { |
| if (IsaEncoding != IsaEncodingKind::Unknown) |
| return IsaEncoding; |
| |
| auto finish = [&](IsaEncodingKind result) -> IsaEncodingKind { |
| IsaEncoding = result; |
| return result; |
| }; |
| |
| /// Look up the given global symbol and bind 'varname' to its |
| /// address if its exists. |
| # define tryFindSymbol(varname, symbolName) \ |
| auto varname = Reader->getSymbolAddress(symbolName); \ |
| if (!varname) \ |
| return finish(IsaEncodingKind::Error) |
| /// Read from the given pointer into 'dest'. |
| # define tryReadSymbol(varname, dest) do { \ |
| if (!Reader->readInteger(varname, &dest)) \ |
| return finish(IsaEncodingKind::Error); \ |
| } while (0) |
| /// Read from the given global symbol into 'dest'. |
| # define tryFindAndReadSymbol(dest, symbolName) do { \ |
| tryFindSymbol(_address, symbolName); \ |
| tryReadSymbol(_address, dest); \ |
| } while (0) |
| |
| // Check for the magic-mask symbol that indicates that the ObjC |
| // runtime is using indexed ISAs. |
| if (auto magicMaskAddress = |
| Reader->getSymbolAddress("objc_debug_indexed_isa_magic_mask")) { |
| tryReadSymbol(magicMaskAddress, IsaMagicMask); |
| if (IsaMagicMask != 0) { |
| tryFindAndReadSymbol(IsaMagicValue, |
| "objc_debug_indexed_isa_magic_value"); |
| tryFindAndReadSymbol(IsaIndexMask, |
| "objc_debug_indexed_isa_index_mask"); |
| tryFindAndReadSymbol(IsaIndexShift, |
| "objc_debug_indexed_isa_index_shift"); |
| tryFindSymbol(indexedClasses, "objc_indexed_classes"); |
| IndexedClassesPointer = indexedClasses.getAddressData(); |
| tryFindSymbol(indexedClassesCount, "objc_indexed_classes_count"); |
| IndexedClassesCountPointer = indexedClassesCount.getAddressData(); |
| |
| return finish(IsaEncodingKind::Indexed); |
| } |
| } |
| |
| // Check for the ISA mask symbol. This has to come second because |
| // the standard library will define this even if the ObjC runtime |
| // doesn't use it. |
| if (auto maskAddress = Reader->getSymbolAddress("swift_isaMask")) { |
| tryReadSymbol(maskAddress, IsaMask); |
| if (IsaMask != 0) { |
| return finish(IsaEncodingKind::Masked); |
| } |
| } |
| |
| return finish(IsaEncodingKind::None); |
| } |
| |
| template <class T> |
| static constexpr T roundUpToAlignment(T offset, T alignment) { |
| return (offset + alignment - 1) & ~(alignment - 1); |
| } |
| }; |
| |
| } // end namespace remote |
| } // end namespace swift |
| |
| namespace llvm { |
| template<typename Runtime, typename T> |
| struct simplify_type<swift::remote::RemoteRef<Runtime, T>> { |
| typedef const T *SimpleType; |
| static SimpleType |
| getSimplifiedValue(swift::remote::RemoteRef<Runtime, T> value) { |
| return value.getLocalBuffer(); |
| } |
| }; |
| } |
| |
| #endif // SWIFT_REFLECTION_READER_H |