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