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