diff --git a/lld/COFF/CMakeLists.txt b/lld/COFF/CMakeLists.txt index 503004272ea0..4610ccc880fd 100644 --- a/lld/COFF/CMakeLists.txt +++ b/lld/COFF/CMakeLists.txt @@ -11,7 +11,6 @@ add_lld_library(lldCOFF DLL.cpp Driver.cpp DriverUtils.cpp - Error.cpp ICF.cpp InputFiles.cpp LTO.cpp diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index 0f0d622eaf3b..00cda81e72c7 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "Chunks.h" -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index e6ade3be5055..0c8a9b9c26f2 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -84,13 +84,10 @@ struct Configuration { bool NoEntry = false; std::string OutputFile; std::string ImportName; - bool ColorDiagnostics; bool DoGC = true; bool DoICF = true; - uint64_t ErrorLimit = 20; bool Relocatable = true; bool Force = false; - bool FatalWarnings = false; bool Debug = false; bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 94dfc31eda70..c3cb1d95d8db 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -9,7 +9,6 @@ #include "Driver.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "MinGW.h" @@ -17,6 +16,7 @@ #include "Symbols.h" #include "Writer.h" #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" @@ -55,12 +55,14 @@ StringSaver Saver{BAlloc}; std::vector SpecificAllocBase::Instances; bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { - ErrorCount = 0; - ErrorOS = &Diag; - + errorHandler().LogName = Args[0]; + errorHandler().ErrorOS = &Diag; + errorHandler().ColorDiagnostics = Diag.has_colors(); + errorHandler().ErrorLimitExceededMsg = + "too many errors emitted, stopping now" + " (use /ERRORLIMIT:0 to see all errors)"; Config = make(); Config->Argv = {Args.begin(), Args.end()}; - Config->ColorDiagnostics = ErrorOS->has_colors(); Config->CanExitEarly = CanExitEarly; Symtab = make(); @@ -70,10 +72,10 @@ bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) { // Call exit() if we can to avoid calling destructors. if (CanExitEarly) - exitLld(ErrorCount ? 1 : 0); + exitLld(errorCount() ? 1 : 0); freeArena(); - return !ErrorCount; + return !errorCount(); } // Drop directory components and replace extension with ".exe" or ".dll". @@ -212,8 +214,8 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &C, enqueueTask([=]() { auto MBOrErr = Future->get(); if (MBOrErr.second) - fatal(MBOrErr.second, - "could not get the buffer for the member defining " + SymName); + fatal("could not get the buffer for the member defining " + SymName + + ": " + MBOrErr.second.message()); Driver->addArchiveBuffer(takeBuffer(std::move(MBOrErr.first)), SymName, ParentName); }); @@ -619,7 +621,7 @@ filterBitcodeFiles(StringRef Path, std::vector &TemporaryFiles) { SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), ".lib", S)) - fatal(EC, "cannot create a temporary file"); + fatal("cannot create a temporary file: " + EC.message()); std::string Temp = S.str(); TemporaryFiles.push_back(Temp); @@ -648,7 +650,7 @@ void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { int Fd; if (auto EC = sys::fs::createTemporaryFile( "lld-" + sys::path::filename(Obj->ParentName), ".obj", Fd, S)) - fatal(EC, "cannot create a temporary file"); + fatal("cannot create a temporary file: " + EC.message()); raw_fd_ostream OS(Fd, /*shouldClose*/ true); OS << Obj->MB.getBuffer(); Temps.push_back(S.str()); @@ -736,7 +738,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { StringRef S = Arg->getValue(); if (S.getAsInteger(10, N)) error(Arg->getSpelling() + " number expected, but got " + S); - Config->ErrorLimit = N; + errorHandler().ErrorLimit = N; } // Handle /help @@ -792,6 +794,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // Handle /verbose if (Args.hasArg(OPT_verbose)) Config->Verbose = true; + errorHandler().Verbose = Config->Verbose; // Handle /force or /force:unresolved if (Args.hasArg(OPT_force) || Args.hasArg(OPT_force_unresolved)) @@ -1010,7 +1013,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { Config->MapFile = getMapFile(Args); - if (ErrorCount) + if (errorCount()) return; bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag); @@ -1191,7 +1194,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { addUndefined(mangle("_load_config_used")); } while (run()); - if (ErrorCount) + if (errorCount()) return; // If /msvclto is given, we use the MSVC linker to link LTO output files. @@ -1208,7 +1211,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { // Make sure we have resolved all symbols. Symtab->reportRemainingUndefines(); - if (ErrorCount) + if (errorCount()) return; // Windows specific -- if no /subsystem is given, we need to infer @@ -1224,7 +1227,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) { for (ObjFile *File : ObjFile::Instances) if (!File->SEHCompat) error("/safeseh: " + File->getName() + " is not compatible with SEH"); - if (ErrorCount) + if (errorCount()) return; } diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index a892d1a24b7a..964a5e1ec970 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -15,9 +15,9 @@ #include "Config.h" #include "Driver.h" -#include "Error.h" #include "Memory.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/BinaryFormat/COFF.h" @@ -57,7 +57,7 @@ public: void run() { ErrorOr ExeOrErr = sys::findProgramByName(Prog); if (auto EC = ExeOrErr.getError()) - fatal(EC, "unable to find " + Prog + " in PATH"); + fatal("unable to find " + Prog + " in PATH: " + EC.message()); StringRef Exe = Saver.save(*ExeOrErr); Args.insert(Args.begin(), Exe); @@ -288,14 +288,14 @@ public: TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") { SmallString<128> S; if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S)) - fatal(EC, "cannot create a temporary file"); + fatal("cannot create a temporary file: " + EC.message()); Path = S.str(); if (!Contents.empty()) { std::error_code EC; raw_fd_ostream OS(Path, EC, sys::fs::F_None); if (EC) - fatal(EC, "failed to open " + Path); + fatal("failed to open " + Path + ": " + EC.message()); OS << Contents; } } @@ -363,13 +363,15 @@ static std::string createManifestXmlWithInternalMt(StringRef DefaultXml) { windows_manifest::WindowsManifestMerger Merger; if (auto E = Merger.merge(*DefaultXmlCopy.get())) - fatal(E, "internal manifest tool failed on default xml"); + fatal("internal manifest tool failed on default xml: " + + toString(std::move(E))); for (StringRef Filename : Config->ManifestInput) { std::unique_ptr Manifest = check(MemoryBuffer::getFile(Filename)); if (auto E = Merger.merge(*Manifest.get())) - fatal(E, "internal manifest tool failed on file " + Filename); + fatal("internal manifest tool failed on file " + Filename + ": " + + toString(std::move(E))); } return Merger.getMergedManifest().get()->getBuffer(); @@ -381,7 +383,7 @@ static std::string createManifestXmlWithExternalMt(StringRef DefaultXml) { std::error_code EC; raw_fd_ostream OS(Default.Path, EC, sys::fs::F_Text); if (EC) - fatal(EC, "failed to open " + Default.Path); + fatal("failed to open " + Default.Path + ": " + EC.message()); OS << DefaultXml; OS.close(); @@ -482,7 +484,7 @@ void createSideBySideManifest() { std::error_code EC; raw_fd_ostream Out(Path, EC, sys::fs::F_Text); if (EC) - fatal(EC, "failed to create manifest"); + fatal("failed to create manifest: " + EC.message()); Out << createManifestXml(); } @@ -649,13 +651,13 @@ MemoryBufferRef convertResToCOFF(const std::vector &MBs) { if (!RF) fatal("cannot compile non-resource file as resource"); if (auto EC = Parser.parse(RF)) - fatal(EC, "failed to parse .res file"); + fatal("failed to parse .res file: " + toString(std::move(EC))); } Expected> E = llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); if (!E) - fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF"); + fatal("failed to write .res to COFF: " + toString(E.takeError())); MemoryBufferRef MBRef = **E; make>(std::move(*E)); // take ownership @@ -739,7 +741,7 @@ opt::InputArgList ArgParser::parse(ArrayRef Argv) { } // Handle /WX early since it converts missing argument warnings to errors. - Config->FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); + errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); diff --git a/lld/COFF/Error.cpp b/lld/COFF/Error.cpp deleted file mode 100644 index 4b9c377cb6b2..000000000000 --- a/lld/COFF/Error.cpp +++ /dev/null @@ -1,120 +0,0 @@ -//===- Error.cpp ----------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Error.h" -#include "Config.h" - -#include "llvm/ADT/Twine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" -#include - -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include -#endif - -using namespace llvm; - -namespace lld { -// The functions defined in this file can be called from multiple threads, -// but outs() or errs() are not thread-safe. We protect them using a mutex. -static std::mutex Mu; - -namespace coff { -uint64_t ErrorCount; -raw_ostream *ErrorOS; - -LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { - // Dealloc/destroy ManagedStatic variables before calling - // _exit(). In a non-LTO build, this is a nop. In an LTO - // build allows us to get the output of -time-passes. - llvm_shutdown(); - - outs().flush(); - errs().flush(); - _exit(Val); -} - -static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Config->Argv[0] << ": "; - if (Config->ColorDiagnostics) { - ErrorOS->changeColor(C, true); - *ErrorOS << S; - ErrorOS->resetColor(); - } else { - *ErrorOS << S; - } -} - -void log(const Twine &Msg) { - if (Config->Verbose) { - std::lock_guard Lock(Mu); - outs() << Config->Argv[0] << ": " << Msg << "\n"; - outs().flush(); - } -} - -void message(const Twine &Msg) { - std::lock_guard Lock(Mu); - outs() << Msg << "\n"; - outs().flush(); -} - -void error(const Twine &Msg) { - std::lock_guard Lock(Mu); - - if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << Msg << "\n"; - } else if (ErrorCount == Config->ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << "too many errors emitted, stopping now" - << " (use /ERRORLIMIT:0 to see all errors)\n"; - if (Config->CanExitEarly) - exitLld(1); - } - - ++ErrorCount; -} - -void fatal(const Twine &Msg) { - if (Config->ColorDiagnostics) { - errs().changeColor(raw_ostream::RED, /*bold=*/true); - errs() << "error: "; - errs().resetColor(); - } else { - errs() << "error: "; - } - errs() << Msg << "\n"; - exitLld(1); -} - -void fatal(std::error_code EC, const Twine &Msg) { - fatal(Msg + ": " + EC.message()); -} - -void fatal(llvm::Error &Err, const Twine &Msg) { - fatal(errorToErrorCode(std::move(Err)), Msg); -} - -void warn(const Twine &Msg) { - if (Config->FatalWarnings) { - error(Msg); - return; - } - - std::lock_guard Lock(Mu); - print("warning: ", raw_ostream::MAGENTA); - *ErrorOS << Msg << "\n"; -} - -} // namespace coff -} // namespace lld diff --git a/lld/COFF/Error.h b/lld/COFF/Error.h deleted file mode 100644 index ac3bf81f30f4..000000000000 --- a/lld/COFF/Error.h +++ /dev/null @@ -1,64 +0,0 @@ -//===- Error.h --------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_COFF_ERROR_H -#define LLD_COFF_ERROR_H - -#include "lld/Common/LLVM.h" -#include "llvm/Support/Error.h" - -namespace lld { -namespace coff { - -extern uint64_t ErrorCount; -extern llvm::raw_ostream *ErrorOS; - -void log(const Twine &Msg); -void message(const Twine &Msg); -void warn(const Twine &Msg); -void error(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); -LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix); - -LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); - -template T check(ErrorOr V, const Twine &Prefix) { - if (auto EC = V.getError()) - fatal(EC, Prefix); - return std::move(*V); -} - -template T check(Expected E, const Twine &Prefix) { - if (llvm::Error Err = E.takeError()) - fatal(Err, Prefix); - return std::move(*E); -} - -template T check(ErrorOr EO) { - if (!EO) - fatal(EO.getError().message()); - return std::move(*EO); -} - -template T check(Expected E) { - if (!E) { - std::string Buf; - llvm::raw_string_ostream OS(Buf); - logAllUnhandledErrors(E.takeError(), OS, ""); - OS.flush(); - fatal(Buf); - } - return std::move(*E); -} - -} // namespace coff -} // namespace lld - -#endif diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp index 1032fb0ec7aa..3247d1e1065b 100644 --- a/lld/COFF/ICF.cpp +++ b/lld/COFF/ICF.cpp @@ -19,8 +19,8 @@ //===----------------------------------------------------------------------===// #include "Chunks.h" -#include "Error.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Parallel.h" diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index ef2938697557..534194de8fd1 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -11,10 +11,10 @@ #include "Chunks.h" #include "Config.h" #include "Driver.h" -#include "Error.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm-c/lto.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" @@ -127,9 +127,9 @@ void ObjFile::initializeChunks() { const coff_section *Sec; StringRef Name; if (auto EC = COFFObj->getSection(I, Sec)) - fatal(EC, "getSection failed: #" + Twine(I)); + fatal("getSection failed: #" + Twine(I) + ": " + EC.message()); if (auto EC = COFFObj->getSectionName(Sec, Name)) - fatal(EC, "getSectionName failed: #" + Twine(I)); + fatal("getSectionName failed: #" + Twine(I) + ": " + EC.message()); if (Name == ".sxdata") { SXData = Sec; continue; @@ -179,7 +179,6 @@ void ObjFile::initializeSymbols() { int32_t LastSectionNumber = 0; for (uint32_t I = 0; I < NumSymbols; ++I) { - // Get a COFFSymbolRef object. COFFSymbolRef Sym = check(COFFObj->getSymbol(I)); const void *AuxP = nullptr; diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index f3c8bfbea958..b84599b59cb8 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -9,9 +9,9 @@ #include "LTO.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp index 076f8637c9d5..570bc9cfc6b7 100644 --- a/lld/COFF/MapFile.cpp +++ b/lld/COFF/MapFile.cpp @@ -20,11 +20,11 @@ //===----------------------------------------------------------------------===// #include "MapFile.h" -#include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp index 1337f131e4c2..0655dc481fa1 100644 --- a/lld/COFF/MinGW.cpp +++ b/lld/COFF/MinGW.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "MinGW.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp index c15462910ec3..799870933258 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -11,10 +11,10 @@ #include "Chunks.h" #include "Config.h" #include "Driver.h" -#include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" @@ -188,7 +188,7 @@ maybeReadTypeServerRecord(CVTypeArray &Types) { return None; TypeServer2Record TS; if (auto EC = TypeDeserializer::deserializeAs(const_cast(Type), TS)) - fatal(EC, "error reading type server record"); + fatal("error reading type server record: " + toString(std::move(EC))); return std::move(TS); } @@ -202,7 +202,7 @@ const CVIndexMap &PDBLinker::mergeDebugT(ObjFile *File, CVTypeArray Types; BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Types, Reader.getLength())) - fatal(EC, "Reader::readArray failed"); + fatal("Reader::readArray failed: " + toString(std::move(EC))); // Look through type servers. If we've already seen this type server, don't // merge any type information. @@ -213,7 +213,8 @@ const CVIndexMap &PDBLinker::mergeDebugT(ObjFile *File, // ObjectIndexMap. if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap.TPIMap, Types)) - fatal(Err, "codeview::mergeTypeAndIdRecords failed"); + fatal("codeview::mergeTypeAndIdRecords failed: " + + toString(std::move(Err))); return ObjectIndexMap; } @@ -275,23 +276,23 @@ const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, ExpectedSession = tryToLoadPDB(TS.getGuid(), Path); } if (auto E = ExpectedSession.takeError()) - fatal(E, "Type server PDB was not found"); + fatal("Type server PDB was not found: " + toString(std::move(E))); // Merge TPI first, because the IPI stream will reference type indices. auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); if (auto E = ExpectedTpi.takeError()) - fatal(E, "Type server does not have TPI stream"); + fatal("Type server does not have TPI stream: " + toString(std::move(E))); if (auto Err = mergeTypeRecords(TypeTable, IndexMap.TPIMap, ExpectedTpi->typeArray())) - fatal(Err, "codeview::mergeTypeRecords failed"); + fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err))); // Merge IPI. auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); if (auto E = ExpectedIpi.takeError()) - fatal(E, "Type server does not have TPI stream"); + fatal("Type server does not have TPI stream: " + toString(std::move(E))); if (auto Err = mergeIdRecords(IDTable, IndexMap.TPIMap, IndexMap.IPIMap, ExpectedIpi->typeArray())) - fatal(Err, "codeview::mergeIdRecords failed"); + fatal("codeview::mergeIdRecords failed: " + toString(std::move(Err))); return IndexMap; } diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 3b3004c68975..04dd6546ab1a 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -10,10 +10,10 @@ #include "SymbolTable.h" #include "Config.h" #include "Driver.h" -#include "Error.h" #include "LTO.h" #include "Memory.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp index 2d61590494e8..e08edc50a1b0 100644 --- a/lld/COFF/Symbols.cpp +++ b/lld/COFF/Symbols.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "Strings.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index db446d083eac..08b7e31f7bcd 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -10,13 +10,13 @@ #include "Writer.h" #include "Config.h" #include "DLL.h" -#include "Error.h" #include "InputFiles.h" #include "MapFile.h" #include "Memory.h" #include "PDB.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -316,7 +316,7 @@ void Writer::run() { writeMapFile(OutputSections); if (auto EC = Buffer->commit()) - fatal(EC, "failed to write the output file"); + fatal("failed to write the output file: " + EC.message()); } static StringRef getOutputSection(StringRef Name) { diff --git a/lld/Common/CMakeLists.txt b/lld/Common/CMakeLists.txt index 46873f80852f..3d19fe96ff8f 100644 --- a/lld/Common/CMakeLists.txt +++ b/lld/Common/CMakeLists.txt @@ -3,6 +3,7 @@ if(NOT LLD_BUILT_STANDALONE) endif() add_lld_library(lldCommon + ErrorHandler.cpp Reproduce.cpp TargetOptionsCommandFlags.cpp Threads.cpp diff --git a/lld/ELF/Error.cpp b/lld/Common/ErrorHandler.cpp similarity index 67% rename from lld/ELF/Error.cpp rename to lld/Common/ErrorHandler.cpp index 8173d6ff2206..6e9158344ad5 100644 --- a/lld/ELF/Error.cpp +++ b/lld/Common/ErrorHandler.cpp @@ -1,4 +1,4 @@ -//===- Error.cpp ----------------------------------------------------------===// +//===- ErrorHandler.cpp ---------------------------------------------------===// // // The LLVM Linker // @@ -7,8 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" -#include "Config.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" @@ -25,10 +24,6 @@ using namespace llvm; using namespace lld; -using namespace lld::elf; - -uint64_t elf::ErrorCount; -raw_ostream *elf::ErrorOS; // The functions defined in this file can be called from multiple threads, // but outs() or errs() are not thread-safe. We protect them using a mutex. @@ -36,7 +31,7 @@ static std::mutex Mu; // Prints "\n" or does nothing, depending on Msg contents of // the previous call of this function. -static void newline(const Twine &Msg) { +static void newline(raw_ostream *ErrorOS, const Twine &Msg) { // True if the previous error message contained "\n". // We want to separate multi-line error messages with a newline. static bool Flag; @@ -46,64 +41,15 @@ static void newline(const Twine &Msg) { Flag = StringRef(Msg.str()).contains('\n'); } -static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Config->Argv[0] << ": "; - if (Config->ColorDiagnostics) { - ErrorOS->changeColor(C, true); - *ErrorOS << S; - ErrorOS->resetColor(); - } else { - *ErrorOS << S; - } +namespace lld { + +ErrorHandler &errorHandler() { + static ErrorHandler Handler; + return Handler; } -void elf::log(const Twine &Msg) { - if (Config->Verbose) { - std::lock_guard Lock(Mu); - outs() << Config->Argv[0] << ": " << Msg << "\n"; - outs().flush(); - } -} - -void elf::message(const Twine &Msg) { - std::lock_guard Lock(Mu); - outs() << Msg << "\n"; - outs().flush(); -} - -void elf::warn(const Twine &Msg) { - if (Config->FatalWarnings) { - error(Msg); - return; - } - - std::lock_guard Lock(Mu); - newline(Msg); - print("warning: ", raw_ostream::MAGENTA); - *ErrorOS << Msg << "\n"; -} - -void elf::error(const Twine &Msg) { - std::lock_guard Lock(Mu); - newline(Msg); - - if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << Msg << "\n"; - } else if (ErrorCount == Config->ErrorLimit) { - print("error: ", raw_ostream::RED); - *ErrorOS << "too many errors emitted, stopping now" - << " (use -error-limit=0 to see all errors)\n"; - if (Config->ExitEarly) - exitLld(1); - } - - ++ErrorCount; -} - -void elf::exitLld(int Val) { +void exitLld(int Val) { waitForBackgroundThreads(); - // Dealloc/destroy ManagedStatic variables before calling // _exit(). In a non-LTO build, this is a nop. In an LTO // build allows us to get the output of -time-passes. @@ -114,7 +60,63 @@ void elf::exitLld(int Val) { _exit(Val); } -void elf::fatal(const Twine &Msg) { +void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << LogName << ": "; + if (ColorDiagnostics) { + ErrorOS->changeColor(C, true); + *ErrorOS << S; + ErrorOS->resetColor(); + } else { + *ErrorOS << S; + } +} + +void ErrorHandler::log(const Twine &Msg) { + if (Verbose) { + std::lock_guard Lock(Mu); + outs() << LogName << ": " << Msg << "\n"; + outs().flush(); + } +} + +void ErrorHandler::message(const Twine &Msg) { + std::lock_guard Lock(Mu); + outs() << Msg << "\n"; + outs().flush(); +} + +void ErrorHandler::warn(const Twine &Msg) { + if (FatalWarnings) { + error(Msg); + return; + } + + std::lock_guard Lock(Mu); + newline(ErrorOS, Msg); + print("warning: ", raw_ostream::MAGENTA); + *ErrorOS << Msg << "\n"; +} + +void ErrorHandler::error(const Twine &Msg) { + std::lock_guard Lock(Mu); + newline(ErrorOS, Msg); + + if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << Msg << "\n"; + } else if (ErrorCount == ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << ErrorLimitExceededMsg << "\n"; + if (ExitEarly) + exitLld(1); + } + + ++ErrorCount; +} + +void ErrorHandler::fatal(const Twine &Msg) { error(Msg); exitLld(1); } + +} // end namespace lld diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index 49312c57c818..934d1823302a 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/Arch/AMDGPU.cpp b/lld/ELF/Arch/AMDGPU.cpp index 6fa6421bce55..c2ecdf9f2f80 100644 --- a/lld/ELF/Arch/AMDGPU.cpp +++ b/lld/ELF/Arch/AMDGPU.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp index 522911ea00a1..6318c24f2778 100644 --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -7,12 +7,12 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/Arch/AVR.cpp b/lld/ELF/Arch/AVR.cpp index a85e4783dda8..5617e4424ccc 100644 --- a/lld/ELF/Arch/AVR.cpp +++ b/lld/ELF/Arch/AVR.cpp @@ -26,10 +26,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 1ffff3f592c1..95fefe4d44a0 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -7,13 +7,13 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/Arch/MipsArchTree.cpp b/lld/ELF/Arch/MipsArchTree.cpp index 6b6d25b84511..5255e893ea2a 100644 --- a/lld/ELF/Arch/MipsArchTree.cpp +++ b/lld/ELF/Arch/MipsArchTree.cpp @@ -11,11 +11,11 @@ // //===---------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "SymbolTable.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" #include "llvm/Support/MipsABIFlags.h" diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index b505788aca95..d825f5776c62 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index e82e08636c1d..571e91ab4bc2 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp index 175579e11dea..9f9bacc579d0 100644 --- a/lld/ELF/Arch/SPARCV9.cpp +++ b/lld/ELF/Arch/SPARCV9.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/lld/ELF/Arch/X86.cpp b/lld/ELF/Arch/X86.cpp index 5301603e897f..4da8dc8bccfc 100644 --- a/lld/ELF/Arch/X86.cpp +++ b/lld/ELF/Arch/X86.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; diff --git a/lld/ELF/Arch/X86_64.cpp b/lld/ELF/Arch/X86_64.cpp index c244d7545b82..01f0d7615e4b 100644 --- a/lld/ELF/Arch/X86_64.cpp +++ b/lld/ELF/Arch/X86_64.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 2057029751ed..aef5ee68f4a7 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -21,7 +21,6 @@ add_lld_library(lldELF Driver.cpp DriverUtils.cpp EhFrame.cpp - Error.cpp Filesystem.cpp GdbIndex.cpp ICF.cpp diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 8da6d4c14f11..9763834d403d 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -108,7 +108,6 @@ struct Configuration { bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; - bool ColorDiagnostics = false; bool CompressDebugSections; bool DefineCommon; bool Demangle = true; @@ -117,7 +116,6 @@ struct Configuration { bool EmitRelocs; bool EnableNewDtags; bool ExportDynamic; - bool FatalWarnings; bool GcSections; bool GdbIndex; bool GnuHash = false; @@ -167,7 +165,6 @@ struct Configuration { ELFKind EKind = ELFNoneKind; uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL; uint16_t EMachine = llvm::ELF::EM_NONE; - uint64_t ErrorLimit = 20; llvm::Optional ImageBase; uint64_t MaxPageSize; uint64_t ZStackSize; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 5ffc877f381e..8849c7088e53 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -25,7 +25,6 @@ #include "Driver.h" #include "Config.h" -#include "Error.h" #include "Filesystem.h" #include "ICF.h" #include "InputFiles.h" @@ -40,6 +39,7 @@ #include "Target.h" #include "Writer.h" #include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" #include "llvm/ADT/StringExtras.h" @@ -72,8 +72,12 @@ static void setConfigs(); bool elf::link(ArrayRef Args, bool CanExitEarly, raw_ostream &Error) { - ErrorCount = 0; - ErrorOS = &Error; + errorHandler().LogName = Args[0]; + errorHandler().ErrorLimitExceededMsg = + "too many errors emitted, stopping now (use " + "-error-limit=0 to see all errors)"; + errorHandler().ErrorOS = &Error; + errorHandler().ColorDiagnostics = Error.has_colors(); InputSections.clear(); OutputSections.clear(); Tar = nullptr; @@ -95,10 +99,10 @@ bool elf::link(ArrayRef Args, bool CanExitEarly, // This saves time because the overhead of calling destructors // for all globally-allocated objects is not negligible. if (Config->ExitEarly) - exitLld(ErrorCount ? 1 : 0); + exitLld(errorCount() ? 1 : 0); freeArena(); - return !ErrorCount; + return !errorCount(); } // Parses a linker -m option. @@ -332,7 +336,7 @@ void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Interpret this flag early because error() depends on them. - Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); + errorHandler().ErrorLimit = getInteger(Args, OPT_error_limit, 20); // Handle -help if (Args.hasArg(OPT_help)) { @@ -365,6 +369,7 @@ void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { return; Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); + errorHandler().ExitEarly = Config->ExitEarly; if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it @@ -388,7 +393,7 @@ void LinkerDriver::main(ArrayRef ArgsArr, bool CanExitEarly) { inferMachineType(); setConfigs(); checkOptions(Args); - if (ErrorCount) + if (errorCount()) return; switch (Config->EKind) { @@ -645,7 +650,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Entry = Args.getLastArgValue(OPT_entry); Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); - Config->FatalWarnings = + errorHandler().FatalWarnings = Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); Config->FilterList = getArgs(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); @@ -694,6 +699,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Undefined = getArgs(Args, OPT_undefined); Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); Config->Verbose = Args.hasArg(OPT_verbose); + errorHandler().Verbose = Config->Verbose; Config->WarnCommon = Args.hasArg(OPT_warn_common); Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); Config->ZExecstack = hasZOption(Args, "execstack"); @@ -881,7 +887,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { } } - if (Files.empty() && ErrorCount == 0) + if (Files.empty() && errorCount() == 0) error("no input files"); } @@ -1009,7 +1015,7 @@ template void LinkerDriver::link(opt::InputArgList &Args) { error("cannot open output file " + Config->OutputFile + ": " + E.message()); if (auto E = tryCreateFile(Config->MapFile)) error("cannot open map file " + Config->MapFile + ": " + E.message()); - if (ErrorCount) + if (errorCount()) return; // Use default entry point name if no name was given via the command @@ -1053,7 +1059,7 @@ template void LinkerDriver::link(opt::InputArgList &Args) { Symtab->fetchIfLazy(Config->Entry); // Return if there were name resolution errors. - if (ErrorCount) + if (errorCount()) return; // Handle undefined symbols in DSOs. @@ -1075,7 +1081,7 @@ template void LinkerDriver::link(opt::InputArgList &Args) { Symtab->addSymbolAlias(Def.first, Def.second); Symtab->addCombinedLTOObject(); - if (ErrorCount) + if (errorCount()) return; // Apply symbol renames for -wrap and -defsym diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp index 0af56c301f5f..ca13b309c4ab 100644 --- a/lld/ELF/DriverUtils.cpp +++ b/lld/ELF/DriverUtils.cpp @@ -14,8 +14,8 @@ //===----------------------------------------------------------------------===// #include "Driver.h" -#include "Error.h" #include "Memory.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Reproduce.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" @@ -51,25 +51,26 @@ static const opt::OptTable::Info OptInfo[] = { ELFOptTable::ELFOptTable() : OptTable(OptInfo) {} -// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics. -static bool getColorDiagnostics(opt::InputArgList &Args) { +// Set color diagnostics according to -color-diagnostics={auto,always,never} +// or -no-color-diagnostics flags. +static void handleColorDiagnostics(opt::InputArgList &Args) { auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, OPT_no_color_diagnostics); if (!Arg) - return ErrorOS->has_colors(); - if (Arg->getOption().getID() == OPT_color_diagnostics) - return true; - if (Arg->getOption().getID() == OPT_no_color_diagnostics) - return false; - - StringRef S = Arg->getValue(); - if (S == "auto") - return ErrorOS->has_colors(); - if (S == "always") - return true; - if (S != "never") - error("unknown option: -color-diagnostics=" + S); - return false; + return; + else if (Arg->getOption().getID() == OPT_color_diagnostics) + errorHandler().ColorDiagnostics = true; + else if (Arg->getOption().getID() == OPT_no_color_diagnostics) + errorHandler().ColorDiagnostics = false; + else { + StringRef S = Arg->getValue(); + if (S == "always") + errorHandler().ColorDiagnostics = true; + else if (S == "never") + errorHandler().ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: -color-diagnostics=" + S); + } } static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { @@ -103,9 +104,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef Argv) { cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); Args = this->ParseArgs(Vec, MissingIndex, MissingCount); - // Interpret -color-diagnostics early so that error messages - // for unknown flags are colored. - Config->ColorDiagnostics = getColorDiagnostics(Args); + handleColorDiagnostics(Args); if (MissingCount) error(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); diff --git a/lld/ELF/EhFrame.cpp b/lld/ELF/EhFrame.cpp index e29110ceab17..ed18f639969e 100644 --- a/lld/ELF/EhFrame.cpp +++ b/lld/ELF/EhFrame.cpp @@ -17,11 +17,11 @@ //===----------------------------------------------------------------------===// #include "EhFrame.h" -#include "Error.h" #include "InputSection.h" #include "Relocations.h" #include "Strings.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Object/ELF.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index fb9559131837..6ced80b2b9bd 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -8,13 +8,13 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" -#include "Error.h" #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 00c8ee936aa7..da1d7ee86e16 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -11,9 +11,9 @@ #define LLD_ELF_INPUT_FILES_H #include "Config.h" -#include "Error.h" #include "InputSection.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 7c3e2ebac2dd..c870d8c08884 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -10,7 +10,6 @@ #include "InputSection.h" #include "Config.h" #include "EhFrame.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" @@ -19,6 +18,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/Decompressor.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 34eb98185eb1..55877df3cf6a 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -9,11 +9,11 @@ #include "LTO.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index b80e3e2f175e..429d2fc28f9d 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -927,7 +927,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef Rels) { Expr = fromPlt(Expr); Expr = adjustExpr(Body, Expr, Type, Sec, Rel.r_offset); - if (ErrorCount) + if (errorCount()) continue; // This relocation does not require got entry, but it is relative to got and diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp index c5cfa5d2b97f..9f33c16f36b0 100644 --- a/lld/ELF/ScriptLexer.cpp +++ b/lld/ELF/ScriptLexer.cpp @@ -33,7 +33,7 @@ //===----------------------------------------------------------------------===// #include "ScriptLexer.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -75,7 +75,7 @@ ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); } // We don't want to record cascading errors. Keep only the first one. void ScriptLexer::setError(const Twine &Msg) { - if (ErrorCount) + if (errorCount()) return; std::string S = (getCurrentLocation() + ": " + Msg).str(); @@ -159,7 +159,7 @@ StringRef ScriptLexer::skipSpace(StringRef S) { } // An erroneous token is handled as if it were the last token before EOF. -bool ScriptLexer::atEOF() { return ErrorCount || Tokens.size() == Pos; } +bool ScriptLexer::atEOF() { return errorCount() || Tokens.size() == Pos; } // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. @@ -207,7 +207,7 @@ static std::vector tokenizeExpr(StringRef S) { // // This function may split the current token into multiple tokens. void ScriptLexer::maybeSplitExpr() { - if (!InExpr || ErrorCount || atEOF()) + if (!InExpr || errorCount() || atEOF()) return; std::vector V = tokenizeExpr(Tokens[Pos]); @@ -220,7 +220,7 @@ void ScriptLexer::maybeSplitExpr() { StringRef ScriptLexer::next() { maybeSplitExpr(); - if (ErrorCount) + if (errorCount()) return ""; if (atEOF()) { setError("unexpected EOF"); @@ -231,7 +231,7 @@ StringRef ScriptLexer::next() { StringRef ScriptLexer::peek() { StringRef Tok = next(); - if (ErrorCount) + if (errorCount()) return ""; Pos = Pos - 1; return Tok; @@ -260,7 +260,7 @@ bool ScriptLexer::consumeLabel(StringRef Tok) { void ScriptLexer::skip() { (void)next(); } void ScriptLexer::expect(StringRef Expect) { - if (ErrorCount) + if (errorCount()) return; StringRef Tok = next(); if (Tok != Expect) diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index 903be2f503c2..7ec61226d7eb 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -209,7 +209,7 @@ void ScriptParser::readVersionScriptCommand() { return; } - while (!atEOF() && !ErrorCount && peek() != "}") { + while (!atEOF() && !errorCount() && peek() != "}") { StringRef VerStr = next(); if (VerStr == "{") { setError("anonymous version definition is used in " @@ -303,7 +303,7 @@ void ScriptParser::readAsNeeded() { expect("("); bool Orig = Config->AsNeeded; Config->AsNeeded = true; - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) addFile(unquote(next())); Config->AsNeeded = Orig; } @@ -319,13 +319,13 @@ void ScriptParser::readEntry() { void ScriptParser::readExtern() { expect("("); - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) Config->Undefined.push_back(next()); } void ScriptParser::readGroup() { expect("("); - while (!ErrorCount && !consume(")")) { + while (!errorCount() && !consume(")")) { if (consume("AS_NEEDED")) readAsNeeded(); else @@ -369,7 +369,7 @@ void ScriptParser::readOutput() { void ScriptParser::readOutputArch() { // OUTPUT_ARCH is ignored for now. expect("("); - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) skip(); } @@ -389,12 +389,12 @@ void ScriptParser::readOutputFormat() { void ScriptParser::readPhdrs() { expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { PhdrsCommand Cmd; Cmd.Name = next(); Cmd.Type = readPhdrType(); - while (!ErrorCount && !consume(";")) { + while (!errorCount() && !consume(";")) { if (consume("FILEHDR")) Cmd.HasFilehdr = true; else if (consume("PHDRS")) @@ -442,7 +442,7 @@ void ScriptParser::readSections() { Config->SingleRoRx = true; expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Tok = next(); BaseCommand *Cmd = readProvideOrAssignment(Tok); if (!Cmd) { @@ -467,7 +467,7 @@ static int precedence(StringRef Op) { StringMatcher ScriptParser::readFilePatterns() { std::vector V; - while (!ErrorCount && !consume(")")) + while (!errorCount() && !consume(")")) V.push_back(next()); return StringMatcher(V); } @@ -499,7 +499,7 @@ SortSectionPolicy ScriptParser::readSortKind() { // any file but a.o, and section .baz in any file but b.o. std::vector ScriptParser::readInputSectionsList() { std::vector Ret; - while (!ErrorCount && peek() != ")") { + while (!errorCount() && peek() != ")") { StringMatcher ExcludeFilePat; if (consume("EXCLUDE_FILE")) { expect("("); @@ -507,7 +507,7 @@ std::vector ScriptParser::readInputSectionsList() { } std::vector V; - while (!ErrorCount && peek() != ")" && peek() != "EXCLUDE_FILE") + while (!errorCount() && peek() != ")" && peek() != "EXCLUDE_FILE") V.push_back(next()); if (!V.empty()) @@ -534,7 +534,7 @@ ScriptParser::readInputSectionRules(StringRef FilePattern) { auto *Cmd = make(FilePattern); expect("("); - while (!ErrorCount && !consume(")")) { + while (!errorCount() && !consume(")")) { SortSectionPolicy Outer = readSortKind(); SortSectionPolicy Inner = SortSectionPolicy::Default; std::vector V; @@ -676,7 +676,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { Cmd->Constraint = ConstraintKind::ReadWrite; expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. @@ -820,7 +820,7 @@ static Expr combine(StringRef Op, Expr L, Expr R) { // This is a part of the operator-precedence parser. This function // assumes that the remaining token stream starts with an operator. Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) { - while (!atEOF() && !ErrorCount) { + while (!atEOF() && !errorCount()) { // Read an operator and an expression. if (consume("?")) return readTernary(Lhs); @@ -1098,7 +1098,7 @@ Expr ScriptParser::readParenExpr() { std::vector ScriptParser::readOutputSectionPhdrs() { std::vector Phdrs; - while (!ErrorCount && peek().startswith(":")) { + while (!errorCount() && peek().startswith(":")) { StringRef Tok = next(); Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1)); } @@ -1201,7 +1201,7 @@ ScriptParser::readSymbols() { std::vector Globals; std::vector *V = &Globals; - while (!ErrorCount) { + while (!errorCount()) { if (consume("}")) break; if (consumeLabel("local")) { @@ -1235,7 +1235,7 @@ std::vector ScriptParser::readVersionExtern() { expect("{"); std::vector Ret; - while (!ErrorCount && peek() != "}") { + while (!errorCount() && peek() != "}") { StringRef Tok = next(); bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok); Ret.push_back({unquote(Tok), IsCXX, HasWildcard}); @@ -1262,7 +1262,7 @@ uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2, // MEMORY { name [(attr)] : ORIGIN = origin, LENGTH = len ... } void ScriptParser::readMemory() { expect("{"); - while (!ErrorCount && !consume("}")) { + while (!errorCount() && !consume("}")) { StringRef Name = next(); uint32_t Flags = 0; diff --git a/lld/ELF/Strings.cpp b/lld/ELF/Strings.cpp index 766258f00ccd..909a306bc19c 100644 --- a/lld/ELF/Strings.cpp +++ b/lld/ELF/Strings.cpp @@ -9,7 +9,7 @@ #include "Strings.h" #include "Config.h" -#include "Error.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index ae78b17eb5bb..65220ff2082c 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -16,10 +16,10 @@ #include "SymbolTable.h" #include "Config.h" -#include "Error.h" #include "LinkerScript.h" #include "Memory.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -91,7 +91,7 @@ template void SymbolTable::addFile(InputFile *File) { if (auto *F = dyn_cast>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); - if (ErrorCount || !SoNames.insert(F->SoName).second) + if (errorCount() || !SoNames.insert(F->SoName).second) return; SharedFiles.push_back(F); F->parseRest(); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 354d2cc23d73..8f6b4082d83c 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" -#include "Error.h" #include "InputFiles.h" #include "InputSection.h" #include "OutputSections.h" @@ -17,6 +16,7 @@ #include "Target.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index faf552304757..bd3549ae3073 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -16,7 +16,6 @@ #include "SyntheticSections.h" #include "Config.h" -#include "Error.h" #include "InputFiles.h" #include "LinkerScript.h" #include "Memory.h" @@ -25,6 +24,7 @@ #include "SymbolTable.h" #include "Target.h" #include "Writer.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" #include "llvm/BinaryFormat/Dwarf.h" diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 7ebecdb1ea10..250a14c52fcd 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -25,11 +25,11 @@ //===----------------------------------------------------------------------===// #include "Target.h" -#include "Error.h" #include "InputFiles.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" using namespace llvm; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index ef2a3f1767eb..cde437ebf64a 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -10,8 +10,8 @@ #ifndef LLD_ELF_TARGET_H #define LLD_ELF_TARGET_H -#include "Error.h" #include "InputSection.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/Object/ELF.h" namespace lld { diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp index 9f05af72cd7c..1d48a0154e0d 100644 --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -23,13 +23,13 @@ #include "Thunks.h" #include "Config.h" -#include "Error.h" #include "InputSection.h" #include "Memory.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/ErrorHandler.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Endian.h" diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 8c962b184c61..89b290467cff 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -188,7 +188,7 @@ template void Writer::run() { // to the string table, and add entries to .got and .plt. // finalizeSections does that. finalizeSections(); - if (ErrorCount) + if (errorCount()) return; // If -compressed-debug-sections is specified, we need to compress @@ -218,11 +218,11 @@ template void Writer::run() { } // It does not make sense try to open the file if we have error already. - if (ErrorCount) + if (errorCount()) return; // Write the result down to a file. openFile(); - if (ErrorCount) + if (errorCount()) return; if (!Config->OFormatBinary) { @@ -236,12 +236,12 @@ template void Writer::run() { // Backfill .note.gnu.build-id section content. This is done at last // because the content is usually a hash value of the entire output file. writeBuildId(); - if (ErrorCount) + if (errorCount()) return; // Handle -Map option. writeMapFile(); - if (ErrorCount) + if (errorCount()) return; if (auto EC = Buffer->commit()) @@ -1287,7 +1287,7 @@ template void Writer::finalizeSections() { } // Do not proceed if there was an undefined symbol. - if (ErrorCount) + if (errorCount()) return; addPredefinedSections(); diff --git a/lld/ELF/Error.h b/lld/include/lld/Common/ErrorHandler.h similarity index 60% rename from lld/ELF/Error.h rename to lld/include/lld/Common/ErrorHandler.h index c6e4f0e62d16..05a1d6cd5fc9 100644 --- a/lld/ELF/Error.h +++ b/lld/include/lld/Common/ErrorHandler.h @@ -1,4 +1,4 @@ -//===- Error.h --------------------------------------------------*- C++ -*-===// +//===- ErrorHandler.h -------------------------------------------*- C++ -*-===// // // The LLVM Linker // @@ -25,24 +25,48 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_ELF_ERROR_H -#define LLD_ELF_ERROR_H +#ifndef LLD_COMMON_ERRORHANDLER_H +#define LLD_COMMON_ERRORHANDLER_H #include "lld/Common/LLVM.h" #include "llvm/Support/Error.h" namespace lld { -namespace elf { -extern uint64_t ErrorCount; -extern llvm::raw_ostream *ErrorOS; +class ErrorHandler { +public: + uint64_t ErrorCount = 0; + uint64_t ErrorLimit = 20; + StringRef ErrorLimitExceededMsg = "too many errors emitted, stopping now"; + StringRef LogName = "lld"; + llvm::raw_ostream *ErrorOS = &llvm::errs(); + bool ColorDiagnostics = llvm::errs().has_colors(); + bool ExitEarly = true; + bool FatalWarnings = false; + bool Verbose = false; -void log(const Twine &Msg); -void message(const Twine &Msg); -void warn(const Twine &Msg); -void error(const Twine &Msg); -LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); + void error(const Twine &Msg); + LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); + void log(const Twine &Msg); + void message(const Twine &Msg); + void warn(const Twine &Msg); + +private: + void print(StringRef S, raw_ostream::Colors C); +}; + +/// Returns the default error handler. +ErrorHandler &errorHandler(); + +inline void error(const Twine &Msg) { errorHandler().error(Msg); } +inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg) { + errorHandler().fatal(Msg); +} +inline void log(const Twine &Msg) { errorHandler().log(Msg); } +inline void message(const Twine &Msg) { errorHandler().message(Msg); } +inline void warn(const Twine &Msg) { errorHandler().warn(Msg); } +inline uint64_t errorCount() { return errorHandler().ErrorCount; } LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); @@ -72,7 +96,6 @@ template T check(Expected E, const Twine &Prefix) { return std::move(*E); } -} // namespace elf } // namespace lld #endif