diff --git a/include/swift/Basic/ExternalUnion.h b/include/swift/Basic/ExternalUnion.h index 0820fc2855e..8a82c78fd6d 100644 --- a/include/swift/Basic/ExternalUnion.h +++ b/include/swift/Basic/ExternalUnion.h @@ -433,27 +433,27 @@ struct MembersHelper<> { LLVM_ATTRIBUTE_ALWAYS_INLINE static void copyConstruct(void *self, int index, const void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void moveConstruct(void *self, int index, void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void copyAssignSame(int index, void *self, const void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void moveAssignSame(int index, void *self, void *other) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } LLVM_ATTRIBUTE_ALWAYS_INLINE static void destruct(int index, void *self) { - llvm_unreachable("bad index"); + assert(false && "bad index"); } }; diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h index d57bcce9044..9d8ecc07e89 100644 --- a/include/swift/Reflection/ReflectionContext.h +++ b/include/swift/Reflection/ReflectionContext.h @@ -608,6 +608,8 @@ public: auto CDAddr = this->readCaptureDescriptorFromMetadata(*MetadataAddress); if (!CDAddr) return nullptr; + if (!CDAddr->isResolved()) + return nullptr; // FIXME: Non-generic SIL boxes also use the HeapLocalVariable metadata // kind, but with a null capture descriptor right now (see @@ -615,7 +617,8 @@ public: // // Non-generic SIL boxes share metadata among types with compatible // layout, but we need some way to get an outgoing pointer map for them. - auto CD = getBuilder().getCaptureDescriptor(*CDAddr); + auto CD = getBuilder().getCaptureDescriptor( + CDAddr->getResolvedAddress().getAddressData()); if (CD == nullptr) return nullptr; diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 6907030c50d..3424e30bda4 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -69,7 +69,7 @@ public: /// NOTE: subclasses MUST override at least one of the readBytes functions. The default /// implementation calls through to the other one. virtual ReadBytesResult - readBytes(RemoteAddress address, uint64_t size) { + readBytes(RemoteAddress address, uint64_t size) { auto *Buf = malloc(size); ReadBytesResult Result(Buf, [](const void *ptr) { free(const_cast(ptr)); @@ -96,6 +96,34 @@ public: memcpy(dest, Ptr.get(), size); return true; } + + /// Attempts to resolve a pointer value read from the given remote address. + virtual RemoteAbsolutePointer resolvePointer(RemoteAddress address, + uint64_t readValue) { + // Default implementation returns the read value as is. + return RemoteAbsolutePointer("", readValue); + } + + /// Attempt to read and resolve a pointer value at the given remote address. + llvm::Optional readPointer(RemoteAddress address, + unsigned pointerSize) { + auto result = readBytes(address, pointerSize); + if (!result) + return llvm::None; + + uint64_t pointerData; + if (pointerSize == 4) { + uint32_t theData; + memcpy(&theData, result.get(), 4); + pointerData = theData; + } else if (pointerSize == 8) { + memcpy(&pointerData, result.get(), 8); + } else { + return llvm::None; + } + + return resolvePointer(address, pointerData); + } virtual ~MemoryReader() = default; }; diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index d180a62813c..cc1a2c99aeb 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -22,6 +22,7 @@ #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" @@ -181,6 +182,75 @@ private: std::unique_ptr, delete_with_free>; + /// 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 @@ -310,30 +380,34 @@ public: auto remoteAddress = mangledName.getAddressData() + offsetInMangledName + offset; + RemoteAbsolutePointer resolved; if (directness == Directness::Indirect) { - if (auto indirectAddress = readPointerValue(remoteAddress)) { - remoteAddress = *indirectAddress; + if (auto indirectAddress = readPointer(remoteAddress)) { + resolved = *indirectAddress; } else { return nullptr; } + } else { + resolved = RemoteAbsolutePointer("", remoteAddress); } switch (kind) { case Demangle::SymbolicReferenceKind::Context: { - auto context = readContextDescriptor(remoteAddress); - 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->getKind() == ContextDescriptorKind::OpaqueType) { - return dem.createNode( - Node::Kind::OpaqueTypeDescriptorSymbolicReference, - context.getAddressData()); - } - - return buildContextMangling(context, dem); + 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 @@ -426,14 +500,6 @@ public: return start; } - /// Given a pointer to an address, attemp to read the pointer value. - Optional readPointerValue(StoredPointer Address) { - StoredPointer PointerVal; - if (!Reader->readInteger(RemoteAddress(Address), &PointerVal)) - return None; - return Optional(PointerVal); - } - /// 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. @@ -821,6 +887,23 @@ public: 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 @@ -954,6 +1037,44 @@ public: 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; + // We don't handle pointers to other symbols yet. + // TODO: Opaque type descriptors could be useful. + 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 @@ -1331,47 +1452,40 @@ public: auto heapMeta = cast>(meta); return heapMeta->OffsetToFirstCapture; } + + Optional readPointer(StoredPointer address) { + return Reader->readPointer(RemoteAddress(address), sizeof(StoredPointer)); + } + + 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. - Optional + Optional readCaptureDescriptorFromMetadata(StoredPointer MetadataAddress) { auto meta = readMetadata(MetadataAddress); if (!meta || meta->getKind() != MetadataKind::HeapLocalVariable) return None; auto heapMeta = cast>(meta); - return heapMeta->CaptureDescription; + return resolvePointerField(meta, heapMeta->CaptureDescription); } protected: - template - Optional - resolveNullableRelativeIndirectableOffset(StoredPointer targetAddress) { - Offset relative; - if (!Reader->readInteger(RemoteAddress(targetAddress), &relative)) - return None; - if (relative == 0) - return 0; - bool indirect = relative & 1; - relative &= ~1u; - - using SignedOffset = typename std::make_signed::type; - using SignedPointer = typename std::make_signed::type; - auto signext = (SignedPointer)(SignedOffset)relative; - - StoredPointer resultAddress = targetAddress + signext; - - // Low bit set in the offset indicates that the offset leads to the absolute - // address in memory. - if (indirect) { - if (!Reader->readBytes(RemoteAddress(resultAddress), - (uint8_t *)&resultAddress, - sizeof(StoredPointer))) - return None; - } - return resultAddress; - } - template StoredPointer getAddress(RemoteRef base) { return (StoredPointer)base.getAddressData(); @@ -1384,14 +1498,14 @@ protected: } template - Optional resolveRelativeIndirectableField( + 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 0; + return Optional(nullptr); bool indirect = offset & 1; offset &= ~1u; @@ -1402,14 +1516,10 @@ protected: // Low bit set in the offset indicates that the offset leads to the absolute // address in memory. if (indirect) { - if (!Reader->readBytes(RemoteAddress(resultAddress), - (uint8_t *)&resultAddress, - sizeof(StoredPointer))) { - return None; - } + return readPointer(resultAddress); } - return resultAddress; + return RemoteAbsolutePointer("", resultAddress); } /// Given a pointer to an Objective-C class, try to read its class name. @@ -1612,17 +1722,26 @@ private: } } - /// Returns Optional(nullptr) if there's no parent descriptor. + /// Returns Optional(ParentContextDescriptorRef()) if there's no parent descriptor. /// Returns None if there was an error reading the parent descriptor. - Optional + Optional readParentContextDescriptor(ContextDescriptorRef base) { auto parentAddress = resolveRelativeIndirectableField(base, base->Parent); if (!parentAddress) return None; - if (!*parentAddress) - return ContextDescriptorRef(nullptr); - if (auto parentDescriptor = readContextDescriptor(*parentAddress)) - return parentDescriptor; + if (!parentAddress->isResolved()) { + // Currently we can only handle references directly to a symbol without + // an offset. + if (parentAddress->getOffset() != 0) { + return None; + } + return ParentContextDescriptorRef(parentAddress->getSymbol()); + } + auto addr = parentAddress->getResolvedAddress(); + if (!addr) + return ParentContextDescriptorRef(); + if (auto parentDescriptor = readContextDescriptor(addr.getAddressData())) + return ParentContextDescriptorRef(parentDescriptor); return None; } @@ -1807,13 +1926,20 @@ private: /// produce a mangled node describing the name of \c context. Demangle::NodePointer adoptAnonymousContextName(ContextDescriptorRef contextRef, - Optional &parentContextRef, - Demangler &dem, - Demangle::NodePointer &outerNode) { + Optional &parentContextRef, + Demangler &dem, + Demangle::NodePointer &outerNode) { outerNode = nullptr; - if (!parentContextRef || !*parentContextRef) + // Bail if there is no parent, or if the parent is in another image. + // (Anonymous contexts should always be emitted in the same image as their + // children.) + if (!parentContextRef + || !*parentContextRef + || !parentContextRef->isResolved()) return nullptr; + + auto parentContextLocalRef = parentContextRef->getResolved(); auto context = contextRef.getLocalBuffer(); auto typeContext = dyn_cast>(context); @@ -1822,11 +1948,11 @@ private: return nullptr; auto anonymousParent = dyn_cast_or_null>( - parentContextRef->getLocalBuffer()); + parentContextLocalRef.getLocalBuffer()); if (!anonymousParent) return nullptr; - auto mangledNode = demangleAnonymousContextName(*parentContextRef, dem); + auto mangledNode = demangleAnonymousContextName(parentContextLocalRef, dem); if (!mangledNode) return nullptr; @@ -1863,7 +1989,7 @@ private: // We have a match. Update the parent context to skip the anonymous // context entirely. - parentContextRef = readParentContextDescriptor(*parentContextRef); + parentContextRef = readParentContextDescriptor(parentContextLocalRef); // The outer node is the first child. outerNode = mangledNode->getChild(0); @@ -1914,6 +2040,26 @@ private: return resultAddress; } + Demangle::NodePointer + buildContextDescriptorMangling(const ParentContextDescriptorRef &descriptor, + Demangler &dem) { + if (descriptor.isResolved()) { + return buildContextDescriptorMangling(descriptor.getResolved(), dem); + } + + // Try to demangle the symbol name to figure out what context it would + // point to. + auto demangledSymbol = buildContextManglingForSymbol(descriptor.getSymbol(), + dem); + if (!demangledSymbol) + return nullptr; + // Look through Type notes since we're building up a mangling here. + if (demangledSymbol->getKind() == Demangle::Node::Kind::Type){ + demangledSymbol = demangledSymbol->getChild(0); + } + return demangledSymbol; + } + Demangle::NodePointer buildContextDescriptorMangling(ContextDescriptorRef descriptor, Demangler &dem) { @@ -2184,17 +2330,13 @@ private: case ContextDescriptorKind::OpaqueType: { // The opaque type may have a named anonymous context for us to map // back to its defining decl. - if (!parentDescriptorResult) - return nullptr; - - auto anonymous = - dyn_cast_or_null>( - parentDescriptorResult->getLocalBuffer()); - if (!anonymous) + if (!parentDescriptorResult + || !*parentDescriptorResult + || !parentDescriptorResult->isResolved()) return nullptr; auto mangledNode = - demangleAnonymousContextName(*parentDescriptorResult, dem); + demangleAnonymousContextName(parentDescriptorResult->getResolved(), dem); if (!mangledNode) return nullptr; if (mangledNode->getKind() == Node::Kind::Global) diff --git a/include/swift/Remote/RemoteAddress.h b/include/swift/Remote/RemoteAddress.h index 1c0d477babf..c1448121bee 100644 --- a/include/swift/Remote/RemoteAddress.h +++ b/include/swift/Remote/RemoteAddress.h @@ -19,6 +19,9 @@ #define SWIFT_REMOTE_REMOTEADDRESS_H #include +#include +#include +#include namespace swift { namespace remote { @@ -46,6 +49,40 @@ public: } }; +/// A symbolic relocated absolute pointer value. +class RemoteAbsolutePointer { + /// The symbol name that the pointer refers to. Empty if the value is absolute. + std::string Symbol; + /// The offset from the symbol, or the resolved remote address if \c Symbol is empty. + int64_t Offset; + +public: + RemoteAbsolutePointer() + : Symbol(), Offset(0) + {} + + RemoteAbsolutePointer(std::nullptr_t) + : RemoteAbsolutePointer() + {} + + RemoteAbsolutePointer(llvm::StringRef Symbol, int64_t Offset) + : Symbol(Symbol), Offset(Offset) + {} + + bool isResolved() const { return Symbol.empty(); } + llvm::StringRef getSymbol() const { return Symbol; } + int64_t getOffset() const { return Offset; } + + RemoteAddress getResolvedAddress() const { + assert(isResolved()); + return RemoteAddress(Offset); + } + + explicit operator bool() const { + return Offset != 0 || !Symbol.empty(); + } +}; + } // end namespace remote } // end namespace swift diff --git a/lib/RemoteAST/RemoteAST.cpp b/lib/RemoteAST/RemoteAST.cpp index ef02e490f8b..0812d6028f0 100644 --- a/lib/RemoteAST/RemoteAST.cpp +++ b/lib/RemoteAST/RemoteAST.cpp @@ -491,7 +491,7 @@ public: Result getDynamicTypeAndAddressClassExistential(RemoteAddress object) { - auto pointerval = Reader.readPointerValue(object.getAddressData()); + auto pointerval = Reader.readResolvedPointerValue(object.getAddressData()); if (!pointerval) return getFailure(); auto result = Reader.readMetadataFromInstance(*pointerval); @@ -508,7 +508,7 @@ public: getDynamicTypeAndAddressErrorExistential(RemoteAddress object, bool dereference=true) { if (dereference) { - auto pointerval = Reader.readPointerValue(object.getAddressData()); + auto pointerval = Reader.readResolvedPointerValue(object.getAddressData()); if (!pointerval) return getFailure(); object = RemoteAddress(*pointerval); @@ -531,7 +531,7 @@ public: auto payloadAddress = result->PayloadAddress; if (!result->IsBridgedError && typeResult->getClassOrBoundGenericClass()) { - auto pointerval = Reader.readPointerValue( + auto pointerval = Reader.readResolvedPointerValue( payloadAddress.getAddressData()); if (!pointerval) return getFailure(); @@ -559,7 +559,7 @@ public: // of the reference. auto payloadAddress = result->PayloadAddress; if (typeResult->getClassOrBoundGenericClass()) { - auto pointerval = Reader.readPointerValue( + auto pointerval = Reader.readResolvedPointerValue( payloadAddress.getAddressData()); if (!pointerval) return getFailure(); @@ -578,7 +578,7 @@ public: // 1) Loading a pointer from the input address // 2) Reading it as metadata and resolving the type // 3) Wrapping the resolved type in an existential metatype. - auto pointerval = Reader.readPointerValue(object.getAddressData()); + auto pointerval = Reader.readResolvedPointerValue(object.getAddressData()); if (!pointerval) return getFailure(); auto typeResult = Reader.readTypeFromMetadata(*pointerval);