xref: /llvm-project/lld/Common/ErrorHandler.cpp (revision f359c1f524bf826eba355b8863a870450eb747b0)
1b8a59c8aSBob Haarman //===- ErrorHandler.cpp ---------------------------------------------------===//
2b8a59c8aSBob Haarman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b8a59c8aSBob Haarman //
7b8a59c8aSBob Haarman //===----------------------------------------------------------------------===//
8b8a59c8aSBob Haarman 
9b8a59c8aSBob Haarman #include "lld/Common/ErrorHandler.h"
10b8a59c8aSBob Haarman 
11932f0276SReid Kleckner #include "llvm/Support/Parallel.h"
12b8a59c8aSBob Haarman 
1383d59e05SAlexandre Ganea #include "lld/Common/CommonLinkerContext.h"
14b8a59c8aSBob Haarman #include "llvm/ADT/Twine.h"
153ad27e92SSam Clegg #include "llvm/IR/DiagnosticInfo.h"
163ad27e92SSam Clegg #include "llvm/IR/DiagnosticPrinter.h"
17f2efb574SAlexandre Ganea #include "llvm/Support/CrashRecoveryContext.h"
18b8a59c8aSBob Haarman #include "llvm/Support/ManagedStatic.h"
19f2efb574SAlexandre Ganea #include "llvm/Support/Process.h"
20cfc32267Sserge-sans-paille #include "llvm/Support/Program.h"
21b8a59c8aSBob Haarman #include "llvm/Support/raw_ostream.h"
2287886299SChris Jackson #include <regex>
23b8a59c8aSBob Haarman 
24b8a59c8aSBob Haarman using namespace llvm;
25b8a59c8aSBob Haarman using namespace lld;
26b8a59c8aSBob Haarman 
276c5fc940SRui Ueyama static StringRef getSeparator(const Twine &msg) {
286c5fc940SRui Ueyama   if (StringRef(msg.str()).contains('\n'))
296c5fc940SRui Ueyama     return "\n";
306c5fc940SRui Ueyama   return "";
31b8a59c8aSBob Haarman }
32b8a59c8aSBob Haarman 
3383d59e05SAlexandre Ganea ErrorHandler::~ErrorHandler() {
3483d59e05SAlexandre Ganea   if (cleanupCallback)
3583d59e05SAlexandre Ganea     cleanupCallback();
36f860fe36SAlexandre Ganea }
37f860fe36SAlexandre Ganea 
3883d59e05SAlexandre Ganea void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS,
3983d59e05SAlexandre Ganea                               llvm::raw_ostream &stderrOS, bool exitEarly,
4083d59e05SAlexandre Ganea                               bool disableOutput) {
4183d59e05SAlexandre Ganea   this->stdoutOS = &stdoutOS;
4283d59e05SAlexandre Ganea   this->stderrOS = &stderrOS;
4383d59e05SAlexandre Ganea   stderrOS.enable_colors(stderrOS.has_colors());
4483d59e05SAlexandre Ganea   this->exitEarly = exitEarly;
4583d59e05SAlexandre Ganea   this->disableOutput = disableOutput;
4683d59e05SAlexandre Ganea }
4783d59e05SAlexandre Ganea 
4883d59e05SAlexandre Ganea void ErrorHandler::flushStreams() {
4983d59e05SAlexandre Ganea   std::lock_guard<std::mutex> lock(mu);
5083d59e05SAlexandre Ganea   outs().flush();
5183d59e05SAlexandre Ganea   errs().flush();
5283d59e05SAlexandre Ganea }
5383d59e05SAlexandre Ganea 
5483d59e05SAlexandre Ganea ErrorHandler &lld::errorHandler() { return context().e; }
5583d59e05SAlexandre Ganea 
56941f0628SFangrui Song void lld::error(const Twine &msg) { errorHandler().error(msg); }
57941f0628SFangrui Song void lld::error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) {
58941f0628SFangrui Song   errorHandler().error(msg, tag, args);
59941f0628SFangrui Song }
60941f0628SFangrui Song void lld::fatal(const Twine &msg) { errorHandler().fatal(msg); }
61941f0628SFangrui Song void lld::log(const Twine &msg) { errorHandler().log(msg); }
62941f0628SFangrui Song void lld::message(const Twine &msg, llvm::raw_ostream &s) {
63941f0628SFangrui Song   errorHandler().message(msg, s);
64941f0628SFangrui Song }
65941f0628SFangrui Song void lld::warn(const Twine &msg) { errorHandler().warn(msg); }
66941f0628SFangrui Song uint64_t lld::errorCount() { return errorHandler().errorCount; }
67941f0628SFangrui Song 
68f2efb574SAlexandre Ganea raw_ostream &lld::outs() {
6983d59e05SAlexandre Ganea   ErrorHandler &e = errorHandler();
7083d59e05SAlexandre Ganea   return e.outs();
7183d59e05SAlexandre Ganea }
7283d59e05SAlexandre Ganea 
7383d59e05SAlexandre Ganea raw_ostream &ErrorHandler::outs() {
7483d59e05SAlexandre Ganea   if (disableOutput)
75f2efb574SAlexandre Ganea     return llvm::nulls();
76f2efb574SAlexandre Ganea   return stdoutOS ? *stdoutOS : llvm::outs();
77f2efb574SAlexandre Ganea }
78f2efb574SAlexandre Ganea 
7983d59e05SAlexandre Ganea raw_ostream &ErrorHandler::errs() {
8083d59e05SAlexandre Ganea   if (disableOutput)
81f2efb574SAlexandre Ganea     return llvm::nulls();
82f2efb574SAlexandre Ganea   return stderrOS ? *stderrOS : llvm::errs();
83f2efb574SAlexandre Ganea }
84f2efb574SAlexandre Ganea 
85136d27abSRui Ueyama void lld::exitLld(int val) {
8683d59e05SAlexandre Ganea   if (hasContext()) {
8783d59e05SAlexandre Ganea     ErrorHandler &e = errorHandler();
880f3d8e23SMartin Storsjo     // Delete any temporary file, while keeping the memory mapping open.
8983d59e05SAlexandre Ganea     if (e.outputBuffer)
9083d59e05SAlexandre Ganea       e.outputBuffer->discard();
9183d59e05SAlexandre Ganea   }
92a4884cc3SRafael Espindola 
93a2ae9e3aSNico Weber   // Re-throw a possible signal or exception once/if it was caught by
9445b8a741SAlexandre Ganea   // safeLldMain().
9545b8a741SAlexandre Ganea   CrashRecoveryContext::throwIfCrash(val);
9645b8a741SAlexandre Ganea 
97564481aeSAndrew Ng   // Dealloc/destroy ManagedStatic variables before calling _exit().
98564481aeSAndrew Ng   // In an LTO build, allows us to get the output of -time-passes.
99564481aeSAndrew Ng   // Ensures that the thread pool for the parallel algorithms is stopped to
100564481aeSAndrew Ng   // avoid intermittent crashes on Windows when exiting.
101f2efb574SAlexandre Ganea   if (!CrashRecoveryContext::GetCurrent())
102b8a59c8aSBob Haarman     llvm_shutdown();
103b8a59c8aSBob Haarman 
10483d59e05SAlexandre Ganea   if (hasContext())
10583d59e05SAlexandre Ganea     lld::errorHandler().flushStreams();
10683d59e05SAlexandre Ganea 
10745b8a741SAlexandre Ganea   // When running inside safeLldMain(), restore the control flow back to the
10845b8a741SAlexandre Ganea   // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
10945b8a741SAlexandre Ganea   // since we want to avoid further crashes on shutdown.
11045b8a741SAlexandre Ganea   llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
111b8a59c8aSBob Haarman }
112b8a59c8aSBob Haarman 
113136d27abSRui Ueyama void lld::diagnosticHandler(const DiagnosticInfo &di) {
114136d27abSRui Ueyama   SmallString<128> s;
115136d27abSRui Ueyama   raw_svector_ostream os(s);
116136d27abSRui Ueyama   DiagnosticPrinterRawOStream dp(os);
11733b38339SFangrui Song 
11833b38339SFangrui Song   // For an inline asm diagnostic, prepend the module name to get something like
11933b38339SFangrui Song   // "$module <inline asm>:1:5: ".
12033b38339SFangrui Song   if (auto *dism = dyn_cast<DiagnosticInfoSrcMgr>(&di))
12133b38339SFangrui Song     if (dism->isInlineAsmDiag())
12233b38339SFangrui Song       os << dism->getModuleName() << ' ';
12333b38339SFangrui Song 
124136d27abSRui Ueyama   di.print(dp);
125136d27abSRui Ueyama   switch (di.getSeverity()) {
126b2144058SSam Clegg   case DS_Error:
127136d27abSRui Ueyama     error(s);
128b2144058SSam Clegg     break;
129b2144058SSam Clegg   case DS_Warning:
130136d27abSRui Ueyama     warn(s);
131b2144058SSam Clegg     break;
132b2144058SSam Clegg   case DS_Remark:
133b2144058SSam Clegg   case DS_Note:
134136d27abSRui Ueyama     message(s);
135b2144058SSam Clegg     break;
136b2144058SSam Clegg   }
1373ad27e92SSam Clegg }
1383ad27e92SSam Clegg 
139136d27abSRui Ueyama void lld::checkError(Error e) {
140136d27abSRui Ueyama   handleAllErrors(std::move(e),
141136d27abSRui Ueyama                   [&](ErrorInfoBase &eib) { error(eib.message()); });
1423ad27e92SSam Clegg }
1433ad27e92SSam Clegg 
1444a67b93fSFangrui Song void lld::checkError(ErrorHandler &eh, Error e) {
1454a67b93fSFangrui Song   handleAllErrors(std::move(e),
1464a67b93fSFangrui Song                   [&](ErrorInfoBase &eib) { eh.error(eib.message()); });
1474a67b93fSFangrui Song }
1484a67b93fSFangrui Song 
14996a7a225SRui Ueyama // This is for --vs-diagnostics.
15096a7a225SRui Ueyama //
15196a7a225SRui Ueyama // Normally, lld's error message starts with argv[0]. Therefore, it usually
15296a7a225SRui Ueyama // looks like this:
15396a7a225SRui Ueyama //
15496a7a225SRui Ueyama //   ld.lld: error: ...
15596a7a225SRui Ueyama //
15696a7a225SRui Ueyama // This error message style is unfortunately unfriendly to Visual Studio
15796a7a225SRui Ueyama // IDE. VS interprets the first word of the first line as an error location
15896a7a225SRui Ueyama // and make it clickable, thus "ld.lld" in the above message would become a
15996a7a225SRui Ueyama // clickable text. When you click it, VS opens "ld.lld" executable file with
16096a7a225SRui Ueyama // a binary editor.
16196a7a225SRui Ueyama //
16296a7a225SRui Ueyama // As a workaround, we print out an error location instead of "ld.lld" if
16396a7a225SRui Ueyama // lld is running in VS diagnostics mode. As a result, error message will
16496a7a225SRui Ueyama // look like this:
16596a7a225SRui Ueyama //
16696a7a225SRui Ueyama //   src/foo.c(35): error: ...
16796a7a225SRui Ueyama //
16896a7a225SRui Ueyama // This function returns an error location string. An error location is
16996a7a225SRui Ueyama // extracted from an error message using regexps.
170cac8df1aSRui Ueyama std::string ErrorHandler::getLocation(const Twine &msg) {
171cac8df1aSRui Ueyama   if (!vsDiagnostics)
172adcd0268SBenjamin Kramer     return std::string(logName);
173cac8df1aSRui Ueyama 
174cac8df1aSRui Ueyama   static std::regex regexes[] = {
175cac8df1aSRui Ueyama       std::regex(
176b65016ddSIgor Kudrin           R"(^undefined (?:\S+ )?symbol:.*\n)"
177b65016ddSIgor Kudrin           R"(>>> referenced by .+\((\S+):(\d+)\))"),
178b65016ddSIgor Kudrin       std::regex(
179b65016ddSIgor Kudrin           R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
18087886299SChris Jackson       std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
18187886299SChris Jackson       std::regex(
18287886299SChris Jackson           R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
183b65016ddSIgor Kudrin       std::regex(
184b65016ddSIgor Kudrin           R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
185b65016ddSIgor Kudrin       std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
186b65016ddSIgor Kudrin       std::regex(
187b65016ddSIgor Kudrin           R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
188cac8df1aSRui Ueyama       std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
18987886299SChris Jackson       std::regex(R"((\S+):(\d+): unclosed quote)"),
19087886299SChris Jackson   };
19187886299SChris Jackson 
192cac8df1aSRui Ueyama   std::string str = msg.str();
193cac8df1aSRui Ueyama   for (std::regex &re : regexes) {
194cac8df1aSRui Ueyama     std::smatch m;
195cac8df1aSRui Ueyama     if (!std::regex_search(str, m, re))
196cac8df1aSRui Ueyama       continue;
197cac8df1aSRui Ueyama 
198cac8df1aSRui Ueyama     assert(m.size() == 2 || m.size() == 3);
199cac8df1aSRui Ueyama     if (m.size() == 2)
200cac8df1aSRui Ueyama       return m.str(1);
201cac8df1aSRui Ueyama     return m.str(1) + "(" + m.str(2) + ")";
20287886299SChris Jackson   }
20387886299SChris Jackson 
204adcd0268SBenjamin Kramer   return std::string(logName);
205b8a59c8aSBob Haarman }
206b8a59c8aSBob Haarman 
2070db402c5SFangrui Song void ErrorHandler::reportDiagnostic(StringRef location, Colors c,
2080db402c5SFangrui Song                                     StringRef diagKind, const Twine &msg) {
2090db402c5SFangrui Song   SmallString<256> buf;
2100db402c5SFangrui Song   raw_svector_ostream os(buf);
2110db402c5SFangrui Song   os << sep << location << ": ";
2120db402c5SFangrui Song   if (!diagKind.empty()) {
213dc6229bdSFangrui Song     if (errs().colors_enabled()) {
2140db402c5SFangrui Song       os.enable_colors(true);
2150db402c5SFangrui Song       os << c << diagKind << ": " << Colors::RESET;
2160db402c5SFangrui Song     } else {
2170db402c5SFangrui Song       os << diagKind << ": ";
2180db402c5SFangrui Song     }
2190db402c5SFangrui Song   }
2200db402c5SFangrui Song   os << msg << '\n';
221dc6229bdSFangrui Song   errs() << buf;
222a6fa51f5SAlexander Richardson   // If msg contains a newline, ensure that the next diagnostic is preceded by
223a6fa51f5SAlexander Richardson   // a blank line separator.
224a6fa51f5SAlexander Richardson   sep = getSeparator(msg);
2250db402c5SFangrui Song }
2260db402c5SFangrui Song 
227136d27abSRui Ueyama void ErrorHandler::log(const Twine &msg) {
228f2efb574SAlexandre Ganea   if (!verbose || disableOutput)
229cac8df1aSRui Ueyama     return;
230136d27abSRui Ueyama   std::lock_guard<std::mutex> lock(mu);
2310db402c5SFangrui Song   reportDiagnostic(logName, Colors::RESET, "", msg);
232b8a59c8aSBob Haarman }
233b8a59c8aSBob Haarman 
23464c17344SNico Weber void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
235f2efb574SAlexandre Ganea   if (disableOutput)
236f2efb574SAlexandre Ganea     return;
237136d27abSRui Ueyama   std::lock_guard<std::mutex> lock(mu);
23864c17344SNico Weber   s << msg << "\n";
23964c17344SNico Weber   s.flush();
240b8a59c8aSBob Haarman }
241b8a59c8aSBob Haarman 
242136d27abSRui Ueyama void ErrorHandler::warn(const Twine &msg) {
243136d27abSRui Ueyama   if (fatalWarnings) {
244136d27abSRui Ueyama     error(msg);
245b8a59c8aSBob Haarman     return;
246b8a59c8aSBob Haarman   }
247b8a59c8aSBob Haarman 
2487d57c698SKeith Smiley   if (suppressWarnings)
2497d57c698SKeith Smiley     return;
2507d57c698SKeith Smiley 
251136d27abSRui Ueyama   std::lock_guard<std::mutex> lock(mu);
2520db402c5SFangrui Song   reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
2534d41c332SRui Ueyama }
254a52f982fSRui Ueyama 
2554d41c332SRui Ueyama void ErrorHandler::error(const Twine &msg) {
256cac8df1aSRui Ueyama   // If Visual Studio-style error message mode is enabled,
257cac8df1aSRui Ueyama   // this particular error is printed out as two errors.
258cac8df1aSRui Ueyama   if (vsDiagnostics) {
259cac8df1aSRui Ueyama     static std::regex re(R"(^(duplicate symbol: .*))"
260da41e210SIgor Kudrin                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
261da41e210SIgor Kudrin                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
262cac8df1aSRui Ueyama     std::string str = msg.str();
263cac8df1aSRui Ueyama     std::smatch m;
264cac8df1aSRui Ueyama 
265cac8df1aSRui Ueyama     if (std::regex_match(str, m, re)) {
266cac8df1aSRui Ueyama       error(m.str(1) + m.str(2));
267cac8df1aSRui Ueyama       error(m.str(1) + m.str(3));
268cac8df1aSRui Ueyama       return;
269cac8df1aSRui Ueyama     }
270cac8df1aSRui Ueyama   }
271cac8df1aSRui Ueyama 
272de2dfc8bSAndrew Ng   bool exit = false;
273de2dfc8bSAndrew Ng   {
274136d27abSRui Ueyama     std::lock_guard<std::mutex> lock(mu);
275b8a59c8aSBob Haarman 
276136d27abSRui Ueyama     if (errorLimit == 0 || errorCount < errorLimit) {
2770db402c5SFangrui Song       reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
278136d27abSRui Ueyama     } else if (errorCount == errorLimit) {
2790db402c5SFangrui Song       reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
280de2dfc8bSAndrew Ng       exit = exitEarly;
281b8a59c8aSBob Haarman     }
282b8a59c8aSBob Haarman 
283136d27abSRui Ueyama     ++errorCount;
284b8a59c8aSBob Haarman   }
285b8a59c8aSBob Haarman 
286de2dfc8bSAndrew Ng   if (exit)
287de2dfc8bSAndrew Ng     exitLld(1);
288de2dfc8bSAndrew Ng }
289de2dfc8bSAndrew Ng 
290cfc32267Sserge-sans-paille void ErrorHandler::error(const Twine &msg, ErrorTag tag,
291cfc32267Sserge-sans-paille                          ArrayRef<StringRef> args) {
292*f359c1f5SFangrui Song   if (errorHandlingScript.empty() || disableOutput) {
293cfc32267Sserge-sans-paille     error(msg);
294cfc32267Sserge-sans-paille     return;
295cfc32267Sserge-sans-paille   }
296cfc32267Sserge-sans-paille   SmallVector<StringRef, 4> scriptArgs;
297cfc32267Sserge-sans-paille   scriptArgs.push_back(errorHandlingScript);
298cfc32267Sserge-sans-paille   switch (tag) {
299cfc32267Sserge-sans-paille   case ErrorTag::LibNotFound:
300cfc32267Sserge-sans-paille     scriptArgs.push_back("missing-lib");
301cfc32267Sserge-sans-paille     break;
3021e70ec10Sserge-sans-paille   case ErrorTag::SymbolNotFound:
3031e70ec10Sserge-sans-paille     scriptArgs.push_back("undefined-symbol");
3041e70ec10Sserge-sans-paille     break;
305cfc32267Sserge-sans-paille   }
306cfc32267Sserge-sans-paille   scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
307cfc32267Sserge-sans-paille   int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
308cfc32267Sserge-sans-paille   if (res == 0) {
309cfc32267Sserge-sans-paille     return error(msg);
310cfc32267Sserge-sans-paille   } else {
311cfc32267Sserge-sans-paille     // Temporarily disable error limit to make sure the two calls to error(...)
312cfc32267Sserge-sans-paille     // only count as one.
313cfc32267Sserge-sans-paille     uint64_t currentErrorLimit = errorLimit;
314cfc32267Sserge-sans-paille     errorLimit = 0;
315cfc32267Sserge-sans-paille     error(msg);
316cfc32267Sserge-sans-paille     errorLimit = currentErrorLimit;
317cfc32267Sserge-sans-paille     --errorCount;
318cfc32267Sserge-sans-paille 
319cfc32267Sserge-sans-paille     switch (res) {
320cfc32267Sserge-sans-paille     case -1:
321cfc32267Sserge-sans-paille       error("error handling script '" + errorHandlingScript +
322cfc32267Sserge-sans-paille             "' failed to execute");
323cfc32267Sserge-sans-paille       break;
324cfc32267Sserge-sans-paille     case -2:
325cfc32267Sserge-sans-paille       error("error handling script '" + errorHandlingScript +
326cfc32267Sserge-sans-paille             "' crashed or timeout");
327cfc32267Sserge-sans-paille       break;
328cfc32267Sserge-sans-paille     default:
329cfc32267Sserge-sans-paille       error("error handling script '" + errorHandlingScript +
330cfc32267Sserge-sans-paille             "' exited with code " + Twine(res));
331cfc32267Sserge-sans-paille     }
332cfc32267Sserge-sans-paille   }
333cfc32267Sserge-sans-paille }
334cfc32267Sserge-sans-paille 
335136d27abSRui Ueyama void ErrorHandler::fatal(const Twine &msg) {
336136d27abSRui Ueyama   error(msg);
337b8a59c8aSBob Haarman   exitLld(1);
338b8a59c8aSBob Haarman }
339201d7607SFangrui Song 
340201d7607SFangrui Song SyncStream::~SyncStream() {
341201d7607SFangrui Song   switch (level) {
342eb4d2f24SFangrui Song   case DiagLevel::None:
343eb4d2f24SFangrui Song     break;
344201d7607SFangrui Song   case DiagLevel::Log:
345201d7607SFangrui Song     e.log(buf);
346201d7607SFangrui Song     break;
3473b75a5c4SFangrui Song   case DiagLevel::Msg:
348686a291cSFangrui Song     e.message(buf, e.outs());
3493b75a5c4SFangrui Song     break;
350201d7607SFangrui Song   case DiagLevel::Warn:
351201d7607SFangrui Song     e.warn(buf);
352201d7607SFangrui Song     break;
353201d7607SFangrui Song   case DiagLevel::Err:
354201d7607SFangrui Song     e.error(buf);
355201d7607SFangrui Song     break;
356201d7607SFangrui Song   case DiagLevel::Fatal:
357201d7607SFangrui Song     e.fatal(buf);
358201d7607SFangrui Song     break;
359201d7607SFangrui Song   }
360201d7607SFangrui Song }
361