Skip to content

Commit f86b951

Browse files
Merge pull request #33321 from augusto2112/read-elf-sections
Fix reading metadata from ELF sections
2 parents 207033e + 7cd9204 commit f86b951

File tree

1 file changed

+124
-46
lines changed

1 file changed

+124
-46
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 124 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/BinaryFormat/MachO.h"
2323
#include "llvm/BinaryFormat/ELF.h"
2424
#include "llvm/Object/COFF.h"
25+
#include "llvm/Support/Memory.h"
2526

2627
#include "swift/ABI/Enum.h"
2728
#include "swift/ABI/ObjectFile.h"
@@ -393,29 +394,60 @@ class ReflectionContext
393394
return readPECOFFSections(ImageStart);
394395
}
395396

396-
template <typename T> bool readELFSections(RemoteAddress ImageStart) {
397-
auto Buf =
398-
this->getReader().readBytes(ImageStart, sizeof(typename T::Header));
397+
template <typename T>
398+
bool readELFSections(RemoteAddress ImageStart,
399+
llvm::Optional<llvm::sys::MemoryBlock> FileBuffer) {
400+
// When reading from the FileBuffer we can simply return a pointer to
401+
// the underlying data.
402+
// When reading from the process, we need to keep the memory around
403+
// until the end of the function, so we store it inside ReadDataBuffer.
404+
// We do this so in both cases we can return a simple pointer.
405+
std::vector<MemoryReader::ReadBytesResult> ReadDataBuffer;
406+
auto readData = [&](uint64_t Offset, uint64_t Size) -> const void * {
407+
if (FileBuffer.hasValue()) {
408+
auto Buffer = FileBuffer.getValue();
409+
if (Offset + Size > Buffer.allocatedSize())
410+
return nullptr;
411+
return (const void *)((uint64_t)Buffer.base() + Offset);
412+
} else {
413+
MemoryReader::ReadBytesResult Buf =
414+
this->getReader().readBytes(ImageStart + Offset, Size);
415+
if (!Buf)
416+
return nullptr;
417+
ReadDataBuffer.push_back(std::move(Buf));
418+
return ReadDataBuffer.back().get();
419+
}
420+
};
399421

400-
auto Hdr = reinterpret_cast<const typename T::Header *>(Buf.get());
422+
const void *Buf = readData(0, sizeof(typename T::Header));
423+
if (!Buf)
424+
return false;
425+
auto Hdr = reinterpret_cast<const typename T::Header *>(Buf);
401426
assert(Hdr->getFileClass() == T::ELFClass && "invalid ELF file class");
402427

403-
// From the header, grab informations about the section header table.
404-
auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff;
405-
auto SectionHdrNumEntries = Hdr->e_shnum;
406-
auto SectionEntrySize = Hdr->e_shentsize;
428+
// From the header, grab information about the section header table.
429+
uint64_t SectionHdrAddress = Hdr->e_shoff;
430+
uint16_t SectionHdrNumEntries = Hdr->e_shnum;
431+
uint16_t SectionEntrySize = Hdr->e_shentsize;
432+
433+
if (sizeof(typename T::Section) > SectionEntrySize)
434+
return false;
435+
if (SectionHdrNumEntries == 0)
436+
return false;
407437

408438
// Collect all the section headers, we need them to look up the
409439
// reflection sections (by name) and the string table.
440+
// We read the section headers from the FileBuffer, since they are
441+
// not mapped in the child process.
410442
std::vector<const typename T::Section *> SecHdrVec;
411443
for (unsigned I = 0; I < SectionHdrNumEntries; ++I) {
412-
auto SecBuf = this->getReader().readBytes(
413-
RemoteAddress(SectionHdrAddress + (I * SectionEntrySize)),
414-
SectionEntrySize);
444+
uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize);
445+
auto SecBuf = readData(Offset, sizeof(typename T::Section));
415446
if (!SecBuf)
416447
return false;
417-
auto SecHdr =
418-
reinterpret_cast<const typename T::Section *>(SecBuf.get());
448+
const typename T::Section *SecHdr =
449+
reinterpret_cast<const typename T::Section *>(SecBuf);
450+
419451
SecHdrVec.push_back(SecHdr);
420452
}
421453

@@ -434,30 +466,54 @@ class ReflectionContext
434466
typename T::Offset StrTabOffset = SecHdrStrTab->sh_offset;
435467
typename T::Size StrTabSize = SecHdrStrTab->sh_size;
436468

437-
auto StrTabStart =
438-
RemoteAddress(ImageStart.getAddressData() + StrTabOffset);
439-
auto StrTabBuf = this->getReader().readBytes(StrTabStart, StrTabSize);
440-
auto StrTab = reinterpret_cast<const char *>(StrTabBuf.get());
441-
442-
auto findELFSectionByName = [&](llvm::StringRef Name)
443-
-> std::pair<RemoteRef<void>, uint64_t> {
444-
// Now for all the sections, find their name.
445-
for (const typename T::Section *Hdr : SecHdrVec) {
446-
uint32_t Offset = Hdr->sh_name;
447-
auto SecName = std::string(StrTab + Offset);
448-
if (SecName != Name)
449-
continue;
450-
auto SecStart =
451-
RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr);
452-
auto SecSize = Hdr->sh_size;
453-
auto SecBuf = this->getReader().readBytes(SecStart, SecSize);
454-
auto SecContents = RemoteRef<void>(SecStart.getAddressData(),
455-
SecBuf.get());
456-
savedBuffers.push_back(std::move(SecBuf));
457-
return {SecContents, SecSize};
458-
}
459-
return {nullptr, 0};
460-
};
469+
auto StrTabBuf = readData(StrTabOffset, StrTabSize);
470+
if (!StrTabBuf)
471+
return false;
472+
auto StrTab = reinterpret_cast<const char *>(StrTabBuf);
473+
bool Error = false;
474+
auto findELFSectionByName =
475+
[&](llvm::StringRef Name) -> std::pair<RemoteRef<void>, uint64_t> {
476+
if (Error)
477+
return {nullptr, 0};
478+
// Now for all the sections, find their name.
479+
for (const typename T::Section *Hdr : SecHdrVec) {
480+
uint32_t Offset = Hdr->sh_name;
481+
const char *Start = (const char *)StrTab + Offset;
482+
uint64_t Size = strnlen(Start, StrTabSize - Offset);
483+
if (Size > StrTabSize - Offset) {
484+
Error = true;
485+
break;
486+
}
487+
std::string SecName(Start, Size);
488+
if (SecName != Name)
489+
continue;
490+
RemoteAddress SecStart =
491+
RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr);
492+
auto SecSize = Hdr->sh_size;
493+
MemoryReader::ReadBytesResult SecBuf;
494+
if (FileBuffer.hasValue()) {
495+
// sh_offset gives us the offset to the section in the file,
496+
// while sh_addr gives us the offset in the process.
497+
auto Offset = Hdr->sh_offset;
498+
if (FileBuffer->allocatedSize() > Offset + Size) {
499+
Error = true;
500+
break;
501+
}
502+
auto *Buf = malloc(SecSize);
503+
SecBuf = MemoryReader::ReadBytesResult(
504+
Buf, [](const void *ptr) { free(const_cast<void *>(ptr)); });
505+
memcpy((void *)Buf,
506+
(const void *)((uint64_t)FileBuffer->base() + Offset), Size);
507+
} else {
508+
SecBuf = this->getReader().readBytes(SecStart, SecSize);
509+
}
510+
auto SecContents =
511+
RemoteRef<void>(SecStart.getAddressData(), SecBuf.get());
512+
savedBuffers.push_back(std::move(SecBuf));
513+
return {SecContents, SecSize};
514+
}
515+
return {nullptr, 0};
516+
};
461517

