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