[RemoteMirrors] Change MemoryReader::readBytes to return a unique_ptr instead of a tuple so that the destructor handles freeing the memory.

This commit is contained in:
Mike Ash
2018-03-02 12:05:36 -05:00
parent 1434fce417
commit 553ef86a4b
5 changed files with 55 additions and 76 deletions

View File

@@ -34,6 +34,7 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <utility>
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
#ifndef __LP64__ #ifndef __LP64__
@@ -75,7 +76,9 @@ class ReflectionContext
std::unordered_map<typename super::StoredPointer, const TypeInfo *> Cache; std::unordered_map<typename super::StoredPointer, const TypeInfo *> Cache;
std::vector<std::function<void()>> freeFuncs; /// 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; std::vector<std::tuple<RemoteAddress, RemoteAddress>> dataSegments;
public: public:
@@ -95,11 +98,6 @@ public:
ReflectionContext(const ReflectionContext &other) = delete; ReflectionContext(const ReflectionContext &other) = delete;
ReflectionContext &operator=(const ReflectionContext &other) = delete; ReflectionContext &operator=(const ReflectionContext &other) = delete;
~ReflectionContext() {
for (auto f : freeFuncs)
f();
}
MemoryReader &getReader() { MemoryReader &getReader() {
return *this->Reader; return *this->Reader;
} }
@@ -115,50 +113,38 @@ public:
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
bool addImage(RemoteAddress ImageStart) { bool addImage(RemoteAddress ImageStart) {
const void *Buf; auto Buf = this->getReader().readBytes(ImageStart, sizeof(MachHeader));
std::function<void()> FreeFunc; if (!Buf)
std::tie(Buf, FreeFunc) =
this->getReader().readBytes(ImageStart, sizeof(MachHeader));
if (Buf == nullptr)
return false; return false;
auto Header = reinterpret_cast<MachHeader *>(Buf); auto Header = reinterpret_cast<MachHeader *>(Buf.get());
if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) { if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) {
FreeFunc();
return false; return false;
} }
auto Length = Header->sizeofcmds; auto Length = Header->sizeofcmds;
FreeFunc();
// Read the commands. // Read the commands.
std::tie(Buf, FreeFunc) = this->getReader().readBytes(ImageStart, Length); Buf = this->getReader().readBytes(ImageStart, Length);
if (!Buf)
if (Buf == nullptr)
return false; return false;
// Find the TEXT segment and figure out where the end is. // Find the TEXT segment and figure out where the end is.
Header = reinterpret_cast<MachHeader *>(Buf); Header = reinterpret_cast<MachHeader *>(Buf.get());
unsigned long TextSize; unsigned long TextSize;
auto *TextSegment = getsegmentdata(Header, "__TEXT", &TextSize); auto *TextSegment = getsegmentdata(Header, "__TEXT", &TextSize);
if (TextSegment == nullptr) { if (TextSegment == nullptr)
FreeFunc();
return false; return false;
}
auto TextEnd = auto TextEnd =
TextSegment - reinterpret_cast<const uint8_t *>(Buf) + TextSize; TextSegment - reinterpret_cast<const uint8_t *>(Buf.get()) + TextSize;
FreeFunc();
// Read everything including the TEXT segment. // Read everything including the TEXT segment.
std::tie(Buf, FreeFunc) = this->getReader().readBytes(ImageStart, TextEnd); Buf = this->getReader().readBytes(ImageStart, TextEnd);
if (!Buf)
if (Buf == nullptr)
return false; return false;
// Read all the metadata parts. // Read all the metadata parts.
Header = reinterpret_cast<MachHeader *>(Buf); Header = reinterpret_cast<MachHeader *>(Buf.get());
// The docs say "not all sections may be present." We'll succeed if ANY of // 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. // them are present. Not sure if that's the right thing to do.
@@ -173,12 +159,10 @@ public:
bool success = FieldMd.second || AssocTyMd.second || BuiltinTyMd.second || bool success = FieldMd.second || AssocTyMd.second || BuiltinTyMd.second ||
CaptureMd.second || TyperefMd.second || ReflStrMd.second; CaptureMd.second || TyperefMd.second || ReflStrMd.second;
if (!success) { if (!success)
FreeFunc(); return false;
return 0;
}
auto LocalStartAddress = reinterpret_cast<uintptr_t>(Buf); auto LocalStartAddress = reinterpret_cast<uintptr_t>(Buf.get());
auto RemoteStartAddress = auto RemoteStartAddress =
reinterpret_cast<uint64_t>(ImageStart.getAddressData()); reinterpret_cast<uint64_t>(ImageStart.getAddressData());
@@ -194,17 +178,18 @@ public:
this->addReflectionInfo(info); this->addReflectionInfo(info);
freeFuncs.push_back(FreeFunc);
unsigned long DataSize; unsigned long DataSize;
auto *DataSegment = getsegmentdata(Header, "__DATA", &DataSize); auto *DataSegment = getsegmentdata(Header, "__DATA", &DataSize);
if (DataSegment != nullptr) { if (DataSegment != nullptr) {
auto DataSegmentStart = DataSegment - reinterpret_cast<const uint8_t *>(Buf) auto DataSegmentStart = DataSegment - reinterpret_cast<const uint8_t *>(Buf.get())
+ ImageStart.getAddressData(); + ImageStart.getAddressData();
auto DataSegmentEnd = DataSegmentStart + DataSize; auto DataSegmentEnd = DataSegmentStart + DataSize;
dataSegments.push_back(std::make_tuple(RemoteAddress(DataSegmentStart), dataSegments.push_back(std::make_tuple(RemoteAddress(DataSegmentStart),
RemoteAddress(DataSegmentEnd))); RemoteAddress(DataSegmentEnd)));
} }
savedBuffers.push_back(std::move(Buf));
return true; return true;
} }
#endif // defined(__APPLE__) && defined(__MACH__) #endif // defined(__APPLE__) && defined(__MACH__)

