xref: /freebsd-src/contrib/llvm-project/lld/Common/ErrorHandler.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- ErrorHandler.cpp ---------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
100b57cec5SDimitry Andric 
115ffd83dbSDimitry Andric #include "llvm/Support/Parallel.h"
120b57cec5SDimitry Andric 
1304eeddc0SDimitry Andric #include "lld/Common/CommonLinkerContext.h"
140b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
150b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
160b57cec5SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h"
17e8d8bef9SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
180b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
19e8d8bef9SDimitry Andric #include "llvm/Support/Process.h"
20e8d8bef9SDimitry Andric #include "llvm/Support/Program.h"
210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
220b57cec5SDimitry Andric #include <regex>
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric using namespace lld;
260b57cec5SDimitry Andric 
getSeparator(const Twine & msg)2785868e8aSDimitry Andric static StringRef getSeparator(const Twine &msg) {
2885868e8aSDimitry Andric   if (StringRef(msg.str()).contains('\n'))
2985868e8aSDimitry Andric     return "\n";
3085868e8aSDimitry Andric   return "";
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric 
~ErrorHandler()3304eeddc0SDimitry Andric ErrorHandler::~ErrorHandler() {
3404eeddc0SDimitry Andric   if (cleanupCallback)
3504eeddc0SDimitry Andric     cleanupCallback();
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
initialize(llvm::raw_ostream & stdoutOS,llvm::raw_ostream & stderrOS,bool exitEarly,bool disableOutput)3804eeddc0SDimitry Andric void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS,
3904eeddc0SDimitry Andric                               llvm::raw_ostream &stderrOS, bool exitEarly,
4004eeddc0SDimitry Andric                               bool disableOutput) {
4104eeddc0SDimitry Andric   this->stdoutOS = &stdoutOS;
4204eeddc0SDimitry Andric   this->stderrOS = &stderrOS;
4304eeddc0SDimitry Andric   stderrOS.enable_colors(stderrOS.has_colors());
4404eeddc0SDimitry Andric   this->exitEarly = exitEarly;
4504eeddc0SDimitry Andric   this->disableOutput = disableOutput;
4604eeddc0SDimitry Andric }
4704eeddc0SDimitry Andric 
flushStreams()4804eeddc0SDimitry Andric void ErrorHandler::flushStreams() {
4904eeddc0SDimitry Andric   std::lock_guard<std::mutex> lock(mu);
5004eeddc0SDimitry Andric   outs().flush();
5104eeddc0SDimitry Andric   errs().flush();
5204eeddc0SDimitry Andric }
5304eeddc0SDimitry Andric 
errorHandler()5404eeddc0SDimitry Andric ErrorHandler &lld::errorHandler() { return context().e; }
5504eeddc0SDimitry Andric 
error(const Twine & msg)5681ad6265SDimitry Andric void lld::error(const Twine &msg) { errorHandler().error(msg); }
error(const Twine & msg,ErrorTag tag,ArrayRef<StringRef> args)5781ad6265SDimitry Andric void lld::error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) {
5881ad6265SDimitry Andric   errorHandler().error(msg, tag, args);
5981ad6265SDimitry Andric }
fatal(const Twine & msg)6081ad6265SDimitry Andric void lld::fatal(const Twine &msg) { errorHandler().fatal(msg); }
log(const Twine & msg)6181ad6265SDimitry Andric void lld::log(const Twine &msg) { errorHandler().log(msg); }
message(const Twine & msg,llvm::raw_ostream & s)6281ad6265SDimitry Andric void lld::message(const Twine &msg, llvm::raw_ostream &s) {
6381ad6265SDimitry Andric   errorHandler().message(msg, s);
6481ad6265SDimitry Andric }
warn(const Twine & msg)6581ad6265SDimitry Andric void lld::warn(const Twine &msg) { errorHandler().warn(msg); }
errorCount()6681ad6265SDimitry Andric uint64_t lld::errorCount() { return errorHandler().errorCount; }
6781ad6265SDimitry Andric 
outs()68e8d8bef9SDimitry Andric raw_ostream &lld::outs() {
6904eeddc0SDimitry Andric   ErrorHandler &e = errorHandler();
7004eeddc0SDimitry Andric   return e.outs();
7104eeddc0SDimitry Andric }
7204eeddc0SDimitry Andric 
errs()7304eeddc0SDimitry Andric raw_ostream &lld::errs() {
7404eeddc0SDimitry Andric   ErrorHandler &e = errorHandler();
7504eeddc0SDimitry Andric   return e.errs();
7604eeddc0SDimitry Andric }
7704eeddc0SDimitry Andric 
outs()7804eeddc0SDimitry Andric raw_ostream &ErrorHandler::outs() {
7904eeddc0SDimitry Andric   if (disableOutput)
80e8d8bef9SDimitry Andric     return llvm::nulls();
81e8d8bef9SDimitry Andric   return stdoutOS ? *stdoutOS : llvm::outs();
82e8d8bef9SDimitry Andric }
83e8d8bef9SDimitry Andric 
errs()8404eeddc0SDimitry Andric raw_ostream &ErrorHandler::errs() {
8504eeddc0SDimitry Andric   if (disableOutput)
86e8d8bef9SDimitry Andric     return llvm::nulls();
87e8d8bef9SDimitry Andric   return stderrOS ? *stderrOS : llvm::errs();
88e8d8bef9SDimitry Andric }
89e8d8bef9SDimitry Andric 
exitLld(int val)900b57cec5SDimitry Andric void lld::exitLld(int val) {
9104eeddc0SDimitry Andric   if (hasContext()) {
9204eeddc0SDimitry Andric     ErrorHandler &e = errorHandler();
930b57cec5SDimitry Andric     // Delete any temporary file, while keeping the memory mapping open.
9404eeddc0SDimitry Andric     if (e.outputBuffer)
9504eeddc0SDimitry Andric       e.outputBuffer->discard();
9604eeddc0SDimitry Andric   }
970b57cec5SDimitry Andric 
98*06c3fb27SDimitry Andric   // Re-throw a possible signal or exception once/if it was caught by
99e8d8bef9SDimitry Andric   // safeLldMain().
100e8d8bef9SDimitry Andric   CrashRecoveryContext::throwIfCrash(val);
101e8d8bef9SDimitry Andric 
102480093f4SDimitry Andric   // Dealloc/destroy ManagedStatic variables before calling _exit().
103480093f4SDimitry Andric   // In an LTO build, allows us to get the output of -time-passes.
104480093f4SDimitry Andric   // Ensures that the thread pool for the parallel algorithms is stopped to
105480093f4SDimitry Andric   // avoid intermittent crashes on Windows when exiting.
106e8d8bef9SDimitry Andric   if (!CrashRecoveryContext::GetCurrent())
1070b57cec5SDimitry Andric     llvm_shutdown();
1080b57cec5SDimitry Andric 
10904eeddc0SDimitry Andric   if (hasContext())
11004eeddc0SDimitry Andric     lld::errorHandler().flushStreams();
11104eeddc0SDimitry Andric 
112e8d8bef9SDimitry Andric   // When running inside safeLldMain(), restore the control flow back to the
113e8d8bef9SDimitry Andric   // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
114e8d8bef9SDimitry Andric   // since we want to avoid further crashes on shutdown.
115e8d8bef9SDimitry Andric   llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
diagnosticHandler(const DiagnosticInfo & di)1180b57cec5SDimitry Andric void lld::diagnosticHandler(const DiagnosticInfo &di) {
1190b57cec5SDimitry Andric   SmallString<128> s;
1200b57cec5SDimitry Andric   raw_svector_ostream os(s);
1210b57cec5SDimitry Andric   DiagnosticPrinterRawOStream dp(os);
1221fd87a68SDimitry Andric 
1231fd87a68SDimitry Andric   // For an inline asm diagnostic, prepend the module name to get something like
1241fd87a68SDimitry Andric   // "$module <inline asm>:1:5: ".
1251fd87a68SDimitry Andric   if (auto *dism = dyn_cast<DiagnosticInfoSrcMgr>(&di))
1261fd87a68SDimitry Andric     if (dism->isInlineAsmDiag())
1271fd87a68SDimitry Andric       os << dism->getModuleName() << ' ';
1281fd87a68SDimitry Andric 
1290b57cec5SDimitry Andric   di.print(dp);
1300b57cec5SDimitry Andric   switch (di.getSeverity()) {
1310b57cec5SDimitry Andric   case DS_Error:
1320b57cec5SDimitry Andric     error(s);
1330b57cec5SDimitry Andric     break;
1340b57cec5SDimitry Andric   case DS_Warning:
1350b57cec5SDimitry Andric     warn(s);
1360b57cec5SDimitry Andric     break;
1370b57cec5SDimitry Andric   case DS_Remark:
1380b57cec5SDimitry Andric   case DS_Note:
1390b57cec5SDimitry Andric     message(s);
1400b57cec5SDimitry Andric     break;
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
checkError(Error e)1440b57cec5SDimitry Andric void lld::checkError(Error e) {
1450b57cec5SDimitry Andric   handleAllErrors(std::move(e),
1460b57cec5SDimitry Andric                   [&](ErrorInfoBase &eib) { error(eib.message()); });
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
14985868e8aSDimitry Andric // This is for --vs-diagnostics.
15085868e8aSDimitry Andric //
15185868e8aSDimitry Andric // Normally, lld's error message starts with argv[0]. Therefore, it usually
15285868e8aSDimitry Andric // looks like this:
15385868e8aSDimitry Andric //
15485868e8aSDimitry Andric //   ld.lld: error: ...
15585868e8aSDimitry Andric //
15685868e8aSDimitry Andric // This error message style is unfortunately unfriendly to Visual Studio
15785868e8aSDimitry Andric // IDE. VS interprets the first word of the first line as an error location
15885868e8aSDimitry Andric // and make it clickable, thus "ld.lld" in the above message would become a
15985868e8aSDimitry Andric // clickable text. When you click it, VS opens "ld.lld" executable file with
16085868e8aSDimitry Andric // a binary editor.
16185868e8aSDimitry Andric //
16285868e8aSDimitry Andric // As a workaround, we print out an error location instead of "ld.lld" if
16385868e8aSDimitry Andric // lld is running in VS diagnostics mode. As a result, error message will
16485868e8aSDimitry Andric // look like this:
16585868e8aSDimitry Andric //
16685868e8aSDimitry Andric //   src/foo.c(35): error: ...
16785868e8aSDimitry Andric //
16885868e8aSDimitry Andric // This function returns an error location string. An error location is
16985868e8aSDimitry Andric // extracted from an error message using regexps.
getLocation(const Twine & msg)17085868e8aSDimitry Andric std::string ErrorHandler::getLocation(const Twine &msg) {
17185868e8aSDimitry Andric   if (!vsDiagnostics)
1725ffd83dbSDimitry Andric     return std::string(logName);
17385868e8aSDimitry Andric 
17485868e8aSDimitry Andric   static std::regex regexes[] = {
17585868e8aSDimitry Andric       std::regex(
17685868e8aSDimitry Andric           R"(^undefined (?:\S+ )?symbol:.*\n)"
17785868e8aSDimitry Andric           R"(>>> referenced by .+\((\S+):(\d+)\))"),
17885868e8aSDimitry Andric       std::regex(
17985868e8aSDimitry Andric           R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
1800b57cec5SDimitry Andric       std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
1810b57cec5SDimitry Andric       std::regex(
1820b57cec5SDimitry Andric           R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
1830b57cec5SDimitry Andric       std::regex(
18485868e8aSDimitry Andric           R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
18585868e8aSDimitry Andric       std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
1860b57cec5SDimitry Andric       std::regex(
18785868e8aSDimitry Andric           R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
18885868e8aSDimitry Andric       std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
1890b57cec5SDimitry Andric       std::regex(R"((\S+):(\d+): unclosed quote)"),
1900b57cec5SDimitry Andric   };
1910b57cec5SDimitry Andric 
19285868e8aSDimitry Andric   std::string str = msg.str();
19385868e8aSDimitry Andric   for (std::regex &re : regexes) {
19485868e8aSDimitry Andric     std::smatch m;
19585868e8aSDimitry Andric     if (!std::regex_search(str, m, re))
19685868e8aSDimitry Andric       continue;
19785868e8aSDimitry Andric 
19885868e8aSDimitry Andric     assert(m.size() == 2 || m.size() == 3);
19985868e8aSDimitry Andric     if (m.size() == 2)
20085868e8aSDimitry Andric       return m.str(1);
20185868e8aSDimitry Andric     return m.str(1) + "(" + m.str(2) + ")";
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric 
2045ffd83dbSDimitry Andric   return std::string(logName);
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
reportDiagnostic(StringRef location,Colors c,StringRef diagKind,const Twine & msg)207349cc55cSDimitry Andric void ErrorHandler::reportDiagnostic(StringRef location, Colors c,
208349cc55cSDimitry Andric                                     StringRef diagKind, const Twine &msg) {
209349cc55cSDimitry Andric   SmallString<256> buf;
210349cc55cSDimitry Andric   raw_svector_ostream os(buf);
211349cc55cSDimitry Andric   os << sep << location << ": ";
212349cc55cSDimitry Andric   if (!diagKind.empty()) {
213349cc55cSDimitry Andric     if (lld::errs().colors_enabled()) {
214349cc55cSDimitry Andric       os.enable_colors(true);
215349cc55cSDimitry Andric       os << c << diagKind << ": " << Colors::RESET;
216349cc55cSDimitry Andric     } else {
217349cc55cSDimitry Andric       os << diagKind << ": ";
218349cc55cSDimitry Andric     }
219349cc55cSDimitry Andric   }
220349cc55cSDimitry Andric   os << msg << '\n';
221349cc55cSDimitry Andric   lld::errs() << buf;
222349cc55cSDimitry Andric }
223349cc55cSDimitry Andric 
log(const Twine & msg)2240b57cec5SDimitry Andric void ErrorHandler::log(const Twine &msg) {
225e8d8bef9SDimitry Andric   if (!verbose || disableOutput)
22685868e8aSDimitry Andric     return;
2270b57cec5SDimitry Andric   std::lock_guard<std::mutex> lock(mu);
228349cc55cSDimitry Andric   reportDiagnostic(logName, Colors::RESET, "", msg);
2290b57cec5SDimitry Andric }
2300b57cec5SDimitry Andric 
message(const Twine & msg,llvm::raw_ostream & s)231349cc55cSDimitry Andric void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
232e8d8bef9SDimitry Andric   if (disableOutput)
233e8d8bef9SDimitry Andric     return;
2340b57cec5SDimitry Andric   std::lock_guard<std::mutex> lock(mu);
235349cc55cSDimitry Andric   s << msg << "\n";
236349cc55cSDimitry Andric   s.flush();
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
warn(const Twine & msg)2390b57cec5SDimitry Andric void ErrorHandler::warn(const Twine &msg) {
2400b57cec5SDimitry Andric   if (fatalWarnings) {
2410b57cec5SDimitry Andric     error(msg);
2420b57cec5SDimitry Andric     return;
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric 
24581ad6265SDimitry Andric   if (suppressWarnings)
24681ad6265SDimitry Andric     return;
24781ad6265SDimitry Andric 
2480b57cec5SDimitry Andric   std::lock_guard<std::mutex> lock(mu);
249349cc55cSDimitry Andric   reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
25085868e8aSDimitry Andric   sep = getSeparator(msg);
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
error(const Twine & msg)2530b57cec5SDimitry Andric void ErrorHandler::error(const Twine &msg) {
25485868e8aSDimitry Andric   // If Visual Studio-style error message mode is enabled,
25585868e8aSDimitry Andric   // this particular error is printed out as two errors.
25685868e8aSDimitry Andric   if (vsDiagnostics) {
25785868e8aSDimitry Andric     static std::regex re(R"(^(duplicate symbol: .*))"
25885868e8aSDimitry Andric                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
25985868e8aSDimitry Andric                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
26085868e8aSDimitry Andric     std::string str = msg.str();
26185868e8aSDimitry Andric     std::smatch m;
26285868e8aSDimitry Andric 
26385868e8aSDimitry Andric     if (std::regex_match(str, m, re)) {
26485868e8aSDimitry Andric       error(m.str(1) + m.str(2));
26585868e8aSDimitry Andric       error(m.str(1) + m.str(3));
26685868e8aSDimitry Andric       return;
26785868e8aSDimitry Andric     }
26885868e8aSDimitry Andric   }
26985868e8aSDimitry Andric 
2705ffd83dbSDimitry Andric   bool exit = false;
2715ffd83dbSDimitry Andric   {
2720b57cec5SDimitry Andric     std::lock_guard<std::mutex> lock(mu);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric     if (errorLimit == 0 || errorCount < errorLimit) {
275349cc55cSDimitry Andric       reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
2760b57cec5SDimitry Andric     } else if (errorCount == errorLimit) {
277349cc55cSDimitry Andric       reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
2785ffd83dbSDimitry Andric       exit = exitEarly;
2790b57cec5SDimitry Andric     }
2800b57cec5SDimitry Andric 
28185868e8aSDimitry Andric     sep = getSeparator(msg);
2820b57cec5SDimitry Andric     ++errorCount;
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric 
2855ffd83dbSDimitry Andric   if (exit)
2865ffd83dbSDimitry Andric     exitLld(1);
2875ffd83dbSDimitry Andric }
2885ffd83dbSDimitry Andric 
error(const Twine & msg,ErrorTag tag,ArrayRef<StringRef> args)289e8d8bef9SDimitry Andric void ErrorHandler::error(const Twine &msg, ErrorTag tag,
290e8d8bef9SDimitry Andric                          ArrayRef<StringRef> args) {
291e8d8bef9SDimitry Andric   if (errorHandlingScript.empty()) {
292e8d8bef9SDimitry Andric     error(msg);
293e8d8bef9SDimitry Andric     return;
294e8d8bef9SDimitry Andric   }
295e8d8bef9SDimitry Andric   SmallVector<StringRef, 4> scriptArgs;
296e8d8bef9SDimitry Andric   scriptArgs.push_back(errorHandlingScript);
297e8d8bef9SDimitry Andric   switch (tag) {
298e8d8bef9SDimitry Andric   case ErrorTag::LibNotFound:
299e8d8bef9SDimitry Andric     scriptArgs.push_back("missing-lib");
300e8d8bef9SDimitry Andric     break;
301e8d8bef9SDimitry Andric   case ErrorTag::SymbolNotFound:
302e8d8bef9SDimitry Andric     scriptArgs.push_back("undefined-symbol");
303e8d8bef9SDimitry Andric     break;
304e8d8bef9SDimitry Andric   }
305e8d8bef9SDimitry Andric   scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
306e8d8bef9SDimitry Andric   int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
307e8d8bef9SDimitry Andric   if (res == 0) {
308e8d8bef9SDimitry Andric     return error(msg);
309e8d8bef9SDimitry Andric   } else {
310e8d8bef9SDimitry Andric     // Temporarily disable error limit to make sure the two calls to error(...)
311e8d8bef9SDimitry Andric     // only count as one.
312e8d8bef9SDimitry Andric     uint64_t currentErrorLimit = errorLimit;
313e8d8bef9SDimitry Andric     errorLimit = 0;
314e8d8bef9SDimitry Andric     error(msg);
315e8d8bef9SDimitry Andric     errorLimit = currentErrorLimit;
316e8d8bef9SDimitry Andric     --errorCount;
317e8d8bef9SDimitry Andric 
318e8d8bef9SDimitry Andric     switch (res) {
319e8d8bef9SDimitry Andric     case -1:
320e8d8bef9SDimitry Andric       error("error handling script '" + errorHandlingScript +
321e8d8bef9SDimitry Andric             "' failed to execute");
322e8d8bef9SDimitry Andric       break;
323e8d8bef9SDimitry Andric     case -2:
324e8d8bef9SDimitry Andric       error("error handling script '" + errorHandlingScript +
325e8d8bef9SDimitry Andric             "' crashed or timeout");
326e8d8bef9SDimitry Andric       break;
327e8d8bef9SDimitry Andric     default:
328e8d8bef9SDimitry Andric       error("error handling script '" + errorHandlingScript +
329e8d8bef9SDimitry Andric             "' exited with code " + Twine(res));
330e8d8bef9SDimitry Andric     }
331e8d8bef9SDimitry Andric   }
332e8d8bef9SDimitry Andric }
333e8d8bef9SDimitry Andric 
fatal(const Twine & msg)3340b57cec5SDimitry Andric void ErrorHandler::fatal(const Twine &msg) {
3350b57cec5SDimitry Andric   error(msg);
3360b57cec5SDimitry Andric   exitLld(1);
3370b57cec5SDimitry Andric }
338