Skip to content

Commit e2b6a3d

Browse files
author
Alexander Shaposhnikov
committed
Fix parsing of ELF images
1 parent e5b31c4 commit e2b6a3d

File tree

3 files changed

+208
-118
lines changed

3 files changed

+208
-118
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 95 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/Reflection/TypeRef.h"
3131
#include "swift/Reflection/TypeRefBuilder.h"
3232
#include "swift/Runtime/Unreachable.h"
33+
#include "../../../stdlib/public/runtime/ImageInspectionELF.h"
3334

3435
#include <iostream>
3536
#include <set>
@@ -59,15 +60,15 @@ template <unsigned char ELFClass> struct ELFTraits;
5960

6061
template <> struct ELFTraits<llvm::ELF::ELFCLASS32> {
6162
using Header = const struct llvm::ELF::Elf32_Ehdr;
62-
using Section = const struct llvm::ELF::Elf32_Shdr;
63+
using ProgramHeader = const struct llvm::ELF::Elf32_Phdr;
6364
using Offset = llvm::ELF::Elf32_Off;
6465
using Size = llvm::ELF::Elf32_Word;
6566
static constexpr unsigned char ELFClass = llvm::ELF::ELFCLASS32;
6667
};
6768

6869
template <> struct ELFTraits<llvm::ELF::ELFCLASS64> {
6970
using Header = const struct llvm::ELF::Elf64_Ehdr;
70-
using Section = const struct llvm::ELF::Elf64_Shdr;
71+
using ProgramHeader = const struct llvm::ELF::Elf64_Phdr;
7172
using Offset = llvm::ELF::Elf64_Off;
7273
using Size = llvm::ELF::Elf64_Xword;
7374
static constexpr unsigned char ELFClass = llvm::ELF::ELFCLASS64;
@@ -112,7 +113,7 @@ class ReflectionContext
112113

113114
ReflectionContext(const ReflectionContext &other) = delete;
114115
ReflectionContext &operator=(const ReflectionContext &other) = delete;
115-
116+
116117
MemoryReader &getReader() {
117118
return *this->Reader;
118119
}
@@ -195,9 +196,9 @@ class ReflectionContext
195196
// introduce misaligned pointers mapping between local and remote
196197
// address space.
197198
RangeStart = RangeStart & ~7;
198-
RangeEnd = RangeEnd + 7 & ~7;
199+
RangeEnd = RangeEnd + 7 & ~7;
199200
}
200-
201+
201202
if (RangeStart == UINT64_MAX && RangeEnd == UINT64_MAX)
202203
return false;
203204

@@ -386,116 +387,105 @@ class ReflectionContext
386387
}
387388