462518
SwiftObjectFileFormatELF ObjectFileFormat;
463519
auto FieldMdSec = findELFSectionByName(
@@ -473,6 +529,9 @@ class ReflectionContext
473529
auto ReflStrMdSec = findELFSectionByName(
474530
ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr));
475531

532+
if (Error)
533+
return false;
534+
476535
// We succeed if at least one of the sections is present in the
477536
// ELF executable.
478537
if (FieldMdSec.first == nullptr &&
@@ -492,12 +551,28 @@ class ReflectionContext
492551
{ReflStrMdSec.first, ReflStrMdSec.second}};
493552

494553
this->addReflectionInfo(info);
495-
496-
savedBuffers.push_back(std::move(Buf));
497554
return true;
498555
}
499-
500-
bool readELF(RemoteAddress ImageStart) {
556+
557+
/// Parses metadata information from an ELF image. Because the Section
558+
/// Header Table maybe be missing (for example, when reading from a
559+
/// process) this method optionally receives a buffer with the contents
560+
/// of the image's file, from where it will the necessary information.
561+
///
562+
///
563+
/// \param[in] ImageStart
564+
/// A remote address pointing to the start of the image in the running
565+
/// process.
566+
///
567+
/// \param[in] FileBuffer
568+
/// A buffer which contains the contents of the image's file
569+
/// in disk. If missing, all the information will be read using the
570+
/// instance's memory reader.
571+
///
572+
/// \return
573+
/// /b True if the metadata information was parsed successfully,
574+
/// /b false otherwise.
575+
bool readELF(RemoteAddress ImageStart, llvm::Optional<llvm::sys::MemoryBlock> FileBuffer) {
501576
auto Buf =
502577
this->getReader().readBytes(ImageStart, sizeof(llvm::ELF::Elf64_Ehdr));
503578

@@ -510,9 +585,11 @@ class ReflectionContext
510585
// Check if we have a ELFCLASS32 or ELFCLASS64
511586
unsigned char FileClass = Hdr->getFileClass();
512587
if (FileClass == llvm::ELF::ELFCLASS64) {
513-
return readELFSections<ELFTraits<llvm::ELF::ELFCLASS64>>(ImageStart);
588+
return readELFSections<ELFTraits<llvm::ELF::ELFCLASS64>>(
589+
ImageStart, FileBuffer);
514590
} else if (FileClass == llvm::ELF::ELFCLASS32) {
515-
return readELFSections<ELFTraits<llvm::ELF::ELFCLASS32>>(ImageStart);
591+
return readELFSections<ELFTraits<llvm::ELF::ELFCLASS32>>(
592+
ImageStart, FileBuffer);
516593
} else {
517594
return false;
518595
}
@@ -542,15 +619,16 @@ class ReflectionContext
542619
if (MagicBytes[0] == 'M' && MagicBytes[1] == 'Z') {
543620
return readPECOFF(ImageStart);
544621
}
545-
622+
623+
546624
// ELF.
547625
if (MagicBytes[0] == llvm::ELF::ElfMagic[0]
548626
&& MagicBytes[1] == llvm::ELF::ElfMagic[1]
549627
&& MagicBytes[2] == llvm::ELF::ElfMagic[2]
550628
&& MagicBytes[3] == llvm::ELF::ElfMagic[3]) {
551-
return readELF(ImageStart);
629+
return readELF(ImageStart, llvm::Optional<llvm::sys::MemoryBlock>());
552630
}
553-
631+
554632
// We don't recognize the format.
555633
return false;
556634
}

0 commit comments

Comments
 (0)