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