388389
template <typename T> bool readELFSections(RemoteAddress ImageStart) {
389-
auto Buf =
390+
auto HeaderBuf =
390391
this->getReader().readBytes(ImageStart, sizeof(typename T::Header));
391392

392-
auto Hdr = reinterpret_cast<const typename T::Header *>(Buf.get());
393+
auto Hdr = reinterpret_cast<const typename T::Header *>(HeaderBuf.get());
393394
assert(Hdr->getFileClass() == T::ELFClass && "invalid ELF file class");
394395

395-
// From the header, grab informations about the section header table.
396-
auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff;
397-
auto SectionHdrNumEntries = Hdr->e_shnum;
398-
auto SectionEntrySize = Hdr->e_shentsize;
399-
400-
// Collect all the section headers, we need them to look up the
401-
// reflection sections (by name) and the string table.
402-
std::vector<const typename T::Section *> SecHdrVec;
403-
for (unsigned I = 0; I < SectionHdrNumEntries; ++I) {
404-
auto SecBuf = this->getReader().readBytes(
405-
RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)),
406-
SectionEntrySize);
407-
auto SecHdr =
408-
reinterpret_cast<const typename T::Section *>(SecBuf.get());
409-
SecHdrVec.push_back(SecHdr);
396+
const auto ProgramHdrAddress = ImageStart.getAddressData() + Hdr->e_phoff;
397+
const auto NumEntries = Hdr->e_phnum;
398+
const auto EntrySize = Hdr->e_phentsize;
399+
400+
uintptr_t MetadataSectionsPtrValue = 0;
401+
for (unsigned I = 0; I < NumEntries; ++I) {
402+
const StringRef MagicString =
403+
SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING;
404+
auto ProgramHdrBuf = this->getReader().readBytes(
405+
RemoteAddress(ProgramHdrAddress + (I * EntrySize)), EntrySize);
406+
auto ProgramHdr = reinterpret_cast<const typename T::ProgramHeader *>(
407+
ProgramHdrBuf.get());
408+
if (ProgramHdr->p_type != llvm::ELF::PT_NOTE ||
409+
ProgramHdr->p_memsz <= MagicString.size())
410+
continue;
411+
const auto SegmentAddr =
412+
ImageStart.getAddressData() + ProgramHdr->p_vaddr;
413+
const auto SegmentSize = ProgramHdr->p_memsz;
414+
auto SegmentBuf =
415+
this->getReader().readBytes(RemoteAddress(SegmentAddr), SegmentSize);
416+
const char *SegmentData =
417+
reinterpret_cast<const char *>(SegmentBuf.get());
418+
if (!StringRef(SegmentData, SegmentSize).startswith(MagicString))
419+
continue;
420+
MetadataSectionsPtrValue = *reinterpret_cast<const uintptr_t *>(
421+
SegmentData + MagicString.size() + 1);
422+
break;
410423
}
424+
if (!MetadataSectionsPtrValue)
425+
return false;
411426

