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