View File

@@ -62,31 +62,26 @@ public:
if (!length) if (!length)
return false; return false;
const void *ptr; auto Buf = readBytes(address, length);
std::function<void()> freeFunc; if (!Buf)
std::tie(ptr, freeFunc) = readBytes(address, length);
if (ptr != nullptr) {
dest = std::string(reinterpret_cast<const char *>(ptr), length);
freeFunc();
return true;
} else {
return false; return false;
}
dest = std::string(reinterpret_cast<const char *>(Buf.get()), length);
return true;
} }
std::tuple<const void *, std::function<void()>> ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
readBytes(RemoteAddress address, uint64_t size) override {
void *FreeContext; void *FreeContext;
auto Ptr = Impl.readBytes(Impl.reader_context, address.getAddressData(), size, auto Ptr = Impl.readBytes(Impl.reader_context, address.getAddressData(), size,
&FreeContext); &FreeContext);
auto Free = Impl.free; auto Free = Impl.free;
if (Free == nullptr) if (Free == nullptr)
return std::make_tuple(Ptr, []{}); return ReadBytesResult(Ptr, [](const void *) {});
auto ReaderContext = Impl.reader_context; auto ReaderContext = Impl.reader_context;
auto freeLambda = [=]{ Free(ReaderContext, Ptr, FreeContext); }; auto freeLambda = [=](const void *Ptr) { Free(ReaderContext, Ptr, FreeContext); };
return std::make_tuple(Ptr, freeLambda); return ReadBytesResult(Ptr, freeLambda);
} }
}; };

View File

@@ -42,9 +42,8 @@ class InProcessMemoryReader final : public MemoryReader {
return true; return true;
} }
std::tuple<const void *, std::function<void()>> ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
readBytes(RemoteAddress address, uint64_t size) override { return ReadBytesResult(address.getLocalPointer<void>(), [](const void *) {});
return std::make_tuple(address.getLocalPointer<void>(), []{});
} }
}; };

