1eb1ff93dSDimitry Andric //===- ErrorHandler.cpp ---------------------------------------------------===//
25a5c549fSDimitry Andric //
3f1e1c239SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f1e1c239SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5f1e1c239SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a5c549fSDimitry Andric //
75a5c549fSDimitry Andric //===----------------------------------------------------------------------===//
85a5c549fSDimitry Andric
9eb1ff93dSDimitry Andric #include "lld/Common/ErrorHandler.h"
10eb1ff93dSDimitry Andric
11cfca06d7SDimitry Andric #include "llvm/Support/Parallel.h"
125a5c549fSDimitry Andric
136f8fc217SDimitry Andric #include "lld/Common/CommonLinkerContext.h"
145a5c549fSDimitry Andric #include "llvm/ADT/Twine.h"
1520d35e67SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
1620d35e67SDimitry Andric #include "llvm/IR/DiagnosticPrinter.h"
17b60736ecSDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
18d93e1dfaSDimitry Andric #include "llvm/Support/ManagedStatic.h"
19b60736ecSDimitry Andric #include "llvm/Support/Process.h"
20b60736ecSDimitry Andric #include "llvm/Support/Program.h"
215a5c549fSDimitry Andric #include "llvm/Support/raw_ostream.h"
22f1e1c239SDimitry Andric #include <regex>
235a5c549fSDimitry Andric
241c986198SDimitry Andric using namespace llvm;
25d2d3ebb8SDimitry Andric using namespace lld;
261c986198SDimitry Andric
getSeparator(const Twine & msg)27d2bd9e70SDimitry Andric static StringRef getSeparator(const Twine &msg) {
28d2bd9e70SDimitry Andric if (StringRef(msg.str()).contains('\n'))
29d2bd9e70SDimitry Andric return "\n";
30d2bd9e70SDimitry Andric return "";
31d2d3ebb8SDimitry Andric }
32d2d3ebb8SDimitry Andric
~ErrorHandler()336f8fc217SDimitry Andric ErrorHandler::~ErrorHandler() {
346f8fc217SDimitry Andric if (cleanupCallback)
356f8fc217SDimitry Andric cleanupCallback();
36d93e1dfaSDimitry Andric }
37d93e1dfaSDimitry Andric
initialize(llvm::raw_ostream & stdoutOS,llvm::raw_ostream & stderrOS,bool exitEarly,bool disableOutput)386f8fc217SDimitry Andric void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS,
396f8fc217SDimitry Andric llvm::raw_ostream &stderrOS, bool exitEarly,
406f8fc217SDimitry Andric bool disableOutput) {
416f8fc217SDimitry Andric this->stdoutOS = &stdoutOS;
426f8fc217SDimitry Andric this->stderrOS = &stderrOS;
436f8fc217SDimitry Andric stderrOS.enable_colors(stderrOS.has_colors());
446f8fc217SDimitry Andric this->exitEarly = exitEarly;
456f8fc217SDimitry Andric this->disableOutput = disableOutput;
466f8fc217SDimitry Andric }
476f8fc217SDimitry Andric
flushStreams()486f8fc217SDimitry Andric void ErrorHandler::flushStreams() {
496f8fc217SDimitry Andric std::lock_guard<std::mutex> lock(mu);
506f8fc217SDimitry Andric outs().flush();
516f8fc217SDimitry Andric errs().flush();
526f8fc217SDimitry Andric }
536f8fc217SDimitry Andric
errorHandler()546f8fc217SDimitry Andric ErrorHandler &lld::errorHandler() { return context().e; }
556f8fc217SDimitry Andric
error(const Twine & msg)56145449b1SDimitry Andric void lld::error(const Twine &msg) { errorHandler().error(msg); }
error(const Twine & msg,ErrorTag tag,ArrayRef<StringRef> args)57145449b1SDimitry Andric void lld::error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) {
58145449b1SDimitry Andric errorHandler().error(msg, tag, args);
59145449b1SDimitry Andric }
fatal(const Twine & msg)60145449b1SDimitry Andric void lld::fatal(const Twine &msg) { errorHandler().fatal(msg); }
log(const Twine & msg)61145449b1SDimitry Andric void lld::log(const Twine &msg) { errorHandler().log(msg); }
message(const Twine & msg,llvm::raw_ostream & s)62145449b1SDimitry Andric void lld::message(const Twine &msg, llvm::raw_ostream &s) {
63145449b1SDimitry Andric errorHandler().message(msg, s);
64145449b1SDimitry Andric }
warn(const Twine & msg)65145449b1SDimitry Andric void lld::warn(const Twine &msg) { errorHandler().warn(msg); }
errorCount()66145449b1SDimitry Andric uint64_t lld::errorCount() { return errorHandler().errorCount; }
67145449b1SDimitry Andric
outs()68b60736ecSDimitry Andric raw_ostream &lld::outs() {
696f8fc217SDimitry Andric ErrorHandler &e = errorHandler();
706f8fc217SDimitry Andric return e.outs();
716f8fc217SDimitry Andric }
726f8fc217SDimitry Andric
errs()736f8fc217SDimitry Andric raw_ostream &lld::errs() {
746f8fc217SDimitry Andric ErrorHandler &e = errorHandler();
756f8fc217SDimitry Andric return e.errs();
766f8fc217SDimitry Andric }
776f8fc217SDimitry Andric
outs()786f8fc217SDimitry Andric raw_ostream &ErrorHandler::outs() {
796f8fc217SDimitry Andric if (disableOutput)
80b60736ecSDimitry Andric return llvm::nulls();
81b60736ecSDimitry Andric return stdoutOS ? *stdoutOS : llvm::outs();
82b60736ecSDimitry Andric }
83b60736ecSDimitry Andric
errs()846f8fc217SDimitry Andric raw_ostream &ErrorHandler::errs() {
856f8fc217SDimitry Andric if (disableOutput)
86b60736ecSDimitry Andric return llvm::nulls();
87b60736ecSDimitry Andric return stderrOS ? *stderrOS : llvm::errs();
88b60736ecSDimitry Andric }
89b60736ecSDimitry Andric
exitLld(int val)90f1e1c239SDimitry Andric void lld::exitLld(int val) {
916f8fc217SDimitry Andric if (hasContext()) {
926f8fc217SDimitry Andric ErrorHandler &e = errorHandler();
93e2fd426bSDimitry Andric // Delete any temporary file, while keeping the memory mapping open.
946f8fc217SDimitry Andric if (e.outputBuffer)
956f8fc217SDimitry Andric e.outputBuffer->discard();
966f8fc217SDimitry Andric }
97d2d3ebb8SDimitry Andric
987fa27ce4SDimitry Andric // Re-throw a possible signal or exception once/if it was caught by
99b60736ecSDimitry Andric // safeLldMain().
100b60736ecSDimitry Andric CrashRecoveryContext::throwIfCrash(val);
101b60736ecSDimitry Andric
102706b4fc4SDimitry Andric // Dealloc/destroy ManagedStatic variables before calling _exit().
103706b4fc4SDimitry Andric // In an LTO build, allows us to get the output of -time-passes.
104706b4fc4SDimitry Andric // Ensures that the thread pool for the parallel algorithms is stopped to
105706b4fc4SDimitry Andric // avoid intermittent crashes on Windows when exiting.
106b60736ecSDimitry Andric if (!CrashRecoveryContext::GetCurrent())
107d93e1dfaSDimitry Andric llvm_shutdown();
108d93e1dfaSDimitry Andric
1096f8fc217SDimitry Andric if (hasContext())
1106f8fc217SDimitry Andric lld::errorHandler().flushStreams();
1116f8fc217SDimitry Andric
112b60736ecSDimitry Andric // When running inside safeLldMain(), restore the control flow back to the
113b60736ecSDimitry Andric // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
114b60736ecSDimitry Andric // since we want to avoid further crashes on shutdown.
115b60736ecSDimitry Andric llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
116d93e1dfaSDimitry Andric }
117d93e1dfaSDimitry Andric
diagnosticHandler(const DiagnosticInfo & di)118f1e1c239SDimitry Andric void lld::diagnosticHandler(const DiagnosticInfo &di) {
119f1e1c239SDimitry Andric SmallString<128> s;
120f1e1c239SDimitry Andric raw_svector_ostream os(s);
121f1e1c239SDimitry Andric DiagnosticPrinterRawOStream dp(os);
122ecbca9f5SDimitry Andric
123ecbca9f5SDimitry Andric // For an inline asm diagnostic, prepend the module name to get something like
124ecbca9f5SDimitry Andric // "$module <inline asm>:1:5: ".
125ecbca9f5SDimitry Andric if (auto *dism = dyn_cast<DiagnosticInfoSrcMgr>(&di))
126ecbca9f5SDimitry Andric if (dism->isInlineAsmDiag())
127ecbca9f5SDimitry Andric os << dism->getModuleName() << ' ';
128ecbca9f5SDimitry Andric
129f1e1c239SDimitry Andric di.print(dp);
130f1e1c239SDimitry Andric switch (di.getSeverity()) {
13120d35e67SDimitry Andric case DS_Error:
132f1e1c239SDimitry Andric error(s);
13320d35e67SDimitry Andric break;
13420d35e67SDimitry Andric case DS_Warning:
135f1e1c239SDimitry Andric warn(s);
13620d35e67SDimitry Andric break;
13720d35e67SDimitry Andric case DS_Remark:
13820d35e67SDimitry Andric case DS_Note:
139f1e1c239SDimitry Andric message(s);
14020d35e67SDimitry Andric break;
14120d35e67SDimitry Andric }
14220d35e67SDimitry Andric }
14320d35e67SDimitry Andric
checkError(Error e)144f1e1c239SDimitry Andric void lld::checkError(Error e) {
145f1e1c239SDimitry Andric handleAllErrors(std::move(e),
146f1e1c239SDimitry Andric [&](ErrorInfoBase &eib) { error(eib.message()); });
14720d35e67SDimitry Andric }
14820d35e67SDimitry Andric
149d2bd9e70SDimitry Andric // This is for --vs-diagnostics.
150d2bd9e70SDimitry Andric //
151d2bd9e70SDimitry Andric // Normally, lld's error message starts with argv[0]. Therefore, it usually
152d2bd9e70SDimitry Andric // looks like this:
153d2bd9e70SDimitry Andric //
154d2bd9e70SDimitry Andric // ld.lld: error: ...
155d2bd9e70SDimitry Andric //
156d2bd9e70SDimitry Andric // This error message style is unfortunately unfriendly to Visual Studio
157d2bd9e70SDimitry Andric // IDE. VS interprets the first word of the first line as an error location
158d2bd9e70SDimitry Andric // and make it clickable, thus "ld.lld" in the above message would become a
159d2bd9e70SDimitry Andric // clickable text. When you click it, VS opens "ld.lld" executable file with
160d2bd9e70SDimitry Andric // a binary editor.
161d2bd9e70SDimitry Andric //
162d2bd9e70SDimitry Andric // As a workaround, we print out an error location instead of "ld.lld" if
163d2bd9e70SDimitry Andric // lld is running in VS diagnostics mode. As a result, error message will
164d2bd9e70SDimitry Andric // look like this:
165d2bd9e70SDimitry Andric //
166d2bd9e70SDimitry Andric // src/foo.c(35): error: ...
167d2bd9e70SDimitry Andric //
168d2bd9e70SDimitry Andric // This function returns an error location string. An error location is
169d2bd9e70SDimitry Andric // extracted from an error message using regexps.
getLocation(const Twine & msg)170d2bd9e70SDimitry Andric std::string ErrorHandler::getLocation(const Twine &msg) {
171d2bd9e70SDimitry Andric if (!vsDiagnostics)
172cfca06d7SDimitry Andric return std::string(logName);
173d2bd9e70SDimitry Andric
174d2bd9e70SDimitry Andric static std::regex regexes[] = {
175d2bd9e70SDimitry Andric std::regex(
176d2bd9e70SDimitry Andric R"(^undefined (?:\S+ )?symbol:.*\n)"
177d2bd9e70SDimitry Andric R"(>>> referenced by .+\((\S+):(\d+)\))"),
178d2bd9e70SDimitry Andric std::regex(
179d2bd9e70SDimitry Andric R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
180f1e1c239SDimitry Andric std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
181f1e1c239SDimitry Andric std::regex(
182f1e1c239SDimitry Andric R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
183f1e1c239SDimitry Andric std::regex(
184d2bd9e70SDimitry Andric R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
185d2bd9e70SDimitry Andric std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
186f1e1c239SDimitry Andric std::regex(
187d2bd9e70SDimitry Andric R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
188d2bd9e70SDimitry Andric std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
189f1e1c239SDimitry Andric std::regex(R"((\S+):(\d+): unclosed quote)"),
190f1e1c239SDimitry Andric };
191f1e1c239SDimitry Andric
192d2bd9e70SDimitry Andric std::string str = msg.str();
193d2bd9e70SDimitry Andric for (std::regex &re : regexes) {
194d2bd9e70SDimitry Andric std::smatch m;
195d2bd9e70SDimitry Andric if (!std::regex_search(str, m, re))
196d2bd9e70SDimitry Andric continue;
197d2bd9e70SDimitry Andric
198d2bd9e70SDimitry Andric assert(m.size() == 2 || m.size() == 3);
199d2bd9e70SDimitry Andric if (m.size() == 2)
200d2bd9e70SDimitry Andric return m.str(1);
201d2bd9e70SDimitry Andric return m.str(1) + "(" + m.str(2) + ")";
202f1e1c239SDimitry Andric }
203f1e1c239SDimitry Andric
204cfca06d7SDimitry Andric return std::string(logName);
205eb1ff93dSDimitry Andric }
206eb1ff93dSDimitry Andric
reportDiagnostic(StringRef location,Colors c,StringRef diagKind,const Twine & msg)207c0981da4SDimitry Andric void ErrorHandler::reportDiagnostic(StringRef location, Colors c,
208c0981da4SDimitry Andric StringRef diagKind, const Twine &msg) {
209c0981da4SDimitry Andric SmallString<256> buf;
210c0981da4SDimitry Andric raw_svector_ostream os(buf);
211c0981da4SDimitry Andric os << sep << location << ": ";
212c0981da4SDimitry Andric if (!diagKind.empty()) {
213c0981da4SDimitry Andric if (lld::errs().colors_enabled()) {
214c0981da4SDimitry Andric os.enable_colors(true);
215c0981da4SDimitry Andric os << c << diagKind << ": " << Colors::RESET;
216c0981da4SDimitry Andric } else {
217c0981da4SDimitry Andric os << diagKind << ": ";
218c0981da4SDimitry Andric }
219c0981da4SDimitry Andric }
220c0981da4SDimitry Andric os << msg << '\n';
221c0981da4SDimitry Andric lld::errs() << buf;
222c0981da4SDimitry Andric }
223c0981da4SDimitry Andric
log(const Twine & msg)224f1e1c239SDimitry Andric void ErrorHandler::log(const Twine &msg) {
225b60736ecSDimitry Andric if (!verbose || disableOutput)
226d2bd9e70SDimitry Andric return;
227f1e1c239SDimitry Andric std::lock_guard<std::mutex> lock(mu);
228c0981da4SDimitry Andric reportDiagnostic(logName, Colors::RESET, "", msg);
229eb1ff93dSDimitry Andric }
230eb1ff93dSDimitry Andric
message(const Twine & msg,llvm::raw_ostream & s)231c0981da4SDimitry Andric void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
232b60736ecSDimitry Andric if (disableOutput)
233b60736ecSDimitry Andric return;
234f1e1c239SDimitry Andric std::lock_guard<std::mutex> lock(mu);
235c0981da4SDimitry Andric s << msg << "\n";
236c0981da4SDimitry Andric s.flush();
237eb1ff93dSDimitry Andric }
238eb1ff93dSDimitry Andric
warn(const Twine & msg)239f1e1c239SDimitry Andric void ErrorHandler::warn(const Twine &msg) {
240f1e1c239SDimitry Andric if (fatalWarnings) {
241f1e1c239SDimitry Andric error(msg);
242eb1ff93dSDimitry Andric return;
243eb1ff93dSDimitry Andric }
244eb1ff93dSDimitry Andric
245145449b1SDimitry Andric if (suppressWarnings)
246145449b1SDimitry Andric return;
247145449b1SDimitry Andric
248f1e1c239SDimitry Andric std::lock_guard<std::mutex> lock(mu);
249c0981da4SDimitry Andric reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
250d2bd9e70SDimitry Andric sep = getSeparator(msg);
251eb1ff93dSDimitry Andric }
252eb1ff93dSDimitry Andric
error(const Twine & msg)253f1e1c239SDimitry Andric void ErrorHandler::error(const Twine &msg) {
254d2bd9e70SDimitry Andric // If Visual Studio-style error message mode is enabled,
255d2bd9e70SDimitry Andric // this particular error is printed out as two errors.
256d2bd9e70SDimitry Andric if (vsDiagnostics) {
257d2bd9e70SDimitry Andric static std::regex re(R"(^(duplicate symbol: .*))"
258d2bd9e70SDimitry Andric R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
259d2bd9e70SDimitry Andric R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
260d2bd9e70SDimitry Andric std::string str = msg.str();
261d2bd9e70SDimitry Andric std::smatch m;
262d2bd9e70SDimitry Andric
263d2bd9e70SDimitry Andric if (std::regex_match(str, m, re)) {
264d2bd9e70SDimitry Andric error(m.str(1) + m.str(2));
265d2bd9e70SDimitry Andric error(m.str(1) + m.str(3));
266d2bd9e70SDimitry Andric return;
267d2bd9e70SDimitry Andric }
268d2bd9e70SDimitry Andric }
269d2bd9e70SDimitry Andric
270cfca06d7SDimitry Andric bool exit = false;
271cfca06d7SDimitry Andric {
272f1e1c239SDimitry Andric std::lock_guard<std::mutex> lock(mu);
273eb1ff93dSDimitry Andric
274f1e1c239SDimitry Andric if (errorLimit == 0 || errorCount < errorLimit) {
275c0981da4SDimitry Andric reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
276f1e1c239SDimitry Andric } else if (errorCount == errorLimit) {
277c0981da4SDimitry Andric reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
278cfca06d7SDimitry Andric exit = exitEarly;
279eb1ff93dSDimitry Andric }
280eb1ff93dSDimitry Andric
281d2bd9e70SDimitry Andric sep = getSeparator(msg);
282f1e1c239SDimitry Andric ++errorCount;
283eb1ff93dSDimitry Andric }
284eb1ff93dSDimitry Andric
285cfca06d7SDimitry Andric if (exit)
286cfca06d7SDimitry Andric exitLld(1);
287cfca06d7SDimitry Andric }
288cfca06d7SDimitry Andric
error(const Twine & msg,ErrorTag tag,ArrayRef<StringRef> args)289b60736ecSDimitry Andric void ErrorHandler::error(const Twine &msg, ErrorTag tag,
290b60736ecSDimitry Andric ArrayRef<StringRef> args) {
291b60736ecSDimitry Andric if (errorHandlingScript.empty()) {
292b60736ecSDimitry Andric error(msg);
293b60736ecSDimitry Andric return;
294b60736ecSDimitry Andric }
295b60736ecSDimitry Andric SmallVector<StringRef, 4> scriptArgs;
296b60736ecSDimitry Andric scriptArgs.push_back(errorHandlingScript);
297b60736ecSDimitry Andric switch (tag) {
298b60736ecSDimitry Andric case ErrorTag::LibNotFound:
299b60736ecSDimitry Andric scriptArgs.push_back("missing-lib");
300b60736ecSDimitry Andric break;
301b60736ecSDimitry Andric case ErrorTag::SymbolNotFound:
302b60736ecSDimitry Andric scriptArgs.push_back("undefined-symbol");
303b60736ecSDimitry Andric break;
304b60736ecSDimitry Andric }
305b60736ecSDimitry Andric scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
306b60736ecSDimitry Andric int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
307b60736ecSDimitry Andric if (res == 0) {
308b60736ecSDimitry Andric return error(msg);
309b60736ecSDimitry Andric } else {
310b60736ecSDimitry Andric // Temporarily disable error limit to make sure the two calls to error(...)
311b60736ecSDimitry Andric // only count as one.
312b60736ecSDimitry Andric uint64_t currentErrorLimit = errorLimit;
313b60736ecSDimitry Andric errorLimit = 0;
314b60736ecSDimitry Andric error(msg);
315b60736ecSDimitry Andric errorLimit = currentErrorLimit;
316b60736ecSDimitry Andric --errorCount;
317b60736ecSDimitry Andric
318b60736ecSDimitry Andric switch (res) {
319b60736ecSDimitry Andric case -1:
320b60736ecSDimitry Andric error("error handling script '" + errorHandlingScript +
321b60736ecSDimitry Andric "' failed to execute");
322b60736ecSDimitry Andric break;
323b60736ecSDimitry Andric case -2:
324b60736ecSDimitry Andric error("error handling script '" + errorHandlingScript +
325b60736ecSDimitry Andric "' crashed or timeout");
326b60736ecSDimitry Andric break;
327b60736ecSDimitry Andric default:
328b60736ecSDimitry Andric error("error handling script '" + errorHandlingScript +
329b60736ecSDimitry Andric "' exited with code " + Twine(res));
330b60736ecSDimitry Andric }
331b60736ecSDimitry Andric }
332b60736ecSDimitry Andric }
333b60736ecSDimitry Andric
fatal(const Twine & msg)334f1e1c239SDimitry Andric void ErrorHandler::fatal(const Twine &msg) {
335f1e1c239SDimitry Andric error(msg);
336d93e1dfaSDimitry Andric exitLld(1);
3375a5c549fSDimitry Andric }
338