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