From 84e71b8d7a9155a27f607f67170d88eabbdb47ea Mon Sep 17 00:00:00 2001 From: "Kuba (Brecka) Mracek" Date: Fri, 16 Mar 2018 14:54:04 -0700 Subject: [PATCH] Change the RemoteMirror API to have extensible data layout callback (#15291) * Change the RemoteMirror API to have extensible data layout callback * Use DLQ_Get prefix on DataLayoutQueryType enum values * Simplify MemoryReaderImpl and synthesize minimalDataLayoutQueryFunction --- include/swift/Remote/CMemoryReader.h | 25 +++-- include/swift/Remote/InProcessMemoryReader.h | 20 +++- include/swift/Remote/MemoryReader.h | 8 +- .../SwiftRemoteMirror/MemoryReaderInterface.h | 94 ++++++++++--------- .../SwiftRemoteMirror/SwiftRemoteMirror.h | 10 ++ .../SwiftRemoteMirror/SwiftRemoteMirror.cpp | 41 ++++++-- .../swift-reflection-dump.cpp | 22 ++++- .../swift-reflection-test.c | 32 +++++-- 8 files changed, 170 insertions(+), 82 deletions(-) diff --git a/include/swift/Remote/CMemoryReader.h b/include/swift/Remote/CMemoryReader.h index a1a168ef05e..f7575fa6f9c 100644 --- a/include/swift/Remote/CMemoryReader.h +++ b/include/swift/Remote/CMemoryReader.h @@ -21,6 +21,17 @@ #include "swift/SwiftRemoteMirror/MemoryReaderInterface.h" #include "swift/Remote/MemoryReader.h" +struct MemoryReaderImpl { + // Opaque pointer passed to all the callback functions. + void *reader_context; + + QueryDataLayoutFunction queryDataLayout; + FreeBytesFunction free; + ReadBytesFunction readBytes; + GetStringLengthFunction getStringLength; + GetSymbolAddressFunction getSymbolAddress; +}; + namespace swift { namespace remote { @@ -31,19 +42,15 @@ class CMemoryReader final : public MemoryReader { public: CMemoryReader(MemoryReaderImpl Impl) : Impl(Impl) { - assert(this->Impl.getPointerSize && "No getPointerSize implementation"); + assert(this->Impl.queryDataLayout && "No queryDataLayout implementation"); assert(this->Impl.getStringLength && "No stringLength implementation"); assert(this->Impl.readBytes && "No readBytes implementation"); - assert(this->Impl.getPointerSize(this->Impl.reader_context) != 0 && - "Invalid target pointer size"); } - uint8_t getPointerSize() override { - return Impl.getPointerSize(Impl.reader_context); - } - - uint8_t getSizeSize() override { - return Impl.getSizeSize(Impl.reader_context); + bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, + void *outBuffer) override { + return Impl.queryDataLayout(Impl.reader_context, type, inBuffer, + outBuffer) != 0; } RemoteAddress getSymbolAddress(const std::string &name) override { diff --git a/include/swift/Remote/InProcessMemoryReader.h b/include/swift/Remote/InProcessMemoryReader.h index e631871b8d1..1163f67ef42 100644 --- a/include/swift/Remote/InProcessMemoryReader.h +++ b/include/swift/Remote/InProcessMemoryReader.h @@ -27,12 +27,22 @@ namespace remote { /// An implementation of MemoryReader which simply reads from the current /// address space. class InProcessMemoryReader final : public MemoryReader { - uint8_t getPointerSize() override { - return sizeof(uintptr_t); - } + bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, + void *outBuffer) override { + switch (type) { + case DLQ_GetPointerSize: { + auto result = static_cast(outBuffer); + *result = sizeof(void *); + return true; + } + case DLQ_GetSizeSize: { + auto result = static_cast(outBuffer); + *result = sizeof(size_t); + return true; + } + } - uint8_t getSizeSize() override { - return sizeof(size_t); + return false; } RemoteAddress getSymbolAddress(const std::string &name) override; diff --git a/include/swift/Remote/MemoryReader.h b/include/swift/Remote/MemoryReader.h index 038ffab6614..6907030c50d 100644 --- a/include/swift/Remote/MemoryReader.h +++ b/include/swift/Remote/MemoryReader.h @@ -19,6 +19,7 @@ #define SWIFT_REMOTE_MEMORYREADER_H #include "swift/Remote/RemoteAddress.h" +#include "swift/SwiftRemoteMirror/MemoryReaderInterface.h" #include #include @@ -38,11 +39,8 @@ public: /// A convenient name for the return type from readBytes. using ReadBytesResult = std::unique_ptr>; - /// Return the size of an ordinary pointer in the remote process, in bytes. - virtual uint8_t getPointerSize() = 0; - - /// Return the size of size_t in the remote process, in bytes. - virtual uint8_t getSizeSize() = 0; + virtual bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, + void *outBuffer) = 0; /// Look up the given public symbol name in the remote process. virtual RemoteAddress getSymbolAddress(const std::string &name) = 0; diff --git a/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h b/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h index f78fc791bf3..93cd4293eaf 100644 --- a/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h +++ b/include/swift/SwiftRemoteMirror/MemoryReaderInterface.h @@ -32,66 +32,70 @@ extern "C" { // in the system library, so we use 'swift_addr_t'. typedef uint64_t swift_addr_t; +/// The following callbacks provide "reader_context", which is an opaque context +/// provided in swift_reflection_createReflectionContext. + +/// Free memory returned from readBytes. May be NULL if memory never needs to be freed. typedef void (*FreeBytesFunction)(void *reader_context, const void *bytes, void *context); +/// Get the size in bytes of the target's pointer type. typedef uint8_t (*PointerSizeFunction)(void *reader_context); + +/// Get the size in bytes of the target's size type. typedef uint8_t (*SizeSizeFunction)(void *reader_context); + +/// Read a sequence of bytes at an address in the target. +/// +/// \param address the address in the target address space +/// \param size the number of bytes to read +/// \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. typedef const void *(*ReadBytesFunction)(void *reader_context, swift_addr_t address, uint64_t size, void **outFreeContext); + +/// Get the string length at the given address. +/// +/// This scan always occurs in a read-only data section. If the scan +/// would go beyond the section boundary, a length of 0 should be +/// returned. +/// +/// \param address the address in the target address space +/// \returns The length of the string or 0 if the scan was unsuccessful. typedef uint64_t (*GetStringLengthFunction)(void *reader_context, swift_addr_t address); + +/// Get the address of a symbol in the target address space. +/// +/// \returns true if the lookup was successful. typedef swift_addr_t (*GetSymbolAddressFunction)(void *reader_context, const char *name, uint64_t name_length); -typedef struct MemoryReaderImpl { - /// An opaque context that the implementor can specify to - /// be passed to each of the APIs below. - void *reader_context; +typedef enum { + /// The query should ignore inBuffer, and treat outBuffer as uint8_t* which + /// should be populated with the size of an ordinary pointer in the remote + /// process, in bytes. + DLQ_GetPointerSize, - /// Get the size in bytes of the target's pointer type. - PointerSizeFunction getPointerSize; + /// The query should ignore inBuffer, and treat outBuffer as uint8_t* which + /// should be populated with the size of size_t in the remote process, in + /// bytes. + DLQ_GetSizeSize, +} DataLayoutQueryType; - /// 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" - - /// Read a sequence of bytes at an address in the target. - /// - /// \param address the address in the target address space - /// \param size the number of bytes to read - /// \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. - /// - /// This scan always occurs in a read-only data section. If the scan - /// would go beyond the section boundary, a length of 0 should be - /// returned. - /// - /// \param address the address in the target address space - /// \returns The length of the string or 0 if the scan was unsuccessful. - GetStringLengthFunction getStringLength; - - /// Get the address of a symbol in the target address space. - /// - /// \returns true if the lookup was successful. - GetSymbolAddressFunction getSymbolAddress; - -#pragma clang diagnostic pop - -} MemoryReaderImpl; +/// Data layout query function, which returns answers based on query types (from +/// the DataLayoutQueryType enum). The meaning of the input and output buffer +/// is defined by the type of the query. Unknown requests should be handled by +/// returning 0. +/// +/// \returns 0 on error, non-zero on success. +typedef int (*QueryDataLayoutFunction)(void *reader_context, + DataLayoutQueryType type, void *inBuffer, + void *outBuffer); #ifdef __cplusplus } // extern "C" diff --git a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h index 345936214c0..d1fafeb9dc9 100644 --- a/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h +++ b/include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h @@ -51,6 +51,16 @@ swift_reflection_createReflectionContext(void *ReaderContext, GetStringLengthFunction GetStringLength, GetSymbolAddressFunction GetSymbolAddress); +/// \returns An opaque reflection context. +SWIFT_REMOTE_MIRROR_LINKAGE +SwiftReflectionContextRef +swift_reflection_createReflectionContextWithDataLayout(void *ReaderContext, + QueryDataLayoutFunction DataLayout, + FreeBytesFunction Free, + ReadBytesFunction ReadBytes, + GetStringLengthFunction GetStringLength, + GetSymbolAddressFunction GetSymbolAddress); + /// Destroys an opaque reflection context. SWIFT_REMOTE_MIRROR_LINKAGE void diff --git a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp index 371df87604b..6bd5c7b6d62 100644 --- a/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp +++ b/stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp @@ -50,6 +50,18 @@ swift_reflection_getSupportedMetadataVersion() { return SWIFT_REFLECTION_METADATA_VERSION; } +template +static int minimalDataLayoutQueryFunction(void *ReaderContext, + DataLayoutQueryType type, + void *inBuffer, void *outBuffer) { + if (type == DLQ_GetPointerSize || type == DLQ_GetSizeSize) { + auto result = static_cast(outBuffer); + *result = WordSize; + return 1; + } + return 0; +} + SwiftReflectionContextRef swift_reflection_createReflectionContext(void *ReaderContext, uint8_t PointerSize, @@ -60,14 +72,31 @@ swift_reflection_createReflectionContext(void *ReaderContext, 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; }; + + auto *DataLayout = PointerSize == 4 ? minimalDataLayoutQueryFunction<4> + : minimalDataLayoutQueryFunction<8>; MemoryReaderImpl ReaderImpl { ReaderContext, - GetSize, - GetSize, + DataLayout, + Free, + ReadBytes, + GetStringLength, + GetSymbolAddress + }; + + return new SwiftReflectionContext(ReaderImpl); +} + +SwiftReflectionContextRef +swift_reflection_createReflectionContextWithDataLayout(void *ReaderContext, + QueryDataLayoutFunction DataLayout, + FreeBytesFunction Free, + ReadBytesFunction ReadBytes, + GetStringLengthFunction GetStringLength, + GetSymbolAddressFunction GetSymbolAddress) { + MemoryReaderImpl ReaderImpl { + ReaderContext, + DataLayout, Free, ReadBytes, GetStringLength, diff --git a/tools/swift-reflection-dump/swift-reflection-dump.cpp b/tools/swift-reflection-dump/swift-reflection-dump.cpp index 3e3579a86d8..8827e50135f 100644 --- a/tools/swift-reflection-dump/swift-reflection-dump.cpp +++ b/tools/swift-reflection-dump/swift-reflection-dump.cpp @@ -161,12 +161,24 @@ public: { } - uint8_t getPointerSize() override { - return sizeof(uintptr_t); - } - uint8_t getSizeSize() override { - return sizeof(size_t); + bool queryDataLayout(DataLayoutQueryType type, void *inBuffer, + void *outBuffer) override { + switch (type) { + case DLQ_GetPointerSize: { + auto result = static_cast(outBuffer); + *result = sizeof(void *); + return true; + } + case DLQ_GetSizeSize: { + auto result = static_cast(outBuffer); + *result = sizeof(size_t); + return true; + } + } + + return false; } + RemoteAddress getSymbolAddress(const std::string &name) override { for (auto &object : ObjectFiles) { for (auto &symbol : object->symbols()) { diff --git a/tools/swift-reflection-test/swift-reflection-test.c b/tools/swift-reflection-test/swift-reflection-test.c index e0652f3d84c..3df286735aa 100644 --- a/tools/swift-reflection-test/swift-reflection-test.c +++ b/tools/swift-reflection-test/swift-reflection-test.c @@ -178,6 +178,25 @@ void PipeMemoryReader_collectBytesFromPipe(const PipeMemoryReader *Reader, } } +static int PipeMemoryReader_queryDataLayout(void *Context, + DataLayoutQueryType type, + void *inBuffer, void *outBuffer) { + switch (type) { + case DLQ_GetPointerSize: { + uint8_t *result = (uint8_t *)outBuffer; + *result = sizeof(void *); + return 1; + } + case DLQ_GetSizeSize: { + uint8_t *result = (uint8_t *)outBuffer; + *result = sizeof(size_t); + return 1; + } + } + + return 0; +} + static void PipeMemoryReader_freeBytes(void *reader_context, const void *bytes, void *context) { free((void *)bytes); @@ -438,13 +457,12 @@ int doDumpHeapInstance(const char *BinaryFilename) { default: { // Parent close(PipeMemoryReader_getChildReadFD(&Pipe)); close(PipeMemoryReader_getChildWriteFD(&Pipe)); - SwiftReflectionContextRef RC = swift_reflection_createReflectionContext( - (void*)&Pipe, - sizeof(void *), - PipeMemoryReader_freeBytes, - PipeMemoryReader_readBytes, - PipeMemoryReader_getStringLength, - PipeMemoryReader_getSymbolAddress); + SwiftReflectionContextRef RC = + swift_reflection_createReflectionContextWithDataLayout( + (void *)&Pipe, PipeMemoryReader_queryDataLayout, + PipeMemoryReader_freeBytes, PipeMemoryReader_readBytes, + PipeMemoryReader_getStringLength, + PipeMemoryReader_getSymbolAddress); uint8_t PointerSize = PipeMemoryReader_getPointerSize((void*)&Pipe); if (PointerSize != sizeof(uintptr_t))