[lld] unified COFF and ELF error handling on new Common/ErrorHandler

Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.

Reviewers: ruiu

Reviewed By: ruiu

Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits

Differential Revision: https://reviews.llvm.org/D39259

llvm-svn: 316624
This commit is contained in:
Bob Haarman 2017-10-25 22:28:38 +00:00
parent 5e6cb9022c
commit b8a59c8aa5
50 changed files with 249 additions and 405 deletions

View File

@ -11,7 +11,6 @@ add_lld_library(lldCOFF
DLL.cpp
Driver.cpp
DriverUtils.cpp
Error.cpp
ICF.cpp
InputFiles.cpp
LTO.cpp

View File

@ -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"

View File

@ -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<unsigned>(DebugType::None);

View File

@ -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 *> SpecificAllocBase::Instances;
bool link(ArrayRef<const char *> 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<Configuration>();
Config->Argv = {Args.begin(), Args.end()};
Config->ColorDiagnostics = ErrorOS->has_colors();
Config->CanExitEarly = CanExitEarly;
Symtab = make<SymbolTable>();
@ -70,10 +72,10 @@ bool link(ArrayRef<const char *> 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<std::string> &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<const char *> 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<const char *> 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<const char *> 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<const char *> 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<const char *> 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<const char *> ArgsArr) {
for (ObjFile *File : ObjFile::Instances)
if (!File->SEHCompat)
error("/safeseh: " + File->getName() + " is not compatible with SEH");
if (ErrorCount)
if (errorCount())
return;
}

View File

@ -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<std::string> 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<MemoryBuffer> 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<MemoryBufferRef> &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<std::unique_ptr<MemoryBuffer>> 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::unique_ptr<MemoryBuffer>>(std::move(*E)); // take ownership
@ -739,7 +741,7 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> 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");

View File

@ -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 <mutex>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#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<std::mutex> Lock(Mu);
outs() << Config->Argv[0] << ": " << Msg << "\n";
outs().flush();
}
}
void message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Msg << "\n";
outs().flush();
}
void error(const Twine &Msg) {
std::lock_guard<std::mutex> 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<std::mutex> Lock(Mu);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
} // namespace coff
} // namespace lld

View File

@ -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 <class T> T check(ErrorOr<T> V, const Twine &Prefix) {
if (auto EC = V.getError())
fatal(EC, Prefix);
return std::move(*V);
}
template <class T> T check(Expected<T> E, const Twine &Prefix) {
if (llvm::Error Err = E.takeError())
fatal(Err, Prefix);
return std::move(*E);
}
template <class T> T check(ErrorOr<T> EO) {
if (!EO)
fatal(EO.getError().message());
return std::move(*EO);
}
template <class T> T check(Expected<T> 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

View File

@ -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"

View File

@ -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;

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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<CVType &>(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;
}

View File

@ -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"

View File

@ -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"

View File

@ -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) {

View File

@ -3,6 +3,7 @@ if(NOT LLD_BUILT_STANDALONE)
endif()
add_lld_library(lldCommon
ErrorHandler.cpp
Reproduce.cpp
TargetOptionsCommandFlags.cpp
Threads.cpp

View File

@ -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<std::mutex> Lock(Mu);
outs() << Config->Argv[0] << ": " << Msg << "\n";
outs().flush();
}
}
void elf::message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Msg << "\n";
outs().flush();
}
void elf::warn(const Twine &Msg) {
if (Config->FatalWarnings) {
error(Msg);
return;
}
std::lock_guard<std::mutex> Lock(Mu);
newline(Msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
void elf::error(const Twine &Msg) {
std::lock_guard<std::mutex> 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<std::mutex> Lock(Mu);
outs() << LogName << ": " << Msg << "\n";
outs().flush();
}
}
void ErrorHandler::message(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
outs() << Msg << "\n";
outs().flush();
}
void ErrorHandler::warn(const Twine &Msg) {
if (FatalWarnings) {
error(Msg);
return;
}
std::lock_guard<std::mutex> Lock(Mu);
newline(ErrorOS, Msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
void ErrorHandler::error(const Twine &Msg) {
std::lock_guard<std::mutex> 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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -21,7 +21,6 @@ add_lld_library(lldELF
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
Error.cpp
Filesystem.cpp
GdbIndex.cpp
ICF.cpp

View File

@ -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<uint64_t> ImageBase;
uint64_t MaxPageSize;
uint64_t ZStackSize;

View File

@ -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<const char *> 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<const char *> 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<const char *> 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<const char *> 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<const char *> 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 <class ELFT> 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 <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Symtab->fetchIfLazy<ELFT>(Config->Entry);
// Return if there were name resolution errors.
if (ErrorCount)
if (errorCount())
return;
// Handle undefined symbols in DSOs.
@ -1075,7 +1081,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Symtab->addSymbolAlias<ELFT>(Def.first, Def.second);
Symtab->addCombinedLTOObject<ELFT>();
if (ErrorCount)
if (errorCount())
return;
// Apply symbol renames for -wrap and -defsym

View File

@ -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<const char *> 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");

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -927,7 +927,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
Expr = fromPlt(Expr);
Expr = adjustExpr<ELFT>(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

View File

@ -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<StringRef> 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<StringRef> 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)

View File

@ -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<StringRef> 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<SectionPattern> ScriptParser::readInputSectionsList() {
std::vector<SectionPattern> Ret;
while (!ErrorCount && peek() != ")") {
while (!errorCount() && peek() != ")") {
StringMatcher ExcludeFilePat;
if (consume("EXCLUDE_FILE")) {
expect("(");
@ -507,7 +507,7 @@ std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
}
std::vector<StringRef> 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<InputSectionDescription>(FilePattern);
expect("(");
while (!ErrorCount && !consume(")")) {
while (!errorCount() && !consume(")")) {
SortSectionPolicy Outer = readSortKind();
SortSectionPolicy Inner = SortSectionPolicy::Default;
std::vector<SectionPattern> 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<StringRef> ScriptParser::readOutputSectionPhdrs() {
std::vector<StringRef> 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<SymbolVersion> Globals;
std::vector<SymbolVersion> *V = &Globals;
while (!ErrorCount) {
while (!errorCount()) {
if (consume("}"))
break;
if (consumeLabel("local")) {
@ -1235,7 +1235,7 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
expect("{");
std::vector<SymbolVersion> 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;

View File

@ -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"

View File

@ -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 <class ELFT> void SymbolTable::addFile(InputFile *File) {
if (auto *F = dyn_cast<SharedFile<ELFT>>(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();

View File

@ -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 <cstring>

View File

@ -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"

View File

@ -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;

View File

@ -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 {

View File

@ -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"

View File

@ -188,7 +188,7 @@ template <class ELFT> void Writer<ELFT>::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 <class ELFT> void Writer<ELFT>::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 <class ELFT> void Writer<ELFT>::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<ELFT>();
if (ErrorCount)
if (errorCount())
return;
if (auto EC = Buffer->commit())
@ -1287,7 +1287,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
// Do not proceed if there was an undefined symbol.
if (ErrorCount)
if (errorCount())
return;
addPredefinedSections();

View File

@ -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 <class T> T check(Expected<T> E, const Twine &Prefix) {
return std::move(*E);
}
} // namespace elf
} // namespace lld
#endif