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 // Prints "\n" or does nothing, depending on Msg contents of 33 // the previous call of this function. 34 static void newline(raw_ostream *errorOS, const Twine &msg) { 35 // True if the previous error message contained "\n". 36 // We want to separate multi-line error messages with a newline. 37 static bool flag; 38 39 if (flag) 40 *errorOS << "\n"; 41 flag = StringRef(msg.str()).contains('\n'); 42 } 43 44 ErrorHandler &lld::errorHandler() { 45 static ErrorHandler handler; 46 return handler; 47 } 48 49 void lld::exitLld(int val) { 50 // Delete any temporary file, while keeping the memory mapping open. 51 if (errorHandler().outputBuffer) 52 errorHandler().outputBuffer->discard(); 53 54 // Dealloc/destroy ManagedStatic variables before calling 55 // _exit(). In a non-LTO build, this is a nop. In an LTO 56 // build allows us to get the output of -time-passes. 57 llvm_shutdown(); 58 59 outs().flush(); 60 errs().flush(); 61 _exit(val); 62 } 63 64 void lld::diagnosticHandler(const DiagnosticInfo &di) { 65 SmallString<128> s; 66 raw_svector_ostream os(s); 67 DiagnosticPrinterRawOStream dp(os); 68 di.print(dp); 69 switch (di.getSeverity()) { 70 case DS_Error: 71 error(s); 72 break; 73 case DS_Warning: 74 warn(s); 75 break; 76 case DS_Remark: 77 case DS_Note: 78 message(s); 79 break; 80 } 81 } 82 83 void lld::checkError(Error e) { 84 handleAllErrors(std::move(e), 85 [&](ErrorInfoBase &eib) { error(eib.message()); }); 86 } 87 88 // This is for --vs-diagnostics. 89 // 90 // Normally, lld's error message starts with argv[0]. Therefore, it usually 91 // looks like this: 92 // 93 // ld.lld: error: ... 94 // 95 // This error message style is unfortunately unfriendly to Visual Studio 96 // IDE. VS interprets the first word of the first line as an error location 97 // and make it clickable, thus "ld.lld" in the above message would become a 98 // clickable text. When you click it, VS opens "ld.lld" executable file with 99 // a binary editor. 100 // 101 // As a workaround, we print out an error location instead of "ld.lld" if 102 // lld is running in VS diagnostics mode. As a result, error message will 103 // look like this: 104 // 105 // src/foo.c(35): error: ... 106 // 107 // This function returns an error location string. An error location is 108 // extracted from an error message using regexps. 109 static std::string getLocation(std::string msg, std::string defaultMsg) { 110 static std::vector<std::regex> Regexes{ 111 std::regex(R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"), 112 std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), 113 std::regex( 114 R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), 115 std::regex( 116 R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"), 117 std::regex( 118 R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), 119 std::regex(R"((\S+):(\d+): unclosed quote)"), 120 }; 121 122 std::smatch Match; 123 for (std::regex &Re : Regexes) { 124 if (std::regex_search(msg, Match, Re)) { 125 return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")" 126 : Match.str(1); 127 } 128 } 129 return defaultMsg; 130 } 131 132 void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c, 133 const Twine &msg) { 134 135 if (vsDiagnostics) { 136 // A Visual Studio-style error message starts with an error location. 137 // If a location cannot be extracted then we default to LogName. 138 *errorOS << getLocation(msg.str(), logName) << ": "; 139 } else { 140 *errorOS << logName << ": "; 141 } 142 143 if (colorDiagnostics) { 144 errorOS->changeColor(c, true); 145 *errorOS << s; 146 errorOS->resetColor(); 147 } else { 148 *errorOS << s; 149 } 150 } 151 152 void ErrorHandler::log(const Twine &msg) { 153 if (verbose) { 154 std::lock_guard<std::mutex> lock(mu); 155 *errorOS << logName << ": " << msg << "\n"; 156 } 157 } 158 159 void ErrorHandler::message(const Twine &msg) { 160 std::lock_guard<std::mutex> lock(mu); 161 outs() << msg << "\n"; 162 outs().flush(); 163 } 164 165 void ErrorHandler::warn(const Twine &msg) { 166 if (fatalWarnings) { 167 error(msg); 168 return; 169 } 170 171 std::lock_guard<std::mutex> lock(mu); 172 newline(errorOS, msg); 173 printHeader("warning: ", raw_ostream::MAGENTA, msg); 174 *errorOS << msg << "\n"; 175 } 176 177 void ErrorHandler::printErrorMsg(const Twine &msg) { 178 newline(errorOS, msg); 179 printHeader("error: ", raw_ostream::RED, msg); 180 *errorOS << msg << "\n"; 181 } 182 183 void ErrorHandler::printError(const Twine &msg) { 184 if (vsDiagnostics) { 185 static std::regex reDuplicateSymbol( 186 R"(^(duplicate symbol: .*))" 187 R"((\n>>> defined at \S+:\d+\n>>>.*))" 188 R"((\n>>> defined at \S+:\d+\n>>>.*))"); 189 std::string msgStr = msg.str(); 190 std::smatch match; 191 if (std::regex_match(msgStr, match, reDuplicateSymbol)) { 192 printErrorMsg(match.str(1) + match.str(2)); 193 printErrorMsg(match.str(1) + match.str(3)); 194 return; 195 } 196 } 197 printErrorMsg(msg); 198 } 199 200 void ErrorHandler::error(const Twine &msg) { 201 std::lock_guard<std::mutex> lock(mu); 202 203 if (errorLimit == 0 || errorCount < errorLimit) { 204 printError(msg); 205 } else if (errorCount == errorLimit) { 206 newline(errorOS, msg); 207 printHeader("error: ", raw_ostream::RED, msg); 208 *errorOS << errorLimitExceededMsg << "\n"; 209 if (exitEarly) 210 exitLld(1); 211 } 212 213 ++errorCount; 214 } 215 216 void ErrorHandler::fatal(const Twine &msg) { 217 error(msg); 218 exitLld(1); 219 } 220