Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -102,16 +102,19 @@ case file_magic::archive: if (WholeArchive) { for (MemoryBufferRef MB : getArchiveMembers(MBRef)) - Files.push_back(createObjectFile(MB)); + if (std::unique_ptr F = createObjectFile(MB)) + Files.push_back(std::move(F)); return; } Files.push_back(make_unique(MBRef)); return; case file_magic::elf_shared_object: - Files.push_back(createSharedFile(MBRef)); + if (std::unique_ptr F = createSharedFile(MBRef)) + Files.push_back(std::move(F)); return; default: - Files.push_back(createObjectFile(MBRef)); + if (std::unique_ptr F = createObjectFile(MBRef)) + Files.push_back(std::move(F)); } } Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -77,7 +77,7 @@ const Elf_Shdr *Symtab = nullptr; ArrayRef SymtabSHNDX; StringRef StringTable; - void initStringTable(); + bool initStringTable(); Elf_Sym_Range getNonLocalSymbols(); Elf_Sym_Range getSymbolsHelper(bool); }; @@ -96,7 +96,7 @@ uint32_t, ELFT::TargetEndianness, 2> uint32_X; - StringRef getShtGroupSignature(const Elf_Shdr &Sec); + bool getShtGroupSignature(const Elf_Shdr &Sec, StringRef &Result); ArrayRef getShtGroupEntries(const Elf_Shdr &Sec); public: @@ -107,7 +107,7 @@ ArrayRef getSymbols() { return SymbolBodies; } explicit ObjectFile(MemoryBufferRef M); - void parse(llvm::DenseSet &ComdatGroups); + bool parse(llvm::DenseSet &ComdatGroups); ArrayRef *> getSections() const { return Sections; } InputSectionBase *getSection(const Elf_Sym &Sym) const; @@ -132,9 +132,9 @@ std::vector KeptLocalSyms; private: - void initializeSections(llvm::DenseSet &ComdatGroups); - void initializeSymbols(); - InputSectionBase *createInputSection(const Elf_Shdr &Sec); + bool initializeSections(llvm::DenseSet &ComdatGroups); + bool initializeSymbols(); + InputSectionBase *createInputSection(const Elf_Shdr &Sec, StringRef Name); SymbolBody *createSymbolBody(const Elf_Sym *Sym); @@ -156,7 +156,7 @@ public: explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } - void parse(); + bool parse(); // Returns a memory buffer for a given symbol. An empty memory buffer // is returned if we have already returned the same memory buffer. @@ -197,8 +197,8 @@ explicit SharedFile(MemoryBufferRef M); - void parseSoName(); - void parseRest(); + bool parseSoName(); + bool parseRest(); // Used for --as-needed bool AsNeeded = false; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -27,7 +27,7 @@ public: std::error_code &getEC() { return EC; } - ~ECRAII() { fatal(EC); } + ~ECRAII() { error(EC); } }; } @@ -50,8 +50,10 @@ Elf_Sym_Range Syms = ELFObj.symbols(Symtab); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); uint32_t FirstNonLocal = Symtab->sh_info; - if (FirstNonLocal > NumSymbols) - fatal("Invalid sh_info in symbol table"); + if (FirstNonLocal > NumSymbols) { + error("Invalid sh_info in symbol table"); + return Elf_Sym_Range(nullptr, nullptr); + } if (!Local) return make_range(Syms.begin() + FirstNonLocal, Syms.end()); // +1 to skip over dummy symbol. @@ -68,12 +70,14 @@ return I; } -template void ELFFileBase::initStringTable() { +template bool ELFFileBase::initStringTable() { if (!Symtab) - return; + return true; ErrorOr StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab); - fatal(StringTableOrErr); + if (error(StringTableOrErr, "corrupted file")) + return false; StringTable = *StringTableOrErr; + return true; } template @@ -108,29 +112,36 @@ } template -void ObjectFile::parse(DenseSet &ComdatGroups) { +bool ObjectFile::parse(DenseSet &ComdatGroups) { // Read section and symbol tables. - initializeSections(ComdatGroups); - initializeSymbols(); + if (!initializeSections(ComdatGroups)) + return false; + if (!initializeSymbols()) + return false; + return true; } // Sections with SHT_GROUP and comdat bits define comdat section groups. // They are identified and deduplicated by group name. This function // returns a group name. template -StringRef ObjectFile::getShtGroupSignature(const Elf_Shdr &Sec) { +bool ObjectFile::getShtGroupSignature(const Elf_Shdr &Sec, StringRef &Result) { const ELFFile &Obj = this->ELFObj; uint32_t SymtabdSectionIndex = Sec.sh_link; ErrorOr SecOrErr = Obj.getSection(SymtabdSectionIndex); - fatal(SecOrErr); + if (error(SecOrErr, "corrupted file")) + return false; const Elf_Shdr *SymtabSec = *SecOrErr; uint32_t SymIndex = Sec.sh_info; const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex); ErrorOr StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec); - fatal(StringTableOrErr); + if (error(StringTableOrErr, "corrupted file")) + return false; ErrorOr SignatureOrErr = Sym->getName(*StringTableOrErr); - fatal(SignatureOrErr); - return *SignatureOrErr; + if (error(SignatureOrErr, "corrupted file")) + return false; + Result = *SignatureOrErr; + return true; } template @@ -139,10 +150,13 @@ const ELFFile &Obj = this->ELFObj; ErrorOr> EntriesOrErr = Obj.template getSectionContentsAsArray(&Sec); - fatal(EntriesOrErr); + if (error(EntriesOrErr, "corrupted file")) + return {}; ArrayRef Entries = *EntriesOrErr; - if (Entries.empty() || Entries[0] != GRP_COMDAT) - fatal("Unsupported SHT_GROUP format"); + if (Entries.empty() || Entries[0] != GRP_COMDAT) { + error("Unsupported SHT_GROUP format"); + return {}; + } return Entries.slice(1); } @@ -152,11 +166,15 @@ uintX_t Flags = Sec.sh_flags; if (!(Flags & SHF_MERGE)) return false; - if (Flags & SHF_WRITE) - fatal("Writable SHF_MERGE sections are not supported"); + if (Flags & SHF_WRITE) { + error("Writable SHF_MERGE sections are not supported"); + return false; + } uintX_t EntSize = Sec.sh_entsize; - if (!EntSize || Sec.sh_size % EntSize) - fatal("SHF_MERGE section size must be a multiple of sh_entsize"); + if (!EntSize || Sec.sh_size % EntSize) { + error("SHF_MERGE section size must be a multiple of sh_entsize"); + return false; + } // Don't try to merge if the aligment is larger than the sh_entsize. // @@ -169,12 +187,11 @@ // justify the effort. if (Sec.sh_addralign > EntSize) return false; - return true; } template -void ObjectFile::initializeSections(DenseSet &ComdatGroups) { +bool ObjectFile::initializeSections(DenseSet &ComdatGroups) { uint64_t Size = this->ELFObj.getNumSections(); Sections.resize(Size); unsigned I = -1; @@ -185,22 +202,29 @@ continue; switch (Sec.sh_type) { - case SHT_GROUP: + case SHT_GROUP: { Sections[I] = &InputSection::Discarded; - if (ComdatGroups.insert(getShtGroupSignature(Sec)).second) + StringRef Sig; + if (!getShtGroupSignature(Sec, Sig)) + return false; + if (ComdatGroups.insert(Sig).second) continue; for (uint32_t SecIndex : getShtGroupEntries(Sec)) { - if (SecIndex >= Size) - fatal("Invalid section index in group"); + if (SecIndex >= Size) { + error("Invalid section index in group"); + return false; + } Sections[SecIndex] = &InputSection::Discarded; } break; + } case SHT_SYMTAB: this->Symtab = &Sec; break; case SHT_SYMTAB_SHNDX: { ErrorOr> ErrorOrTable = Obj.getSHNDXTable(Sec); - fatal(ErrorOrTable); + if (error(ErrorOrTable, "corrupted file")) + return false; this->SymtabSHNDX = *ErrorOrTable; break; } @@ -210,35 +234,43 @@ case SHT_RELA: case SHT_REL: { uint32_t RelocatedSectionIndex = Sec.sh_info; - if (RelocatedSectionIndex >= Size) - fatal("Invalid relocated section index"); + if (RelocatedSectionIndex >= Size) { + error("Invalid relocated section index"); + return false; + } InputSectionBase *RelocatedSection = Sections[RelocatedSectionIndex]; - if (!RelocatedSection) - fatal("Unsupported relocation reference"); + if (!RelocatedSection) { + error("Unsupported relocation reference"); + return false; + } if (auto *S = dyn_cast>(RelocatedSection)) { S->RelocSections.push_back(&Sec); - } else if (auto *S = dyn_cast>(RelocatedSection)) { - if (S->RelocSection) - fatal("Multiple relocation sections to .eh_frame are not supported"); + break; + } + if (auto *S = dyn_cast>(RelocatedSection)) { + if (S->RelocSection) { + error("Multiple relocation sections to .eh_frame are not supported"); + return false; + } S->RelocSection = &Sec; - } else { - fatal("Relocations pointing to SHF_MERGE are not supported"); + break; } - break; + error("Relocations pointing to SHF_MERGE are not supported"); + return false; } default: - Sections[I] = createInputSection(Sec); + ErrorOr NameOrErr = this->ELFObj.getSectionName(&Sec); + if (error(NameOrErr, "corrupted file")) + return false; + Sections[I] = createInputSection(Sec, *NameOrErr); } } + return true; } template InputSectionBase * -ObjectFile::createInputSection(const Elf_Shdr &Sec) { - ErrorOr NameOrErr = this->ELFObj.getSectionName(&Sec); - fatal(NameOrErr); - StringRef Name = *NameOrErr; - +ObjectFile::createInputSection(const Elf_Shdr &Sec, StringRef Name) { // .note.GNU-stack is a marker section to control the presence of // PT_GNU_STACK segment in outputs. Since the presence of the segment // is controlled only by the command line option (-z execstack) in LLD, @@ -260,13 +292,19 @@ return new (Alloc) InputSection(this, &Sec); } -template void ObjectFile::initializeSymbols() { - this->initStringTable(); +template bool ObjectFile::initializeSymbols() { + if (!this->initStringTable()) + return false; Elf_Sym_Range Syms = this->getNonLocalSymbols(); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); - for (const Elf_Sym &Sym : Syms) - SymbolBodies.push_back(createSymbolBody(&Sym)); + for (const Elf_Sym &Sym : Syms) { + SymbolBody *B = createSymbolBody(&Sym); + if (!B) + return false; + SymbolBodies.push_back(B); + } + return true; } template @@ -275,15 +313,18 @@ uint32_t Index = this->getSectionIndex(Sym); if (Index == 0) return nullptr; - if (Index >= Sections.size() || !Sections[Index]) - fatal("Invalid section index"); + if (Index >= Sections.size() || !Sections[Index]) { + error("Invalid section index"); + return nullptr; + } return Sections[Index]; } template SymbolBody *ObjectFile::createSymbolBody(const Elf_Sym *Sym) { ErrorOr NameOrErr = Sym->getName(this->StringTable); - fatal(NameOrErr); + if (error(NameOrErr, "corrupted file")) + return nullptr; StringRef Name = *NameOrErr; switch (Sym->st_shndx) { @@ -297,7 +338,8 @@ switch (Sym->getBinding()) { default: - fatal("unexpected binding"); + error("unexpected binding"); + return nullptr; case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: { @@ -309,9 +351,10 @@ } } -void ArchiveFile::parse() { +bool ArchiveFile::parse() { ErrorOr> FileOrErr = Archive::create(MB); - fatal(FileOrErr, "Failed to parse archive"); + if (error(FileOrErr, "Failed to parse archive")) + return false; File = std::move(*FileOrErr); // Allocate a buffer for Lazy objects. @@ -321,21 +364,23 @@ // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) LazySymbols.emplace_back(this, Sym); + return true; } // Returns a buffer pointing to a member file containing a given symbol. MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { ErrorOr COrErr = Sym->getMember(); - fatal(COrErr, "Could not get the member for symbol " + Sym->getName()); + if (error(COrErr, "Could not get the member for symbol " + Sym->getName())) + return MemoryBufferRef(); const Archive::Child &C = *COrErr; if (!Seen.insert(C.getChildOffset()).second) return MemoryBufferRef(); ErrorOr RefOrErr = C.getMemoryBufferRef(); - if (!RefOrErr) - fatal(RefOrErr, "Could not get the buffer for the member defining symbol " + - Sym->getName()); + if (error(RefOrErr, "Could not get the buffer for the member defining symbol " + + Sym->getName())) + return MemoryBufferRef(); return *RefOrErr; } @@ -350,13 +395,14 @@ if (Index == 0) return nullptr; ErrorOr Ret = this->ELFObj.getSection(Index); - fatal(Ret); + if (error(Ret, "corrupted file")) + return nullptr; return *Ret; } // Partially parse the shared object file so that we can call // getSoName on this object. -template void SharedFile::parseSoName() { +template bool SharedFile::parseSoName() { typedef typename ELFFile::Elf_Dyn Elf_Dyn; typedef typename ELFFile::uintX_t uintX_t; const Elf_Shdr *DynamicSec = nullptr; @@ -374,18 +420,20 @@ break; case SHT_SYMTAB_SHNDX: { ErrorOr> ErrorOrTable = Obj.getSHNDXTable(Sec); - fatal(ErrorOrTable); + if (error(ErrorOrTable, "corrupted file")) + return false; this->SymtabSHNDX = *ErrorOrTable; break; } } } - this->initStringTable(); + if (!this->initStringTable()) + return false; SoName = this->getName(); if (!DynamicSec) - return; + return true; auto *Begin = reinterpret_cast(Obj.base() + DynamicSec->sh_offset); const Elf_Dyn *End = Begin + DynamicSec->sh_size / sizeof(Elf_Dyn); @@ -393,22 +441,26 @@ for (const Elf_Dyn &Dyn : make_range(Begin, End)) { if (Dyn.d_tag == DT_SONAME) { uintX_t Val = Dyn.getVal(); - if (Val >= this->StringTable.size()) - fatal("Invalid DT_SONAME entry"); + if (Val >= this->StringTable.size()) { + error("Invalid DT_SONAME entry"); + return false; + } SoName = StringRef(this->StringTable.data() + Val); - return; + return true; } } + return true; } // Fully parse the shared object file. This must be called after parseSoName(). -template void SharedFile::parseRest() { +template bool SharedFile::parseRest() { Elf_Sym_Range Syms = this->getNonLocalSymbols(); uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) { ErrorOr NameOrErr = Sym.getName(this->StringTable); - fatal(NameOrErr.getError()); + if (error(NameOrErr, "Failed to get a string table")) + return false; StringRef Name = *NameOrErr; if (Sym.isUndefined()) @@ -416,6 +468,7 @@ else SymbolBodies.emplace_back(this, Name, Sym); } + return true; } template @@ -436,8 +489,10 @@ template