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
getSeparator(const Twine & msg)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
~ErrorHandler()3383d59e05SAlexandre Ganea ErrorHandler::~ErrorHandler() {
3483d59e05SAlexandre Ganea if (cleanupCallback)
3583d59e05SAlexandre Ganea cleanupCallback();
36f860fe36SAlexandre Ganea }
37f860fe36SAlexandre Ganea
initialize(llvm::raw_ostream & stdoutOS,llvm::raw_ostream & stderrOS,bool exitEarly,bool disableOutput)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
flushStreams()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
errorHandler()5483d59e05SAlexandre Ganea ErrorHandler &lld::errorHandler() { return context().e; }
5583d59e05SAlexandre Ganea
error(const Twine & msg)56941f0628SFangrui Song void lld::error(const Twine &msg) { errorHandler().error(msg); }
error(const Twine & msg,ErrorTag tag,ArrayRef<StringRef> args)57941f0628SFangrui Song void lld::error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) {
58941f0628SFangrui Song errorHandler().error(msg, tag, args);
59941f0628SFangrui Song }
fatal(const Twine & msg)60941f0628SFangrui Song void lld::fatal(const Twine &msg) { errorHandler().fatal(msg); }
log(const Twine & msg)61941f0628SFangrui Song void lld::log(const Twine &msg) { errorHandler().log(msg); }
message(const Twine & msg,llvm::raw_ostream & s)62941f0628SFangrui Song void lld::message(const Twine &msg, llvm::raw_ostream &s) {
63941f0628SFangrui Song errorHandler().message(msg, s);
64941f0628SFangrui Song }
warn(const Twine & msg)65941f0628SFangrui Song void lld::warn(const Twine &msg) { errorHandler().warn(msg); }
errorCount()66941f0628SFangrui Song uint64_t lld::errorCount() { return errorHandler().errorCount; }
67941f0628SFangrui Song
outs()68f2efb574SAlexandre Ganea raw_ostream &lld::outs() {
6983d59e05SAlexandre Ganea ErrorHandler &e = errorHandler();
7083d59e05SAlexandre Ganea return e.outs();
7183d59e05SAlexandre Ganea }
7283d59e05SAlexandre Ganea
errs()7383d59e05SAlexandre Ganea raw_ostream &lld::errs() {
7483d59e05SAlexandre Ganea ErrorHandler &e = errorHandler();
7583d59e05SAlexandre Ganea return e.errs();
7683d59e05SAlexandre Ganea }
7783d59e05SAlexandre Ganea
outs()7883d59e05SAlexandre Ganea raw_ostream &ErrorHandler::outs() {
7983d59e05SAlexandre Ganea if (disableOutput)
80f2efb574SAlexandre Ganea return llvm::nulls();
81f2efb574SAlexandre Ganea return stdoutOS ? *stdoutOS : llvm::outs();
82f2efb574SAlexandre Ganea }
83f2efb574SAlexandre Ganea
errs()8483d59e05SAlexandre Ganea raw_ostream &ErrorHandler::errs() {
8583d59e05SAlexandre Ganea if (disableOutput)
86f2efb574SAlexandre Ganea return llvm::nulls();
87f2efb574SAlexandre Ganea return stderrOS ? *stderrOS : llvm::errs();
88f2efb574SAlexandre Ganea }
89f2efb574SAlexandre Ganea
exitLld(int val)90136d27abSRui Ueyama void lld::exitLld(int val) {
9183d59e05SAlexandre Ganea if (hasContext()) {
9283d59e05SAlexandre Ganea ErrorHandler &e = errorHandler();
930f3d8e23SMartin Storsjo // Delete any temporary file, while keeping the memory mapping open.
9483d59e05SAlexandre Ganea if (e.outputBuffer)
9583d59e05SAlexandre Ganea e.outputBuffer->discard();
9683d59e05SAlexandre Ganea }
97a4884cc3SRafael Espindola
9845b8a741SAlexandre Ganea // Re-throw a possible signal or exception once/if it was catched by
9945b8a741SAlexandre Ganea // safeLldMain().
10045b8a741SAlexandre Ganea CrashRecoveryContext::throwIfCrash(val);
10145b8a741SAlexandre Ganea
102564481aeSAndrew Ng // Dealloc/destroy ManagedStatic variables before calling _exit().
103564481aeSAndrew Ng // In an LTO build, allows us to get the output of -time-passes.
104564481aeSAndrew Ng // Ensures that the thread pool for the parallel algorithms is stopped to
105564481aeSAndrew Ng // avoid intermittent crashes on Windows when exiting.
106f2efb574SAlexandre Ganea if (!CrashRecoveryContext::GetCurrent())
107b8a59c8aSBob Haarman llvm_shutdown();
108b8a59c8aSBob Haarman
10983d59e05SAlexandre Ganea if (hasContext())
11083d59e05SAlexandre Ganea lld::errorHandler().flushStreams();
11183d59e05SAlexandre Ganea
11245b8a741SAlexandre Ganea // When running inside safeLldMain(), restore the control flow back to the
11345b8a741SAlexandre Ganea // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
11445b8a741SAlexandre Ganea // since we want to avoid further crashes on shutdown.
11545b8a741SAlexandre Ganea llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
116b8a59c8aSBob Haarman }
117b8a59c8aSBob Haarman
diagnosticHandler(const DiagnosticInfo & di)118136d27abSRui Ueyama void lld::diagnosticHandler(const DiagnosticInfo &di) {
119136d27abSRui Ueyama SmallString<128> s;
120136d27abSRui Ueyama raw_svector_ostream os(s);
121136d27abSRui Ueyama DiagnosticPrinterRawOStream dp(os);
12233b38339SFangrui Song
12333b38339SFangrui Song // For an inline asm diagnostic, prepend the module name to get something like
12433b38339SFangrui Song // "$module <inline asm>:1:5: ".
12533b38339SFangrui Song if (auto *dism = dyn_cast<DiagnosticInfoSrcMgr>(&di))
12633b38339SFangrui Song if (dism->isInlineAsmDiag())
12733b38339SFangrui Song os << dism->getModuleName() << ' ';
12833b38339SFangrui Song
129136d27abSRui Ueyama di.print(dp);
130136d27abSRui Ueyama switch (di.getSeverity()) {
131b2144058SSam Clegg case DS_Error:
132136d27abSRui Ueyama error(s);
133b2144058SSam Clegg break;
134b2144058SSam Clegg case DS_Warning:
135136d27abSRui Ueyama warn(s);
136b2144058SSam Clegg break;
137b2144058SSam Clegg case DS_Remark:
138b2144058SSam Clegg case DS_Note:
139136d27abSRui Ueyama message(s);
140b2144058SSam Clegg break;
141b2144058SSam Clegg }
1423ad27e92SSam Clegg }
1433ad27e92SSam Clegg
checkError(Error e)144136d27abSRui Ueyama void lld::checkError(Error e) {
145136d27abSRui Ueyama handleAllErrors(std::move(e),
146136d27abSRui Ueyama [&](ErrorInfoBase &eib) { error(eib.message()); });
1473ad27e92SSam Clegg }
1483ad27e92SSam Clegg
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.
getLocation(const Twine & msg)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
reportDiagnostic(StringRef location,Colors c,StringRef diagKind,const Twine & msg)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()) {
2130db402c5SFangrui Song if (lld::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';
2210db402c5SFangrui Song lld::errs() << buf;
2220db402c5SFangrui Song }
2230db402c5SFangrui Song
log(const Twine & msg)224136d27abSRui Ueyama void ErrorHandler::log(const Twine &msg) {
225f2efb574SAlexandre Ganea if (!verbose || disableOutput)
226cac8df1aSRui Ueyama return;
227136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu);
2280db402c5SFangrui Song reportDiagnostic(logName, Colors::RESET, "", msg);
229b8a59c8aSBob Haarman }
230b8a59c8aSBob Haarman
message(const Twine & msg,llvm::raw_ostream & s)23164c17344SNico Weber void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
232f2efb574SAlexandre Ganea if (disableOutput)
233f2efb574SAlexandre Ganea return;
234136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu);
23564c17344SNico Weber s << msg << "\n";
23664c17344SNico Weber s.flush();
237b8a59c8aSBob Haarman }
238b8a59c8aSBob Haarman
warn(const Twine & msg)239136d27abSRui Ueyama void ErrorHandler::warn(const Twine &msg) {
240136d27abSRui Ueyama if (fatalWarnings) {
241136d27abSRui Ueyama error(msg);
242b8a59c8aSBob Haarman return;
243b8a59c8aSBob Haarman }
244b8a59c8aSBob Haarman
245*7d57c698SKeith Smiley if (suppressWarnings)
246*7d57c698SKeith Smiley return;
247*7d57c698SKeith Smiley
248136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu);
2490db402c5SFangrui Song reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
2506c5fc940SRui Ueyama sep = getSeparator(msg);
2514d41c332SRui Ueyama }
252a52f982fSRui Ueyama
error(const Twine & msg)2534d41c332SRui Ueyama void ErrorHandler::error(const Twine &msg) {
254cac8df1aSRui Ueyama // If Visual Studio-style error message mode is enabled,
255cac8df1aSRui Ueyama // this particular error is printed out as two errors.
256cac8df1aSRui Ueyama if (vsDiagnostics) {
257cac8df1aSRui Ueyama static std::regex re(R"(^(duplicate symbol: .*))"
258da41e210SIgor Kudrin R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
259da41e210SIgor Kudrin R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
260cac8df1aSRui Ueyama std::string str = msg.str();
261cac8df1aSRui Ueyama std::smatch m;
262cac8df1aSRui Ueyama
263cac8df1aSRui Ueyama if (std::regex_match(str, m, re)) {
264cac8df1aSRui Ueyama error(m.str(1) + m.str(2));
265cac8df1aSRui Ueyama error(m.str(1) + m.str(3));
266cac8df1aSRui Ueyama return;
267cac8df1aSRui Ueyama }
268cac8df1aSRui Ueyama }
269cac8df1aSRui Ueyama
270de2dfc8bSAndrew Ng bool exit = false;
271de2dfc8bSAndrew Ng {
272136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu);
273b8a59c8aSBob Haarman
274136d27abSRui Ueyama if (errorLimit == 0 || errorCount < errorLimit) {
2750db402c5SFangrui Song reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
276136d27abSRui Ueyama } else if (errorCount == errorLimit) {
2770db402c5SFangrui Song reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
278de2dfc8bSAndrew Ng exit = exitEarly;
279b8a59c8aSBob Haarman }
280b8a59c8aSBob Haarman
2816c5fc940SRui Ueyama sep = getSeparator(msg);
282136d27abSRui Ueyama ++errorCount;
283b8a59c8aSBob Haarman }
284b8a59c8aSBob Haarman
285de2dfc8bSAndrew Ng if (exit)
286de2dfc8bSAndrew Ng exitLld(1);
287de2dfc8bSAndrew Ng }
288de2dfc8bSAndrew Ng
error(const Twine & msg,ErrorTag tag,ArrayRef<StringRef> args)289cfc32267Sserge-sans-paille void ErrorHandler::error(const Twine &msg, ErrorTag tag,
290cfc32267Sserge-sans-paille ArrayRef<StringRef> args) {
291cfc32267Sserge-sans-paille if (errorHandlingScript.empty()) {
292cfc32267Sserge-sans-paille error(msg);
293cfc32267Sserge-sans-paille return;
294cfc32267Sserge-sans-paille }
295cfc32267Sserge-sans-paille SmallVector<StringRef, 4> scriptArgs;
296cfc32267Sserge-sans-paille scriptArgs.push_back(errorHandlingScript);
297cfc32267Sserge-sans-paille switch (tag) {
298cfc32267Sserge-sans-paille case ErrorTag::LibNotFound:
299cfc32267Sserge-sans-paille scriptArgs.push_back("missing-lib");
300cfc32267Sserge-sans-paille break;
3011e70ec10Sserge-sans-paille case ErrorTag::SymbolNotFound:
3021e70ec10Sserge-sans-paille scriptArgs.push_back("undefined-symbol");
3031e70ec10Sserge-sans-paille break;
304cfc32267Sserge-sans-paille }
305cfc32267Sserge-sans-paille scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
306cfc32267Sserge-sans-paille int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
307cfc32267Sserge-sans-paille if (res == 0) {
308cfc32267Sserge-sans-paille return error(msg);
309cfc32267Sserge-sans-paille } else {
310cfc32267Sserge-sans-paille // Temporarily disable error limit to make sure the two calls to error(...)
311cfc32267Sserge-sans-paille // only count as one.
312cfc32267Sserge-sans-paille uint64_t currentErrorLimit = errorLimit;
313cfc32267Sserge-sans-paille errorLimit = 0;
314cfc32267Sserge-sans-paille error(msg);
315cfc32267Sserge-sans-paille errorLimit = currentErrorLimit;
316cfc32267Sserge-sans-paille --errorCount;
317cfc32267Sserge-sans-paille
318cfc32267Sserge-sans-paille switch (res) {
319cfc32267Sserge-sans-paille case -1:
320cfc32267Sserge-sans-paille error("error handling script '" + errorHandlingScript +
321cfc32267Sserge-sans-paille "' failed to execute");
322cfc32267Sserge-sans-paille break;
323cfc32267Sserge-sans-paille case -2:
324cfc32267Sserge-sans-paille error("error handling script '" + errorHandlingScript +
325cfc32267Sserge-sans-paille "' crashed or timeout");
326cfc32267Sserge-sans-paille break;
327cfc32267Sserge-sans-paille default:
328cfc32267Sserge-sans-paille error("error handling script '" + errorHandlingScript +
329cfc32267Sserge-sans-paille "' exited with code " + Twine(res));
330cfc32267Sserge-sans-paille }
331cfc32267Sserge-sans-paille }
332cfc32267Sserge-sans-paille }
333cfc32267Sserge-sans-paille
fatal(const Twine & msg)334136d27abSRui Ueyama void ErrorHandler::fatal(const Twine &msg) {
335136d27abSRui Ueyama error(msg);
336b8a59c8aSBob Haarman exitLld(1);
337b8a59c8aSBob Haarman }
338