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