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/CrashRecoveryContext.h" 17 #include "llvm/Support/ManagedStatic.h" 18 #include "llvm/Support/Process.h" 19 #include "llvm/Support/Program.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <mutex> 22 #include <regex> 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 lld::outs() or lld::errs() are not thread-safe. We protect them using a 29 // 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 raw_ostream *lld::stdoutOS; 43 raw_ostream *lld::stderrOS; 44 45 ErrorHandler &lld::errorHandler() { 46 static ErrorHandler handler; 47 return handler; 48 } 49 50 raw_ostream &lld::outs() { 51 if (errorHandler().disableOutput) 52 return llvm::nulls(); 53 return stdoutOS ? *stdoutOS : llvm::outs(); 54 } 55 56 raw_ostream &lld::errs() { 57 if (errorHandler().disableOutput) 58 return llvm::nulls(); 59 return stderrOS ? *stderrOS : llvm::errs(); 60 } 61 62 void lld::exitLld(int val) { 63 // Delete any temporary file, while keeping the memory mapping open. 64 if (errorHandler().outputBuffer) 65 errorHandler().outputBuffer->discard(); 66 67 // Re-throw a possible signal or exception once/if it was catched by 68 // safeLldMain(). 69 CrashRecoveryContext::throwIfCrash(val); 70 71 // Dealloc/destroy ManagedStatic variables before calling _exit(). 72 // In an LTO build, allows us to get the output of -time-passes. 73 // Ensures that the thread pool for the parallel algorithms is stopped to 74 // avoid intermittent crashes on Windows when exiting. 75 if (!CrashRecoveryContext::GetCurrent()) 76 llvm_shutdown(); 77 78 { 79 std::lock_guard<std::mutex> lock(mu); 80 lld::outs().flush(); 81 lld::errs().flush(); 82 } 83 // When running inside safeLldMain(), restore the control flow back to the 84 // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup, 85 // since we want to avoid further crashes on shutdown. 86 llvm::sys::Process::Exit(val, /*NoCleanup=*/true); 87 } 88 89 void lld::diagnosticHandler(const DiagnosticInfo &di) { 90 SmallString<128> s; 91 raw_svector_ostream os(s); 92 DiagnosticPrinterRawOStream dp(os); 93 di.print(dp); 94 switch (di.getSeverity()) { 95 case DS_Error: 96 error(s); 97 break; 98 case DS_Warning: 99 warn(s); 100 break; 101 case DS_Remark: 102 case DS_Note: 103 message(s); 104 break; 105 } 106 } 107 108 void lld::checkError(Error e) { 109 handleAllErrors(std::move(e), 110 [&](ErrorInfoBase &eib) { error(eib.message()); }); 111 } 112 113 // This is for --vs-diagnostics. 114 // 115 // Normally, lld's error message starts with argv[0]. Therefore, it usually 116 // looks like this: 117 // 118 // ld.lld: error: ... 119 // 120 // This error message style is unfortunately unfriendly to Visual Studio 121 // IDE. VS interprets the first word of the first line as an error location 122 // and make it clickable, thus "ld.lld" in the above message would become a 123 // clickable text. When you click it, VS opens "ld.lld" executable file with 124 // a binary editor. 125 // 126 // As a workaround, we print out an error location instead of "ld.lld" if 127 // lld is running in VS diagnostics mode. As a result, error message will 128 // look like this: 129 // 130 // src/foo.c(35): error: ... 131 // 132 // This function returns an error location string. An error location is 133 // extracted from an error message using regexps. 134 std::string ErrorHandler::getLocation(const Twine &msg) { 135 if (!vsDiagnostics) 136 return std::string(logName); 137 138 static std::regex regexes[] = { 139 std::regex( 140 R"(^undefined (?:\S+ )?symbol:.*\n)" 141 R"(>>> referenced by .+\((\S+):(\d+)\))"), 142 std::regex( 143 R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"), 144 std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), 145 std::regex( 146 R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), 147 std::regex( 148 R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"), 149 std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"), 150 std::regex( 151 R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"), 152 std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), 153 std::regex(R"((\S+):(\d+): unclosed quote)"), 154 }; 155 156 std::string str = msg.str(); 157 for (std::regex &re : regexes) { 158 std::smatch m; 159 if (!std::regex_search(str, m, re)) 160 continue; 161 162 assert(m.size() == 2 || m.size() == 3); 163 if (m.size() == 2) 164 return m.str(1); 165 return m.str(1) + "(" + m.str(2) + ")"; 166 } 167 168 return std::string(logName); 169 } 170 171 void ErrorHandler::reportDiagnostic(StringRef location, Colors c, 172 StringRef diagKind, const Twine &msg) { 173 SmallString<256> buf; 174 raw_svector_ostream os(buf); 175 os << sep << location << ": "; 176 if (!diagKind.empty()) { 177 if (lld::errs().colors_enabled()) { 178 os.enable_colors(true); 179 os << c << diagKind << ": " << Colors::RESET; 180 } else { 181 os << diagKind << ": "; 182 } 183 } 184 os << msg << '\n'; 185 lld::errs() << buf; 186 } 187 188 void ErrorHandler::log(const Twine &msg) { 189 if (!verbose || disableOutput) 190 return; 191 std::lock_guard<std::mutex> lock(mu); 192 reportDiagnostic(logName, Colors::RESET, "", msg); 193 } 194 195 void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) { 196 if (disableOutput) 197 return; 198 std::lock_guard<std::mutex> lock(mu); 199 s << msg << "\n"; 200 s.flush(); 201 } 202 203 void ErrorHandler::warn(const Twine &msg) { 204 if (fatalWarnings) { 205 error(msg); 206 return; 207 } 208 209 std::lock_guard<std::mutex> lock(mu); 210 reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg); 211 sep = getSeparator(msg); 212 } 213 214 void ErrorHandler::error(const Twine &msg) { 215 // If Visual Studio-style error message mode is enabled, 216 // this particular error is printed out as two errors. 217 if (vsDiagnostics) { 218 static std::regex re(R"(^(duplicate symbol: .*))" 219 R"((\n>>> defined at \S+:\d+.*\n>>>.*))" 220 R"((\n>>> defined at \S+:\d+.*\n>>>.*))"); 221 std::string str = msg.str(); 222 std::smatch m; 223 224 if (std::regex_match(str, m, re)) { 225 error(m.str(1) + m.str(2)); 226 error(m.str(1) + m.str(3)); 227 return; 228 } 229 } 230 231 bool exit = false; 232 { 233 std::lock_guard<std::mutex> lock(mu); 234 235 if (errorLimit == 0 || errorCount < errorLimit) { 236 reportDiagnostic(getLocation(msg), Colors::RED, "error", msg); 237 } else if (errorCount == errorLimit) { 238 reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg); 239 exit = exitEarly; 240 } 241 242 sep = getSeparator(msg); 243 ++errorCount; 244 } 245 246 if (exit) 247 exitLld(1); 248 } 249 250 void ErrorHandler::error(const Twine &msg, ErrorTag tag, 251 ArrayRef<StringRef> args) { 252 if (errorHandlingScript.empty()) { 253 error(msg); 254 return; 255 } 256 SmallVector<StringRef, 4> scriptArgs; 257 scriptArgs.push_back(errorHandlingScript); 258 switch (tag) { 259 case ErrorTag::LibNotFound: 260 scriptArgs.push_back("missing-lib"); 261 break; 262 case ErrorTag::SymbolNotFound: 263 scriptArgs.push_back("undefined-symbol"); 264 break; 265 } 266 scriptArgs.insert(scriptArgs.end(), args.begin(), args.end()); 267 int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs); 268 if (res == 0) { 269 return error(msg); 270 } else { 271 // Temporarily disable error limit to make sure the two calls to error(...) 272 // only count as one. 273 uint64_t currentErrorLimit = errorLimit; 274 errorLimit = 0; 275 error(msg); 276 errorLimit = currentErrorLimit; 277 --errorCount; 278 279 switch (res) { 280 case -1: 281 error("error handling script '" + errorHandlingScript + 282 "' failed to execute"); 283 break; 284 case -2: 285 error("error handling script '" + errorHandlingScript + 286 "' crashed or timeout"); 287 break; 288 default: 289 error("error handling script '" + errorHandlingScript + 290 "' exited with code " + Twine(res)); 291 } 292 } 293 } 294 295 void ErrorHandler::fatal(const Twine &msg) { 296 error(msg); 297 exitLld(1); 298 } 299