//===--- MetadataReader.h - Abstract access to remote metadata --*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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/Basic/Demangle.h" #include "swift/Basic/LLVM.h" #include #include namespace swift { namespace remote { /// A utility class for constructing abstract types from /// a textual mangling. template 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 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::ExistentialMetatype: { auto instance = decodeMangledType(Node->getChild(0)); if (!instance) return BuiltType(); return Builder.createExistentialMetatypeType(instance); } case NodeKind::Metatype: { auto instance = decodeMangledType(Node->getChild(0)); if (!instance) return BuiltType(); return Builder.createMetatypeType(instance); } case NodeKind::ProtocolList: { std::vector 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(); else return Builder.createProtocolCompositionType(protocols); } case NodeKind::Protocol: { auto moduleName = Node->getChild(0)->getText(); auto name = Node->getChild(1)->getText(); // Consistent handling of protocols and protocol compositions auto protocolList = Demangle::NodeFactory::create(NodeKind::ProtocolList); auto typeList = Demangle::NodeFactory::create(NodeKind::TypeList); auto type = Demangle::NodeFactory::create(NodeKind::Type); type->addChild(Node); typeList->addChild(type); protocolList->addChild(typeList); auto mangledName = Demangle::mangleNode(protocolList); return Builder.createProtocolType(mangledName, moduleName, 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 arguments; std::vector 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::ArgumentTuple: return decodeMangledType(Node->getChild(0)); case NodeKind::ReturnType: return decodeMangledType(Node->getChild(0)); case NodeKind::NonVariadicTuple: case NodeKind::VariadicTuple: { std::vector elements; std::string labels; for (auto &element : *Node) { if (element->getKind() != NodeKind::TupleElement) return BuiltType(); // If the tuple element is labelled, add its label to 'labels'. unsigned typeChildIndex = 0; if (element->getChild(0)->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 = 1; // 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); } bool variadic = (Node->getKind() == NodeKind::VariadicTuple); 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); } 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 &args, std::vector &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::VariadicTuple || node->getKind() == NodeKind::NonVariadicTuple) { // 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 static inline typename BuilderType::BuiltType decodeMangledType(BuilderType &Builder, const Demangle::NodePointer &Node) { return TypeDecoder(Builder).decodeMangledType(Node); } /// A pointer to the local buffer of an object that also remembers the /// address at which it was stored remotely. template 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(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 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 TypeCache; using MetadataRef = RemoteRef>; using OwnedMetadataRef = std::unique_ptr, delete_with_free>; /// A cache of read type metadata, keyed by the address of the metadata. std::unordered_map MetadataCache; using NominalTypeDescriptorRef = RemoteRef>; using OwnedNominalTypeDescriptorRef = std::unique_ptr, delete_with_free>; /// A cache of read nominal type descriptors, keyed by the address of the /// nominal type descriptor. std::unordered_map NominalTypeDescriptorCache; using OwnedProtocolDescriptorRef = std::unique_ptr, delete_with_free>; using OwnedCaptureDescriptor = std::unique_ptr; public: BuilderType Builder; BuilderType &getBuilder() { return this->Builder; } std::shared_ptr Reader; template MetadataReader(std::shared_ptr reader, T &&... args) : Builder(std::forward(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); } /// Given a remote pointer to metadata, attempt to discover its MetadataKind. std::pair readKindFromMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta) return {false, MetadataKind::Opaque}; return {true, meta->getKind()}; } /// Given a remote pointer to metadata, attempt to turn it into a type. BuiltType readTypeFromMetadata(StoredPointer MetadataAddress) { auto Cached = TypeCache.find(MetadataAddress); if (Cached != TypeCache.end()) return Cached->second; auto Meta = readMetadata(MetadataAddress); if (!Meta) return BuiltType(); switch (Meta->getKind()) { case MetadataKind::Class: return readNominalTypeFromMetadata(Meta); case MetadataKind::Struct: return readNominalTypeFromMetadata(Meta); case MetadataKind::Enum: case MetadataKind::Optional: return readNominalTypeFromMetadata(Meta); case MetadataKind::Tuple: { auto tupleMeta = cast>(Meta); std::vector elementTypes; elementTypes.reserve(tupleMeta->NumElements); StoredPointer elementAddress = MetadataAddress + sizeof(TargetTupleTypeMetadata); using Element = typename TargetTupleTypeMetadata::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(); return Builder.createTupleType(elementTypes, std::move(labels), /*variadic*/ false); } case MetadataKind::Function: { auto Function = cast>(Meta); std::vector Arguments; std::vector ArgumentIsInOut; StoredPointer ArgumentAddress = MetadataAddress + sizeof(TargetFunctionTypeMetadata); 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()); return Builder.createFunctionType(Arguments, ArgumentIsInOut, Result, flags); } case MetadataKind::Existential: { auto Exist = cast>(Meta); std::vector Protocols; 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(); auto Demangled = Demangle::demangleSymbolAsNode(MangledName); auto Protocol = decodeMangledType(Demangled); if (!Protocol) return BuiltType(); Protocols.push_back(Protocol); } return Builder.createProtocolCompositionType(Protocols); } case MetadataKind::Metatype: { auto Metatype = cast>(Meta); auto Instance = readTypeFromMetadata(Metatype->InstanceType); if (!Instance) return BuiltType(); return Builder.createMetatypeType(Instance); } case MetadataKind::ObjCClassWrapper: { auto objcWrapper = cast>(Meta); auto classAddress = objcWrapper->Class; std::string className; if (!readObjCClassName(classAddress, className)) return BuiltType(); return Builder.createObjCClassType(std::move(className)); } case MetadataKind::ExistentialMetatype: { auto Exist = cast>(Meta); auto Instance = readTypeFromMetadata(Exist->InstanceType); if (!Instance) return BuiltType(); return Builder.createExistentialMetatypeType(Instance); } case MetadataKind::ForeignClass: { auto namePtrAddress = Meta.getAddress() + TargetForeignClassMetadata::OffsetToName; StoredPointer namePtr; if (!Reader->readInteger(RemoteAddress(namePtrAddress), &namePtr) || namePtr == 0) return BuiltType(); std::string name; if (!Reader->readString(RemoteAddress(namePtr), name)) return BuiltType(); return Builder.createForeignClassType(std::move(name)); } case MetadataKind::HeapLocalVariable: return Builder.getUnnamedForeignClassType(); // FIXME? case MetadataKind::HeapGenericLocalVariable: return Builder.getUnnamedForeignClassType(); // FIXME? case MetadataKind::ErrorObject: return Builder.getUnnamedForeignClassType(); // FIXME? case MetadataKind::Opaque: return Builder.getOpaqueType(); // FIXME? } } /// 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); } protected: template StoredPointer resolveRelativeOffset(StoredPointer targetAddress) { Offset relative; if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) return 0; using SignedOffset = typename std::make_signed::type; using SignedPointer = typename std::make_signed::type; auto signext = (SignedPointer)(SignedOffset)relative; return targetAddress + signext; } private: template