| //===- ErrorHandler.cpp ---------------------------------------------------===// | |
| // | |
| // The LLVM Linker | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "lld/Common/ErrorHandler.h" | |
| #include "lld/Common/Threads.h" | |
| #include "llvm/ADT/Twine.h" | |
| #include "llvm/IR/DiagnosticInfo.h" | |
| #include "llvm/IR/DiagnosticPrinter.h" | |
| #include "llvm/Support/ManagedStatic.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <mutex> | |
| #if !defined(_MSC_VER) && !defined(__MINGW32__) | |
| #include <unistd.h> | |
| #endif | |
| using namespace llvm; | |
| using 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; | |
| // Prints "\n" or does nothing, depending on Msg contents of | |
| // the previous call of this function. | |
| 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; | |
| if (Flag) | |
| *ErrorOS << "\n"; | |
| Flag = StringRef(Msg.str()).contains('\n'); | |
| } | |
| ErrorHandler &lld::errorHandler() { | |
| static ErrorHandler Handler; | |
| return Handler; | |
| } | |
| void lld::exitLld(int Val) { | |
| // Delete the output buffer so that any tempory file is deleted. | |
| errorHandler().OutputBuffer.reset(); | |
| // 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); | |
| } | |
| void lld::diagnosticHandler(const DiagnosticInfo &DI) { | |
| SmallString<128> S; | |
| raw_svector_ostream OS(S); | |
| DiagnosticPrinterRawOStream DP(OS); | |
| DI.print(DP); | |
| switch (DI.getSeverity()) { | |
| case DS_Error: | |
| error(S); | |
| break; | |
| case DS_Warning: | |
| warn(S); | |
| break; | |
| case DS_Remark: | |
| case DS_Note: | |
| message(S); | |
| break; | |
| } | |
| } | |
| void lld::checkError(Error E) { | |
| handleAllErrors(std::move(E), | |
| [&](ErrorInfoBase &EIB) { error(EIB.message()); }); | |
| } | |
| 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); | |
| *ErrorOS << LogName << ": " << Msg << "\n"; | |
| } | |
| } | |
| 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); | |
| } |