3c3609e00743471bb298fae90b3c20e46a082ef4
[lldb.git] / lld / Common / ErrorHandler.cpp
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 "llvm/ADT/Twine.h"
14 #include "llvm/IR/DiagnosticInfo.h"
15 #include "llvm/IR/DiagnosticPrinter.h"
16 #include "llvm/Support/CrashRecoveryContext.h"
17 #include "llvm/Support/ManagedStatic.h"
18 #include "llvm/Support/Process.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include <mutex>
21 #include <regex>
22
23 using namespace llvm;
24 using namespace lld;
25
26 // The functions defined in this file can be called from multiple threads,
27 // but lld::outs() or lld::errs() are not thread-safe. We protect them using a
28 // mutex.
29 static std::mutex mu;
30
31 // We want to separate multi-line messages with a newline. `sep` is "\n"
32 // if the last messages was multi-line. Otherwise "".
33 static StringRef sep;
34
35 static StringRef getSeparator(const Twine &msg) {
36   if (StringRef(msg.str()).contains('\n'))
37     return "\n";
38   return "";
39 }
40
41 raw_ostream *lld::stdoutOS;
42 raw_ostream *lld::stderrOS;
43
44 ErrorHandler &lld::errorHandler() {
45   static ErrorHandler handler;
46   return handler;
47 }
48
49 raw_ostream &lld::outs() {
50   if (errorHandler().disableOutput)
51     return llvm::nulls();
52   return stdoutOS ? *stdoutOS : llvm::outs();
53 }
54
55 raw_ostream &lld::errs() {
56   if (errorHandler().disableOutput)
57     return llvm::nulls();
58   return stderrOS ? *stderrOS : llvm::errs();
59 }
60
61 void lld::exitLld(int val) {
62   // Delete any temporary file, while keeping the memory mapping open.
63   if (errorHandler().outputBuffer)
64     errorHandler().outputBuffer->discard();
65
66   // Dealloc/destroy ManagedStatic variables before calling _exit().
67   // In an LTO build, allows us to get the output of -time-passes.
68   // Ensures that the thread pool for the parallel algorithms is stopped to
69   // avoid intermittent crashes on Windows when exiting.
70   if (!CrashRecoveryContext::GetCurrent())
71     llvm_shutdown();
72
73   {
74     std::lock_guard<std::mutex> lock(mu);
75     lld::outs().flush();
76     lld::errs().flush();
77   }
78   llvm::sys::Process::Exit(val);
79 }
80
81 void lld::diagnosticHandler(const DiagnosticInfo &di) {
82   SmallString<128> s;
83   raw_svector_ostream os(s);
84   DiagnosticPrinterRawOStream dp(os);
85   di.print(dp);
86   switch (di.getSeverity()) {
87   case DS_Error:
88     error(s);
89     break;
90   case DS_Warning:
91     warn(s);
92     break;
93   case DS_Remark:
94   case DS_Note:
95     message(s);
96     break;
97   }
98 }
99
100 void lld::checkError(Error e) {
101   handleAllErrors(std::move(e),
102                   [&](ErrorInfoBase &eib) { error(eib.message()); });
103 }
104
105 // This is for --vs-diagnostics.
106 //
107 // Normally, lld's error message starts with argv[0]. Therefore, it usually
108 // looks like this:
109 //
110 //   ld.lld: error: ...
111 //
112 // This error message style is unfortunately unfriendly to Visual Studio
113 // IDE. VS interprets the first word of the first line as an error location
114 // and make it clickable, thus "ld.lld" in the above message would become a
115 // clickable text. When you click it, VS opens "ld.lld" executable file with
116 // a binary editor.
117 //
118 // As a workaround, we print out an error location instead of "ld.lld" if
119 // lld is running in VS diagnostics mode. As a result, error message will
120 // look like this:
121 //
122 //   src/foo.c(35): error: ...
123 //
124 // This function returns an error location string. An error location is
125 // extracted from an error message using regexps.
126 std::string ErrorHandler::getLocation(const Twine &msg) {
127   if (!vsDiagnostics)
128     return std::string(logName);
129
130   static std::regex regexes[] = {
131       std::regex(
132           R"(^undefined (?:\S+ )?symbol:.*\n)"
133           R"(>>> referenced by .+\((\S+):(\d+)\))"),
134       std::regex(
135           R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
136       std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
137       std::regex(
138           R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
139       std::regex(
140           R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
141       std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
142       std::regex(
143           R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
144       std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
145       std::regex(R"((\S+):(\d+): unclosed quote)"),
146   };
147
148   std::string str = msg.str();
149   for (std::regex &re : regexes) {
150     std::smatch m;
151     if (!std::regex_search(str, m, re))
152       continue;
153
154     assert(m.size() == 2 || m.size() == 3);
155     if (m.size() == 2)
156       return m.str(1);
157     return m.str(1) + "(" + m.str(2) + ")";
158   }
159
160   return std::string(logName);
161 }
162
163 void ErrorHandler::log(const Twine &msg) {
164   if (!verbose || disableOutput)
165     return;
166   std::lock_guard<std::mutex> lock(mu);
167   lld::errs() << logName << ": " << msg << "\n";
168 }
169
170 void ErrorHandler::message(const Twine &msg) {
171   if (disableOutput)
172     return;
173   std::lock_guard<std::mutex> lock(mu);
174   lld::outs() << msg << "\n";
175   lld::outs().flush();
176 }
177
178 void ErrorHandler::warn(const Twine &msg) {
179   if (fatalWarnings) {
180     error(msg);
181     return;
182   }
183
184   std::lock_guard<std::mutex> lock(mu);
185   lld::errs() << sep << getLocation(msg) << ": " << Colors::MAGENTA
186               << "warning: " << Colors::RESET << msg << "\n";
187   sep = getSeparator(msg);
188 }
189
190 void ErrorHandler::error(const Twine &msg) {
191   // If Visual Studio-style error message mode is enabled,
192   // this particular error is printed out as two errors.
193   if (vsDiagnostics) {
194     static std::regex re(R"(^(duplicate symbol: .*))"
195                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
196                          R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
197     std::string str = msg.str();
198     std::smatch m;
199
200     if (std::regex_match(str, m, re)) {
201       error(m.str(1) + m.str(2));
202       error(m.str(1) + m.str(3));
203       return;
204     }
205   }
206
207   bool exit = false;
208   {
209     std::lock_guard<std::mutex> lock(mu);
210
211     if (errorLimit == 0 || errorCount < errorLimit) {
212       lld::errs() << sep << getLocation(msg) << ": " << Colors::RED
213                   << "error: " << Colors::RESET << msg << "\n";
214     } else if (errorCount == errorLimit) {
215       lld::errs() << sep << getLocation(msg) << ": " << Colors::RED
216                   << "error: " << Colors::RESET << errorLimitExceededMsg
217                   << "\n";
218       exit = exitEarly;
219     }
220
221     sep = getSeparator(msg);
222     ++errorCount;
223   }
224
225   if (exit)
226     exitLld(1);
227 }
228
229 void ErrorHandler::fatal(const Twine &msg) {
230   error(msg);
231   exitLld(1);
232 }