412-
// This provides quick access to the section header string table index.
413-
// We also here handle the unlikely even where the section index overflows
414-
// and it's just a pointer to secondary storage (SHN_XINDEX).
415-
uint32_t SecIdx = Hdr->e_shstrndx;
416-
if (SecIdx == llvm::ELF::SHN_XINDEX) {
417-
assert(!SecHdrVec.empty() && "malformed ELF object");
418-
SecIdx = SecHdrVec[0]->sh_link;
427+
auto MetadataSectionsStructBuf = this->getReader().readBytes(
428+
RemoteAddress(MetadataSectionsPtrValue), sizeof(MetadataSections));
429+
const auto *Sections = reinterpret_cast<const MetadataSections *>(
430+
MetadataSectionsStructBuf.get());
431+
432+
auto BeginAddr = std::min(
433+
{Sections->swift5_fieldmd.start, Sections->swift5_assocty.start,
434+
Sections->swift5_builtin.start, Sections->swift5_capture.start,
435+
Sections->swift5_typeref.start, Sections->swift5_reflstr.start});
436+
auto EndAddr = std::max({
437+
Sections->swift5_fieldmd.start + Sections->swift5_fieldmd.length,
438+
Sections->swift5_assocty.start + Sections->swift5_assocty.length,
439+
Sections->swift5_builtin.start + Sections->swift5_builtin.length,
440+
Sections->swift5_capture.start + Sections->swift5_capture.length,
441+
Sections->swift5_typeref.start + Sections->swift5_typeref.length,
442+
Sections->swift5_reflstr.start + Sections->swift5_reflstr.length,
443+
});
444+
445+
// Extend the range [BeginAddr, EndAddr) to include the data segments.
446+
for (unsigned I = 0; I < NumEntries; ++I) {
447+
auto ProgramHdrBuf = this->getReader().readBytes(
448+
RemoteAddress(ProgramHdrAddress + (I * EntrySize)), EntrySize);
449+
auto ProgramHdr = reinterpret_cast<const typename T::ProgramHeader *>(
450+
ProgramHdrBuf.get());
451+
if (ProgramHdr->p_type == llvm::ELF::PT_LOAD &&
452+
ProgramHdr->p_flags & (llvm::ELF::PF_W & llvm::ELF::PF_R)) {
453+
const decltype(BeginAddr) SegmentBeginAddr =
454+
ImageStart.getAddressData() + ProgramHdr->p_vaddr;
455+
const decltype(BeginAddr) SegmentEndAddr =
456+
SegmentBeginAddr + ProgramHdr->p_memsz;
457+
BeginAddr = std::min(BeginAddr, SegmentBeginAddr);
458+
EndAddr = std::max(EndAddr, SegmentEndAddr);
459+
}
419460
}
420461

421-
assert(SecIdx < SecHdrVec.size() && "malformed ELF object");
422-
423-
const typename T::Section *SecHdrStrTab = SecHdrVec[SecIdx];
424-
typename T::Offset StrTabOffset = SecHdrStrTab->sh_offset;
425-
typename T::Size StrTabSize = SecHdrStrTab->sh_size;
426-
427-
auto StrTabStart =
428-
RemoteAddress(ImageStart.getAddressData() + StrTabOffset);
429-
auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize);
430-
auto StrTab = reinterpret_cast<const char *>(StrTabBuf.get());
431-
432-
auto findELFSectionByName = [&](std::string Name)
433-
-> std::pair<RemoteRef<void>, uint64_t> {
434-
// Now for all the sections, find their name.
435-
for (const typename T::Section *Hdr : SecHdrVec) {
436-
uint32_t Offset = Hdr->sh_name;
437-
auto SecName = std::string(StrTab + Offset);
438-
if (SecName != Name)
439-
continue;
440-
auto SecStart =
441-
RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr);
442-
auto SecSize = Hdr->sh_size;
443-
auto SecBuf = this->getReader().readBytes(SecStart, SecSize);
444-
auto SecContents = RemoteRef<void>(SecStart.getAddressData(),
445-
SecBuf.get());
446-
savedBuffers.push_back(std::move(SecBuf));
447-
return {SecContents, SecSize};
448-
}
449-
return {nullptr, 0};
462+
auto Buf = this->getReader().readBytes(RemoteAddress(BeginAddr),
463+
EndAddr - BeginAddr);
464+
auto RemoteAddrToRemoteRef = [&](uintptr_t Addr) -> RemoteRef<void> {
465+
return RemoteRef<void>(
466+
Addr, reinterpret_cast<void *>(
467+
reinterpret_cast<uintptr_t>(Buf.get()) + Addr - BeginAddr));
450468
};
451-
452-
auto FieldMdSec = findELFSectionByName("swift5_fieldmd");
453-
auto AssocTySec = findELFSectionByName("swift5_assocty");
454-
auto BuiltinTySec = findELFSectionByName("swift5_builtin");
455-
auto CaptureSec = findELFSectionByName("swift5_capture");
456-
auto TypeRefMdSec = findELFSectionByName("swift5_typeref");
457-
auto ReflStrMdSec = findELFSectionByName("swift5_reflstr");
458-
459-
// We succeed if at least one of the sections is present in the
460-
// ELF executable.
461-
if (FieldMdSec.first == nullptr &&
462-
AssocTySec.first == nullptr &&
463-
BuiltinTySec.first == nullptr &&
464-
CaptureSec.first == nullptr &&
465-
TypeRefMdSec.first == nullptr &&
466-
ReflStrMdSec.first == nullptr)
467-
return false;
468-
469-
auto LocalStartAddress = reinterpret_cast<uint64_t>(Buf.get());
470-
auto RemoteStartAddress =
471-
static_cast<uint64_t>(ImageStart.getAddressData());
472-
473-
ReflectionInfo info = {
474-
{FieldMdSec.first, FieldMdSec.second},
475-
{AssocTySec.first, AssocTySec.second},
476-
{BuiltinTySec.first, BuiltinTySec.second},
477-
{CaptureSec.first, CaptureSec.second},
478-
{TypeRefMdSec.first, TypeRefMdSec.second},
479-
{ReflStrMdSec.first, ReflStrMdSec.second},
480-
LocalStartAddress,
481-
RemoteStartAddress};
482-
483-
this->addReflectionInfo(info);
484-
469+
#define SECTION_INFO(NAME) \
470+
{RemoteAddrToRemoteRef(Sections->NAME.start), Sections->NAME.length}
471+
ReflectionInfo Info = {
472+
SECTION_INFO(swift5_fieldmd), SECTION_INFO(swift5_assocty),
473+
SECTION_INFO(swift5_builtin), SECTION_INFO(swift5_capture),
474+
SECTION_INFO(swift5_typeref), SECTION_INFO(swift5_reflstr),
475+
reinterpret_cast<uint64_t>(Buf.get()), BeginAddr};
476+
#undef SECTION_INFO
477+
this->addReflectionInfo(Info);
485478
savedBuffers.push_back(std::move(Buf));
486479
return true;
487480
}
488-
481+
489482
bool readELF(RemoteAddress ImageStart) {
490483
auto Buf =
491484
this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr));
492-
493485
// Read the header.
494486
auto Hdr = reinterpret_cast<const llvm::ELF::Elf64_Ehdr *>(Buf.get());
495-
496487
if (!Hdr->checkMagic())
497488
return false;
498-
499489
// Check if we have a ELFCLASS32 or ELFCLASS64
500490
unsigned char FileClass = Hdr->getFileClass();
501491
if (FileClass == llvm::ELF::ELFCLASS64) {
@@ -512,34 +502,34 @@ class ReflectionContext
512502
auto Magic = this->getReader().readBytes(ImageStart, sizeof(uint32_t));
513503
if (!Magic)
514504
return false;
515-
505+
516506
uint32_t MagicWord;
517507
memcpy(&MagicWord, Magic.get(), sizeof(MagicWord));
518-
508+
519509
// 32- and 64-bit Mach-O.
520510
if (MagicWord == llvm::MachO::MH_MAGIC) {
521511
return readMachOSections<MachOTraits<4>>(ImageStart);
522512
}
523-
513+
524514
if (MagicWord == llvm::MachO::MH_MAGIC_64) {
525515
return readMachOSections<MachOTraits<8>>(ImageStart);
526516
}
527-
517+
528518
// PE. (This just checks for the DOS header; `readPECOFF` will further
529519
// validate the existence of the PE header.)
530520
auto MagicBytes = (const char*)Magic.get();
531521
if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') {
532522
return readPECOFF(ImageStart);
533523
}
534-
524+
535525
// ELF.
536526
if (MagicBytes[0] == llvm::ELF::ElfMagic[0]
537527
&& MagicBytes[1] == llvm::ELF::ElfMagic[1]
538528
&& MagicBytes[2] == llvm::ELF::ElfMagic[2]
539529
&& MagicBytes[3] == llvm::ELF::ElfMagic[3]) {
540530
return readELF(ImageStart);
541531
}
542-
532+
543533
// We don't recognize the format.
544534
return false;
545535
}
@@ -554,7 +544,7 @@ class ReflectionContext
554544
return true;
555545
return ownsAddress(RemoteAddress(*MetadataAddress));
556546
}
557-
547+
558548
/// Returns true if the address falls within a registered image.
559549
bool ownsAddress(RemoteAddress Address) {
560550
for (auto Range : imageRanges) {
@@ -564,10 +554,10 @@ class ReflectionContext
564554
&& Address.getAddressData() < End.getAddressData())
565555
return true;
566556
}
567-
557+
568558
return false;
569559
}
570-
560+
571561
/// Return a description of the layout of a class instance with the given
572562
/// metadata as its isa pointer.
573563
const TypeInfo *getMetadataTypeInfo(StoredPointer MetadataAddress) {

stdlib/public/runtime/ImageInspectionELF.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121

2222
#define SWIFT_REFLECTION_METADATA_ELF_NOTE_MAGIC_STRING "swift_reflection_metadata_magic_string"
2323

24-
#if defined(__ELF__)
25-
2624
#include "../SwiftShims/Visibility.h"
2725
#include <cstdint>
2826
#include <cstddef>
@@ -61,10 +59,10 @@ struct MetadataSections {
6159
};
6260
} // namespace swift
6361

62+
#if defined(__ELF__)
6463
// Called by injected constructors when a dynamic library is loaded.
6564
SWIFT_RUNTIME_EXPORT
6665
void swift_addNewDSOImage(const void *addr);
67-
6866
#endif // defined(__ELF__)
6967

7068
#endif // SWIFT_RUNTIME_IMAGE_INSPECTION_ELF_H

0 commit comments

Comments
 (0)