1 //===- ErrorHandler.cpp ---------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lld/Common/ErrorHandler.h"
10 
11 #include "llvm/Support/Parallel.h"
12 
13 #include "lld/Common/CommonLinkerContext.h"
14 #include "llvm/ADT/Twine.h"
15 #include "llvm/IR/DiagnosticInfo.h"
16 #include "llvm/IR/DiagnosticPrinter.h"
17 #include "llvm/Support/CrashRecoveryContext.h"
18 #include "llvm/Support/ManagedStatic.h"
19 #include "llvm/Support/Process.h"
20 #include "llvm/Support/Program.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include <regex>
23 
24 using namespace llvm;
25 using namespace lld;
26 
27 static StringRef getSeparator(const Twine &msg) {
28   if (StringRef(msg.str()).contains('\n'))
29     return "\n";
30   return "";
31 }
32 
33 ErrorHandler::~ErrorHandler() {
34   if (cleanupCallback)
35     cleanupCallback();
36 }
37 
38 void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS,
39                               llvm::raw_ostream &stderrOS, bool exitEarly,
40                               bool disableOutput) {
41   this->stdoutOS = &stdoutOS;
42   this->stderrOS = &stderrOS;
43   stderrOS.enable_colors(stderrOS.has_colors());
44   this->exitEarly = exitEarly;
45   this->disableOutput = disableOutput;
46 }
47 
48 void ErrorHandler::flushStreams() {
49   std::lock_guard<std::mutex> lock(mu);
50   outs().flush();
51   errs().flush();
52 }
53 
54 ErrorHandler &lld::errorHandler() { return context().e; }
55 
56 raw_ostream &lld::outs() {
57   ErrorHandler &e = errorHandler();
58   return e.outs();
59 }
60 
61 raw_ostream &lld::errs() {
62   ErrorHandler &e = errorHandler();
63   return e.errs();
64 }
65 
66 raw_ostream &ErrorHandler::outs() {
67   if (disableOutput)
68     return llvm::nulls();
69   return stdoutOS ? *stdoutOS : llvm::outs();
70 }
71 
72 raw_ostream &ErrorHandler::errs() {
73   if (disableOutput)
74     return llvm::nulls();
75   return stderrOS ? *stderrOS : llvm::errs();
76 }
77 
78 void lld::exitLld(int val) {
79   if (hasContext()) {
80     ErrorHandler &e = errorHandler();
81     // Delete any temporary file, while keeping the memory mapping open.
82     if (e.outputBuffer)
83       e.outputBuffer->discard();
84   }
85 
86   // Re-throw a possible signal or exception once/if it was catched by
87   // safeLldMain().
88   CrashRecoveryContext::throwIfCrash(val);
89 
90   // Dealloc/destroy ManagedStatic variables before calling _exit().
91   // In an LTO build, allows us to get the output of -time-passes.
92   // Ensures that the thread pool for the parallel algorithms is stopped to
93   // avoid intermittent crashes on Windows when exiting.
94   if (!CrashRecoveryContext::GetCurrent())
95     llvm_shutdown();
96 
97   if (hasContext())
98     lld::errorHandler().flushStreams();
99 
100   // When running inside safeLldMain(), restore the control flow back to the
101   // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
102   // since we want to avoid further crashes on shutdown.
103   llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
104 }
105 
106 void lld::diagnosticHandler(const DiagnosticInfo &di) {
107   SmallString<128> s;
108   raw_svector_ostream os(s);
109   DiagnosticPrinterRawOStream dp(os);
110   di.print(dp);
111   switch (di.getSeverity()) {
112   case DS_Error:
113     error(s);
114     break;
115   case DS_Warning:
116     warn(s);
117     break;
118   case DS_Remark:
119   case DS_Note:
120     message(s);
121     break;
122   }
123 }
124 
125 void lld::checkError(Error e) {
126   handleAllErrors(std::move(e),
127                   [&](ErrorInfoBase &eib) { error(eib.message()); });
128 }
129 
130 // This is for --vs-diagnostics.
131 //
132 // Normally, lld's error message starts with argv[0]. Therefore, it usually
133 // looks like this:
134 //
135 //   ld.lld: error: ...
136 //
137 // This error message style is unfortunately unfriendly to Visual Studio
138 // IDE. VS interprets the first word of the first line as an error location
139 // and make it clickable, thus "ld.lld" in the above message would become a
140 // clickable text. When you click it, VS opens "ld.lld" executable file with
141 // a binary editor.
142 //
143 // As a workaround, we print out an error location instead of "ld.lld" if
144 // lld is running in VS diagnostics mode. As a result, error message will
145 // look like this:
146 //
147 //   src/foo.c(35): error: ...
148 //
149 // This function returns an error location string. An error location is
150 // extracted from an error message using regexps.
151 std::string ErrorHandler::getLocation(const Twine &msg) {
152   if (!vsDiagnostics)
153     return std::string(logName);
154 
155   static std::regex regexes[] = {
156       std::regex(
157           R"(^undefined (?:\S+ )?symbol:.*\n)"
158           R"(>>> referenced by .+\((\S+):(\d+)\))"),
159       std::regex(
160           R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
161       std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
162       std::regex(
163           R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
164       std::regex(
165           R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
166       std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
167       std::regex(
168           R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
169       std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
170       std::regex(R"((\S+):(\d+): unclosed quote)"),
171   };
172 
173   std::string str = msg.str();
174   for (std::regex &re : regexes) {
175     std::smatch m;
176     if (!std::regex_search(str, m, re))
177       continue;
178 
179     assert(m.size() == 2 || m.size() == 3);
180     if (m.size() == 2)
181       return m.str(1);
182     return m.str(1) + "(" + m.str(2) + ")";
183   }
184 
185   return std::string(logName);
186 }
187 
188 void ErrorHandler::reportDiagnostic(StringRef location, Colors c,
189                                     StringRef diagKind, const Twine &msg) {
190   SmallString<256> buf;
191   raw_svector_ostream os(buf);
192   os << sep << location << ": ";
193   if (!diagKind.empty()) {
194     if (lld::errs().colors_enabled()) {
195       os.enable_colors(true);
196       os << c << diagKind << ": " << Colors::RESET;
197     } else {
198       os << diagKind << ": ";
199     }
200   }
201   os << msg << '\n';
202   lld::errs() << buf;
203 }
204 
205 void ErrorHandler::log(const Twine &msg) {
206   if (!verbose || disableOutput)
207     return;
208   std::lock_guard<std::mutex> lock(mu);
209   reportDiagnostic(logName, Colors::RESET, "", msg);
210 }
211 
212 void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
213   if (disableOutput)
214     return;
215   std::lock_guard<std::mutex> lock(mu);
216   s << msg << "\n";
217   s.flush();
218 }
219 
220 void ErrorHandler::warn(const Twine &msg) {
221   if (fatalWarnings) {
222     error(msg);
223     return;
224   }
225 
226   std::lock_guard<std::mutex> lock(mu);
227   reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
228   sep = getSeparator(msg);
229 }
230 
231 void ErrorHandler::error(const Twine &msg) {
232   // If Visual Studio-style error message mode is enabled,
233   // this particular error is printed out as two errors.
234   if (vsDiagnostics) {
235     static std::regex re(R"(^(duplicate symbol: .*))"
236                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
237                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
238     std::string str = msg.str();
239     std::smatch m;
240 
241     if (std::regex_match(str, m, re)) {
242       error(m.str(1) + m.str(2));
243       error(m.str(1) + m.str(3));
244       return;
245     }
246   }
247 
248   bool exit = false;
249   {
250     std::lock_guard<std::mutex> lock(mu);
251 
252     if (errorLimit == 0 || errorCount < errorLimit) {
253       reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
254     } else if (errorCount == errorLimit) {
255       reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
256       exit = exitEarly;
257     }
258 
259     sep = getSeparator(msg);
260     ++errorCount;
261   }
262 
263   if (exit)
264     exitLld(1);
265 }
266 
267 void ErrorHandler::error(const Twine &msg, ErrorTag tag,
268                          ArrayRef<StringRef> args) {
269   if (errorHandlingScript.empty()) {
270     error(msg);
271     return;
272   }
273   SmallVector<StringRef, 4> scriptArgs;
274   scriptArgs.push_back(errorHandlingScript);
275   switch (tag) {
276   case ErrorTag::LibNotFound:
277     scriptArgs.push_back("missing-lib");
278     break;
279   case ErrorTag::SymbolNotFound:
280     scriptArgs.push_back("undefined-symbol");
281     break;
282   }
283   scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
284   int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
285   if (res == 0) {
286     return error(msg);
287   } else {
288     // Temporarily disable error limit to make sure the two calls to error(...)
289     // only count as one.
290     uint64_t currentErrorLimit = errorLimit;
291     errorLimit = 0;
292     error(msg);
293     errorLimit = currentErrorLimit;
294     --errorCount;
295 
296     switch (res) {
297     case -1:
298       error("error handling script '" + errorHandlingScript +
299             "' failed to execute");
300       break;
301     case -2:
302       error("error handling script '" + errorHandlingScript +
303             "' crashed or timeout");
304       break;
305     default:
306       error("error handling script '" + errorHandlingScript +
307             "' exited with code " + Twine(res));
308     }
309   }
310 }
311 
312 void ErrorHandler::fatal(const Twine &msg) {
313   error(msg);
314   exitLld(1);
315 }
316