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/raw_ostream.h" 20 #include <mutex> 21 #include <regex> 22 23 using namespace llvm; 24 using namespace lld; 25 26 // The functions defined in this file can be called from multiple threads, 27 // but lld::outs() or lld::errs() are not thread-safe. We protect them using a 28 // mutex. 29 static std::mutex mu; 30 31 // We want to separate multi-line messages with a newline. `sep` is "\n" 32 // if the last messages was multi-line. Otherwise "". 33 static StringRef sep; 34 35 static StringRef getSeparator(const Twine &msg) { 36 if (StringRef(msg.str()).contains('\n')) 37 return "\n"; 38 return ""; 39 } 40 41 raw_ostream *lld::stdoutOS; 42 raw_ostream *lld::stderrOS; 43 44 ErrorHandler &lld::errorHandler() { 45 static ErrorHandler handler; 46 return handler; 47 } 48 49 raw_ostream &lld::outs() { 50 if (errorHandler().disableOutput) 51 return llvm::nulls(); 52 return stdoutOS ? *stdoutOS : llvm::outs(); 53 } 54 55 raw_ostream &lld::errs() { 56 if (errorHandler().disableOutput) 57 return llvm::nulls(); 58 return stderrOS ? *stderrOS : llvm::errs(); 59 } 60 61 void lld::exitLld(int val) { 62 // Delete any temporary file, while keeping the memory mapping open. 63 if (errorHandler().outputBuffer) 64 errorHandler().outputBuffer->discard(); 65 66 // Dealloc/destroy ManagedStatic variables before calling _exit(). 67 // In an LTO build, allows us to get the output of -time-passes. 68 // Ensures that the thread pool for the parallel algorithms is stopped to 69 // avoid intermittent crashes on Windows when exiting. 70 if (!CrashRecoveryContext::GetCurrent()) 71 llvm_shutdown(); 72 73 { 74 std::lock_guard<std::mutex> lock(mu); 75 lld::outs().flush(); 76 lld::errs().flush(); 77 } 78 llvm::sys::Process::Exit(val); 79 } 80 81 void lld::diagnosticHandler(const DiagnosticInfo &di) { 82 SmallString<128> s; 83 raw_svector_ostream os(s); 84 DiagnosticPrinterRawOStream dp(os); 85 di.print(dp); 86 switch (di.getSeverity()) { 87 case DS_Error: 88 error(s); 89 break; 90 case DS_Warning: 91 warn(s); 92 break; 93 case DS_Remark: 94 case DS_Note: 95 message(s); 96 break; 97 } 98 } 99 100 void lld::checkError(Error e) { 101 handleAllErrors(std::move(e), 102 [&](ErrorInfoBase &eib) { error(eib.message()); }); 103 } 104 105 // This is for --vs-diagnostics. 106 // 107 // Normally, lld's error message starts with argv[0]. Therefore, it usually 108 // looks like this: 109 // 110 // ld.lld: error: ... 111 // 112 // This error message style is unfortunately unfriendly to Visual Studio 113 // IDE. VS interprets the first word of the first line as an error location 114 // and make it clickable, thus "ld.lld" in the above message would become a 115 // clickable text. When you click it, VS opens "ld.lld" executable file with 116 // a binary editor. 117 // 118 // As a workaround, we print out an error location instead of "ld.lld" if 119 // lld is running in VS diagnostics mode. As a result, error message will 120 // look like this: 121 // 122 // src/foo.c(35): error: ... 123 // 124 // This function returns an error location string. An error location is 125 // extracted from an error message using regexps. 126 std::string ErrorHandler::getLocation(const Twine &msg) { 127 if (!vsDiagnostics) 128 return std::string(logName); 129 130 static std::regex regexes[] = { 131 std::regex( 132 R"(^undefined (?:\S+ )?symbol:.*\n)" 133 R"(>>> referenced by .+\((\S+):(\d+)\))"), 134 std::regex( 135 R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"), 136 std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), 137 std::regex( 138 R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), 139 std::regex( 140 R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"), 141 std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"), 142 std::regex( 143 R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"), 144 std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), 145 std::regex(R"((\S+):(\d+): unclosed quote)"), 146 }; 147 148 std::string str = msg.str(); 149 for (std::regex &re : regexes) { 150 std::smatch m; 151 if (!std::regex_search(str, m, re)) 152 continue; 153 154 assert(m.size() == 2 || m.size() == 3); 155 if (m.size() == 2) 156 return m.str(1); 157 return m.str(1) + "(" + m.str(2) + ")"; 158 } 159 160 return std::string(logName); 161 } 162 163 void ErrorHandler::log(const Twine &msg) { 164 if (!verbose || disableOutput) 165 return; 166 std::lock_guard<std::mutex> lock(mu); 167 lld::errs() << logName << ": " << msg << "\n"; 168 } 169 170 void ErrorHandler::message(const Twine &msg) { 171 if (disableOutput) 172 return; 173 std::lock_guard<std::mutex> lock(mu); 174 lld::outs() << msg << "\n"; 175 lld::outs().flush(); 176 } 177 178 void ErrorHandler::warn(const Twine &msg) { 179 if (fatalWarnings) { 180 error(msg); 181 return; 182 } 183 184 std::lock_guard<std::mutex> lock(mu); 185 lld::errs() << sep << getLocation(msg) << ": " << Colors::MAGENTA 186 << "warning: " << Colors::RESET << msg << "\n"; 187 sep = getSeparator(msg); 188 } 189 190 void ErrorHandler::error(const Twine &msg) { 191 // If Visual Studio-style error message mode is enabled, 192 // this particular error is printed out as two errors. 193 if (vsDiagnostics) { 194 static std::regex re(R"(^(duplicate symbol: .*))" 195 R"((\n>>> defined at \S+:\d+.*\n>>>.*))" 196 R"((\n>>> defined at \S+:\d+.*\n>>>.*))"); 197 std::string str = msg.str(); 198 std::smatch m; 199 200 if (std::regex_match(str, m, re)) { 201 error(m.str(1) + m.str(2)); 202 error(m.str(1) + m.str(3)); 203 return; 204 } 205 } 206 207 bool exit = false; 208 { 209 std::lock_guard<std::mutex> lock(mu); 210 211 if (errorLimit == 0 || errorCount < errorLimit) { 212 lld::errs() << sep << getLocation(msg) << ": " << Colors::RED 213 << "error: " << Colors::RESET << msg << "\n"; 214 } else if (errorCount == errorLimit) { 215 lld::errs() << sep << getLocation(msg) << ": " << Colors::RED 216 << "error: " << Colors::RESET << errorLimitExceededMsg 217 << "\n"; 218 exit = exitEarly; 219 } 220 221 sep = getSeparator(msg); 222 ++errorCount; 223 } 224 225 if (exit) 226 exitLld(1); 227 } 228 229 void ErrorHandler::fatal(const Twine &msg) { 230 error(msg); 231 exitLld(1); 232 } 233