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
25using namespace llvm;
26using 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.
31static 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 "".
35static StringRef sep;
36
37static StringRef getSeparator(const Twine &msg) {
38  if (StringRef(msg.str()).contains('\n'))
39    return "\n";
40  return "";
41}
42
43raw_ostream *lld::stdoutOS;
44raw_ostream *lld::stderrOS;
45
46raw_ostream &lld::outs() { return stdoutOS ? *stdoutOS : llvm::outs(); }
47raw_ostream &lld::errs() { return stderrOS ? *stderrOS : llvm::errs(); }
48
49ErrorHandler &lld::errorHandler() {
50  static ErrorHandler handler;
51  return handler;
52}
53
54void 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
73void 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
92void 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.
118std::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
155void 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
162void ErrorHandler::message(const Twine &msg) {
163  std::lock_guard<std::mutex> lock(mu);
164  lld::outs() << msg << "\n";
165  lld::outs().flush();
166}
167
168void 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
180void 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
219void ErrorHandler::fatal(const Twine &msg) {
220  error(msg);
221  exitLld(1);
222}
223