View File

@@ -21,6 +21,7 @@
#include "swift/Remote/RemoteAddress.h" #include "swift/Remote/RemoteAddress.h"
#include <functional> #include <functional>
#include <memory>
#include <string> #include <string>
#include <tuple> #include <tuple>
@@ -33,6 +34,9 @@ namespace remote {
/// representation of the address space of a remote process. /// representation of the address space of a remote process.
class MemoryReader { class MemoryReader {
public: 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. /// Return the size of an ordinary pointer in the remote process, in bytes.
virtual uint8_t getPointerSize() = 0; virtual uint8_t getPointerSize() = 0;
@@ -47,7 +51,7 @@ public:
/// ///
/// Returns false if the operation failed. /// Returns false if the operation failed.
virtual bool readString(RemoteAddress address, std::string &dest) = 0; virtual bool readString(RemoteAddress address, std::string &dest) = 0;
/// Attempts to read an integer from the given address in the remote /// Attempts to read an integer from the given address in the remote
/// process. /// process.
/// ///
@@ -65,15 +69,17 @@ public:
/// ///
/// NOTE: subclasses MUST override at least one of the readBytes functions. The default /// NOTE: subclasses MUST override at least one of the readBytes functions. The default
/// implementation calls through to the other one. /// implementation calls through to the other one.
virtual std::tuple<const void *, std::function<void()>> virtual ReadBytesResult
readBytes(RemoteAddress address, uint64_t size) { readBytes(RemoteAddress address, uint64_t size) {
void *buffer = malloc(size); auto *Buf = malloc(size);
bool success = readBytes(address, reinterpret_cast<uint8_t *>(buffer), size); ReadBytesResult Result(Buf, [](const void *ptr) {
free(const_cast<void *>(ptr));
});
bool success = readBytes(address, reinterpret_cast<uint8_t *>(Buf), size);
if (!success) { if (!success) {
free(buffer); Result.reset();
return std::make_tuple(nullptr, []{});
} }
return std::make_tuple(buffer, [=]{ free(buffer); }); return Result;
} }
/// Attempts to read 'size' bytes from the given address in the /// Attempts to read 'size' bytes from the given address in the
@@ -84,16 +90,12 @@ public:
/// NOTE: subclasses MUST override at least one of the readBytes functions. The default /// NOTE: subclasses MUST override at least one of the readBytes functions. The default
/// implementation calls through to the other one. /// implementation calls through to the other one.
virtual bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) { virtual bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) {
const void *ptr; auto Ptr = readBytes(address, size);
std::function<void()> freeFunc; if (!Ptr)
std::tie(ptr, freeFunc) = readBytes(address, size);
if (ptr != nullptr) {
memcpy(dest, ptr, size);
freeFunc();
return true;
} else {
return false; return false;
}
memcpy(dest, Ptr.get(), size);
return true;
} }
virtual ~MemoryReader() = default; virtual ~MemoryReader() = default;

View File

@@ -196,14 +196,12 @@ public:
return false; return false;
} }
std::tuple<const void *, std::function<void()>> ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
readBytes(RemoteAddress address, uint64_t size) override {
if (!isAddressValid(address, size)) if (!isAddressValid(address, size))
return std::make_tuple(nullptr, []{}); return ReadBytesResult(nullptr, [](const void *){});
// TODO: Account for offset in ELF binaries // TODO: Account for offset in ELF binaries
auto ptr = (const void *)address.getAddressData(); return ReadBytesResult((const void *)address.getAddressData(), [](const void *) {});
return std::make_tuple(ptr, []{});
} }
bool readString(RemoteAddress address, std::string &dest) override { bool readString(RemoteAddress address, std::string &dest) override {