Skip to content

Commit 5a57d1b

Browse files
authored
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.
2 parents 30f95f4 + c01b9e0 commit 5a57d1b

File tree

18 files changed

+1602
-91
lines changed

18 files changed

+1602
-91
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818
#ifndef SWIFT_REFLECTION_REFLECTIONCONTEXT_H
1919
#define SWIFT_REFLECTION_REFLECTIONCONTEXT_H
2020

21+
#if defined(__APPLE__) && defined(__MACH__)
22+
#include <mach-o/getsect.h>
23+
#endif
24+
2125
#include "swift/Remote/MemoryReader.h"
2226
#include "swift/Remote/MetadataReader.h"
2327
#include "swift/Reflection/Records.h"
@@ -30,6 +34,32 @@
3034
#include <set>
3135
#include <vector>
3236
#include <unordered_map>
37+
#include <utility>
38+
39+
#if defined(__APPLE__) && defined(__MACH__)
40+
#ifndef __LP64__
41+
typedef const struct mach_header MachHeader;
42+
#else
43+
typedef const struct mach_header_64 MachHeader;
44+
#endif
45+
#endif
46+
47+
#if defined(__APPLE__) && defined(__MACH__)
48+
template <typename Section>
49+
static std::pair<Section, bool> findSection(MachHeader *Header,
50+
const char *Name) {
51+
unsigned long Size;
52+
auto Address = getsectiondata(Header, "__TEXT", Name, &Size);
53+
if (!Address)
54+
return {{nullptr, nullptr}, false};
55+
56+
auto End = reinterpret_cast<uintptr_t>(Address) + Size;
57+
58+
return {{reinterpret_cast<const void *>(Address),
59+
reinterpret_cast<const void *>(End)},
60+
true};
61+
}
62+
#endif
3363

