[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
//===- ErrorHandler.cpp ---------------------------------------------------===//
|
2015-08-06 15:08:23 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-08-06 15:08:23 +00:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-10-13 18:22:55 +00:00
|
|
|
|
2022-01-20 14:53:18 -05:00
|
|
|
#include "lld/Common/CommonLinkerContext.h"
|
2015-08-06 15:08:23 +00:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2018-05-22 20:20:25 +00:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2020-09-24 15:00:43 -04:00
|
|
|
#include "llvm/Support/CrashRecoveryContext.h"
|
2016-11-10 19:39:05 +00:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2020-09-24 15:00:43 -04:00
|
|
|
#include "llvm/Support/Process.h"
|
2020-10-19 13:19:52 +02:00
|
|
|
#include "llvm/Support/Program.h"
|
2015-08-06 15:08:23 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2019-07-17 14:54:02 +00:00
|
|
|
#include <regex>
|
2015-08-06 15:08:23 +00:00
|
|
|
|
2016-07-07 14:06:38 +00:00
|
|
|
using namespace llvm;
|
2017-03-24 00:15:37 +00:00
|
|
|
using namespace lld;
|
ELF: Rename error -> fatal and redefine error as a non-noreturn function.
In many situations, we don't want to exit at the first error even in the
process model. For example, it is better to report all undefined symbols
rather than reporting the first one that the linker picked up randomly.
In order to handle such errors, we don't need to wrap everything with
ErrorOr (thanks for David Blaikie for pointing this out!) Instead, we
can set a flag to record the fact that we found an error and keep it
going until it reaches a reasonable checkpoint.
This idea should be applicable to other places. For example, we can
ignore broken relocations and check for errors after visiting all relocs.
In this patch, I rename error to fatal, and introduce another version of
error which doesn't call exit. That function instead sets HasError to true.
Once HasError becomes true, it stays true, so that we know that there
was an error if it is true.
I think introducing a non-noreturn error reporting function is by itself
a good idea, and it looks to me that this also provides a gradual path
towards lld-as-a-library (or at least embed-lld-to-your-program) without
sacrificing code readability with lots of ErrorOr's.
http://reviews.llvm.org/D16641
llvm-svn: 259069
2016-01-28 18:40:06 +00:00
|
|
|
|
2019-08-07 10:11:24 +00:00
|
|
|
static StringRef getSeparator(const Twine &msg) {
|
|
|
|
|
if (StringRef(msg.str()).contains('\n'))
|
|
|
|
|
return "\n";
|
|
|
|
|
return "";
|
2017-03-30 19:13:47 +00:00
|
|
|
}
|
|
|
|
|
|
2022-01-20 14:53:18 -05:00
|
|
|
ErrorHandler::~ErrorHandler() {
|
|
|
|
|
if (cleanupCallback)
|
|
|
|
|
cleanupCallback();
|
2022-01-15 21:47:54 -05:00
|
|
|
}
|
|
|
|
|
|
2022-01-20 14:53:18 -05:00
|
|
|
void ErrorHandler::initialize(llvm::raw_ostream &stdoutOS,
|
|
|
|
|
llvm::raw_ostream &stderrOS, bool exitEarly,
|
|
|
|
|
bool disableOutput) {
|
|
|
|
|
this->stdoutOS = &stdoutOS;
|
|
|
|
|
this->stderrOS = &stderrOS;
|
|
|
|
|
stderrOS.enable_colors(stderrOS.has_colors());
|
|
|
|
|
this->exitEarly = exitEarly;
|
|
|
|
|
this->disableOutput = disableOutput;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ErrorHandler::flushStreams() {
|
|
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
|
|
|
|
outs().flush();
|
|
|
|
|
errs().flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorHandler &lld::errorHandler() { return context().e; }
|
|
|
|
|
|
2022-02-17 11:54:57 -08:00
|
|
|
void lld::error(const Twine &msg) { errorHandler().error(msg); }
|
|
|
|
|
void lld::error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) {
|
|
|
|
|
errorHandler().error(msg, tag, args);
|
|
|
|
|
}
|
|
|
|
|
void lld::fatal(const Twine &msg) { errorHandler().fatal(msg); }
|
|
|
|
|
void lld::log(const Twine &msg) { errorHandler().log(msg); }
|
|
|
|
|
void lld::message(const Twine &msg, llvm::raw_ostream &s) {
|
|
|
|
|
errorHandler().message(msg, s);
|
|
|
|
|
}
|
|
|
|
|
void lld::warn(const Twine &msg) { errorHandler().warn(msg); }
|
|
|
|
|
uint64_t lld::errorCount() { return errorHandler().errorCount; }
|
|
|
|
|
|
2020-09-24 15:00:43 -04:00
|
|
|
raw_ostream &lld::outs() {
|
2022-01-20 14:53:18 -05:00
|
|
|
ErrorHandler &e = errorHandler();
|
|
|
|
|
return e.outs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
raw_ostream &ErrorHandler::outs() {
|
|
|
|
|
if (disableOutput)
|
2020-09-24 15:00:43 -04:00
|
|
|
return llvm::nulls();
|
|
|
|
|
return stdoutOS ? *stdoutOS : llvm::outs();
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-20 14:53:18 -05:00
|
|
|
raw_ostream &ErrorHandler::errs() {
|
|
|
|
|
if (disableOutput)
|
2020-09-24 15:00:43 -04:00
|
|
|
return llvm::nulls();
|
|
|
|
|
return stderrOS ? *stderrOS : llvm::errs();
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-27 18:04:49 +00:00
|
|
|
void lld::exitLld(int val) {
|
2022-01-20 14:53:18 -05:00
|
|
|
if (hasContext()) {
|
|
|
|
|
ErrorHandler &e = errorHandler();
|
|
|
|
|
// Delete any temporary file, while keeping the memory mapping open.
|
|
|
|
|
if (e.outputBuffer)
|
|
|
|
|
e.outputBuffer->discard();
|
|
|
|
|
}
|
2017-11-13 18:06:43 +00:00
|
|
|
|
2023-02-04 15:23:24 -05:00
|
|
|
// Re-throw a possible signal or exception once/if it was caught by
|
[LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures
This is a follow-up for D70378 (Cover usage of LLD as a library).
While debugging an intermittent failure on a bot, I recalled this scenario which
causes the issue:
1.When executing lld/test/ELF/invalid/symtab-sh-info.s L45, we reach
lld::elf::Obj-File::ObjFile() which goes straight into its base ELFFileBase(),
then ELFFileBase::init().
2.At that point fatal() is thrown in lld/ELF/InputFiles.cpp L381, leaving a
half-initialized ObjFile instance.
3.We then end up in lld::exitLld() and since we are running with LLD_IN_TEST, we
hapily restore the control flow to CrashRecoveryContext::RunSafely() then back
in lld::safeLldMain().
4.Before this patch, we called errorHandler().reset() just after, and this
attempted to reset the associated SpecificAlloc<ObjFile<ELF64LE>>. That tried
to free the half-initialized ObjFile instance, and more precisely its
ObjFile::dwarf member.
Sometimes that worked, sometimes it failed and was catched by the
CrashRecoveryContext. This scenario was the reason we called
errorHandler().reset() through a CrashRecoveryContext.
But in some rare cases, the above repro somehow corrupted the heap, creating a
stack overflow. When the CrashRecoveryContext's filter (that is,
__except (ExceptionFilter(GetExceptionInformation()))) tried to handle the
exception, it crashed again since the stack was exhausted -- and that took the
whole application down. That is the issue seen on the bot. Locally it happens
about 1 times out of 15.
Now this situation can happen anywhere in LLD. Since catching stack overflows is
not a reliable scenario ATM when using CrashRecoveryContext, we're now
preventing further re-entrance when such failures occur, by signaling
lld::SafeReturn::canRunAgain=false. When running with LLD_IN_TEST=2 (or above),
only one iteration will be executed, instead of two.
Differential Revision: https://reviews.llvm.org/D88348
2020-11-12 08:14:20 -05:00
|
|
|
// safeLldMain().
|
|
|
|
|
CrashRecoveryContext::throwIfCrash(val);
|
|
|
|
|
|
2019-03-16 19:36:29 +00:00
|
|
|
// Dealloc/destroy ManagedStatic variables before calling _exit().
|
|
|
|
|
// In an LTO build, allows us to get the output of -time-passes.
|
|
|
|
|
// Ensures that the thread pool for the parallel algorithms is stopped to
|
|
|
|
|
// avoid intermittent crashes on Windows when exiting.
|
2020-09-24 15:00:43 -04:00
|
|
|
if (!CrashRecoveryContext::GetCurrent())
|
|
|
|
|
llvm_shutdown();
|
2016-11-10 19:39:05 +00:00
|
|
|
|
2022-01-20 14:53:18 -05:00
|
|
|
if (hasContext())
|
|
|
|
|
lld::errorHandler().flushStreams();
|
|
|
|
|
|
[LLD][COFF] When using LLD-as-a-library, always prevent re-entrance on failures
This is a follow-up for D70378 (Cover usage of LLD as a library).
While debugging an intermittent failure on a bot, I recalled this scenario which
causes the issue:
1.When executing lld/test/ELF/invalid/symtab-sh-info.s L45, we reach
lld::elf::Obj-File::ObjFile() which goes straight into its base ELFFileBase(),
then ELFFileBase::init().
2.At that point fatal() is thrown in lld/ELF/InputFiles.cpp L381, leaving a
half-initialized ObjFile instance.
3.We then end up in lld::exitLld() and since we are running with LLD_IN_TEST, we
hapily restore the control flow to CrashRecoveryContext::RunSafely() then back
in lld::safeLldMain().
4.Before this patch, we called errorHandler().reset() just after, and this
attempted to reset the associated SpecificAlloc<ObjFile<ELF64LE>>. That tried
to free the half-initialized ObjFile instance, and more precisely its
ObjFile::dwarf member.
Sometimes that worked, sometimes it failed and was catched by the
CrashRecoveryContext. This scenario was the reason we called
errorHandler().reset() through a CrashRecoveryContext.
But in some rare cases, the above repro somehow corrupted the heap, creating a
stack overflow. When the CrashRecoveryContext's filter (that is,
__except (ExceptionFilter(GetExceptionInformation()))) tried to handle the
exception, it crashed again since the stack was exhausted -- and that took the
whole application down. That is the issue seen on the bot. Locally it happens
about 1 times out of 15.
Now this situation can happen anywhere in LLD. Since catching stack overflows is
not a reliable scenario ATM when using CrashRecoveryContext, we're now
preventing further re-entrance when such failures occur, by signaling
lld::SafeReturn::canRunAgain=false. When running with LLD_IN_TEST=2 (or above),
only one iteration will be executed, instead of two.
Differential Revision: https://reviews.llvm.org/D88348
2020-11-12 08:14:20 -05:00
|
|
|
// When running inside safeLldMain(), restore the control flow back to the
|
|
|
|
|
// CrashRecoveryContext. Otherwise simply use _exit(), meanning no cleanup,
|
|
|
|
|
// since we want to avoid further crashes on shutdown.
|
|
|
|
|
llvm::sys::Process::Exit(val, /*NoCleanup=*/true);
|
2016-10-27 13:32:32 +00:00
|
|
|
}
|
|
|
|
|
|
2018-05-22 20:20:25 +00:00
|
|
|
void lld::diagnosticHandler(const DiagnosticInfo &di) {
|
|
|
|
|
SmallString<128> s;
|
|
|
|
|
raw_svector_ostream os(s);
|
|
|
|
|
DiagnosticPrinterRawOStream dp(os);
|
2022-01-28 11:32:42 -08:00
|
|
|
|
|
|
|
|
// For an inline asm diagnostic, prepend the module name to get something like
|
|
|
|
|
// "$module <inline asm>:1:5: ".
|
|
|
|
|
if (auto *dism = dyn_cast<DiagnosticInfoSrcMgr>(&di))
|
|
|
|
|
if (dism->isInlineAsmDiag())
|
|
|
|
|
os << dism->getModuleName() << ' ';
|
|
|
|
|
|
2018-05-22 20:20:25 +00:00
|
|
|
di.print(dp);
|
2018-07-02 21:01:43 +00:00
|
|
|
switch (di.getSeverity()) {
|
|
|
|
|
case DS_Error:
|
|
|
|
|
error(s);
|
|
|
|
|
break;
|
|
|
|
|
case DS_Warning:
|
|
|
|
|
warn(s);
|
|
|
|
|
break;
|
|
|
|
|
case DS_Remark:
|
|
|
|
|
case DS_Note:
|
|
|
|
|
message(s);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-05-22 20:20:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lld::checkError(Error e) {
|
|
|
|
|
handleAllErrors(std::move(e),
|
|
|
|
|
[&](ErrorInfoBase &eib) { error(eib.message()); });
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-16 15:43:05 -08:00
|
|
|
void lld::checkError(ErrorHandler &eh, Error e) {
|
|
|
|
|
handleAllErrors(std::move(e),
|
|
|
|
|
[&](ErrorInfoBase &eib) { eh.error(eib.message()); });
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-02 05:04:27 +00:00
|
|
|
// This is for --vs-diagnostics.
|
|
|
|
|
//
|
|
|
|
|
// Normally, lld's error message starts with argv[0]. Therefore, it usually
|
|
|
|
|
// looks like this:
|
|
|
|
|
//
|
|
|
|
|
// ld.lld: error: ...
|
|
|
|
|
//
|
|
|
|
|
// This error message style is unfortunately unfriendly to Visual Studio
|
|
|
|
|
// IDE. VS interprets the first word of the first line as an error location
|
|
|
|
|
// and make it clickable, thus "ld.lld" in the above message would become a
|
|
|
|
|
// clickable text. When you click it, VS opens "ld.lld" executable file with
|
|
|
|
|
// a binary editor.
|
|
|
|
|
//
|
|
|
|
|
// As a workaround, we print out an error location instead of "ld.lld" if
|
|
|
|
|
// lld is running in VS diagnostics mode. As a result, error message will
|
|
|
|
|
// look like this:
|
|
|
|
|
//
|
|
|
|
|
// src/foo.c(35): error: ...
|
|
|
|
|
//
|
|
|
|
|
// This function returns an error location string. An error location is
|
|
|
|
|
// extracted from an error message using regexps.
|
2019-08-07 08:08:17 +00:00
|
|
|
std::string ErrorHandler::getLocation(const Twine &msg) {
|
|
|
|
|
if (!vsDiagnostics)
|
2020-01-28 20:23:46 +01:00
|
|
|
return std::string(logName);
|
2019-08-07 08:08:17 +00:00
|
|
|
|
|
|
|
|
static std::regex regexes[] = {
|
|
|
|
|
std::regex(
|
2019-08-09 08:29:03 +00:00
|
|
|
R"(^undefined (?:\S+ )?symbol:.*\n)"
|
|
|
|
|
R"(>>> referenced by .+\((\S+):(\d+)\))"),
|
|
|
|
|
std::regex(
|
|
|
|
|
R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+))"),
|
2019-07-17 14:54:02 +00:00
|
|
|
std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
|
|
|
|
|
std::regex(
|
|
|
|
|
R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
|
2019-08-09 08:29:03 +00:00
|
|
|
std::regex(
|
|
|
|
|
R"(^duplicate symbol: .*\n>>> defined at .+\((\S+):(\d+)\))"),
|
|
|
|
|
std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+))"),
|
|
|
|
|
std::regex(
|
|
|
|
|
R"(.*\n>>> defined in .*\n>>> referenced by .+\((\S+):(\d+)\))"),
|
2019-08-07 08:08:17 +00:00
|
|
|
std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
|
2019-07-17 14:54:02 +00:00
|
|
|
std::regex(R"((\S+):(\d+): unclosed quote)"),
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-07 08:08:17 +00:00
|
|
|
std::string str = msg.str();
|
|
|
|
|
for (std::regex &re : regexes) {
|
|
|
|
|
std::smatch m;
|
|
|
|
|
if (!std::regex_search(str, m, re))
|
|
|
|
|
continue;
|
2019-07-17 14:54:02 +00:00
|
|
|
|
2019-08-07 08:08:17 +00:00
|
|
|
assert(m.size() == 2 || m.size() == 3);
|
|
|
|
|
if (m.size() == 2)
|
|
|
|
|
return m.str(1);
|
|
|
|
|
return m.str(1) + "(" + m.str(2) + ")";
|
2019-07-17 14:54:02 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-28 20:23:46 +01:00
|
|
|
return std::string(logName);
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
2021-09-09 09:27:14 -07:00
|
|
|
void ErrorHandler::reportDiagnostic(StringRef location, Colors c,
|
|
|
|
|
StringRef diagKind, const Twine &msg) {
|
|
|
|
|
SmallString<256> buf;
|
|
|
|
|
raw_svector_ostream os(buf);
|
|
|
|
|
os << sep << location << ": ";
|
|
|
|
|
if (!diagKind.empty()) {
|
2024-11-16 18:25:50 -08:00
|
|
|
if (errs().colors_enabled()) {
|
2021-09-09 09:27:14 -07:00
|
|
|
os.enable_colors(true);
|
|
|
|
|
os << c << diagKind << ": " << Colors::RESET;
|
|
|
|
|
} else {
|
|
|
|
|
os << diagKind << ": ";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
os << msg << '\n';
|
2024-11-16 18:25:50 -08:00
|
|
|
errs() << buf;
|
2024-12-02 10:36:32 -08:00
|
|
|
// If msg contains a newline, ensure that the next diagnostic is preceded by
|
|
|
|
|
// a blank line separator.
|
|
|
|
|
sep = getSeparator(msg);
|
2021-09-09 09:27:14 -07:00
|
|
|
}
|
|
|
|
|
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
void ErrorHandler::log(const Twine &msg) {
|
2020-09-24 15:00:43 -04:00
|
|
|
if (!verbose || disableOutput)
|
2019-08-07 08:08:17 +00:00
|
|
|
return;
|
|
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
2021-09-09 09:27:14 -07:00
|
|
|
reportDiagnostic(logName, Colors::RESET, "", msg);
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
2021-11-02 10:13:27 -04:00
|
|
|
void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
|
2020-09-24 15:00:43 -04:00
|
|
|
if (disableOutput)
|
|
|
|
|
return;
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
2021-11-02 10:13:27 -04:00
|
|
|
s << msg << "\n";
|
|
|
|
|
s.flush();
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ErrorHandler::warn(const Twine &msg) {
|
|
|
|
|
if (fatalWarnings) {
|
|
|
|
|
error(msg);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-11 00:10:48 -07:00
|
|
|
if (suppressWarnings)
|
|
|
|
|
return;
|
|
|
|
|
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
2021-09-09 09:27:14 -07:00
|
|
|
reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
|
2019-08-02 07:22:34 +00:00
|
|
|
}
|
Improve raw_ostream so that you can "write" colors using operator<<
1. raw_ostream supports ANSI colors so that you can write messages to
the termina with colors. Previously, in order to change and reset
color, you had to call `changeColor` and `resetColor` functions,
respectively.
So, if you print out "error: " in red, for example, you had to do
something like this:
OS.changeColor(raw_ostream::RED);
OS << "error: ";
OS.resetColor();
With this patch, you can write the same code as follows:
OS << raw_ostream::RED << "error: " << raw_ostream::RESET;
2. Add a boolean flag to raw_ostream so that you can disable colored
output. If you disable colors, changeColor, operator<<(Color),
resetColor and other color-related functions have no effect.
Most LLVM tools automatically prints out messages using colors, and
you can disable it by passing a flag such as `--disable-colors`.
This new flag makes it easy to write code that works that way.
Differential Revision: https://reviews.llvm.org/D65564
llvm-svn: 367649
2019-08-02 04:48:30 +00:00
|
|
|
|
2019-08-02 07:22:34 +00:00
|
|
|
void ErrorHandler::error(const Twine &msg) {
|
2019-08-07 08:08:17 +00:00
|
|
|
// If Visual Studio-style error message mode is enabled,
|
|
|
|
|
// this particular error is printed out as two errors.
|
|
|
|
|
if (vsDiagnostics) {
|
|
|
|
|
static std::regex re(R"(^(duplicate symbol: .*))"
|
2019-08-07 11:32:43 +00:00
|
|
|
R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
|
|
|
|
|
R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
|
2019-08-07 08:08:17 +00:00
|
|
|
std::string str = msg.str();
|
|
|
|
|
std::smatch m;
|
|
|
|
|
|
|
|
|
|
if (std::regex_match(str, m, re)) {
|
|
|
|
|
error(m.str(1) + m.str(2));
|
|
|
|
|
error(m.str(1) + m.str(3));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:08:09 +00:00
|
|
|
bool exit = false;
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
|
2020-01-22 17:08:09 +00:00
|
|
|
if (errorLimit == 0 || errorCount < errorLimit) {
|
2021-09-09 09:27:14 -07:00
|
|
|
reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
|
2020-01-22 17:08:09 +00:00
|
|
|
} else if (errorCount == errorLimit) {
|
2021-09-09 09:27:14 -07:00
|
|
|
reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
|
2020-01-22 17:08:09 +00:00
|
|
|
exit = exitEarly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++errorCount;
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-22 17:08:09 +00:00
|
|
|
if (exit)
|
|
|
|
|
exitLld(1);
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-19 13:19:52 +02:00
|
|
|
void ErrorHandler::error(const Twine &msg, ErrorTag tag,
|
|
|
|
|
ArrayRef<StringRef> args) {
|
2025-01-25 18:01:52 -08:00
|
|
|
if (errorHandlingScript.empty() || disableOutput) {
|
2020-10-19 13:19:52 +02:00
|
|
|
error(msg);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SmallVector<StringRef, 4> scriptArgs;
|
|
|
|
|
scriptArgs.push_back(errorHandlingScript);
|
|
|
|
|
switch (tag) {
|
|
|
|
|
case ErrorTag::LibNotFound:
|
|
|
|
|
scriptArgs.push_back("missing-lib");
|
|
|
|
|
break;
|
2020-10-19 13:21:23 +02:00
|
|
|
case ErrorTag::SymbolNotFound:
|
|
|
|
|
scriptArgs.push_back("undefined-symbol");
|
|
|
|
|
break;
|
2020-10-19 13:19:52 +02:00
|
|
|
}
|
|
|
|
|
scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
|
|
|
|
|
int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
|
|
|
|
|
if (res == 0) {
|
|
|
|
|
return error(msg);
|
|
|
|
|
} else {
|
|
|
|
|
// Temporarily disable error limit to make sure the two calls to error(...)
|
|
|
|
|
// only count as one.
|
|
|
|
|
uint64_t currentErrorLimit = errorLimit;
|
|
|
|
|
errorLimit = 0;
|
|
|
|
|
error(msg);
|
|
|
|
|
errorLimit = currentErrorLimit;
|
|
|
|
|
--errorCount;
|
|
|
|
|
|
|
|
|
|
switch (res) {
|
|
|
|
|
case -1:
|
|
|
|
|
error("error handling script '" + errorHandlingScript +
|
|
|
|
|
"' failed to execute");
|
|
|
|
|
break;
|
|
|
|
|
case -2:
|
|
|
|
|
error("error handling script '" + errorHandlingScript +
|
|
|
|
|
"' crashed or timeout");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
error("error handling script '" + errorHandlingScript +
|
|
|
|
|
"' exited with code " + Twine(res));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[lld] unified COFF and ELF error handling on new Common/ErrorHandler
Summary:
The COFF linker and the ELF linker have long had similar but separate
Error.h and Error.cpp files to implement error handling. This change
introduces new error handling code in Common/ErrorHandler.h, changes the
COFF and ELF linkers to use it, and removes the old, separate
implementations.
Reviewers: ruiu
Reviewed By: ruiu
Subscribers: smeenai, jyknight, emaste, sdardis, nemanjai, nhaehnle, mgorny, javed.absar, kbarton, fedor.sergeev, llvm-commits
Differential Revision: https://reviews.llvm.org/D39259
llvm-svn: 316624
2017-10-25 22:28:38 +00:00
|
|
|
void ErrorHandler::fatal(const Twine &msg) {
|
2017-03-30 19:13:47 +00:00
|
|
|
error(msg);
|
2016-10-27 13:32:32 +00:00
|
|
|
exitLld(1);
|
ELF: Rename error -> fatal and redefine error as a non-noreturn function.
In many situations, we don't want to exit at the first error even in the
process model. For example, it is better to report all undefined symbols
rather than reporting the first one that the linker picked up randomly.
In order to handle such errors, we don't need to wrap everything with
ErrorOr (thanks for David Blaikie for pointing this out!) Instead, we
can set a flag to record the fact that we found an error and keep it
going until it reaches a reasonable checkpoint.
This idea should be applicable to other places. For example, we can
ignore broken relocations and check for errors after visiting all relocs.
In this patch, I rename error to fatal, and introduce another version of
error which doesn't call exit. That function instead sets HasError to true.
Once HasError becomes true, it stays true, so that we know that there
was an error if it is true.
I think introducing a non-noreturn error reporting function is by itself
a good idea, and it looks to me that this also provides a gradual path
towards lld-as-a-library (or at least embed-lld-to-your-program) without
sacrificing code readability with lots of ErrorOr's.
http://reviews.llvm.org/D16641
llvm-svn: 259069
2016-01-28 18:40:06 +00:00
|
|
|
}
|
2024-11-06 08:25:58 -08:00
|
|
|
|
|
|
|
|
SyncStream::~SyncStream() {
|
|
|
|
|
switch (level) {
|
2024-11-23 22:49:28 -08:00
|
|
|
case DiagLevel::None:
|
|
|
|
|
break;
|
2024-11-06 08:25:58 -08:00
|
|
|
case DiagLevel::Log:
|
|
|
|
|
e.log(buf);
|
|
|
|
|
break;
|
2024-11-16 15:34:42 -08:00
|
|
|
case DiagLevel::Msg:
|
2024-11-17 20:45:08 -08:00
|
|
|
e.message(buf, e.outs());
|
2024-11-16 15:34:42 -08:00
|
|
|
break;
|
2024-11-06 08:25:58 -08:00
|
|
|
case DiagLevel::Warn:
|
|
|
|
|
e.warn(buf);
|
|
|
|
|
break;
|
|
|
|
|
case DiagLevel::Err:
|
|
|
|
|
e.error(buf);
|
|
|
|
|
break;
|
|
|
|
|
case DiagLevel::Fatal:
|
|
|
|
|
e.fatal(buf);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|