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 
20 #if !defined(_MSC_VER) && !defined(__MINGW32__)
21 #include <unistd.h>
22 #endif
23 
24 using namespace llvm;
25 using namespace lld;
26 
27 // The functions defined in this file can be called from multiple threads,
28 // but outs() or errs() are not thread-safe. We protect them using a mutex.
29 static std::mutex mu;
30 
31 // Prints "\n" or does nothing, depending on Msg contents of
32 // the previous call of this function.
33 static void newline(raw_ostream *errorOS, const Twine &msg) {
34   // True if the previous error message contained "\n".
35   // We want to separate multi-line error messages with a newline.
36   static bool flag;
37 
38   if (flag)
39     *errorOS << "\n";
40   flag = StringRef(msg.str()).contains('\n');
41 }
42 
43 ErrorHandler &lld::errorHandler() {
44   static ErrorHandler handler;
45   return handler;
46 }
47 
48 void lld::exitLld(int val) {
49   // Delete any temporary file, while keeping the memory mapping open.
50   if (errorHandler().outputBuffer)
51     errorHandler().outputBuffer->discard();
52 
53   // Dealloc/destroy ManagedStatic variables before calling
54   // _exit(). In a non-LTO build, this is a nop. In an LTO
55   // build allows us to get the output of -time-passes.
56   llvm_shutdown();
57 
58   outs().flush();
59   errs().flush();
60   _exit(val);
61 }
62 
63 void lld::diagnosticHandler(const DiagnosticInfo &di) {
64   SmallString<128> s;
65   raw_svector_ostream os(s);
66   DiagnosticPrinterRawOStream dp(os);
67   di.print(dp);
68   switch (di.getSeverity()) {
69   case DS_Error:
70     error(s);
71     break;
72   case DS_Warning:
73     warn(s);
74     break;
75   case DS_Remark:
76   case DS_Note:
77     message(s);
78     break;
79   }
80 }
81 
82 void lld::checkError(Error e) {
83   handleAllErrors(std::move(e),
84                   [&](ErrorInfoBase &eib) { error(eib.message()); });
85 }
86 
87 void ErrorHandler::print(StringRef s, raw_ostream::Colors c) {
88   *errorOS << logName << ": ";
89   if (colorDiagnostics) {
90     errorOS->changeColor(c, true);
91     *errorOS << s;
92     errorOS->resetColor();
93   } else {
94     *errorOS << s;
95   }
96 }
97 
98 void ErrorHandler::log(const Twine &msg) {
99   if (verbose) {
100     std::lock_guard<std::mutex> lock(mu);
101     *errorOS << logName << ": " << msg << "\n";
102   }
103 }
104 
105 void ErrorHandler::message(const Twine &msg) {
106   std::lock_guard<std::mutex> lock(mu);
107   outs() << msg << "\n";
108   outs().flush();
109 }
110 
111 void ErrorHandler::warn(const Twine &msg) {
112   if (fatalWarnings) {
113     error(msg);
114     return;
115   }
116 
117   std::lock_guard<std::mutex> lock(mu);
118   newline(errorOS, msg);
119   print("warning: ", raw_ostream::MAGENTA);
120   *errorOS << msg << "\n";
121 }
122 
123 void ErrorHandler::error(const Twine &msg) {
124   std::lock_guard<std::mutex> lock(mu);
125   newline(errorOS, msg);
126 
127   if (errorLimit == 0 || errorCount < errorLimit) {
128     print("error: ", raw_ostream::RED);
129     *errorOS << msg << "\n";
130   } else if (errorCount == errorLimit) {
131     print("error: ", raw_ostream::RED);
132     *errorOS << errorLimitExceededMsg << "\n";
133     if (exitEarly)
134       exitLld(1);
135   }
136 
137   ++errorCount;
138 }
139 
140 void ErrorHandler::fatal(const Twine &msg) {
141   error(msg);
142   exitLld(1);
143 }
144