3464
namespace swift {
3565
namespace reflection {
@@ -46,6 +76,11 @@ class ReflectionContext
4676

4777
std::unordered_map<typename super::StoredPointer, const TypeInfo *> Cache;
4878

79+
/// All buffers we need to keep around long term. This will automatically free them
80+
/// when this object is destroyed.
81+
std::vector<MemoryReader::ReadBytesResult> savedBuffers;
82+
std::vector<std::tuple<RemoteAddress, RemoteAddress>> dataSegments;
83+
4984
public:
5085
using super::getBuilder;
5186
using super::readDemanglingForContextDescriptor;
@@ -62,7 +97,7 @@ class ReflectionContext
6297

6398
ReflectionContext(const ReflectionContext &other) = delete;
6499
ReflectionContext &operator=(const ReflectionContext &other) = delete;
65-
100+
66101
MemoryReader &getReader() {
67102
return *this->Reader;
68103
}
@@ -76,10 +111,108 @@ class ReflectionContext
76111
getBuilder().dumpAllSections();
77112
}
78113

114+
#if defined(__APPLE__) && defined(__MACH__)
115+
bool addImage(RemoteAddress ImageStart) {
116+
auto Buf = this->getReader().readBytes(ImageStart, sizeof(MachHeader));
117+
if (!Buf)
118+
return false;
119+
120+
auto Header = reinterpret_cast<MachHeader *>(Buf.get());
121+
if (Header->magic != MH_MAGIC && Header->magic != MH_MAGIC_64) {
122+
return false;
123+
}
124+
auto Length = Header->sizeofcmds;
125+
126+
// Read the commands.
127+
Buf = this->getReader().readBytes(ImageStart, Length);
128+
if (!Buf)
129+
return false;
130+
131+
// Find the TEXT segment and figure out where the end is.
132+
Header = reinterpret_cast<MachHeader *>(Buf.get());
133+
unsigned long TextSize;
134+
auto *TextSegment = getsegmentdata(Header, "__TEXT", &TextSize);
135+
if (TextSegment == nullptr)
136+
return false;
137+
138+
auto TextEnd =
139+
TextSegment - reinterpret_cast<const uint8_t *>(Buf.get()) + TextSize;
140+
141+
// Read everything including the TEXT segment.
142+
Buf = this->getReader().readBytes(ImageStart, TextEnd);
143+
if (!Buf)
144+
return false;
145+
146+
// Read all the metadata parts.
147+
Header = reinterpret_cast<MachHeader *>(Buf.get());
148+
149+
// The docs say "not all sections may be present." We'll succeed if ANY of
150+
// them are present. Not sure if that's the right thing to do.
151+
auto FieldMd = findSection<FieldSection>(Header, "__swift5_fieldmd");
152+
auto AssocTyMd =
153+
findSection<AssociatedTypeSection>(Header, "__swift5_assocty");
154+
auto BuiltinTyMd =
155+
findSection<BuiltinTypeSection>(Header, "__swift5_builtin");
156+
auto CaptureMd = findSection<CaptureSection>(Header, "__swift5_capture");
157+
auto TyperefMd = findSection<GenericSection>(Header, "__swift5_typeref");
158+
auto ReflStrMd = findSection<GenericSection>(Header, "__swift5_reflstr");
159+
160+
bool success = FieldMd.second || AssocTyMd.second || BuiltinTyMd.second ||
161+
CaptureMd.second || TyperefMd.second || ReflStrMd.second;
162+
if (!success)
163+
return false;
164+
165+
auto LocalStartAddress = reinterpret_cast<uintptr_t>(Buf.get());
166+
auto RemoteStartAddress = static_cast<uintptr_t>(ImageStart.getAddressData());
167+
168+
ReflectionInfo info = {
169+
{{FieldMd.first.startAddress(), FieldMd.first.endAddress()}, 0},
170+
{{AssocTyMd.first.startAddress(), AssocTyMd.first.endAddress()}, 0},
171+
{{BuiltinTyMd.first.startAddress(), BuiltinTyMd.first.endAddress()}, 0},
172+
{{CaptureMd.first.startAddress(), CaptureMd.first.endAddress()}, 0},
173+
{{TyperefMd.first.startAddress(), TyperefMd.first.endAddress()}, 0},
174+
{{ReflStrMd.first.startAddress(), ReflStrMd.first.endAddress()}, 0},
175+
LocalStartAddress,
176+
RemoteStartAddress};
177+
178+
this->addReflectionInfo(info);
179+
180+
unsigned long DataSize;
181+
auto *DataSegment = getsegmentdata(Header, "__DATA", &DataSize);
182+
if (DataSegment != nullptr) {
183+
auto DataSegmentStart = DataSegment - reinterpret_cast<const uint8_t *>(Buf.get())
184+
+ ImageStart.getAddressData();
185+
auto DataSegmentEnd = DataSegmentStart + DataSize;
186+
dataSegments.push_back(std::make_tuple(RemoteAddress(DataSegmentStart),
187+
RemoteAddress(DataSegmentEnd)));
188+
}
189+
190+
savedBuffers.push_back(std::move(Buf));
191+
192+
return true;
193+
}
194+
#endif // defined(__APPLE__) && defined(__MACH__)
195+
79196
void addReflectionInfo(ReflectionInfo I) {
80197
getBuilder().addReflectionInfo(I);
81198
}
82-
199+
200+
bool ownsObject(RemoteAddress ObjectAddress) {
201+
auto MetadataAddress = readMetadataFromInstance(ObjectAddress.getAddressData());
202+
if (!MetadataAddress)
203+
return 0;
204+
205+
for (auto Segment : dataSegments) {
206+
auto Start = std::get<0>(Segment);
207+
auto End = std::get<1>(Segment);
208+
if (Start.getAddressData() <= *MetadataAddress
209+
&& *MetadataAddress < End.getAddressData())
210+
return 1;
211+
}
212+
213+
return 0;
214+
}
215+
83216
/// Return a description of the layout of a class instance with the given
84217
/// metadata as its isa pointer.
85218
const TypeInfo *getMetadataTypeInfo(StoredPointer MetadataAddress) {

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ class ReflectionSection {
5757
const void *startAddress() const {
5858
return Begin;
5959
}
60+
61+
const void *endAddress() const {
62+
return End;
63+
}
6064

6165
const_iterator begin() const {
6266
return const_iterator(Begin, End);
@@ -334,6 +338,10 @@ class TypeRefBuilder {
334338
void addReflectionInfo(ReflectionInfo I) {
335339
ReflectionInfos.push_back(I);
336340
}
341+
342+
const std::vector<ReflectionInfo> &getReflectionInfos() {
343+
return ReflectionInfos;
344+
}
337345

338346
private:
339347
std::vector<ReflectionInfo> ReflectionInfos;

include/swift/Remote/CMemoryReader.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,26 @@ class CMemoryReader final : public MemoryReader {
6262
if (!length)
6363
return false;
6464

65-
auto buffer = std::unique_ptr<uint8_t>(new uint8_t[length + 1]);
66-
if (!readBytes(address, buffer.get(), length + 1))
65+
auto Buf = readBytes(address, length);
66+
if (!Buf)
6767
return false;
68-
69-
dest = std::string(reinterpret_cast<const char *>(buffer.get()));
68+
69+
dest = std::string(reinterpret_cast<const char *>(Buf.get()), length);
7070
return true;
7171
}
7272

73-
bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) override {
74-
return Impl.readBytes(Impl.reader_context,
75-
address.getAddressData(), dest, size) != 0;
73+
ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
74+
void *FreeContext;
75+
auto Ptr = Impl.readBytes(Impl.reader_context, address.getAddressData(), size,
76+
&FreeContext);
77+
78+
auto Free = Impl.free;
79+
if (Free == nullptr)
80+
return ReadBytesResult(Ptr, [](const void *) {});
81+
82+
auto ReaderContext = Impl.reader_context;
83+
auto freeLambda = [=](const void *Ptr) { Free(ReaderContext, Ptr, FreeContext); };
84+
return ReadBytesResult(Ptr, freeLambda);
7685
}
7786
};
7887

include/swift/Remote/InProcessMemoryReader.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,8 @@ class InProcessMemoryReader final : public MemoryReader {
4242
return true;
4343
}
4444

45-
bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) override {
46-
std::memcpy(dest, address.getLocalPointer<void>(), (size_t) size);
47-
return true;
45+
ReadBytesResult readBytes(RemoteAddress address, uint64_t size) override {
46+
return ReadBytesResult(address.getLocalPointer<void>(), [](const void *) {});
4847
}
4948
};
5049

include/swift/Remote/MemoryReader.h

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020

2121
#include "swift/Remote/RemoteAddress.h"
2222

23+
#include <cstring>
24+
#include <functional>
25+
#include <memory>
2326
#include <string>
27+
#include <tuple>
2428

2529
namespace swift {
2630
namespace remote {
@@ -31,6 +35,9 @@ namespace remote {
3135
/// representation of the address space of a remote process.
3236
class MemoryReader {
3337
public:
38+
/// A convenient name for the return type from readBytes.
39+
using ReadBytesResult = std::unique_ptr<const void, std::function<void(const void *)>>;
40+
3441
/// Return the size of an ordinary pointer in the remote process, in bytes.
3542
virtual uint8_t getPointerSize() = 0;
3643

@@ -40,19 +47,12 @@ class MemoryReader {
4047
/// Look up the given public symbol name in the remote process.
4148
virtual RemoteAddress getSymbolAddress(const std::string &name) = 0;
4249

43-
/// Attempts to read 'size' bytes from the given address in the
44-
/// remote process.
45-
///
46-
/// Returns false if the operation failed.
47-
virtual bool readBytes(RemoteAddress address, uint8_t *dest,
48-
uint64_t size) = 0;
49-
5050
/// Attempts to read a C string from the given address in the remote
5151
/// process.
5252
///
5353
/// Returns false if the operation failed.
5454
virtual bool readString(RemoteAddress address, std::string &dest) = 0;
55-
55+
5656
/// Attempts to read an integer from the given address in the remote
5757
/// process.
5858
///
@@ -63,6 +63,42 @@ class MemoryReader {
6363
sizeof(IntegerType));
6464
}
6565

66+
/// Attempts to read 'size' bytes from the given address in the remote process.
67+
///
68+
/// Returns a pointer to the requested data and a function that must be called to
69+
/// free that data when done. The pointer will be NULL if the operation failed.
70+
///
71+
/// NOTE: subclasses MUST override at least one of the readBytes functions. The default
72+
/// implementation calls through to the other one.
73+
virtual ReadBytesResult
74+
readBytes(RemoteAddress address, uint64_t size) {
75+
auto *Buf = malloc(size);
76+
ReadBytesResult Result(Buf, [](const void *ptr) {
77+
free(const_cast<void *>(ptr));
78+
});
79+
bool success = readBytes(address, reinterpret_cast<uint8_t *>(Buf), size);
80+
if (!success) {
81+
Result.reset();
82+
}
83+
return Result;
84+
}
85+
86+
/// Attempts to read 'size' bytes from the given address in the
87+
/// remote process.
88+
///
89+
/// Returns false if the operation failed.
90+
///
91+
/// NOTE: subclasses MUST override at least one of the readBytes functions. The default
92+
/// implementation calls through to the other one.
93+
virtual bool readBytes(RemoteAddress address, uint8_t *dest, uint64_t size) {
94+
auto Ptr = readBytes(address, size);
95+
if (!Ptr)
96+
return false;
97+
98+
memcpy(dest, Ptr.get(), size);
99+
return true;
100+
}
101+
66102
virtual ~MemoryReader() = default;
67103
};
68104

include/swift/SwiftRemoteMirror/MemoryReaderInterface.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ extern "C" {
3232
// in the system library, so we use 'swift_addr_t'.
3333
typedef uint64_t swift_addr_t;
3434

35+
typedef void (*FreeBytesFunction)(void *reader_context, const void *bytes, void *context);
36+
3537
typedef uint8_t (*PointerSizeFunction)(void *reader_context);
3638
typedef uint8_t (*SizeSizeFunction)(void *reader_context);
37-
typedef int (*ReadBytesFunction)(void *reader_context, swift_addr_t address,
38-
void *dest, uint64_t size);
39+
typedef const void *(*ReadBytesFunction)(void *reader_context, swift_addr_t address,
40+
uint64_t size,
41+
void **outFreeContext);
3942
typedef uint64_t (*GetStringLengthFunction)(void *reader_context,
4043
swift_addr_t address);
4144
typedef swift_addr_t (*GetSymbolAddressFunction)(void *reader_context,
@@ -53,16 +56,22 @@ typedef struct MemoryReaderImpl {
5356
/// Get the size in bytes of the target's size type.
5457
SizeSizeFunction getSizeSize;
5558

59+
/// Free memory returned from readBytes. May be NULL if memory never needs to be freed.
60+
FreeBytesFunction free;
61+
5662
// FIXME: -Wdocumentation complains about \param and \returns on function pointers.
5763
#pragma clang diagnostic push
5864
#pragma clang diagnostic ignored "-Wdocumentation"
5965

6066
/// Read a sequence of bytes at an address in the target.
6167
///
6268
/// \param address the address in the target address space
63-
/// \param dest the caller-owned buffer into which to store the string
6469
/// \param size the number of bytes to read
65-
/// \returns true if the read was successful
70+
/// \param outFreeContext on return, an arbitrary context pointer that the caller will
71+
/// pass to the free function
72+
/// \returns A pointer to the requested memory, or NULL if the memory could not be read.
73+
/// The caller must invoke the free function on the returned pointer once it's
74+
/// done using the memory.
6675
ReadBytesFunction readBytes;
6776

6877
/// Get the string length at the given address.

0 commit comments

Comments
 (0)