From 64cfffd333b261ebb68a6ee04b09cc42d32c1992 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 28 Jan 2016 18:40:06 +0000 Subject: [PATCH] ELF: Rename error -> fatal and redefine error as a non-noreturn function. In many situations, we don't want to exit at the first error even in the process model. For example, it is better to report all undefined symbols rather than reporting the first one that the linker picked up randomly. In order to handle such errors, we don't need to wrap everything with ErrorOr (thanks for David Blaikie for pointing this out!) Instead, we can set a flag to record the fact that we found an error and keep it going until it reaches a reasonable checkpoint. This idea should be applicable to other places. For example, we can ignore broken relocations and check for errors after visiting all relocs. In this patch, I rename error to fatal, and introduce another version of error which doesn't call exit. That function instead sets HasError to true. Once HasError becomes true, it stays true, so that we know that there was an error if it is true. I think introducing a non-noreturn error reporting function is by itself a good idea, and it looks to me that this also provides a gradual path towards lld-as-a-library (or at least embed-lld-to-your-program) without sacrificing code readability with lots of ErrorOr's. http://reviews.llvm.org/D16641 llvm-svn: 259069 --- lld/ELF/Driver.cpp | 30 ++++++++++--------- lld/ELF/Driver.h | 4 +-- lld/ELF/DriverUtils.cpp | 6 ++-- lld/ELF/Error.cpp | 29 +++++++++++++----- lld/ELF/Error.h | 13 ++++++++- lld/ELF/InputFiles.cpp | 60 +++++++++++++++++++------------------- lld/ELF/InputSection.cpp | 8 ++--- lld/ELF/LinkerScript.cpp | 18 ++++++------ lld/ELF/OutputSections.cpp | 42 +++++++++++++------------- lld/ELF/SymbolTable.cpp | 6 ++-- lld/ELF/Target.cpp | 28 +++++++++--------- lld/ELF/Writer.cpp | 8 ++--- lld/include/lld/Driver/Driver.h | 2 +- lld/lib/Driver/UniversalDriver.cpp | 3 +- 14 files changed, 142 insertions(+), 115 deletions(-) diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index f48b594..a0fc13a 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -29,12 +29,14 @@ using namespace lld::elf2; Configuration *elf2::Config; LinkerDriver *elf2::Driver; -void elf2::link(ArrayRef Args) { +bool elf2::link(ArrayRef Args) { + HasError = false; Configuration C; LinkerDriver D; Config = &C; Driver = &D; Driver->main(Args.slice(1)); + return !HasError; } static std::pair parseEmulation(StringRef S) { @@ -53,22 +55,22 @@ static std::pair parseEmulation(StringRef S) { if (S == "aarch64linux") return {ELF64LEKind, EM_AARCH64}; if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - error("Windows targets are not supported on the ELF frontend: " + S); - error("Unknown emulation: " + S); + fatal("Windows targets are not supported on the ELF frontend: " + S); + fatal("Unknown emulation: " + S); } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. static std::vector getArchiveMembers(MemoryBufferRef MB) { ErrorOr> FileOrErr = Archive::create(MB); - error(FileOrErr, "Failed to parse archive"); + fatal(FileOrErr, "Failed to parse archive"); std::unique_ptr File = std::move(*FileOrErr); std::vector V; for (const ErrorOr &C : File->children()) { - error(C, "Could not get the child of the archive " + File->getFileName()); + fatal(C, "Could not get the child of the archive " + File->getFileName()); ErrorOr MbOrErr = C->getMemoryBufferRef(); - error(MbOrErr, "Could not get the buffer for a child of the archive " + + fatal(MbOrErr, "Could not get the buffer for a child of the archive " + File->getFileName()); V.push_back(*MbOrErr); } @@ -82,7 +84,7 @@ void LinkerDriver::addFile(StringRef Path) { if (Config->Verbose) llvm::outs() << Path << "\n"; auto MBOrErr = MemoryBuffer::getFile(Path); - error(MBOrErr, "cannot open " + Path); + fatal(MBOrErr, "cannot open " + Path); std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); OwningMBs.push_back(std::move(MB)); // take MB ownership @@ -114,15 +116,15 @@ static void checkOptions(opt::InputArgList &Args) { // of executables or DSOs. We don't support that since the feature // does not seem to provide more value than the static archiver. if (Args.hasArg(OPT_relocatable)) - error("-r option is not supported. Use 'ar' command instead."); + fatal("-r option is not supported. Use 'ar' command instead."); // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) - error("The .gnu.hash section is not compatible with the MIPS target."); + fatal("The .gnu.hash section is not compatible with the MIPS target."); if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty()) - error("-e option is not valid for AMDGPU."); + fatal("-e option is not valid for AMDGPU."); } static StringRef @@ -161,7 +163,7 @@ void LinkerDriver::main(ArrayRef ArgsArr) { link(Args); return; default: - error("-m or at least a .o file required"); + fatal("-m or at least a .o file required"); } } @@ -217,7 +219,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_O)) { StringRef Val = Arg->getValue(); if (Val.getAsInteger(10, Config->Optimize)) - error("Invalid optimization level"); + fatal("Invalid optimization level"); } if (auto *Arg = Args.getLastArg(OPT_hash_style)) { @@ -228,7 +230,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { } else if (S == "both") { Config->GnuHash = true; } else if (S != "sysv") - error("Unknown hash style: " + S); + fatal("Unknown hash style: " + S); } for (auto *Arg : Args.filtered(OPT_undefined)) @@ -267,7 +269,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { } if (Files.empty()) - error("no input files."); + fatal("no input files."); } template void LinkerDriver::link(opt::InputArgList &Args) { diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h index 720ef46..95b6d96 100644 --- a/lld/ELF/Driver.h +++ b/lld/ELF/Driver.h @@ -20,8 +20,8 @@ namespace elf2 { extern class LinkerDriver *Driver; -// Entry point of the ELF linker. -void link(ArrayRef Args); +// Entry point of the ELF linker. Returns true on success. +bool link(ArrayRef Args); class LinkerDriver { public: diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp index 965ed4f..52e4633 100644 --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -66,7 +66,7 @@ opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A, // Parse options and then do error checking. opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); if (MissingCount) - error(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + + fatal(Twine("missing arg value for \"") + Args.getArgString(MissingIndex) + "\", expected " + Twine(MissingCount) + (MissingCount == 1 ? " argument.\n" : " arguments")); @@ -74,7 +74,7 @@ opt::InputArgList elf2::parseArgs(llvm::BumpPtrAllocator *A, for (auto *Arg : Unknowns) warning("warning: unknown argument: " + Arg->getSpelling()); if (Unknowns.begin() != Unknowns.end()) - error("unknown argument(s) found"); + fatal("unknown argument(s) found"); return Args; } @@ -104,7 +104,7 @@ std::string elf2::searchLibrary(StringRef Path) { if (!S.empty()) return S; } - error("Unable to find library -l" + Path); + fatal("Unable to find library -l" + Path); } // Makes a path by concatenating Dir and File. diff --git a/lld/ELF/Error.cpp b/lld/ELF/Error.cpp index e0701f7f4..327bb26 100644 --- a/lld/ELF/Error.cpp +++ b/lld/ELF/Error.cpp @@ -15,23 +15,38 @@ namespace lld { namespace elf2 { +bool HasError; + void warning(const Twine &Msg) { llvm::errs() << Msg << "\n"; } void error(const Twine &Msg) { llvm::errs() << Msg << "\n"; - exit(1); + HasError = true; } void error(std::error_code EC, const Twine &Prefix) { - if (!EC) - return; - error(Prefix + ": " + EC.message()); + if (EC) + error(Prefix + ": " + EC.message()); } void error(std::error_code EC) { - if (!EC) - return; - error(EC.message()); + if (EC) + error(EC.message()); +} + +void fatal(const Twine &Msg) { + llvm::errs() << Msg << "\n"; + exit(1); +} + +void fatal(std::error_code EC, const Twine &Prefix) { + if (EC) + fatal(Prefix + ": " + EC.message()); +} + +void fatal(std::error_code EC) { + if (EC) + fatal(EC.message()); } } // namespace elf2 diff --git a/lld/ELF/Error.h b/lld/ELF/Error.h index b1d2e7a..3b6aa69 100644 --- a/lld/ELF/Error.h +++ b/lld/ELF/Error.h @@ -15,9 +15,11 @@ namespace lld { namespace elf2 { +extern bool HasError; + void warning(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void error(const Twine &Msg); +void error(const Twine &Msg); void error(std::error_code EC, const Twine &Prefix); void error(std::error_code EC); @@ -26,6 +28,15 @@ template void error(const ErrorOr &V, const Twine &Prefix) { } template void error(const ErrorOr &V) { error(V.getError()); } +LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); +void fatal(std::error_code EC, const Twine &Prefix); +void fatal(std::error_code EC); + +template void fatal(const ErrorOr &V, const Twine &Prefix) { + fatal(V.getError(), Prefix); +} +template void fatal(const ErrorOr &V) { fatal(V.getError()); } + } // namespace elf2 } // namespace lld diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index b43a9b3..fa7c339 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -27,7 +27,7 @@ class ECRAII { public: std::error_code &getEC() { return EC; } - ~ECRAII() { error(EC); } + ~ECRAII() { fatal(EC); } }; } @@ -51,7 +51,7 @@ ELFFileBase::getSymbolsHelper(bool Local) { uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); uint32_t FirstNonLocal = Symtab->sh_info; if (FirstNonLocal > NumSymbols) - error("Invalid sh_info in symbol table"); + fatal("Invalid sh_info in symbol table"); if (!Local) return make_range(Syms.begin() + FirstNonLocal, Syms.end()); // +1 to skip over dummy symbol. @@ -72,7 +72,7 @@ template void ELFFileBase::initStringTable() { if (!Symtab) return; ErrorOr StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab); - error(StringTableOrErr); + fatal(StringTableOrErr); StringTable = *StringTableOrErr; } @@ -122,14 +122,14 @@ StringRef ObjectFile::getShtGroupSignature(const Elf_Shdr &Sec) { const ELFFile &Obj = this->ELFObj; uint32_t SymtabdSectionIndex = Sec.sh_link; ErrorOr SecOrErr = Obj.getSection(SymtabdSectionIndex); - error(SecOrErr); + fatal(SecOrErr); const Elf_Shdr *SymtabSec = *SecOrErr; uint32_t SymIndex = Sec.sh_info; const Elf_Sym *Sym = Obj.getSymbol(SymtabSec, SymIndex); ErrorOr StringTableOrErr = Obj.getStringTableForSymtab(*SymtabSec); - error(StringTableOrErr); + fatal(StringTableOrErr); ErrorOr SignatureOrErr = Sym->getName(*StringTableOrErr); - error(SignatureOrErr); + fatal(SignatureOrErr); return *SignatureOrErr; } @@ -139,10 +139,10 @@ ObjectFile::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile &Obj = this->ELFObj; ErrorOr> EntriesOrErr = Obj.template getSectionContentsAsArray(&Sec); - error(EntriesOrErr); + fatal(EntriesOrErr); ArrayRef Entries = *EntriesOrErr; if (Entries.empty() || Entries[0] != GRP_COMDAT) - error("Unsupported SHT_GROUP format"); + fatal("Unsupported SHT_GROUP format"); return Entries.slice(1); } @@ -153,10 +153,10 @@ static bool shouldMerge(const typename ELFFile::Elf_Shdr &Sec) { if (!(Flags & SHF_MERGE)) return false; if (Flags & SHF_WRITE) - error("Writable SHF_MERGE sections are not supported"); + fatal("Writable SHF_MERGE sections are not supported"); uintX_t EntSize = Sec.sh_entsize; if (!EntSize || Sec.sh_size % EntSize) - error("SHF_MERGE section size must be a multiple of sh_entsize"); + fatal("SHF_MERGE section size must be a multiple of sh_entsize"); // Don't try to merge if the aligment is larger than the sh_entsize. // @@ -191,7 +191,7 @@ void ObjectFile::initializeSections(DenseSet &ComdatGroups) { continue; for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) - error("Invalid section index in group"); + fatal("Invalid section index in group"); Sections[SecIndex] = &InputSection::Discarded; } break; @@ -200,7 +200,7 @@ void ObjectFile::initializeSections(DenseSet &ComdatGroups) { break; case SHT_SYMTAB_SHNDX: { ErrorOr> ErrorOrTable = Obj.getSHNDXTable(Sec); - error(ErrorOrTable); + fatal(ErrorOrTable); this->SymtabSHNDX = *ErrorOrTable; break; } @@ -211,19 +211,19 @@ void ObjectFile::initializeSections(DenseSet &ComdatGroups) { case SHT_REL: { uint32_t RelocatedSectionIndex = Sec.sh_info; if (RelocatedSectionIndex >= Size) - error("Invalid relocated section index"); + fatal("Invalid relocated section index"); InputSectionBase *RelocatedSection = Sections[RelocatedSectionIndex]; if (!RelocatedSection) - error("Unsupported relocation reference"); + fatal("Unsupported relocation reference"); if (auto *S = dyn_cast>(RelocatedSection)) { S->RelocSections.push_back(&Sec); } else if (auto *S = dyn_cast>(RelocatedSection)) { if (S->RelocSection) - error("Multiple relocation sections to .eh_frame are not supported"); + fatal("Multiple relocation sections to .eh_frame are not supported"); S->RelocSection = &Sec; } else { - error("Relocations pointing to SHF_MERGE are not supported"); + fatal("Relocations pointing to SHF_MERGE are not supported"); } break; } @@ -236,7 +236,7 @@ void ObjectFile::initializeSections(DenseSet &ComdatGroups) { template InputSectionBase * ObjectFile::createInputSection(const Elf_Shdr &Sec) { ErrorOr NameOrErr = this->ELFObj.getSectionName(&Sec); - error(NameOrErr); + fatal(NameOrErr); StringRef Name = *NameOrErr; // .note.GNU-stack is a marker section to control the presence of @@ -276,14 +276,14 @@ ObjectFile::getSection(const Elf_Sym &Sym) const { if (Index == 0) return nullptr; if (Index >= Sections.size() || !Sections[Index]) - error("Invalid section index"); + fatal("Invalid section index"); return Sections[Index]; } template SymbolBody *ObjectFile::createSymbolBody(const Elf_Sym *Sym) { ErrorOr NameOrErr = Sym->getName(this->StringTable); - error(NameOrErr); + fatal(NameOrErr); StringRef Name = *NameOrErr; switch (Sym->st_shndx) { @@ -297,7 +297,7 @@ SymbolBody *ObjectFile::createSymbolBody(const Elf_Sym *Sym) { switch (Sym->getBinding()) { default: - error("unexpected binding"); + fatal("unexpected binding"); case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: { @@ -311,7 +311,7 @@ SymbolBody *ObjectFile::createSymbolBody(const Elf_Sym *Sym) { void ArchiveFile::parse() { ErrorOr> FileOrErr = Archive::create(MB); - error(FileOrErr, "Failed to parse archive"); + fatal(FileOrErr, "Failed to parse archive"); File = std::move(*FileOrErr); // Allocate a buffer for Lazy objects. @@ -326,7 +326,7 @@ void ArchiveFile::parse() { // Returns a buffer pointing to a member file containing a given symbol. MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { ErrorOr COrErr = Sym->getMember(); - error(COrErr, "Could not get the member for symbol " + Sym->getName()); + fatal(COrErr, "Could not get the member for symbol " + Sym->getName()); const Archive::Child &C = *COrErr; if (!Seen.insert(C.getChildOffset()).second) @@ -334,8 +334,8 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { ErrorOr RefOrErr = C.getMemoryBufferRef(); if (!RefOrErr) - error(RefOrErr, "Could not get the buffer for the member defining symbol " + - Sym->getName()); + fatal(RefOrErr, "Could not get the buffer for the member defining symbol " + + Sym->getName()); return *RefOrErr; } @@ -350,7 +350,7 @@ SharedFile::getSection(const Elf_Sym &Sym) const { if (Index == 0) return nullptr; ErrorOr Ret = this->ELFObj.getSection(Index); - error(Ret); + fatal(Ret); return *Ret; } @@ -374,7 +374,7 @@ template void SharedFile::parseSoName() { break; case SHT_SYMTAB_SHNDX: { ErrorOr> ErrorOrTable = Obj.getSHNDXTable(Sec); - error(ErrorOrTable); + fatal(ErrorOrTable); this->SymtabSHNDX = *ErrorOrTable; break; } @@ -394,7 +394,7 @@ template void SharedFile::parseSoName() { if (Dyn.d_tag == DT_SONAME) { uintX_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) - error("Invalid DT_SONAME entry"); + fatal("Invalid DT_SONAME entry"); SoName = StringRef(this->StringTable.data() + Val); return; } @@ -408,7 +408,7 @@ template void SharedFile::parseRest() { SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) { ErrorOr NameOrErr = Sym.getName(this->StringTable); - error(NameOrErr.getError()); + fatal(NameOrErr.getError()); StringRef Name = *NameOrErr; if (Sym.isUndefined()) @@ -437,7 +437,7 @@ template