Skip to content

[Reflection] Add support for reading ELF. #17771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 110 additions & 2 deletions include/swift/Reflection/ReflectionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#define SWIFT_REFLECTION_REFLECTIONCONTEXT_H

#include "llvm/BinaryFormat/MachO.h"
#include "llvm/BinaryFormat/ELF.h"

#include "swift/Remote/MemoryReader.h"
#include "swift/Remote/MetadataReader.h"
#include "swift/Reflection/Records.h"
Expand Down Expand Up @@ -227,8 +229,114 @@ class ReflectionContext
return readMachOSections<MachOTraits<8>>(ImageStart);
return false;
}
#endif // defined(__APPLE__) && defined(__MACH__)

#else // ELF platforms.
bool addImage(RemoteAddress ImageStart) {
auto Buf =
this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr));

// Read the header.
auto Hdr = reinterpret_cast<const llvm::ELF::Elf64_Ehdr *>(Buf.get());

if (!Hdr->checkMagic())
return false;

// From the header, grab informations about the section header table.
auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely broken with 32-bit images. offsetof(Elf_Ehdr, e_shoff) is going to be 0x20 vs 0x28. It also is a 4-byte vs 8-byte value.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this all is 64-bit specific. We can generalize to 32-bits later.

auto SectionHdrNumEntries = Hdr->e_shnum;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again broken: offsetof(Elf_EHdr, e_shnum) is 0x30 vs 0x3c.

auto SectionEntrySize = Hdr->e_shentsize;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again broken: offsetof(Elf_EHdr, e_shentsize) is 0x2e vs 0x3a


// Collect all the section headers, we need them to look up the
// reflection sections (by name) and the string table.
std::vector<const llvm::ELF::Elf64_Shdr *> SecHdrVec;
for (unsigned I = 0; I < SectionHdrNumEntries; ++I) {
auto SecBuf = this->getReader().readBytes(
RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)),
SectionEntrySize);
auto SecHdr =
reinterpret_cast<const llvm::ELF::Elf64_Shdr *>(SecBuf.get());
SecHdrVec.push_back(SecHdr);
}

// This provides quick access to the section header string table index.
// We also here handle the unlikely even where the section index overflows
// and it's just a pointer to secondary storage (SHN_XINDEX).
uint32_t SecIdx = Hdr->e_shstrndx;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again broken: offsetof(Elf_EHdr, e_shstrndx) is 0x32 vs 0x3e

if (SecIdx == llvm::ELF::SHN_XINDEX) {
assert(!SecHdrVec.empty() && "malformed ELF object");
SecIdx = SecHdrVec[0]->sh_link;
}

assert(SecIdx < SecHdrVec.size() && "malformed ELF object");

const llvm::ELF::Elf64_Shdr *SecHdrStrTab = SecHdrVec[SecIdx];
llvm::ELF::Elf64_Off StrTabOffset = SecHdrStrTab->sh_offset;
llvm::ELF::Elf64_Xword StrTabSize = SecHdrStrTab->sh_size;

auto StrTabStart =
RemoteAddress(ImageStart.getAddressData() + StrTabOffset);
auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize);
auto StrTab = reinterpret_cast<const char *>(StrTabBuf.get());

auto findELFSectionByName = [&](std::string Name)
-> std::pair<std::pair<const char *, const char *>, uint32_t> {
// Now for all the sections, find their name.
for (const llvm::ELF::Elf64_Shdr *Hdr : SecHdrVec) {
uint32_t Offset = Hdr->sh_name;
auto SecName = std::string(StrTab + Offset);
if (SecName != Name)
continue;
auto SecStart =
RemoteAddress(ImageStart.getAddressData() + Hdr->sh_offset);
auto SecSize = Hdr->sh_size;
auto SecBuf = this->getReader().readBytes(SecStart, SecSize);
auto SecContents = reinterpret_cast<const char *>(SecBuf.get());
return {{SecContents, SecContents + SecSize},
Hdr->sh_addr - Hdr->sh_offset};
}
return {{nullptr, nullptr}, 0};
};

auto FieldMdSec = findELFSectionByName("swift5_fieldmd");
auto AssocTySec = findELFSectionByName("swift5_assocty");
auto BuiltinTySec = findELFSectionByName("swift5_builtin");
auto CaptureSec = findELFSectionByName("swift5_capture");
auto TypeRefMdSec = findELFSectionByName("swift5_typeref");
auto ReflStrMdSec = findELFSectionByName("swift5_reflstr");

// We succeed if at least one of the sections is present in the
// ELF executable.
if (FieldMdSec.first.first == nullptr &&
AssocTySec.first.first == nullptr &&
BuiltinTySec.first.first == nullptr &&
CaptureSec.first.first == nullptr &&
TypeRefMdSec.first.first == nullptr &&
ReflStrMdSec.first.first == nullptr)
return false;

auto LocalStartAddress = reinterpret_cast<uintptr_t>(Buf.get());
auto RemoteStartAddress =
static_cast<uintptr_t>(ImageStart.getAddressData());

ReflectionInfo info = {
{{FieldMdSec.first.first, FieldMdSec.first.second}, FieldMdSec.second},
{{AssocTySec.first.first, AssocTySec.first.second}, AssocTySec.second},
{{BuiltinTySec.first.first, BuiltinTySec.first.second},
BuiltinTySec.second},
{{CaptureSec.first.first, CaptureSec.first.second}, CaptureSec.second},
{{TypeRefMdSec.first.first, TypeRefMdSec.first.second},
TypeRefMdSec.second},
{{ReflStrMdSec.first.first, ReflStrMdSec.first.second},
ReflStrMdSec.second},
LocalStartAddress,
RemoteStartAddress};

this->addReflectionInfo(info);

savedBuffers.push_back(std::move(Buf));
return true;
}
#endif

void addReflectionInfo(ReflectionInfo I) {
getBuilder().addReflectionInfo(I);
}
Expand Down
4 changes: 0 additions & 4 deletions tools/swift-reflection-dump/swift-reflection-dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,8 @@ static int doDumpReflectionSections(ArrayRef<std::string> binaryFilenames,
objectOwners.push_back(std::move(objectOwner));
objectFiles.push_back(objectFile);

#if defined(__APPLE__)
auto startAddress = (uintptr_t)objectFile->getData().begin();
context.addImage(RemoteAddress(startAddress));
#else
context.addReflectionInfo(findReflectionInfo(objectFile));
#endif
}

switch (action) {
Expand Down