Skip to content

Commit b93096c

Browse files
committed
swift-reflection-dump: Use a 32-bit friendly multi-image VM mapping.
My previous attempt doesn't work well for 32-bit targets; 32-bit memory readers reasonably assume that they only get 32-bit RemoteAddress values. When working with multiple images, instead pack them all into a contiguous subset of the address space.
1 parent 8821c6c commit b93096c

File tree

1 file changed

+44
-28
lines changed

1 file changed

+44
-28
lines changed

tools/swift-reflection-dump/swift-reflection-dump.cpp

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,6 @@ class Image {
232232
fputs("unsupported image format\n", stderr);
233233
abort();
234234
}
235-
236-
// ObjectMemoryReader uses the most significant 16 bits of the address to
237-
// index multiple images, so if an object maps stuff out of that range
238-
// we won't be able to read it. 2**48 of virtual address space ought to be
239-
// enough for anyone, but warn if we blow that limit.
240-
for (auto Segment : Segments) {
241-
if (Segment.Addr >= 0xFFFFFFFFFFFFull) {
242-
fputs("warning: segment mapped at address above 2**48\n", stderr);
243-
continue;
244-
}
245-
}
246235
}
247236

248237
unsigned getBytesInAddress() const {
@@ -252,6 +241,14 @@ class Image {
252241
uint64_t getStartAddress() const {
253242
return HeaderAddress;
254243
}
244+
245+
uint64_t getEndAddress() const {
246+
uint64_t max = 0;
247+
for (auto &Segment : Segments) {
248+
max = std::max(max, Segment.Addr + Segment.Contents.size());
249+
}
250+
return max;
251+
}
255252

256253
StringRef getContentsAtAddress(uint64_t Addr, uint64_t Size) const {
257254
for (auto &Segment : Segments) {
@@ -288,21 +285,27 @@ class Image {
288285
/// and the low 48 bits correspond to the preferred virtual address mapping of
289286
/// the image.
290287
class ObjectMemoryReader : public MemoryReader {
291-
std::vector<Image> Images;
288+
struct ImageEntry {
289+
Image TheImage;
290+
uint64_t Slide;
291+
};
292+
std::vector<ImageEntry> Images;
292293

293294
std::pair<const Image *, uint64_t>
294295
decodeImageIndexAndAddress(uint64_t Addr) const {
295-
unsigned index = Addr >> 48;
296-
if (index >= Images.size())
297-
return {nullptr, 0};
298-
299-
return {&Images[index], Addr & ((1ull << 48) - 1)};
296+
for (auto &Image : Images) {
297+
if (Image.TheImage.getStartAddress() + Image.Slide <= Addr
298+
&& Addr < Image.TheImage.getEndAddress() + Image.Slide) {
299+
return {&Image.TheImage, Addr - Image.Slide};
300+
}
301+
}
302+
return {nullptr, 0};
300303
}
301304

302305
uint64_t
303306
encodeImageIndexAndAddress(const Image *image, uint64_t imageAddr) const {
304-
unsigned index = image - Images.data();
305-
return imageAddr | ((uint64_t)index << 48);
307+
auto entry = (const ImageEntry*)image;
308+
return imageAddr + entry->Slide;
306309
}
307310

308311
StringRef getContentsAtAddress(uint64_t Addr, uint64_t Size) {
@@ -323,11 +326,6 @@ class ObjectMemoryReader : public MemoryReader {
323326
fputs("no object files provided\n", stderr);
324327
abort();
325328
}
326-
// We use a 16-bit index for images, so can't take more than 64K at once.
327-
if (ObjectFiles.size() > 0x10000) {
328-
fputs("can't dump more than 65,536 images at once\n", stderr);
329-
abort();
330-
}
331329
unsigned WordSize = 0;
332330
for (const ObjectFile *O : ObjectFiles) {
333331
// All the object files we look at should share a word size.
@@ -337,15 +335,32 @@ class ObjectMemoryReader : public MemoryReader {
337335
fputs("object files must all be for the same architecture\n", stderr);
338336
abort();
339337
}
340-
Images.emplace_back(O);
338+
Images.push_back({Image(O), 0});
339+
}
340+
341+
// If there is more than one image loaded, try to fit them into one address
342+
// space.
343+
if (Images.size() > 1) {
344+
uint64_t NextAddrSpace = 0;
345+
for (auto &Image : Images) {
346+
Image.Slide = NextAddrSpace - Image.TheImage.getStartAddress();
347+
NextAddrSpace +=
348+
Image.TheImage.getEndAddress() - Image.TheImage.getStartAddress();
349+
NextAddrSpace = (NextAddrSpace + 16383) & ~16383;
350+
}
351+
352+
if (WordSize < 8 && NextAddrSpace > 0xFFFFFFFFu) {
353+
fputs("object files did not fit in address space", stderr);
354+
abort();
355+
}
341356
}
342357
}
343358

344-
ArrayRef<Image> getImages() const { return Images; }
359+
ArrayRef<ImageEntry> getImages() const { return Images; }
345360

346361
bool queryDataLayout(DataLayoutQueryType type, void *inBuffer,
347362
void *outBuffer) override {
348-
auto wordSize = Images.front().getBytesInAddress();
363+
auto wordSize = Images.front().TheImage.getBytesInAddress();
349364
switch (type) {
350365
case DLQ_GetPointerSize: {
351366
auto result = static_cast<uint8_t *>(outBuffer);
@@ -366,7 +381,8 @@ class ObjectMemoryReader : public MemoryReader {
366381
assert(i < Images.size());
367382

368383
return RemoteAddress(
369-
encodeImageIndexAndAddress(&Images[i], Images[i].getStartAddress()));
384+
encodeImageIndexAndAddress(&Images[i].TheImage,
385+
Images[i].TheImage.getStartAddress()));
370386
}
371387

372388
// TODO: We could consult the dynamic symbol tables of the images to

0 commit comments

Comments
 (0)