1b8a59c8aSBob Haarman //===- ErrorHandler.cpp ---------------------------------------------------===// 2b8a59c8aSBob Haarman // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b8a59c8aSBob Haarman // 7b8a59c8aSBob Haarman //===----------------------------------------------------------------------===// 8b8a59c8aSBob Haarman 9b8a59c8aSBob Haarman #include "lld/Common/ErrorHandler.h" 10b8a59c8aSBob Haarman 11932f0276SReid Kleckner #include "llvm/Support/Parallel.h" 12b8a59c8aSBob Haarman 1383d59e05SAlexandre Ganea #include "lld/Common/CommonLinkerContext.h" 14b8a59c8aSBob Haarman #include "llvm/ADT/Twine.h" 153ad27e92SSam Clegg #include "llvm/IR/DiagnosticInfo.h" 163ad27e92SSam Clegg #include "llvm/IR/DiagnosticPrinter.h" 17f2efb574SAlexandre Ganea #include "llvm/Support/CrashRecoveryContext.h" 18b8a59c8aSBob Haarman #include "llvm/Support/ManagedStatic.h" 19f2efb574SAlexandre Ganea #include "llvm/Support/Process.h" 20cfc32267Sserge-sans-paille #include "llvm/Support/Program.h" 21b8a59c8aSBob Haarman #include "llvm/Support/raw_ostream.h" 2287886299SChris Jackson #include <regex> 23b8a59c8aSBob Haarman 24b8a59c8aSBob Haarman using namespace llvm; 25b8a59c8aSBob Haarman using namespace lld; 26b8a59c8aSBob Haarman 276c5fc940SRui Ueyama static StringRef getSeparator(const Twine &msg) { 286c5fc940SRui Ueyama if (StringRef(msg.str()).contains('\n')) 296c5fc940SRui Ueyama return "\n"; 306c5fc940SRui Ueyama return ""; 31b8a59c8aSBob Haarman } 32b8a59c8aSBob Haarman 3383d59e05SAlexandre Ganea ErrorHandler::~ErrorHandler() { 3483d59e05SAlexandre Ganea if (cleanupCallback) 3583d59e05SAlexandre Ganea cleanupCallback(); 36f860fe36SAlexandre Ganea } 37f860fe36SAlexandre Ganea 3883d59e05SAlexandre Ganea void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS, 3983d59e05SAlexandre Ganea llvm::raw_ostream &stderrOS, bool exitEarly, 4083d59e05SAlexandre Ganea bool disableOutput) { 4183d59e05SAlexandre Ganea this->stdoutOS = &stdoutOS; 4283d59e05SAlexandre Ganea this->stderrOS = &stderrOS; 4383d59e05SAlexandre Ganea stderrOS.enable_colors(stderrOS.has_colors()); 4483d59e05SAlexandre Ganea this->exitEarly = exitEarly; 4583d59e05SAlexandre Ganea this->disableOutput = disableOutput; 4683d59e05SAlexandre Ganea } 4783d59e05SAlexandre Ganea 4883d59e05SAlexandre Ganea void ErrorHandler::flushStreams() { 4983d59e05SAlexandre Ganea std::lock_guard<std::mutex> lock(mu); 5083d59e05SAlexandre Ganea outs().flush(); 5183d59e05SAlexandre Ganea errs().flush(); 5283d59e05SAlexandre Ganea } 5383d59e05SAlexandre Ganea 5483d59e05SAlexandre Ganea ErrorHandler &lld::errorHandler() { return context().e; } 5583d59e05SAlexandre Ganea 56941f0628SFangrui Song void lld::error(const Twine &msg) { errorHandler().error(msg); } 57941f0628SFangrui Song void lld::error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) { 58941f0628SFangrui Song errorHandler().error(msg, tag, args); 59941f0628SFangrui Song } 60941f0628SFangrui Song void lld::fatal(const Twine &msg) { errorHandler().fatal(msg); } 61941f0628SFangrui Song void lld::log(const Twine &msg) { errorHandler().log(msg); } 62941f0628SFangrui Song void lld::message(const Twine &msg, llvm::raw_ostream &s) { 63941f0628SFangrui Song errorHandler().message(msg, s); 64941f0628SFangrui Song } 65941f0628SFangrui Song void lld::warn(const Twine &msg) { errorHandler().warn(msg); } 66941f0628SFangrui Song uint64_t lld::errorCount() { return errorHandler().errorCount; } 67941f0628SFangrui Song 68f2efb574SAlexandre Ganea raw_ostream &lld::outs() { 6983d59e05SAlexandre Ganea ErrorHandler &e = errorHandler(); 7083d59e05SAlexandre Ganea return e.outs(); 7183d59e05SAlexandre Ganea } 7283d59e05SAlexandre Ganea 7383d59e05SAlexandre Ganea raw_ostream &ErrorHandler::outs() { 7483d59e05SAlexandre Ganea if (disableOutput) 75f2efb574SAlexandre Ganea return llvm::nulls(); 76f2efb574SAlexandre Ganea return stdoutOS ? *stdoutOS : llvm::outs(); 77f2efb574SAlexandre Ganea } 78f2efb574SAlexandre Ganea 7983d59e05SAlexandre Ganea raw_ostream &ErrorHandler::errs() { 8083d59e05SAlexandre Ganea if (disableOutput) 81f2efb574SAlexandre Ganea return llvm::nulls(); 82f2efb574SAlexandre Ganea return stderrOS ? *stderrOS : llvm::errs(); 83f2efb574SAlexandre Ganea } 84f2efb574SAlexandre Ganea 85136d27abSRui Ueyama void lld::exitLld(int val) { 8683d59e05SAlexandre Ganea if (hasContext()) { 8783d59e05SAlexandre Ganea ErrorHandler &e = errorHandler(); 880f3d8e23SMartin Storsjo // Delete any temporary file, while keeping the memory mapping open. 8983d59e05SAlexandre Ganea if (e.outputBuffer) 9083d59e05SAlexandre Ganea e.outputBuffer->discard(); 9183d59e05SAlexandre Ganea } 92a4884cc3SRafael Espindola 93a2ae9e3aSNico Weber // Re-throw a possible signal or exception once/if it was caught by 9445b8a741SAlexandre Ganea // safeLldMain(). 9545b8a741SAlexandre Ganea CrashRecoveryContext::throwIfCrash(val); 9645b8a741SAlexandre Ganea 97564481aeSAndrew Ng // Dealloc/destroy ManagedStatic variables before calling _exit(). 98564481aeSAndrew Ng // In an LTO build, allows us to get the output of -time-passes. 99564481aeSAndrew Ng // Ensures that the thread pool for the parallel algorithms is stopped to 100564481aeSAndrew Ng // avoid intermittent crashes on Windows when exiting. 101f2efb574SAlexandre Ganea if (!CrashRecoveryContext::GetCurrent()) 102b8a59c8aSBob Haarman llvm_shutdown(); 103b8a59c8aSBob Haarman 10483d59e05SAlexandre Ganea if (hasContext()) 10583d59e05SAlexandre Ganea lld::errorHandler().flushStreams(); 10683d59e05SAlexandre Ganea 10745b8a741SAlexandre Ganea // When running inside safeLldMain(), restore the control flow back to the 10845b8a741SAlexandre Ganea // CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup, 10945b8a741SAlexandre Ganea // since we want to avoid further crashes on shutdown. 11045b8a741SAlexandre Ganea llvm::sys::Process::Exit(val, /*NoCleanup=*/true); 111b8a59c8aSBob Haarman } 112b8a59c8aSBob Haarman 113136d27abSRui Ueyama void lld::diagnosticHandler(const DiagnosticInfo &di) { 114136d27abSRui Ueyama SmallString<128> s; 115136d27abSRui Ueyama raw_svector_ostream os(s); 116136d27abSRui Ueyama DiagnosticPrinterRawOStream dp(os); 11733b38339SFangrui Song 11833b38339SFangrui Song // For an inline asm diagnostic, prepend the module name to get something like 11933b38339SFangrui Song // "$module <inline asm>:1:5: ". 12033b38339SFangrui Song if (auto *dism = dyn_cast<DiagnosticInfoSrcMgr>(&di)) 12133b38339SFangrui Song if (dism->isInlineAsmDiag()) 12233b38339SFangrui Song os << dism->getModuleName() << ' '; 12333b38339SFangrui Song 124136d27abSRui Ueyama di.print(dp); 125136d27abSRui Ueyama switch (di.getSeverity()) { 126b2144058SSam Clegg case DS_Error: 127136d27abSRui Ueyama error(s); 128b2144058SSam Clegg break; 129b2144058SSam Clegg case DS_Warning: 130136d27abSRui Ueyama warn(s); 131b2144058SSam Clegg break; 132b2144058SSam Clegg case DS_Remark: 133b2144058SSam Clegg case DS_Note: 134136d27abSRui Ueyama message(s); 135b2144058SSam Clegg break; 136b2144058SSam Clegg } 1373ad27e92SSam Clegg } 1383ad27e92SSam Clegg 139136d27abSRui Ueyama void lld::checkError(Error e) { 140136d27abSRui Ueyama handleAllErrors(std::move(e), 141136d27abSRui Ueyama [&](ErrorInfoBase &eib) { error(eib.message()); }); 1423ad27e92SSam Clegg } 1433ad27e92SSam Clegg 1444a67b93fSFangrui Song void lld::checkError(ErrorHandler &eh, Error e) { 1454a67b93fSFangrui Song handleAllErrors(std::move(e), 1464a67b93fSFangrui Song [&](ErrorInfoBase &eib) { eh.error(eib.message()); }); 1474a67b93fSFangrui Song } 1484a67b93fSFangrui Song 14996a7a225SRui Ueyama // This is for --vs-diagnostics. 15096a7a225SRui Ueyama // 15196a7a225SRui Ueyama // Normally, lld's error message starts with argv[0]. Therefore, it usually 15296a7a225SRui Ueyama // looks like this: 15396a7a225SRui Ueyama // 15496a7a225SRui Ueyama // ld.lld: error: ... 15596a7a225SRui Ueyama // 15696a7a225SRui Ueyama // This error message style is unfortunately unfriendly to Visual Studio 15796a7a225SRui Ueyama // IDE. VS interprets the first word of the first line as an error location 15896a7a225SRui Ueyama // and make it clickable, thus "ld.lld" in the above message would become a 15996a7a225SRui Ueyama // clickable text. When you click it, VS opens "ld.lld" executable file with 16096a7a225SRui Ueyama // a binary editor. 16196a7a225SRui Ueyama // 16296a7a225SRui Ueyama // As a workaround, we print out an error location instead of "ld.lld" if 16396a7a225SRui Ueyama // lld is running in VS diagnostics mode. As a result, error message will 16496a7a225SRui Ueyama // look like this: 16596a7a225SRui Ueyama // 16696a7a225SRui Ueyama // src/foo.c(35): error: ... 16796a7a225SRui Ueyama // 16896a7a225SRui Ueyama // This function returns an error location string. An error location is 16996a7a225SRui Ueyama // extracted from an error message using regexps. 170cac8df1aSRui Ueyama std::string ErrorHandler::getLocation(const Twine &msg) { 171cac8df1aSRui Ueyama if (!vsDiagnostics) 172adcd0268SBenjamin Kramer return std::string(logName); 173cac8df1aSRui Ueyama 174cac8df1aSRui Ueyama static std::regex regexes[] = { 175cac8df1aSRui Ueyama std::regex( 176b65016ddSIgor Kudrin R"(^undefined (?:\S+ )?symbol:.*\n)" 177b65016ddSIgor Kudrin R"(>>> referenced by .+\((\S+):(\d+)\))"), 178b65016ddSIgor Kudrin std::regex( 179b65016ddSIgor Kudrin R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"), 18087886299SChris Jackson std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"), 18187886299SChris Jackson std::regex( 18287886299SChris Jackson R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"), 183b65016ddSIgor Kudrin std::regex( 184b65016ddSIgor Kudrin R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"), 185b65016ddSIgor Kudrin std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"), 186b65016ddSIgor Kudrin std::regex( 187b65016ddSIgor Kudrin R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"), 188cac8df1aSRui Ueyama std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"), 18987886299SChris Jackson std::regex(R"((\S+):(\d+): unclosed quote)"), 19087886299SChris Jackson }; 19187886299SChris Jackson 192cac8df1aSRui Ueyama std::string str = msg.str(); 193cac8df1aSRui Ueyama for (std::regex &re : regexes) { 194cac8df1aSRui Ueyama std::smatch m; 195cac8df1aSRui Ueyama if (!std::regex_search(str, m, re)) 196cac8df1aSRui Ueyama continue; 197cac8df1aSRui Ueyama 198cac8df1aSRui Ueyama assert(m.size() == 2 || m.size() == 3); 199cac8df1aSRui Ueyama if (m.size() == 2) 200cac8df1aSRui Ueyama return m.str(1); 201cac8df1aSRui Ueyama return m.str(1) + "(" + m.str(2) + ")"; 20287886299SChris Jackson } 20387886299SChris Jackson 204adcd0268SBenjamin Kramer return std::string(logName); 205b8a59c8aSBob Haarman } 206b8a59c8aSBob Haarman 2070db402c5SFangrui Song void ErrorHandler::reportDiagnostic(StringRef location, Colors c, 2080db402c5SFangrui Song StringRef diagKind, const Twine &msg) { 2090db402c5SFangrui Song SmallString<256> buf; 2100db402c5SFangrui Song raw_svector_ostream os(buf); 2110db402c5SFangrui Song os << sep << location << ": "; 2120db402c5SFangrui Song if (!diagKind.empty()) { 213dc6229bdSFangrui Song if (errs().colors_enabled()) { 2140db402c5SFangrui Song os.enable_colors(true); 2150db402c5SFangrui Song os << c << diagKind << ": " << Colors::RESET; 2160db402c5SFangrui Song } else { 2170db402c5SFangrui Song os << diagKind << ": "; 2180db402c5SFangrui Song } 2190db402c5SFangrui Song } 2200db402c5SFangrui Song os << msg << '\n'; 221dc6229bdSFangrui Song errs() << buf; 222a6fa51f5SAlexander Richardson // If msg contains a newline, ensure that the next diagnostic is preceded by 223a6fa51f5SAlexander Richardson // a blank line separator. 224a6fa51f5SAlexander Richardson sep = getSeparator(msg); 2250db402c5SFangrui Song } 2260db402c5SFangrui Song 227136d27abSRui Ueyama void ErrorHandler::log(const Twine &msg) { 228f2efb574SAlexandre Ganea if (!verbose || disableOutput) 229cac8df1aSRui Ueyama return; 230136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu); 2310db402c5SFangrui Song reportDiagnostic(logName, Colors::RESET, "", msg); 232b8a59c8aSBob Haarman } 233b8a59c8aSBob Haarman 23464c17344SNico Weber void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) { 235f2efb574SAlexandre Ganea if (disableOutput) 236f2efb574SAlexandre Ganea return; 237136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu); 23864c17344SNico Weber s << msg << "\n"; 23964c17344SNico Weber s.flush(); 240b8a59c8aSBob Haarman } 241b8a59c8aSBob Haarman 242136d27abSRui Ueyama void ErrorHandler::warn(const Twine &msg) { 243136d27abSRui Ueyama if (fatalWarnings) { 244136d27abSRui Ueyama error(msg); 245b8a59c8aSBob Haarman return; 246b8a59c8aSBob Haarman } 247b8a59c8aSBob Haarman 2487d57c698SKeith Smiley if (suppressWarnings) 2497d57c698SKeith Smiley return; 2507d57c698SKeith Smiley 251136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu); 2520db402c5SFangrui Song reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg); 2534d41c332SRui Ueyama } 254a52f982fSRui Ueyama 2554d41c332SRui Ueyama void ErrorHandler::error(const Twine &msg) { 256cac8df1aSRui Ueyama // If Visual Studio-style error message mode is enabled, 257cac8df1aSRui Ueyama // this particular error is printed out as two errors. 258cac8df1aSRui Ueyama if (vsDiagnostics) { 259cac8df1aSRui Ueyama static std::regex re(R"(^(duplicate symbol: .*))" 260da41e210SIgor Kudrin R"((\n>>> defined at \S+:\d+.*\n>>>.*))" 261da41e210SIgor Kudrin R"((\n>>> defined at \S+:\d+.*\n>>>.*))"); 262cac8df1aSRui Ueyama std::string str = msg.str(); 263cac8df1aSRui Ueyama std::smatch m; 264cac8df1aSRui Ueyama 265cac8df1aSRui Ueyama if (std::regex_match(str, m, re)) { 266cac8df1aSRui Ueyama error(m.str(1) + m.str(2)); 267cac8df1aSRui Ueyama error(m.str(1) + m.str(3)); 268cac8df1aSRui Ueyama return; 269cac8df1aSRui Ueyama } 270cac8df1aSRui Ueyama } 271cac8df1aSRui Ueyama 272de2dfc8bSAndrew Ng bool exit = false; 273de2dfc8bSAndrew Ng { 274136d27abSRui Ueyama std::lock_guard<std::mutex> lock(mu); 275b8a59c8aSBob Haarman 276136d27abSRui Ueyama if (errorLimit == 0 || errorCount < errorLimit) { 2770db402c5SFangrui Song reportDiagnostic(getLocation(msg), Colors::RED, "error", msg); 278136d27abSRui Ueyama } else if (errorCount == errorLimit) { 2790db402c5SFangrui Song reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg); 280de2dfc8bSAndrew Ng exit = exitEarly; 281b8a59c8aSBob Haarman } 282b8a59c8aSBob Haarman 283136d27abSRui Ueyama ++errorCount; 284b8a59c8aSBob Haarman } 285b8a59c8aSBob Haarman 286de2dfc8bSAndrew Ng if (exit) 287de2dfc8bSAndrew Ng exitLld(1); 288de2dfc8bSAndrew Ng } 289de2dfc8bSAndrew Ng 290cfc32267Sserge-sans-paille void ErrorHandler::error(const Twine &msg, ErrorTag tag, 291cfc32267Sserge-sans-paille ArrayRef<StringRef> args) { 292*f359c1f5SFangrui Song if (errorHandlingScript.empty() || disableOutput) { 293cfc32267Sserge-sans-paille error(msg); 294cfc32267Sserge-sans-paille return; 295cfc32267Sserge-sans-paille } 296cfc32267Sserge-sans-paille SmallVector<StringRef, 4> scriptArgs; 297cfc32267Sserge-sans-paille scriptArgs.push_back(errorHandlingScript); 298cfc32267Sserge-sans-paille switch (tag) { 299cfc32267Sserge-sans-paille case ErrorTag::LibNotFound: 300cfc32267Sserge-sans-paille scriptArgs.push_back("missing-lib"); 301cfc32267Sserge-sans-paille break; 3021e70ec10Sserge-sans-paille case ErrorTag::SymbolNotFound: 3031e70ec10Sserge-sans-paille scriptArgs.push_back("undefined-symbol"); 3041e70ec10Sserge-sans-paille break; 305cfc32267Sserge-sans-paille } 306cfc32267Sserge-sans-paille scriptArgs.insert(scriptArgs.end(), args.begin(), args.end()); 307cfc32267Sserge-sans-paille int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs); 308cfc32267Sserge-sans-paille if (res == 0) { 309cfc32267Sserge-sans-paille return error(msg); 310cfc32267Sserge-sans-paille } else { 311cfc32267Sserge-sans-paille // Temporarily disable error limit to make sure the two calls to error(...) 312cfc32267Sserge-sans-paille // only count as one. 313cfc32267Sserge-sans-paille uint64_t currentErrorLimit = errorLimit; 314cfc32267Sserge-sans-paille errorLimit = 0; 315cfc32267Sserge-sans-paille error(msg); 316cfc32267Sserge-sans-paille errorLimit = currentErrorLimit; 317cfc32267Sserge-sans-paille --errorCount; 318cfc32267Sserge-sans-paille 319cfc32267Sserge-sans-paille switch (res) { 320cfc32267Sserge-sans-paille case -1: 321cfc32267Sserge-sans-paille error("error handling script '" + errorHandlingScript + 322cfc32267Sserge-sans-paille "' failed to execute"); 323cfc32267Sserge-sans-paille break; 324cfc32267Sserge-sans-paille case -2: 325cfc32267Sserge-sans-paille error("error handling script '" + errorHandlingScript + 326cfc32267Sserge-sans-paille "' crashed or timeout"); 327cfc32267Sserge-sans-paille break; 328cfc32267Sserge-sans-paille default: 329cfc32267Sserge-sans-paille error("error handling script '" + errorHandlingScript + 330cfc32267Sserge-sans-paille "' exited with code " + Twine(res)); 331cfc32267Sserge-sans-paille } 332cfc32267Sserge-sans-paille } 333cfc32267Sserge-sans-paille } 334cfc32267Sserge-sans-paille 335136d27abSRui Ueyama void ErrorHandler::fatal(const Twine &msg) { 336136d27abSRui Ueyama error(msg); 337b8a59c8aSBob Haarman exitLld(1); 338b8a59c8aSBob Haarman } 339201d7607SFangrui Song 340201d7607SFangrui Song SyncStream::~SyncStream() { 341201d7607SFangrui Song switch (level) { 342eb4d2f24SFangrui Song case DiagLevel::None: 343eb4d2f24SFangrui Song break; 344201d7607SFangrui Song case DiagLevel::Log: 345201d7607SFangrui Song e.log(buf); 346201d7607SFangrui Song break; 3473b75a5c4SFangrui Song case DiagLevel::Msg: 348686a291cSFangrui Song e.message(buf, e.outs()); 3493b75a5c4SFangrui Song break; 350201d7607SFangrui Song case DiagLevel::Warn: 351201d7607SFangrui Song e.warn(buf); 352201d7607SFangrui Song break; 353201d7607SFangrui Song case DiagLevel::Err: 354201d7607SFangrui Song e.error(buf); 355201d7607SFangrui Song break; 356201d7607SFangrui Song case DiagLevel::Fatal: 357201d7607SFangrui Song e.fatal(buf); 358201d7607SFangrui Song break; 359201d7607SFangrui Song } 360201d7607SFangrui Song } 361