Merge pull request #14916 from mikeash/remotemirror-hide-reflection-sections
[RemoteMirrors] Improve the API to no longer require clients to know about section names, and make it easier to interoperate with multiple versions of the library.
diff --git a/include/swift/Reflection/ReflectionContext.h b/include/swift/Reflection/ReflectionContext.h
index 95aaa18..c46fba2 100644
--- a/include/swift/Reflection/ReflectionContext.h
+++ b/include/swift/Reflection/ReflectionContext.h
@@ -18,6 +18,10 @@
#ifndef SWIFT_REFLECTION_REFLECTIONCONTEXT_H
#define SWIFT_REFLECTION_REFLECTIONCONTEXT_H
+#if defined(__APPLE__) && defined(__MACH__)
+#include <mach-o/getsect.h>
+#endif
+
#include "swift/Remote/MemoryReader.h"
#include "swift/Remote/MetadataReader.h"
#include "swift/Reflection/Records.h"
@@ -30,6 +34,32 @@
#include <set>
#include <vector>
#include <unordered_map>
+#include <utility>
+
+#if defined(__APPLE__) && defined(__MACH__)
+#ifndef __LP64__
+typedef const struct mach_header MachHeader;
+#else
+typedef const struct mach_header_64 MachHeader;
+#endif
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+template <typename Section>
+static std::pair<Section, bool> findSection(MachHeader *Header,
+ const char *Name) {
+ unsigned long Size;
+ auto Address = getsectiondata(Header, "__TEXT", Name, &Size);
+ if (!Address)
+ return {{nullptr, nullptr}, false};
+
+ auto End = reinterpret_cast<uintptr_t>(Address) + Size;
+
+ return {{reinterpret_cast<const void *>(Address),
+ reinterpret_cast<const void *>(End)},
+ true};
+}
+#endif
namespace swift {
namespace reflection {
@@ -46,6 +76,11 @@
std::unordered_map<typename super::StoredPointer, const TypeInfo *> Cache;
+ /// All buffers we need to keep around long term. This will automatically free them
+ /// when this object is destroyed.
+ std::vector<MemoryReader::ReadBytesResult> savedBuffers;
+ std::vector<std::tuple<RemoteAddress, RemoteAddress>> dataSegments;
+
public:
using super::getBuilder;
using super::readDemanglingForContextDescriptor;
@@ -62,7 +97,7 @@
ReflectionContext(const ReflectionContext &other) = delete;
ReflectionContext &operator=(const ReflectionContext &other) = delete;
-
+
MemoryReader &getReader() {
return *this->Reader;
}
@@ -76,10 +111,108 @@
getBuilder().dumpAllSections();
}
+#if defined(__APPLE__) && defined(__MACH__)
+ bool addImage(RemoteAddress ImageStart) {
+ auto Buf = this->getReader().readBytes(ImageStart, sizeof(MachHeader));
+ if (!Buf)
+ return false;
+
+ auto Header = reinterpret_cast<MachHeader *>(Buf.get());
+ if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) {
+ return false;
+ }
+ auto Length = Header->sizeofcmds;
+
+ // Read the commands.
+ Buf = this->getReader().readBytes(ImageStart, Length);
+ if (!Buf)
+ return false;
+
+ // Find the TEXT segment and figure out where the end is.
+ Header = reinterpret_cast<MachHeader *>(Buf.get());
+ unsigned long TextSize;
+ auto *TextSegment = getsegmentdata(Header, "__TEXT", &TextSize);
+ if (TextSegment == nullptr)
+ return false;
+
+ auto TextEnd =
+ TextSegment - reinterpret_cast<const uint8_t *>(Buf.get()) + TextSize;
+
+ // Read everything including the TEXT segment.
+ Buf = this->getReader().readBytes(ImageStart, TextEnd);
+ if (!Buf)
+ return false;
+
+ // Read all the metadata parts.
+ Header = reinterpret_cast<MachHeader *>(Buf.get());
+
+ // The docs say "not all sections may be present." We'll succeed if ANY of
+ // them are present. Not sure if that's the right thing to do.
+ auto FieldMd = findSection<FieldSection>(Header, "__swift5_fieldmd");
+ auto AssocTyMd =
+ findSection<AssociatedTypeSection>(Header, "__swift5_assocty");
+ auto BuiltinTyMd =
+ findSection<BuiltinTypeSection>(Header, "__swift5_builtin");
+ auto CaptureMd = findSection<CaptureSection>(Header, "__swift5_capture");
+ auto TyperefMd = findSection<GenericSection>(Header, "__swift5_typeref");
+ auto ReflStrMd = findSection<GenericSection>(Header, "__swift5_reflstr");
+
+ bool success = FieldMd.second || AssocTyMd.second || BuiltinTyMd.second ||
+ CaptureMd.second || TyperefMd.second || ReflStrMd.second;
+ if (!success)
+ return false;
+
+ auto LocalStartAddress = reinterpret_cast<uintptr_t>(Buf.get());
+ auto RemoteStartAddress = static_cast<uintptr_t>(ImageStart.getAddressData());
+
+ ReflectionInfo info = {
+ {{FieldMd.first.startAddress(), FieldMd.first.endAddress()}, 0},
+ {{AssocTyMd.first.startAddress(), AssocTyMd.first.endAddress()}, 0},
+ {{BuiltinTyMd.first.startAddress(), BuiltinTyMd.first.endAddress()}, 0},
+ {{CaptureMd.first.startAddress(), CaptureMd.first.endAddress()}, 0},
+ {{TyperefMd.first.startAddress(), TyperefMd.first.endAddress()}, 0},
+ {{ReflStrMd.first.startAddress(), ReflStrMd.first.endAddress()}, 0},
+ LocalStartAddress,
+ RemoteStartAddress};
+
+ this->addReflectionInfo(info);
+
+ unsigned long DataSize;
+ auto *DataSegment = getsegmentdata(Header, "__DATA", &DataSize);
+ if (DataSegment != nullptr) {
+ auto DataSegmentStart = DataSegment - reinterpret_cast<const uint8_t *>(Buf.get())
+ + ImageStart.getAddressData();
+ auto DataSegmentEnd = DataSegmentStart + DataSize;
+ dataSegments.push_back(std::make_tuple(RemoteAddress(DataSegmentStart),
+ RemoteAddress(DataSegmentEnd)));
+ }
+
+ savedBuffers.push_back(std::move(Buf));
+
+ return true;
+ }
+#endif // defined(__APPLE__) && defined(__MACH__)
+
void addReflectionInfo(ReflectionInfo I) {
getBuilder().addReflectionInfo(I);
}
+
+ bool ownsObject(RemoteAddress ObjectAddress) {
+ auto MetadataAddress = readMetadataFromInstance(ObjectAddress.getAddressData());
+ if (!MetadataAddress)
+ return 0;
+ for (auto Segment : dataSegments) {
+ auto Start = std::get<0>(Segment);
+ auto End = std::get<1>(Segment);
+ if (Start.getAddressData() <= *MetadataAddress
+ && *MetadataAddress < End.getAddressData())
+ return 1;
+ }
+
+ return 0;
+ }
+
/// Return a description of the layout of a class instance with the given
/// metadata as its isa pointer.
const TypeInfo *getMetadataTypeInfo(StoredPointer MetadataAddress) {
diff --git a/include/swift/Reflection/TypeRefBuilder.h b/include/swift/Reflection/TypeRefBuilder.h
index c50af6a..c63b608 100644
--- a/include/swift/Reflection/TypeRefBuilder.h
+++ b/include/swift/Reflection/TypeRefBuilder.h
@@ -57,6 +57,10 @@
const void *startAddress() const {
return Begin;
}
+
+ const void *endAddress() const {
+ return End;
+ }
const_iterator begin() const {
return const_iterator(Begin, End);
@@ -334,6 +338,10 @@
void addReflectionInfo(ReflectionInfo I) {
ReflectionInfos.push_back(I);
}
+
+ const std::vector<ReflectionInfo> &getReflectionInfos() {
+ return ReflectionInfos;
+ }
private:
std::vector<ReflectionInfo> ReflectionInfos;
diff --git a/include/swift/Remote/CMemoryReader.h b/include/swift/Remote/CMemoryReader.h
index a9303e7..a1a168e 100644
--- a/include/swift/Remote/CMemoryReader.h
+++ b/include/swift/Remote/CMemoryReader.h
@@ -62,17 +62,26 @@
if (!length)
return false;
- auto buffer = std::unique_ptr<uint8_t>(new uint8_t[length + 1]);
- if (!readBytes(address, buffer.get(), length + 1))
+ auto Buf = readBytes(address, length);
+ if (!Buf)
return false;
-
- dest = std::string(reinterpret_cast<const char *>(buffer.get()));
+
+ dest = std::string(reinterpret_cast<const char *>(Buf.get()), length);
return true;
}
- bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) override {
- return Impl.readBytes(Impl.reader_context,
- address.getAddressData(), dest, size) != 0;
+ ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
+ void *FreeContext;
+ auto Ptr = Impl.readBytes(Impl.reader_context, address.getAddressData(), size,
+ &FreeContext);
+
+ auto Free = Impl.free;
+ if (Free == nullptr)
+ return ReadBytesResult(Ptr, [](const void *) {});
+
+ auto ReaderContext = Impl.reader_context;
+ auto freeLambda = [=](const void *Ptr) { Free(ReaderContext, Ptr, FreeContext); };
+ return ReadBytesResult(Ptr, freeLambda);
}
};
diff --git a/include/swift/Remote/InProcessMemoryReader.h b/include/swift/Remote/InProcessMemoryReader.h
index c1e01a3..e631871 100644
--- a/include/swift/Remote/InProcessMemoryReader.h
+++ b/include/swift/Remote/InProcessMemoryReader.h
@@ -42,9 +42,8 @@
return true;
}
- bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) override {
- std::memcpy(dest, address.getLocalPointer<void>(), (size_t) size);
- return true;
+ ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
+ return ReadBytesResult(address.getLocalPointer<void>(), [](const void *) {});
}
};
diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h
index 53e48ca..038ffab 100644
--- a/include/swift/Remote/MemoryReader.h
+++ b/include/swift/Remote/MemoryReader.h
@@ -20,7 +20,11 @@
#include "swift/Remote/RemoteAddress.h"
+#include <cstring>
+#include <functional>
+#include <memory>
#include <string>
+#include <tuple>
namespace swift {
namespace remote {
@@ -31,6 +35,9 @@
/// representation of the address space of a remote process.
class MemoryReader {
public:
+ /// A convenient name for the return type from readBytes.
+ using ReadBytesResult = std::unique_ptr<const void, std::function<void(const void *)>>;
+
/// Return the size of an ordinary pointer in the remote process, in bytes.
virtual uint8_t getPointerSize() = 0;
@@ -40,19 +47,12 @@
/// Look up the given public symbol name in the remote process.
virtual RemoteAddress getSymbolAddress(const std::string &name) = 0;
- /// Attempts to read 'size' bytes from the given address in the
- /// remote process.
- ///
- /// Returns false if the operation failed.
- virtual bool readBytes(RemoteAddress address, uint8_t *dest,
- uint64_t size) = 0;
-
/// Attempts to read a C string from the given address in the remote
/// process.
///
/// Returns false if the operation failed.
virtual bool readString(RemoteAddress address, std::string &dest) = 0;
-
+
/// Attempts to read an integer from the given address in the remote
/// process.
///
@@ -63,6 +63,42 @@
sizeof(IntegerType));
}
+ /// Attempts to read 'size' bytes from the given address in the remote process.
+ ///
+ /// Returns a pointer to the requested data and a function that must be called to
+ /// free that data when done. The pointer will be NULL if the operation failed.
+ ///
+ /// 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) {
+ auto *Buf = malloc(size);
+ ReadBytesResult Result(Buf, [](const void *ptr) {
+ free(const_cast<void *>(ptr));
+ });
+ bool success = readBytes(address, reinterpret_cast<uint8_t *>(Buf), size);
+ if (!success) {
+ Result.reset();
+ }
+ return Result;
+ }
+
+ /// Attempts to read 'size' bytes from the given address in the
+ /// remote process.
+ ///
+ /// Returns false if the operation failed.
+ ///
+ /// NOTE: subclasses MUST override at least one of the readBytes functions. The default
+ /// implementation calls through to the other one.
+ virtual bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) {
+ auto Ptr = readBytes(address, size);
+ if (!Ptr)
+ return false;
+
+ memcpy(dest, Ptr.get(), size);
+ return true;
+ }
+
virtual ~MemoryReader() = default;
};
diff --git a/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h b/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h
index df98c73..f78fc79 100644
--- a/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h
+++ b/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h
@@ -32,10 +32,13 @@
// in the system library, so we use 'swift_addr_t'.
typedef uint64_t swift_addr_t;
+typedef void (*FreeBytesFunction)(void *reader_context, const void *bytes, void *context);
+
typedef uint8_t (*PointerSizeFunction)(void *reader_context);
typedef uint8_t (*SizeSizeFunction)(void *reader_context);
-typedef int (*ReadBytesFunction)(void *reader_context, swift_addr_t address,
- void *dest, uint64_t size);
+typedef const void *(*ReadBytesFunction)(void *reader_context, swift_addr_t address,
+ uint64_t size,
+ void **outFreeContext);
typedef uint64_t (*GetStringLengthFunction)(void *reader_context,
swift_addr_t address);
typedef swift_addr_t (*GetSymbolAddressFunction)(void *reader_context,
@@ -53,6 +56,9 @@
/// Get the size in bytes of the target's size type.
SizeSizeFunction getSizeSize;
+ /// Free memory returned from readBytes. May be NULL if memory never needs to be freed.
+ FreeBytesFunction free;
+
// FIXME: -Wdocumentation complains about \param and \returns on function pointers.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
@@ -60,9 +66,12 @@
/// Read a sequence of bytes at an address in the target.
///
/// \param address the address in the target address space
- /// \param dest the caller-owned buffer into which to store the string
/// \param size the number of bytes to read
- /// \returns true if the read was successful
+ /// \param outFreeContext on return, an arbitrary context pointer that the caller will
+ /// pass to the free function
+ /// \returns A pointer to the requested memory, or NULL if the memory could not be read.
+ /// The caller must invoke the free function on the returned pointer once it's
+ /// done using the memory.
ReadBytesFunction readBytes;
/// Get the string length at the given address.
diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h
index 1909b94..3459362 100644
--- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h
+++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h
@@ -17,8 +17,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef SWIFT_REFLECTION_SWIFT_REFLECTION_H
-#define SWIFT_REFLECTION_SWIFT_REFLECTION_H
+#ifndef SWIFT_REMOTE_MIRROR_H
+#define SWIFT_REMOTE_MIRROR_H
#include "Platform.h"
#include "MemoryReaderInterface.h"
@@ -45,11 +45,11 @@
SWIFT_REMOTE_MIRROR_LINKAGE
SwiftReflectionContextRef
swift_reflection_createReflectionContext(void *ReaderContext,
- PointerSizeFunction getPointerSize,
- SizeSizeFunction getSizeSize,
- ReadBytesFunction readBytes,
- GetStringLengthFunction getStringLength,
- GetSymbolAddressFunction getSymbolAddress);
+ uint8_t PointerSize,
+ FreeBytesFunction Free,
+ ReadBytesFunction ReadBytes,
+ GetStringLengthFunction GetStringLength,
+ GetSymbolAddressFunction GetSymbolAddress);
/// Destroys an opaque reflection context.
SWIFT_REMOTE_MIRROR_LINKAGE
@@ -58,8 +58,18 @@
/// Add reflection sections for a loaded Swift image.
SWIFT_REMOTE_MIRROR_LINKAGE
-void swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
- swift_reflection_info_t Info);
+void
+swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
+ swift_reflection_info_t Info);
+
+#if defined(__APPLE__) && defined(__MACH__)
+/// Add reflection information from a loaded Swift image.
+/// Returns true on success, false if the image's memory couldn't be read.
+SWIFT_REMOTE_MIRROR_LINKAGE
+int
+swift_reflection_addImage(SwiftReflectionContextRef ContextRef,
+ swift_addr_t imageStart);
+#endif
/// Returns a boolean indicating if the isa mask was successfully
/// read, in which case it is stored in the isaMask out parameter.
@@ -78,6 +88,24 @@
swift_reflection_typeRefForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata);
+/// Returns whether the given object appears to have metadata understood
+/// by this library. Images must be added using
+/// swift_reflection_addImage, not swift_reflection_addReflectionInfo,
+/// for this function to work properly. If addImage is used, a negative
+/// result is always correct, but a positive result may be a false
+/// positive if the address in question is not really a Swift or
+/// Objective-C object. If addReflectionInfo is used, the return value
+/// will always be false.
+SWIFT_REMOTE_MIRROR_LINKAGE
+int
+swift_reflection_ownsObject(SwiftReflectionContextRef ContextRef, uintptr_t Object);
+
+/// Returns the metadata pointer for a given object.
+SWIFT_REMOTE_MIRROR_LINKAGE
+uintptr_t
+swift_reflection_metadataForObject(SwiftReflectionContextRef ContextRef,
+ uintptr_t Object);
+
/// Returns an opaque type reference for a class or closure context
/// instance pointer, or NULL if one can't be constructed.
///
diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h
new file mode 100644
index 0000000..631df0d
--- /dev/null
+++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInterop.h
@@ -0,0 +1,887 @@
+//===--- SwiftRemoteMirrorLegacyInterop.h - Interop with legacy libs. -*- 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
+//
+//===----------------------------------------------------------------------------===//
+///
+/// \file
+/// This header provides an interface for using multiple versions of the Swift remote
+/// mirror library to inspect processes built with different versions of Swift, or
+/// processes where different libraries are built with different versions of Swift.
+///
+//===----------------------------------------------------------------------------===//
+
+#ifndef SWIFT_REMOTE_MIRROR_LEGACY_INTEROP_H
+#define SWIFT_REMOTE_MIRROR_LEGACY_INTEROP_H
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+#include "SwiftRemoteMirrorLegacyInteropTypes.h"
+#include "SwiftRemoteMirror.h"
+
+#include <dlfcn.h>
+#include <mach-o/getsect.h>
+
+/// The "public" interface follows. All of these functions are the same
+/// as the corresponding swift_reflection_* functions, except for taking
+/// or returning _interop data types in some circumstances.
+
+static inline SwiftReflectionInteropContextRef
+swift_reflection_interop_createReflectionContext(
+ void *ReaderContext,
+ void *LibraryHandle,
+ void *LegacyLibraryHandle,
+ uint8_t PointerSize,
+ FreeBytesFunction FreeBytes,
+ ReadBytesFunction ReadBytes,
+ GetStringLengthFunction GetStringLength,
+ GetSymbolAddressFunction GetSymbolAddress);
+
+static inline void
+swift_reflection_interop_destroyReflectionContext(
+ SwiftReflectionInteropContextRef ContextRef);
+
+static inline int
+swift_reflection_interop_addImage(SwiftReflectionInteropContextRef ContextRef,
+ swift_addr_t imageStart);
+
+static inline int
+swift_reflection_interop_readIsaMask(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t *outIsaMask);
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_typeRefForMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata);
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_typeRefForInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object);
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_typeRefForMangledTypeName(
+ SwiftReflectionInteropContextRef ContextRef,
+ const char *MangledName,
+ uint64_t Length);
+
+static inline swift_typeinfo_t
+swift_reflection_interop_infoForTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef);
+
+static inline swift_childinfo_t
+swift_reflection_interop_childOfTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef,
+ unsigned Index);
+
+static inline swift_typeinfo_t
+swift_reflection_interop_infoForMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata);
+
+static inline swift_childinfo_t
+swift_reflection_interop_childOfMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata,
+ unsigned Index);
+
+static inline swift_typeinfo_t
+swift_reflection_interop_infoForInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object);
+
+static inline swift_childinfo_t
+swift_reflection_interop_childOfInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object,
+ unsigned Index);
+
+static inline unsigned
+swift_reflection_interop_genericArgumentCountOfTypeRef(
+ SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef);
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_genericArgumentOfTypeRef(
+ SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef,
+ unsigned Index);
+
+static inline int
+swift_reflection_interop_projectExistential(SwiftReflectionInteropContextRef ContextRef,
+ swift_addr_t ExistentialAddress,
+ swift_typeref_interop_t ExistentialTypeRef,
+ swift_typeref_interop_t *OutInstanceTypeRef,
+ swift_addr_t *OutStartOfInstanceData);
+
+static inline void
+swift_reflection_interop_dumpTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef);
+
+static inline void
+swift_reflection_interop_dumpInfoForTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef);
+
+static inline void
+swift_reflection_interop_dumpInfoForMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata);
+
+static inline void
+swift_reflection_interop_dumpInfoForInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object);
+
+static inline size_t
+swift_reflection_interop_demangle(SwiftReflectionInteropContextRef ContextRef,
+ const char *MangledName,
+ size_t Length,
+ char *OutDemangledName,
+ size_t MaxLength);
+
+
+
+/// \name Internal implementation details, clients don't need to use these.
+/// @{
+
+/// The minimum supported metadata version for the legacy library.
+#define SWIFT_LEGACY_METADATA_MIN_VERSION 3
+
+/// The legacy reflection info struct.
+typedef struct swift_reflection_legacy_info {
+ swift_reflection_section_t fieldmd;
+ swift_reflection_section_t assocty;
+ swift_reflection_section_t builtin;
+ swift_reflection_section_t capture;
+ swift_reflection_section_t typeref;
+ swift_reflection_section_t reflstr;
+ uintptr_t LocalStartAddress;
+ uintptr_t RemoteStartAddress;
+} swift_reflection_legacy_info_t;
+
+/// The signature of the legacy ReadBytesFunction.
+typedef int (*ReadBytesFunctionLegacy)(void *reader_context, swift_addr_t address,
+ void *dest, uint64_t size);
+
+struct SwiftReflectionFunctions {
+ uint16_t (*getSupportedMetadataVersion)(void);
+
+ SwiftReflectionContextRef (*createReflectionContext)(
+ void *ReaderContext,
+ uint8_t PointerSize,
+ FreeBytesFunction FreeBytes,
+ ReadBytesFunction ReadBytes,
+ GetStringLengthFunction GetStringLength,
+ GetSymbolAddressFunction GetSymbolAddress);
+
+ SwiftReflectionContextRef (*createReflectionContextLegacy)(
+ void *ReaderContext,
+ PointerSizeFunction getPointerSize,
+ SizeSizeFunction getSizeSize,
+ ReadBytesFunctionLegacy readBytes,
+ GetStringLengthFunction getStringLength,
+ GetSymbolAddressFunction getSymbolAddress);
+
+ void (*destroyReflectionContext)(SwiftReflectionContextRef Context);
+
+ void (*addReflectionInfo)(SwiftReflectionContextRef Context,
+ swift_reflection_info_t Info);
+
+ void (*addReflectionInfoLegacy)(SwiftReflectionContextRef Context,
+ swift_reflection_legacy_info_t Info);
+
+ int (*addImage)(SwiftReflectionContextRef ContextRef,
+ swift_addr_t imageStart);
+
+ int (*readIsaMask)(SwiftReflectionContextRef ContextRef, uintptr_t *outIsaMask);
+
+ swift_typeref_t (*typeRefForMetadata)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Metadata);
+
+ int (*ownsObject)(SwiftReflectionContextRef ContextRef, uintptr_t Object);
+
+ uintptr_t (*metadataForObject)(SwiftReflectionContextRef ContextRef, uintptr_t Object);
+
+ swift_typeref_t (*typeRefForInstance)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Object);
+
+ swift_typeref_t (*typeRefForMangledTypeName)(SwiftReflectionContextRef ContextRef,
+ const char *MangledName,
+ uint64_t Length);
+
+ swift_typeinfo_t (*infoForTypeRef)(SwiftReflectionContextRef ContextRef,
+ swift_typeref_t OpaqueTypeRef);
+
+ swift_childinfo_t (*childOfTypeRef)(SwiftReflectionContextRef ContextRef,
+ swift_typeref_t OpaqueTypeRef,
+ unsigned Index);
+
+ swift_typeinfo_t (*infoForMetadata)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Metadata);
+
+ swift_childinfo_t (*childOfMetadata)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Metadata,
+ unsigned Index);
+ swift_typeinfo_t (*infoForInstance)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Object);
+
+ swift_childinfo_t (*childOfInstance)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Object,
+ unsigned Index);
+
+ unsigned (*genericArgumentCountOfTypeRef)(swift_typeref_t OpaqueTypeRef);
+
+ swift_typeref_t (*genericArgumentOfTypeRef)(swift_typeref_t OpaqueTypeRef,
+ unsigned Index);
+
+ int (*projectExistential)(SwiftReflectionContextRef ContextRef,
+ swift_addr_t ExistentialAddress,
+ swift_typeref_t ExistentialTypeRef,
+ swift_typeref_t *OutInstanceTypeRef,
+ swift_addr_t *OutStartOfInstanceData);
+
+ void (*dumpTypeRef)(swift_typeref_t OpaqueTypeRef);
+
+ void (*dumpInfoForTypeRef)(SwiftReflectionContextRef ContextRef,
+ swift_typeref_t OpaqueTypeRef);
+
+ void (*dumpInfoForMetadata)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Metadata);
+
+ void (*dumpInfoForInstance)(SwiftReflectionContextRef ContextRef,
+ uintptr_t Object);
+
+ size_t (*demangle)(const char *MangledName,
+ size_t Length,
+ char *OutDemangledName,
+ size_t MaxLength);
+};
+
+struct SwiftReflectionInteropContextLibrary {
+ SwiftReflectionContextRef Context;
+ struct SwiftReflectionFunctions Functions;
+ int IsLegacy;
+};
+
+struct SwiftReflectionInteropContextFreeList {
+ struct SwiftReflectionInteropContextFreeList *Next;
+ const void *Pointer;
+ void *Context;
+};
+
+struct SwiftReflectionInteropContextLegacyDataSegmentList {
+ struct SwiftReflectionInteropContextLegacyDataSegmentList *Next;
+ swift_addr_t Start, End;
+};
+
+struct SwiftReflectionInteropContext {
+ void *ReaderContext;
+ FreeBytesFunction FreeBytes;
+ ReadBytesFunction ReadBytes;
+ uint64_t (*GetStringLength)(void *reader_context,
+ swift_addr_t address);
+ swift_addr_t (*GetSymbolAddress)(void *reader_context,
+ const char *name,
+ uint64_t name_length);
+
+ // Currently we support at most two libraries.
+ struct SwiftReflectionInteropContextLibrary Libraries[2];
+ int LibraryCount;
+
+ struct SwiftReflectionInteropContextFreeList *FreeList;
+ struct SwiftReflectionInteropContextLegacyDataSegmentList *LegacyDataSegmentList;
+};
+
+#define FOREACH_LIBRARY \
+ for (struct SwiftReflectionInteropContextLibrary *Library = &ContextRef->Libraries[0]; \
+ Library < &ContextRef->Libraries[ContextRef->LibraryCount]; \
+ ++Library)
+#define LIBRARY_INDEX (Library - ContextRef->Libraries)
+#define DECLARE_LIBRARY(index) \
+ struct SwiftReflectionInteropContextLibrary *Library = &ContextRef->Libraries[index]
+
+static inline int
+swift_reflection_interop_libraryOwnsObject(
+ struct SwiftReflectionInteropContext *ContextRef,
+ struct SwiftReflectionInteropContextLibrary *Library,
+ uintptr_t Object) {
+ if (!Library->IsLegacy)
+ return Library->Functions.ownsObject(Library->Context, Object);
+
+ // The legacy library doesn't have this. Do it ourselves if we can. We need
+ // metadataForObject from a non-legacy library to do it.
+ uintptr_t Metadata = 0;
+ FOREACH_LIBRARY {
+ if (Library->IsLegacy)
+ continue;
+
+ Metadata = Library->Functions.metadataForObject(Library->Context, Object);
+ break;
+ }
+
+ // If we couldn't retrieve metadata, assume it's ours.
+ if (Metadata == 0)
+ return 1;
+
+ // Search the data segment list to see if the metadata is in one of them.
+ struct SwiftReflectionInteropContextLegacyDataSegmentList *Node =
+ ContextRef->LegacyDataSegmentList;
+ while (Node != NULL) {
+ if (Node->Start <= Metadata && Metadata < Node->End)
+ return 1;
+ Node = Node->Next;
+ }
+ return 0;
+}
+
+static inline void
+swift_reflection_interop_loadFunctions(struct SwiftReflectionInteropContext *Context,
+ void *Handle,
+ int IsLegacy) {
+ if (Handle == NULL)
+ return;
+
+ struct SwiftReflectionInteropContextLibrary *Library = &Context
+ ->Libraries[Context->LibraryCount];
+ struct SwiftReflectionFunctions *Functions = &Library->Functions;
+
+#ifndef __cplusplus
+#define decltype(x) void *
+#endif
+#define LOAD_NAMED(field, symbol) do { \
+ Functions->field = (decltype(Functions->field))dlsym(Handle, symbol); \
+ if (Functions->field == NULL) return; \
+ } while (0)
+#define LOAD(name) LOAD_NAMED(name, "swift_reflection_" #name)
+
+ LOAD(getSupportedMetadataVersion);
+ uint16_t version = Functions->getSupportedMetadataVersion();
+ if (version < SWIFT_LEGACY_METADATA_MIN_VERSION)
+ return;
+
+ if (IsLegacy) {
+ LOAD_NAMED(createReflectionContextLegacy, "swift_reflection_createReflectionContext");
+ LOAD_NAMED(addReflectionInfoLegacy, "swift_reflection_addReflectionInfo");
+ } else {
+ LOAD(createReflectionContext);
+ LOAD(addReflectionInfo);
+ LOAD(addImage);
+ LOAD(ownsObject);
+ LOAD(metadataForObject);
+ }
+
+ LOAD(destroyReflectionContext);
+ LOAD(readIsaMask);
+ LOAD(typeRefForMetadata);
+ LOAD(typeRefForInstance);
+ LOAD(typeRefForMangledTypeName);
+ LOAD(infoForTypeRef);
+ LOAD(childOfTypeRef);
+ LOAD(infoForMetadata);
+ LOAD(childOfMetadata);
+ LOAD(infoForInstance);
+ LOAD(childOfInstance);
+ LOAD(genericArgumentCountOfTypeRef);
+ LOAD(genericArgumentOfTypeRef);
+ LOAD(projectExistential);
+ LOAD(dumpTypeRef);
+ LOAD(dumpInfoForTypeRef);
+
+ Library->IsLegacy = IsLegacy;
+ Context->LibraryCount++;
+
+ return;
+
+#undef LOAD
+#undef LOAD_NAMED
+#ifndef __cplusplus
+#undef decltype
+#endif
+}
+
+static inline int
+swift_reflection_interop_readBytesAdapter(void *reader_context,
+ swift_addr_t address,
+ void *dest,
+ uint64_t size) {
+ SwiftReflectionInteropContextRef Context =
+ (SwiftReflectionInteropContextRef)reader_context;
+
+ void *FreeContext;
+ const void *ptr = Context->ReadBytes(Context->ReaderContext, address, size,
+ &FreeContext);
+ if (ptr == NULL)
+ return 0;
+
+ memcpy(dest, ptr, size);
+ if (Context->FreeBytes != NULL)
+ Context->FreeBytes(Context->ReaderContext, ptr, FreeContext);
+ return 1;
+}
+
+static inline uint8_t
+swift_reflection_interop_getSizeAdapter(void *reader_context) {
+ // Legacy library doesn't pay attention to these anyway.
+ return sizeof(void *);
+}
+
+static inline uint64_t
+swift_reflection_interop_GetStringLengthAdapter(
+ void *reader_context, swift_addr_t address) {
+ SwiftReflectionInteropContextRef Context =
+ (SwiftReflectionInteropContextRef)reader_context;
+ return Context->GetStringLength(Context->ReaderContext, address);
+}
+
+static inline swift_addr_t
+swift_reflection_interop_GetSymbolAddressAdapter(
+ void *reader_context, const char *name, uint64_t name_length) {
+ SwiftReflectionInteropContextRef Context =
+ (SwiftReflectionInteropContextRef)reader_context;
+ return Context->GetSymbolAddress(Context->ReaderContext, name, name_length);
+}
+
+static inline SwiftReflectionInteropContextRef
+swift_reflection_interop_createReflectionContext(
+ void *ReaderContext,
+ void *LibraryHandle,
+ void *LegacyLibraryHandle,
+ uint8_t PointerSize,
+ FreeBytesFunction FreeBytes,
+ ReadBytesFunction ReadBytes,
+ GetStringLengthFunction GetStringLength,
+ GetSymbolAddressFunction GetSymbolAddress) {
+
+ SwiftReflectionInteropContextRef ContextRef =
+ (SwiftReflectionInteropContextRef)calloc(sizeof(*ContextRef), 1);
+
+ swift_reflection_interop_loadFunctions(ContextRef, LibraryHandle, 0);
+ swift_reflection_interop_loadFunctions(ContextRef, LegacyLibraryHandle, 1);
+
+ if (ContextRef->LibraryCount == 0) {
+ free(ContextRef);
+ return NULL;
+ }
+
+ FOREACH_LIBRARY {
+ if (Library->IsLegacy) {
+ Library->Context = Library->Functions.createReflectionContextLegacy(
+ ContextRef,
+ swift_reflection_interop_getSizeAdapter, swift_reflection_interop_getSizeAdapter,
+ swift_reflection_interop_readBytesAdapter,
+ swift_reflection_interop_GetStringLengthAdapter,
+ swift_reflection_interop_GetSymbolAddressAdapter);
+ } else {
+ Library->Context = Library->Functions.createReflectionContext(ReaderContext,
+ PointerSize, FreeBytes, ReadBytes, GetStringLength, GetSymbolAddress);
+ }
+ }
+
+ ContextRef->ReaderContext = ReaderContext;
+ ContextRef->FreeBytes = FreeBytes;
+ ContextRef->ReadBytes = ReadBytes;
+ ContextRef->GetStringLength = GetStringLength;
+ ContextRef->GetSymbolAddress = GetSymbolAddress;
+
+ return ContextRef;
+}
+
+static inline void
+swift_reflection_interop_destroyReflectionContext(
+ SwiftReflectionInteropContextRef ContextRef) {
+ FOREACH_LIBRARY {
+ Library->Functions.destroyReflectionContext(Library->Context);
+ }
+ struct SwiftReflectionInteropContextLegacyDataSegmentList *LegacyDataSegmentList
+ = ContextRef->LegacyDataSegmentList;
+ while (LegacyDataSegmentList != NULL) {
+ struct SwiftReflectionInteropContextLegacyDataSegmentList *Next
+ = LegacyDataSegmentList->Next;
+ free(LegacyDataSegmentList);
+ LegacyDataSegmentList = Next;
+ }
+ struct SwiftReflectionInteropContextFreeList *FreeList = ContextRef->FreeList;
+ while (FreeList != NULL) {
+ ContextRef->FreeBytes(ContextRef->ReaderContext,
+ FreeList->Pointer, FreeList->Context);
+ struct SwiftReflectionInteropContextFreeList *Next = FreeList->Next;
+ free(FreeList);
+ FreeList = Next;
+ }
+ free(ContextRef);
+}
+
+#ifndef __LP64__
+typedef const struct mach_header MachHeader;
+#else
+typedef const struct mach_header_64 MachHeader;
+#endif
+
+static inline int
+swift_reflection_interop_findSection(MachHeader *Header, const char *Name,
+ swift_reflection_section_t *Sect) {
+ unsigned long Size;
+ void *Address = getsectiondata(Header, "__TEXT", Name, &Size);
+ if (!Address)
+ return 0;
+
+ Sect->Begin = Address;
+ Sect->End = (void *)((uintptr_t)Address + Size);
+ return 1;
+}
+
+static inline int
+swift_reflection_interop_addImageLegacy(
+ SwiftReflectionInteropContextRef ContextRef,
+ struct SwiftReflectionInteropContextLibrary *Library,
+ swift_addr_t ImageStart) {
+ void *FreeContext;
+ const void *Buf;
+ Buf = ContextRef->ReadBytes(ContextRef->ReaderContext,
+ ImageStart,
+ sizeof(MachHeader),
+ &FreeContext);
+ if (Buf == NULL)
+ return 0;
+
+ MachHeader *Header = (MachHeader *)Buf;
+
+ if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) {
+ if (ContextRef->FreeBytes != NULL)
+ ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext);
+ return 0;
+ }
+
+ // Read the commands.
+ uint32_t Length = Header->sizeofcmds;
+ if (ContextRef->FreeBytes != NULL)
+ ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext);
+
+ Buf = ContextRef->ReadBytes(ContextRef->ReaderContext,
+ ImageStart,
+ Length,
+ &FreeContext);
+ if (Buf == NULL)
+ return 0;
+ Header = (MachHeader *)Buf;
+
+ // Find the TEXT segment and figure out where the end is.
+ unsigned long TextSize;
+ uint8_t *TextSegment = getsegmentdata(Header, "__TEXT", &TextSize);
+ if (ContextRef->FreeBytes != NULL)
+ ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext);
+
+ if (TextSegment == NULL) {
+ return 0;
+ }
+ unsigned long TextEnd = TextSegment - (uint8_t *)Buf + TextSize;
+
+ // Read everything including the TEXT segment.
+ Buf = ContextRef->ReadBytes(ContextRef->ReaderContext,
+ ImageStart,
+ TextEnd,
+ &FreeContext);
+ if (Buf == NULL)
+ return 0;
+ Header = (MachHeader *)Buf;
+
+ // Find all the sections and fill out the reflection info.
+ swift_reflection_legacy_info_t info = {};
+
+ int success = 0;
+ success = swift_reflection_interop_findSection(Header,
+ "__swift3_fieldmd",
+ &info.fieldmd) || success;
+ success = swift_reflection_interop_findSection(Header,
+ "__swift3_assocty",
+ &info.assocty) || success;
+ success = swift_reflection_interop_findSection(Header,
+ "__swift3_builtin",
+ &info.builtin) || success;
+ success = swift_reflection_interop_findSection(Header,
+ "__swift3_capture",
+ &info.capture) || success;
+ success = swift_reflection_interop_findSection(Header,
+ "__swift3_typeref",
+ &info.typeref) || success;
+ success = swift_reflection_interop_findSection(Header,
+ "__swift3_reflstr",
+ &info.reflstr) || success;
+
+ if (!success) {
+ if (ContextRef->FreeBytes != NULL)
+ ContextRef->FreeBytes(ContextRef->ReaderContext, Buf, FreeContext);
+ return 0;
+ }
+
+ info.LocalStartAddress = (uintptr_t)Buf;
+ info.RemoteStartAddress = ImageStart;
+
+ Library->Functions.addReflectionInfoLegacy(Library->Context, info);
+
+ // Find the data segment and add it to our list.
+ unsigned long DataSize;
+ const uint8_t *DataSegment = getsegmentdata(Header, "__DATA", &DataSize);
+
+ struct SwiftReflectionInteropContextLegacyDataSegmentList *Node =
+ (struct SwiftReflectionInteropContextLegacyDataSegmentList *)malloc(sizeof(*Node));
+ Node->Next = ContextRef->LegacyDataSegmentList;
+ Node->Start = DataSegment - (const uint8_t *)Buf + ImageStart;
+ Node->End = Node->Start + DataSize;
+ ContextRef->LegacyDataSegmentList = Node;
+
+ // If the buffer needs to be freed, save buffer and free context to free it when the
+ // reflection context is destroyed.
+ if (ContextRef->FreeBytes != NULL) {
+ struct SwiftReflectionInteropContextFreeList *Node =
+ (struct SwiftReflectionInteropContextFreeList *)malloc(sizeof(*Node));
+ Node->Next = ContextRef->FreeList;
+ Node->Pointer = Buf;
+ Node->Context = FreeContext;
+ ContextRef->FreeList = Node;
+ }
+
+ return 1;
+}
+
+static inline int
+swift_reflection_interop_addImage(SwiftReflectionInteropContextRef ContextRef,
+ swift_addr_t imageStart) {
+ FOREACH_LIBRARY {
+ int Success;
+ if (Library->IsLegacy) {
+ Success = swift_reflection_interop_addImageLegacy(ContextRef,
+ Library,
+ imageStart);
+ } else {
+ Success = Library->Functions.addImage(Library->Context, imageStart);
+ }
+ if (Success) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static inline int
+swift_reflection_interop_readIsaMask(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t *outIsaMask) {
+ FOREACH_LIBRARY {
+ int Success = Library->Functions.readIsaMask(Library->Context, outIsaMask);
+ if (Success)
+ return 1;
+ }
+ return 0;
+}
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_typeRefForMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata) {
+ DECLARE_LIBRARY(Metadata.Library);
+ swift_typeref_interop_t Result;
+ Result.Typeref = Library->Functions.
+ typeRefForMetadata(Library->Context, Metadata.Metadata);
+ Result.Library = Metadata.Library;
+ return Result;
+}
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_typeRefForInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object) {
+ swift_typeref_interop_t Result;
+ FOREACH_LIBRARY {
+ if (!swift_reflection_interop_libraryOwnsObject(ContextRef, Library, Object))
+ continue;
+ swift_typeref_t Typeref = Library->Functions.typeRefForInstance(Library->Context,
+ Object);
+ if (Typeref == 0)
+ continue;
+
+ Result.Typeref = Typeref;
+ Result.Library = LIBRARY_INDEX;
+ return Result;
+ }
+
+ Result.Typeref = 0;
+ Result.Library = 0;
+ return Result;
+}
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_typeRefForMangledTypeName(
+ SwiftReflectionInteropContextRef ContextRef,
+ const char *MangledName,
+ uint64_t Length) {
+ swift_typeref_interop_t Result;
+ FOREACH_LIBRARY {
+ swift_typeref_t Typeref = Library->Functions.typeRefForMangledTypeName(
+ Library->Context, MangledName, Length);
+ if (Typeref == 0)
+ continue;
+
+ Result.Typeref = Typeref;
+ Result.Library = LIBRARY_INDEX;
+ return Result;
+ }
+
+ Result.Typeref = 0;
+ Result.Library = 0;
+ return Result;
+}
+
+static inline swift_typeinfo_t
+swift_reflection_interop_infoForTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef) {
+ DECLARE_LIBRARY(OpaqueTypeRef.Library);
+ return Library->Functions.infoForTypeRef(Library->Context, OpaqueTypeRef.Typeref);
+}
+
+static inline swift_childinfo_t
+swift_reflection_interop_childOfTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef,
+ unsigned Index) {
+ DECLARE_LIBRARY(OpaqueTypeRef.Library);
+ return Library->Functions.childOfTypeRef(Library->Context,
+ OpaqueTypeRef.Typeref,
+ Index);
+}
+
+static inline swift_typeinfo_t
+swift_reflection_interop_infoForMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata) {
+ DECLARE_LIBRARY(Metadata.Library);
+ return Library->Functions.infoForMetadata(Library->Context, Metadata.Metadata);
+}
+
+static inline swift_childinfo_t
+swift_reflection_interop_childOfMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata,
+ unsigned Index) {
+ DECLARE_LIBRARY(Metadata.Library);
+ return Library->Functions.childOfMetadata(Library->Context, Metadata.Metadata, Index);
+}
+
+static inline swift_typeinfo_t
+swift_reflection_interop_infoForInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object) {
+ swift_typeinfo_t Result = {};
+ FOREACH_LIBRARY {
+ if (!swift_reflection_interop_libraryOwnsObject(ContextRef, Library, Object))
+ continue;
+
+ Result = Library->Functions.infoForInstance(Library->Context, Object);
+ if (Result.Kind == SWIFT_UNKNOWN)
+ continue;
+
+ return Result;
+ }
+
+ Result.Kind = SWIFT_UNKNOWN;
+ return Result;
+}
+
+static inline swift_childinfo_t
+swift_reflection_interop_childOfInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object,
+ unsigned Index) {
+ FOREACH_LIBRARY {
+ if (!swift_reflection_interop_libraryOwnsObject(ContextRef, Library, Object))
+ continue;
+
+ return Library->Functions.childOfInstance(Library->Context, Object, Index);
+ }
+
+ swift_childinfo_t Result = {};
+ Result.Kind = SWIFT_UNKNOWN;
+ return Result;
+}
+
+static inline unsigned
+swift_reflection_interop_genericArgumentCountOfTypeRef(
+ SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef) {
+ DECLARE_LIBRARY(OpaqueTypeRef.Library);
+ return Library->Functions.genericArgumentCountOfTypeRef(OpaqueTypeRef.Typeref);
+}
+
+static inline swift_typeref_interop_t
+swift_reflection_interop_genericArgumentOfTypeRef(
+ SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef,
+ unsigned Index) {
+ DECLARE_LIBRARY(OpaqueTypeRef.Library);
+ swift_typeref_interop_t Result;
+ Result.Typeref = Library->Functions.genericArgumentOfTypeRef(OpaqueTypeRef.Typeref,
+ Index);
+ Result.Library = OpaqueTypeRef.Library;
+ return Result;
+}
+
+static inline int
+swift_reflection_interop_projectExistential(SwiftReflectionInteropContextRef ContextRef,
+ swift_addr_t ExistentialAddress,
+ swift_typeref_interop_t ExistentialTypeRef,
+ swift_typeref_interop_t *OutInstanceTypeRef,
+ swift_addr_t *OutStartOfInstanceData) {
+ DECLARE_LIBRARY(ExistentialTypeRef.Library);
+ int Success = Library->Functions.projectExistential(Library->Context,
+ ExistentialAddress,
+ ExistentialTypeRef.Typeref,
+ &OutInstanceTypeRef->Typeref,
+ OutStartOfInstanceData);
+ if (!Success)
+ return 0;
+
+ OutInstanceTypeRef->Library = ExistentialTypeRef.Library;
+ return 1;
+}
+
+static inline void
+swift_reflection_interop_dumpTypeRef(SwiftReflectionInteropContextRef ContextRef,
+ swift_typeref_interop_t OpaqueTypeRef) {
+ DECLARE_LIBRARY(OpaqueTypeRef.Library);
+ Library->Functions.dumpTypeRef(OpaqueTypeRef.Typeref);
+}
+
+static inline void
+swift_reflection_interop_dumpInfoForTypeRef(
+ SwiftReflectionInteropContextRef ContextRef, swift_typeref_interop_t OpaqueTypeRef) {
+ DECLARE_LIBRARY(OpaqueTypeRef.Library);
+ Library->Functions.dumpInfoForTypeRef(Library->Context, OpaqueTypeRef.Typeref);
+}
+
+static inline void
+swift_reflection_interop_dumpInfoForMetadata(SwiftReflectionInteropContextRef ContextRef,
+ swift_metadata_interop_t Metadata) {
+ DECLARE_LIBRARY(Metadata.Library);
+ Library->Functions.dumpInfoForMetadata(Library->Context, Metadata.Metadata);
+}
+
+static inline void
+swift_reflection_interop_dumpInfoForInstance(SwiftReflectionInteropContextRef ContextRef,
+ uintptr_t Object) {
+ FOREACH_LIBRARY {
+ if (!swift_reflection_interop_libraryOwnsObject(ContextRef, Library, Object))
+ continue;
+
+ Library->Functions.dumpInfoForInstance(Library->Context, Object);
+ return;
+ }
+}
+
+static inline size_t
+swift_reflection_interop_demangle(SwiftReflectionInteropContextRef ContextRef,
+ const char *MangledName,
+ size_t Length,
+ char *OutDemangledName,
+ size_t MaxLength) {
+ FOREACH_LIBRARY {
+ return Library->Functions.demangle(MangledName, Length, OutDemangledName, MaxLength);
+ }
+ return 0;
+}
+
+#undef FOREACH_LIBRARY
+#undef LIBRARY_INDEX
+#undef DECLARE_LIBRARY
+
+/// @}
+
+#endif // defined(__APPLE__) && defined(__MACH__)
+
+#endif // SWIFT_REMOTE_MIRROR_LEGACY_INTEROP_H
+
diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInteropTypes.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInteropTypes.h
new file mode 100644
index 0000000..934bf34
--- /dev/null
+++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirrorLegacyInteropTypes.h
@@ -0,0 +1,43 @@
+//===--- SwiftRemoteMirrorLegacyInteropTypes.h - Legacy lib interop types. ------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------------===//
+///
+/// \file
+/// This header provides an interface for using multiple versions of the Swift remote
+/// mirror library to inspect processes built with different versions of Swift, or
+/// processes where different libraries are built with different versions of Swift.
+///
+//===----------------------------------------------------------------------------===//
+
+#ifndef SWIFT_REMOTE_MIRROR_LEGACY_INTEROP_TYPES_H
+#define SWIFT_REMOTE_MIRROR_LEGACY_INTEROP_TYPES_H
+
+#include "SwiftRemoteMirror.h"
+
+/// The remote representation of a Swift metada pointer as returned by
+/// interop wrappers.
+typedef struct swift_metadata_interop {
+ uintptr_t Metadata;
+ int Library;
+} swift_metadata_interop_t;
+
+/// The remote representation of a Swift typeref as returned by interop
+/// wrappers.
+typedef struct swift_typeref_interop {
+ swift_typeref_t Typeref;
+ int Library;
+} swift_typeref_interop_t;
+
+/// An opaque reflection context object.
+typedef struct SwiftReflectionInteropContext *SwiftReflectionInteropContextRef;
+
+#endif // SWIFT_REMOTE_MIRROR_LEGACY_INTEROP_TYPES_H
+
diff --git a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift
index eb98ce8..ecb24b6 100644
--- a/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift
+++ b/stdlib/private/SwiftReflectionTest/SwiftReflectionTest.swift
@@ -24,6 +24,7 @@
let RequestInstanceKind = "k"
let RequestInstanceAddress = "i"
let RequestReflectionInfos = "r"
+let RequestImages = "m"
let RequestReadBytes = "b"
let RequestSymbolAddress = "s"
let RequestStringLength = "l"
@@ -137,6 +138,21 @@
reflstr: reflstr)
}
+/// Get the TEXT segment location and size for a loaded image.
+///
+/// - Parameter i: The index of the loaded image as reported by Dyld.
+/// - Returns: The image name, address, and size.
+internal func getAddressInfoForImage(atIndex i: UInt32) ->
+ (name: String, address: UnsafeMutablePointer<UInt8>?, size: UInt) {
+ debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
+ let header = unsafeBitCast(_dyld_get_image_header(i),
+ to: UnsafePointer<MachHeader>.self)
+ let name = String(validatingUTF8: _dyld_get_image_name(i)!)!
+ var size: UInt = 0
+ let address = getsegmentdata(header, "__TEXT", &size)
+ return (name, address, size)
+}
+
internal func sendBytes<T>(from address: UnsafePointer<T>, count: Int) {
var source = address
var bytesLeft = count
@@ -194,6 +210,21 @@
}
}
+/// Send all loadedimages loaded in the current process.
+internal func sendImages() {
+ debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
+ let infos = (0..<_dyld_image_count()).map(getAddressInfoForImage)
+
+ debugLog("\(infos.count) reflection info bundles.")
+ precondition(infos.count >= 1)
+ sendValue(infos.count)
+ for (name, address, size) in infos {
+ debugLog("Sending info for \(name)")
+ sendValue(address)
+ sendValue(size)
+ }
+}
+
internal func printErrnoAndExit() {
debugLog("BEGIN \(#function)"); defer { debugLog("END \(#function)") }
let errorCString = strerror(errno)!
@@ -256,8 +287,7 @@
/// This is the main "run loop" of the test harness.
///
/// The parent will necessarily need to:
-/// - Get the addresses of all of the reflection sections for any swift dylibs
-/// that are loaded, where applicable.
+/// - Get the addresses of any swift dylibs that are loaded, where applicable.
/// - Get the address of the `instance`
/// - Get the pointer size of this process, which affects assumptions about the
/// the layout of runtime structures with pointer-sized fields.
@@ -275,6 +305,8 @@
sendValue(instanceAddress)
case String(validatingUTF8: RequestReflectionInfos)!:
sendReflectionInfos()
+ case String(validatingUTF8: RequestImages)!:
+ sendImages()
case String(validatingUTF8: RequestReadBytes)!:
sendBytes()
case String(validatingUTF8: RequestSymbolAddress)!:
diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp
index 58277cf..371df87 100644
--- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp
+++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp
@@ -16,6 +16,10 @@
#include "swift/Runtime/Unreachable.h"
#include "swift/SwiftRemoteMirror/SwiftRemoteMirror.h"
+#if defined(__APPLE__) && defined(__MACH__)
+#include <mach-o/getsect.h>
+#endif
+
using namespace swift;
using namespace swift::reflection;
using namespace swift::remote;
@@ -23,6 +27,24 @@
using NativeReflectionContext
= ReflectionContext<External<RuntimeTarget<sizeof(uintptr_t)>>>;
+struct SwiftReflectionContext {
+ NativeReflectionContext *nativeContext;
+ std::vector<std::function<void()>> freeFuncs;
+ std::vector<std::tuple<swift_addr_t, swift_addr_t>> dataSegments;
+
+ SwiftReflectionContext(MemoryReaderImpl impl) {
+ auto Reader = std::make_shared<CMemoryReader>(impl);
+ nativeContext = new NativeReflectionContext(Reader);
+ }
+
+ ~SwiftReflectionContext() {
+ delete nativeContext;
+ for (auto f : freeFuncs)
+ f();
+ }
+};
+
+
uint16_t
swift_reflection_getSupportedMetadataVersion() {
return SWIFT_REFLECTION_METADATA_VERSION;
@@ -30,42 +52,78 @@
SwiftReflectionContextRef
swift_reflection_createReflectionContext(void *ReaderContext,
- PointerSizeFunction getPointerSize,
- SizeSizeFunction getSizeSize,
- ReadBytesFunction readBytes,
- GetStringLengthFunction getStringLength,
- GetSymbolAddressFunction getSymbolAddress) {
+ uint8_t PointerSize,
+ FreeBytesFunction Free,
+ ReadBytesFunction ReadBytes,
+ GetStringLengthFunction GetStringLength,
+ GetSymbolAddressFunction GetSymbolAddress) {
+ assert((PointerSize == 4 || PointerSize == 8) && "We only support 32-bit and 64-bit.");
+ assert(PointerSize == sizeof(uintptr_t) &&
+ "We currently only support the pointer size this file was compiled with.");
+
+ auto GetSize = PointerSize == 4
+ ? [](void *){ return (uint8_t)4; }
+ : [](void *){ return (uint8_t)8; };
MemoryReaderImpl ReaderImpl {
ReaderContext,
- getPointerSize,
- getSizeSize,
- readBytes,
- getStringLength,
- getSymbolAddress
+ GetSize,
+ GetSize,
+ Free,
+ ReadBytes,
+ GetStringLength,
+ GetSymbolAddress
};
- auto Reader = std::make_shared<CMemoryReader>(ReaderImpl);
- auto Context
- = new swift::reflection::ReflectionContext<External<RuntimeTarget<sizeof(uintptr_t)>>>(Reader);
- return reinterpret_cast<SwiftReflectionContextRef>(Context);
+ return new SwiftReflectionContext(ReaderImpl);
}
void swift_reflection_destroyReflectionContext(SwiftReflectionContextRef ContextRef) {
- auto Context = reinterpret_cast<swift::reflection::ReflectionContext<InProcess> *>(ContextRef);
- delete Context;
+ delete ContextRef;
}
void
swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
swift_reflection_info_t Info) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
+
Context->addReflectionInfo(*reinterpret_cast<ReflectionInfo *>(&Info));
}
+#if defined(__APPLE__) && defined(__MACH__)
+#ifndef __LP64__
+typedef const struct mach_header MachHeader;
+#else
+typedef const struct mach_header_64 MachHeader;
+#endif
+
+template <typename Section>
+static bool findSection(MachHeader *Header, const char *Name,
+ Section &Sect) {
+ unsigned long Size;
+ auto Address = getsectiondata(Header, "__TEXT", Name, &Size);
+ if (!Address)
+ return false;
+
+ Sect.section.Begin = Address;
+ auto End = reinterpret_cast<uintptr_t>(Address) + Size;
+ Sect.section.End = reinterpret_cast<void *>(End);
+ Sect.offset = 0;
+
+ return true;
+}
+
+int
+swift_reflection_addImage(SwiftReflectionContextRef ContextRef,
+ swift_addr_t imageStart) {
+ auto Context = ContextRef->nativeContext;
+ return Context->addImage(RemoteAddress(imageStart));
+}
+#endif
+
int
swift_reflection_readIsaMask(SwiftReflectionContextRef ContextRef,
uintptr_t *outIsaMask) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto isaMask = Context->readIsaMask();
if (isaMask) {
*outIsaMask = *isaMask;
@@ -78,15 +136,31 @@
swift_typeref_t
swift_reflection_typeRefForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TR = Context->readTypeFromMetadata(Metadata);
return reinterpret_cast<swift_typeref_t>(TR);
}
+int
+swift_reflection_ownsObject(SwiftReflectionContextRef ContextRef, uintptr_t Object) {
+ auto Context = ContextRef->nativeContext;
+ return Context->ownsObject(RemoteAddress(Object));
+}
+
+uintptr_t
+swift_reflection_metadataForObject(SwiftReflectionContextRef ContextRef,
+ uintptr_t Object) {
+ auto Context = ContextRef->nativeContext;
+ auto MetadataAddress = Context->readMetadataFromInstance(Object);
+ if (!MetadataAddress)
+ return 0;
+ return *MetadataAddress;
+}
+
swift_typeref_t
swift_reflection_typeRefForInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto MetadataAddress = Context->readMetadataFromInstance(Object);
if (!MetadataAddress)
return 0;
@@ -98,7 +172,7 @@
swift_reflection_typeRefForMangledTypeName(SwiftReflectionContextRef ContextRef,
const char *MangledTypeName,
uint64_t Length) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TR = Context->readTypeFromMangledName(MangledTypeName, Length);
return reinterpret_cast<swift_typeref_t>(TR);
}
@@ -223,7 +297,7 @@
swift_typeinfo_t
swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t OpaqueTypeRef) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
auto TI = Context->getTypeInfo(TR);
return convertTypeInfo(TI);
@@ -233,7 +307,7 @@
swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t OpaqueTypeRef,
unsigned Index) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
auto *TI = Context->getTypeInfo(TR);
return convertChild(TI, Index);
@@ -242,7 +316,7 @@
swift_typeinfo_t
swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto *TI = Context->getMetadataTypeInfo(Metadata);
return convertTypeInfo(TI);
}
@@ -251,7 +325,7 @@
swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata,
unsigned Index) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto *TI = Context->getMetadataTypeInfo(Metadata);
return convertChild(TI, Index);
}
@@ -259,7 +333,7 @@
swift_typeinfo_t
swift_reflection_infoForInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto *TI = Context->getInstanceTypeInfo(Object);
return convertTypeInfo(TI);
}
@@ -268,7 +342,7 @@
swift_reflection_childOfInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object,
unsigned Index) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto *TI = Context->getInstanceTypeInfo(Object);
return convertChild(TI, Index);
}
@@ -278,7 +352,7 @@
swift_typeref_t ExistentialTypeRef,
swift_typeref_t *InstanceTypeRef,
swift_addr_t *StartOfInstanceData) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto ExistentialTR = reinterpret_cast<const TypeRef *>(ExistentialTypeRef);
auto RemoteExistentialAddress = RemoteAddress(ExistentialAddress);
const TypeRef *InstanceTR = nullptr;
@@ -307,7 +381,7 @@
void swift_reflection_dumpInfoForTypeRef(SwiftReflectionContextRef ContextRef,
swift_typeref_t OpaqueTypeRef) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
auto TI = Context->getTypeInfo(TR);
if (TI == nullptr) {
@@ -319,7 +393,7 @@
void swift_reflection_dumpInfoForMetadata(SwiftReflectionContextRef ContextRef,
uintptr_t Metadata) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TI = Context->getMetadataTypeInfo(Metadata);
if (TI == nullptr) {
std::cout << "<null type info>\n";
@@ -330,7 +404,7 @@
void swift_reflection_dumpInfoForInstance(SwiftReflectionContextRef ContextRef,
uintptr_t Object) {
- auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
+ auto Context = ContextRef->nativeContext;
auto TI = Context->getInstanceTypeInfo(Object);
if (TI == nullptr) {
std::cout << "<null type info>\n";
diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp
index e80b8fe..c88912d 100644
--- a/tools/swift-reflection-dump/swift-reflection-dump.cpp
+++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp
@@ -13,6 +13,10 @@
// binaries.
//===----------------------------------------------------------------------===//
+// FIXME davidino: this needs to be included first to avoid textual
+// replacement. It's silly and needs to be fixed.
+#include "llvm/Object/MachO.h"
+
#include "swift/ABI/MetadataValues.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Basic/LLVMInitialize.h"
@@ -20,7 +24,6 @@
#include "swift/Reflection/TypeRef.h"
#include "swift/Reflection/TypeRefBuilder.h"
#include "llvm/Object/Archive.h"
-#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -191,15 +194,12 @@
return false;
}
- bool readBytes(RemoteAddress address, uint8_t *dest,
- uint64_t size) override {
+ ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
if (!isAddressValid(address, size))
- return false;
+ return ReadBytesResult(nullptr, [](const void *){});
// TODO: Account for offset in ELF binaries
- auto src = (const void *)address.getAddressData();
- memcpy(dest, (const void*)src, size);
- return true;
+ return ReadBytesResult((const void *)address.getAddressData(), [](const void *) {});
}
bool readString(RemoteAddress address, std::string &dest) override {
@@ -246,12 +246,12 @@
objectFile = objectOwner.get();
}
- context.addReflectionInfo(findReflectionInfo(objectFile));
-
// Retain the objects that own section memory
binaryOwners.push_back(std::move(binaryOwner));
objectOwners.push_back(std::move(objectOwner));
objectFiles.push_back(objectFile);
+
+ context.addReflectionInfo(findReflectionInfo(objectFile));
}
switch (action) {
diff --git a/tools/swift-reflection-test/messages.h b/tools/swift-reflection-test/messages.h
index 436c86b..ef61b97 100644
--- a/tools/swift-reflection-test/messages.h
+++ b/tools/swift-reflection-test/messages.h
@@ -13,6 +13,7 @@
static const char *REQUEST_INSTANCE_KIND = "k\n";
static const char *REQUEST_INSTANCE_ADDRESS = "i\n";
static const char *REQUEST_REFLECTION_INFO = "r\n";
+static const char *REQUEST_IMAGES = "m\n";
static const char *REQUEST_READ_BYTES = "b\n";
static const char *REQUEST_SYMBOL_ADDRESS = "s\n";
static const char *REQUEST_STRING_LENGTH = "l\n";
diff --git a/tools/swift-reflection-test/swift-reflection-test.c b/tools/swift-reflection-test/swift-reflection-test.c
index 283919a..e0652f3 100644
--- a/tools/swift-reflection-test/swift-reflection-test.c
+++ b/tools/swift-reflection-test/swift-reflection-test.c
@@ -29,17 +29,17 @@
#include <string.h>
#include <unistd.h>
+typedef struct PipeMemoryReader {
+ int to_child[2];
+ int from_child[2];
+} PipeMemoryReader;
+
typedef struct RemoteSection {
uintptr_t StartAddress;
uintptr_t Size;
uintptr_t EndAddress;
} RemoteSection;
-typedef struct PipeMemoryReader {
- int to_child[2];
- int from_child[2];
-} PipeMemoryReader;
-
typedef struct RemoteReflectionInfo {
RemoteSection fieldmd;
RemoteSection assocty;
@@ -161,11 +161,6 @@
}
static
-uint8_t PipeMemoryReader_getSizeSize(void *Context) {
- return sizeof(size_t);
-}
-
-static
void PipeMemoryReader_collectBytesFromPipe(const PipeMemoryReader *Reader,
void *Dest, size_t Size) {
int ReadFD = PipeMemoryReader_getParentReadFD(Reader);
@@ -183,9 +178,15 @@
}
}
+static void PipeMemoryReader_freeBytes(void *reader_context, const void *bytes,
+ void *context) {
+ free((void *)bytes);
+}
+
static
-int PipeMemoryReader_readBytes(void *Context, swift_addr_t Address, void *Dest,
- uint64_t Size) {
+const void *PipeMemoryReader_readBytes(void *Context, swift_addr_t Address,
+ uint64_t Size,
+ void **outFreeContext) {
const PipeMemoryReader *Reader = (const PipeMemoryReader *)Context;
uintptr_t TargetAddress = Address;
size_t TargetSize = (size_t)Size;
@@ -193,8 +194,13 @@
write(WriteFD, REQUEST_READ_BYTES, 2);
write(WriteFD, &TargetAddress, sizeof(TargetAddress));
write(WriteFD, &TargetSize, sizeof(size_t));
- PipeMemoryReader_collectBytesFromPipe(Reader, Dest, Size);
- return 1;
+
+ void *Buf = malloc(Size);
+ PipeMemoryReader_collectBytesFromPipe(Reader, Buf, Size);
+
+ *outFreeContext = NULL;
+
+ return Buf;
}
static
@@ -259,6 +265,32 @@
return RS;
}
+#if defined(__APPLE__) && defined(__MACH__)
+static void
+PipeMemoryReader_receiveImages(SwiftReflectionContextRef RC,
+ const PipeMemoryReader *Reader) {
+ int WriteFD = PipeMemoryReader_getParentWriteFD(Reader);
+ write(WriteFD, REQUEST_IMAGES, 2);
+ size_t NumReflectionInfos;
+ PipeMemoryReader_collectBytesFromPipe(Reader, &NumReflectionInfos,
+ sizeof(NumReflectionInfos));
+
+ if (NumReflectionInfos == 0)
+ return;
+
+ struct { uintptr_t Start, Size; } *Images;
+ Images = calloc(NumReflectionInfos, sizeof(*Images));
+ PipeMemoryReader_collectBytesFromPipe(Reader, Images,
+ NumReflectionInfos * sizeof(*Images));
+
+ for (size_t i = 0; i < NumReflectionInfos; ++i) {
+ swift_reflection_addImage(RC, Images[i].Start);
+ }
+
+ free(Images);
+}
+#endif
+
static void
PipeMemoryReader_receiveReflectionInfo(SwiftReflectionContextRef RC,
const PipeMemoryReader *Reader) {
@@ -408,8 +440,8 @@
close(PipeMemoryReader_getChildWriteFD(&Pipe));
SwiftReflectionContextRef RC = swift_reflection_createReflectionContext(
(void*)&Pipe,
- PipeMemoryReader_getPointerSize,
- PipeMemoryReader_getSizeSize,
+ sizeof(void *),
+ PipeMemoryReader_freeBytes,
PipeMemoryReader_readBytes,
PipeMemoryReader_getStringLength,
PipeMemoryReader_getSymbolAddress);
@@ -418,7 +450,11 @@
if (PointerSize != sizeof(uintptr_t))
errorAndExit("Child process had unexpected architecture");
+#if defined(__APPLE__) && defined(__MACH__)
+ PipeMemoryReader_receiveImages(RC, &Pipe);
+#else
PipeMemoryReader_receiveReflectionInfo(RC, &Pipe);
+#endif
while (1) {
InstanceKind Kind = PipeMemoryReader_receiveInstanceKind(&Pipe);
diff --git a/unittests/Reflection/RemoteMirrorInterop/test.m b/unittests/Reflection/RemoteMirrorInterop/test.m
new file mode 100644
index 0000000..22bcb95
--- /dev/null
+++ b/unittests/Reflection/RemoteMirrorInterop/test.m
@@ -0,0 +1,131 @@
+//===--- test.m - SwiftRemoteMirrorLegacyInterop test program. ------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2018 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
+//
+//===----------------------------------------------------------------------------===//
+///
+/// \file
+/// This is a test program that exercises the SwiftRemoteMirrorLegacyInterop header.
+///
+//===----------------------------------------------------------------------------===//
+
+#import <dlfcn.h>
+#import <Foundation/Foundation.h>
+#import <mach/mach.h>
+#import <mach-o/dyld.h>
+
+#import "SwiftRemoteMirrorLegacyInterop.h"
+
+
+void *Load(char *path) {
+ void *Handle = dlopen(path, RTLD_LAZY);
+ if (Handle == NULL) {
+ fprintf(stderr, "loading %s: %s\n", path, dlerror());
+ exit(1);
+ }
+ return Handle;
+}
+
+void Free(void *reader_context, const void *bytes, void *context) {
+ assert(reader_context == (void *)0xdeadbeef);
+ assert(context == (void *)0xfeedface);
+ free((void *)bytes);
+}
+
+const void *ReadBytes(void *context, swift_addr_t address, uint64_t size,
+ void **outFreeContext) {
+ assert(context == (void *)0xdeadbeef);
+ *outFreeContext = (void *)0xfeedface;
+
+ void *Buffer = malloc(size);
+ vm_size_t InOutSize = size;
+ kern_return_t result = vm_read_overwrite(mach_task_self(), address, size, (vm_address_t)Buffer, &InOutSize);
+ if (result != KERN_SUCCESS) abort();
+ if (InOutSize != size) abort();
+ return Buffer;
+}
+
+uint64_t GetStringLength(void *context, swift_addr_t address) {
+ assert(context == (void *)0xdeadbeef);
+ return strlen((char *)address);
+}
+
+swift_addr_t GetSymbolAddress(void *context, const char *name, uint64_t name_length) {
+ assert(context == (void *)0xdeadbeef);
+ return (swift_addr_t)dlsym(RTLD_DEFAULT, name);
+}
+
+int main(int argc, char **argv) {
+ if (argc != 4) {
+ fprintf(stderr, "usage: %s <libtestswift.dylib> <libswiftRemoteMirror4.dylib> "
+ "<libswiftRemoteMirror5.dylib>\n",
+ argv[0]);
+ exit(1);
+ }
+
+ char *TestLibPath = argv[1];
+ char *Mirror4Path = argv[2];
+ char *Mirror5Path = argv[3];
+
+ void *TestHandle = Load(TestLibPath);
+ intptr_t (*Test)(void) = dlsym(TestHandle, "test");
+
+ uintptr_t Obj = Test();
+
+ void *Mirror4Handle = Mirror4Path[0] == '-' ? NULL : Load(Mirror4Path);
+ void *Mirror5Handle = Mirror5Path[0] == '-' ? NULL : Load(Mirror5Path);
+ SwiftReflectionInteropContextRef Context =
+ swift_reflection_interop_createReflectionContext(
+ (void *)0xdeadbeef,
+ Mirror5Handle,
+ Mirror4Handle,
+ sizeof(void *),
+ Free,
+ ReadBytes,
+ GetStringLength,
+ GetSymbolAddress);
+ if (Context == NULL) {
+ fprintf(stderr, "Unable to create a reflection context!\n");
+ exit(1);
+ }
+
+ uint32_t ImageCount = _dyld_image_count();
+ for (uint32_t i = 0; i < ImageCount; i++) {
+ swift_addr_t Image = (swift_addr_t)_dyld_get_image_header(i);
+ swift_reflection_interop_addImage(Context, Image);
+ }
+
+ swift_typeref_interop_t Type = swift_reflection_interop_typeRefForInstance(Context, Obj);
+ if (Type.Typeref != 0) {
+ swift_typeinfo_t TypeInfo = swift_reflection_interop_infoForTypeRef(Context, Type);
+ printf("Kind:%u Size:%u Alignment:%u Stride:%u NumFields:%u\n",
+ TypeInfo.Kind, TypeInfo.Size, TypeInfo.Alignment, TypeInfo.Stride,
+ TypeInfo.NumFields);
+ } else {
+ printf("Unknown typeref!\n");
+ }
+
+ swift_typeinfo_t TypeInfo = swift_reflection_interop_infoForInstance(Context, Obj);
+ if (TypeInfo.Kind != SWIFT_UNKNOWN) {
+ printf("Kind:%u Size:%u Alignment:%u Stride:%u NumFields:%u\n",
+ TypeInfo.Kind, TypeInfo.Size, TypeInfo.Alignment, TypeInfo.Stride,
+ TypeInfo.NumFields);
+
+ for (unsigned i = 0; i < TypeInfo.NumFields; ++i) {
+ swift_childinfo_t ChildInfo = swift_reflection_interop_childOfInstance(
+ Context, Obj, i);
+ printf(" [%u]: %s Offset:%u Kind:%u\n", i,
+ ChildInfo.Name, ChildInfo.Offset, ChildInfo.Kind);
+ }
+ } else {
+ printf("Unknown typeinfo!\n");
+ }
+
+ swift_reflection_interop_destroyReflectionContext(Context);
+}
diff --git a/unittests/Reflection/RemoteMirrorInterop/test.sh b/unittests/Reflection/RemoteMirrorInterop/test.sh
new file mode 100755
index 0000000..849a9e2
--- /dev/null
+++ b/unittests/Reflection/RemoteMirrorInterop/test.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# Exercise the SwiftRemoteMirrorLegacyInterop API. This requires a build
+# of an old (circa 4.0.3) version of Swift as well as the current one.
+# It then builds Swift code using the old and new compilers, and
+# exercises the Interop API using the old and new remote mirrors
+# libraries.
+
+set -euo pipefail
+
+if [[ $# -ne 4 ]]; then
+ echo -n "Usage: $0 <swiftc4-path> <swiftc5-path> "
+ echo "<libswiftRemoteMirror4.dylib> <libswiftRemoteMirror5.dylib>"
+ exit 1
+fi
+
+swiftc4="$1"
+swiftc5="$2"
+mirrorlib4="$3"
+mirrorlib5="$4"
+
+SDK=`xcrun --show-sdk-path`
+
+cd `dirname $0`
+
+"$swiftc4" -sdk "$SDK" -emit-library test4.swift -o /tmp/libtest4.dylib
+"$swiftc5" -sdk "$SDK" -emit-library test5.swift -o /tmp/libtest5.dylib
+
+clang -framework Foundation -I ../../../include/swift/SwiftRemoteMirror \
+ -o /tmp/test -g test.m
+
+
+echo "Testing 4 with both mirror libs"
+/tmp/test /tmp/libtest4.dylib "$mirrorlib4" "$mirrorlib5"
+echo ""
+
+echo "Testing 4 with only mirror lib 5"
+/tmp/test /tmp/libtest4.dylib "-" "$mirrorlib5"
+echo ""
+
+echo "Testing 4 with only mirror lib 4"
+/tmp/test /tmp/libtest4.dylib "$mirrorlib4" "-"
+echo ""
+
+echo "Testing 4 with no mirror libs"
+/tmp/test /tmp/libtest4.dylib "-" "-" || true
+echo ""
+
+echo "Testing 5 with both mirror libs"
+/tmp/test /tmp/libtest5.dylib "$mirrorlib4" "$mirrorlib5"
+echo ""
+
+echo "Testing 5 with only mirror lib 5"
+/tmp/test /tmp/libtest5.dylib "-" "$mirrorlib5"
+echo ""
+
+# Not supported (yet?)
+#echo "Testing 5 with only mirror lib 4"
+#/tmp/test /tmp/libtest5.dylib "$mirrorlib4" "-"
+#echo ""
+
+echo "Testing 5 with no mirror libs"
+/tmp/test /tmp/libtest5.dylib "-" "-" || true
diff --git a/unittests/Reflection/RemoteMirrorInterop/test4.swift b/unittests/Reflection/RemoteMirrorInterop/test4.swift
new file mode 100644
index 0000000..da7959c
--- /dev/null
+++ b/unittests/Reflection/RemoteMirrorInterop/test4.swift
@@ -0,0 +1,11 @@
+@_cdecl("test")
+public func test() -> UInt {
+ return unsafeBitCast(c, to: UInt.self)
+}
+
+class C {
+ let x = "123"
+ let y = 456
+}
+
+let c = C()
diff --git a/unittests/Reflection/RemoteMirrorInterop/test5.swift b/unittests/Reflection/RemoteMirrorInterop/test5.swift
new file mode 100644
index 0000000..da7959c
--- /dev/null
+++ b/unittests/Reflection/RemoteMirrorInterop/test5.swift
@@ -0,0 +1,11 @@
+@_cdecl("test")
+public func test() -> UInt {
+ return unsafeBitCast(c, to: UInt.self)
+}
+
+class C {
+ let x = "123"
+ let y = 456
+}
+
+let c = C()