[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-26 06:28:38 +08:00
|
|
|
//===- ErrorHandler.cpp ---------------------------------------------------===//
|
2015-08-06 23:08:23 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08: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 23:08:23 +08: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-26 06:28:38 +08:00
|
|
|
#include "lld/Common/ErrorHandler.h"
|
2017-10-14 02:22:55 +08:00
|
|
|
|
[Support] Move LLD's parallel algorithm wrappers to support
Essentially takes the lld/Common/Threads.h wrappers and moves them to
the llvm/Support/Paralle.h algorithm header.
The changes are:
- Remove policy parameter, since all clients use `par`.
- Rename the methods to `parallelSort` etc to match LLVM style, since
they are no longer C++17 pstl compatible.
- Move algorithms from llvm::parallel:: to llvm::, since they have
"parallel" in the name and are no longer overloads of the regular
algorithms.
- Add range overloads
- Use the sequential algorithm directly when 1 thread is requested
(skips task grouping)
- Fix the index type of parallelForEachN to size_t. Nobody in LLVM was
using any other parameter, and it made overload resolution hard for
for_each_n(par, 0, foo.size(), ...) because 0 is int, not size_t.
Remove Threads.h and update LLD for that.
This is a prerequisite for parallel public symbol processing in the PDB
library, which is in LLVM.
Reviewed By: MaskRay, aganea
Differential Revision: https://reviews.llvm.org/D79390
2020-05-05 11:03:19 +08:00
|
|
|
#include "llvm/Support/Parallel.h"
|
2015-08-06 23:08:23 +08:00
|
|
|
|
2022-01-21 03:53:18 +08:00
|
|
|
#include "lld/Common/CommonLinkerContext.h"
|
2015-08-06 23:08:23 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2018-05-23 04:20:25 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2020-09-25 03:00:43 +08:00
|
|
|
#include "llvm/Support/CrashRecoveryContext.h"
|
2016-11-11 03:39:05 +08:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2020-09-25 03:00:43 +08:00
|
|
|
#include "llvm/Support/Process.h"
|
2020-10-19 19:19:52 +08:00
|
|
|
#include "llvm/Support/Program.h"
|
2015-08-06 23:08:23 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2019-07-17 22:54:02 +08:00
|
|
|
#include <regex>
|
2015-08-06 23:08:23 +08:00
|
|
|
|
2016-07-07 22:06:38 +08:00
|
|
|
using namespace llvm;
|
2017-03-24 08:15:37 +08: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-29 02:40:06 +08:00
|
|
|
|
2019-08-07 18:11:24 +08:00
|
|
|
static StringRef getSeparator(const Twine &msg) {
|
|
|
|
if (StringRef(msg.str()).contains('\n'))
|
|
|
|
return "\n";
|
|
|
|
return "";
|
2017-03-31 03:13:47 +08:00
|
|
|
}
|
|
|
|
|
2022-01-21 03:53:18 +08:00
|
|
|
ErrorHandler::~ErrorHandler() {
|
|
|
|
if (cleanupCallback)
|
|
|
|
cleanupCallback();
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
Make it possible to redirect not only errs() but also outs()
This change is for those who use lld as a library. Context:
https://reviews.llvm.org/D70287
This patch adds a new parmeter to lld::*::link() so that we can pass
an raw_ostream object representing stdout. Previously, lld::*::link()
took only an stderr object.
Justification for making stdoutOS and stderrOS mandatory: I wanted to
make link() functions to take stdout and stderr in that order.
However, if we change the function signature from
bool link(ArrayRef<const char *> args, bool canExitEarly,
raw_ostream &stderrOS = llvm::errs());
to
bool link(ArrayRef<const char *> args, bool canExitEarly,
raw_ostream &stdoutOS = llvm::outs(),
raw_ostream &stderrOS = llvm::errs());
, then the meaning of existing code that passes stderrOS silently
changes (stderrOS would be interpreted as stdoutOS). So, I chose to
make existing code not to compile, so that developers can fix their
code.
Differential Revision: https://reviews.llvm.org/D70292
2019-11-15 13:06:57 +08:00
|
|
|
|
2022-01-21 03:53:18 +08:00
|
|
|
void ErrorHandler::flushStreams() {
|
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
|
|
|
outs().flush();
|
|
|
|
errs().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-26 06:28:38 +08:00
|
|
|
}
|
|
|
|
|
2022-01-21 03:53:18 +08:00
|
|
|
ErrorHandler &lld::errorHandler() { return context().e; }
|
|
|
|
|
2020-09-25 03:00:43 +08:00
|
|
|
raw_ostream &lld::outs() {
|
2022-01-21 03:53:18 +08:00
|
|
|
ErrorHandler &e = errorHandler();
|
|
|
|
return e.outs();
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &lld::errs() {
|
|
|
|
ErrorHandler &e = errorHandler();
|
|
|
|
return e.errs();
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_ostream &ErrorHandler::outs() {
|
|
|
|
if (disableOutput)
|
2020-09-25 03:00:43 +08:00
|
|
|
return llvm::nulls();
|
|
|
|
return stdoutOS ? *stdoutOS : llvm::outs();
|
|
|
|
}
|
|
|
|
|
2022-01-21 03:53:18 +08:00
|
|
|
raw_ostream &ErrorHandler::errs() {
|
|
|
|
if (disableOutput)
|
2020-09-25 03:00:43 +08:00
|
|
|
return llvm::nulls();
|
|
|
|
return stderrOS ? *stderrOS : llvm::errs();
|
|
|
|
}
|
|
|
|
|
2017-10-28 02:04:49 +08:00
|
|
|
void lld::exitLld(int val) {
|
2022-01-21 03:53:18 +08:00
|
|
|
if (hasContext()) {
|
|
|
|
ErrorHandler &e = errorHandler();
|
|
|
|
// Delete any temporary file, while keeping the memory mapping open.
|
|
|
|
if (e.outputBuffer)
|
|
|
|
e.outputBuffer->discard();
|
|
|
|
}
|
2017-11-14 02:06:43 +08:00
|
|
|
|
[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 21:14:20 +08:00
|
|
|
// Re-throw a possible signal or exception once/if it was catched by
|
|
|
|
// safeLldMain().
|
|
|
|
CrashRecoveryContext::throwIfCrash(val);
|
|
|
|
|
2019-03-17 03:36:29 +08: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-25 03:00:43 +08:00
|
|
|
if (!CrashRecoveryContext::GetCurrent())
|
|
|
|
llvm_shutdown();
|
[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-26 06:28:38 +08:00
|
|
|
|
2022-01-21 03:53:18 +08: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 21:14:20 +08: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);
|
[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-26 06:28:38 +08:00
|
|
|
}
|
|
|
|
|
2018-05-23 04:20:25 +08:00
|
|
|
void lld::diagnosticHandler(const DiagnosticInfo &di) {
|
|
|
|
SmallString<128> s;
|
|
|
|
raw_svector_ostream os(s);
|
|
|
|
DiagnosticPrinterRawOStream dp(os);
|
2022-01-29 03: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-23 04:20:25 +08:00
|
|
|
di.print(dp);
|
2018-07-03 05:01:43 +08: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-23 04:20:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void lld::checkError(Error e) {
|
|
|
|
handleAllErrors(std::move(e),
|
|
|
|
[&](ErrorInfoBase &eib) { error(eib.message()); });
|
|
|
|
}
|
|
|
|
|
2019-08-02 13:04:27 +08: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 16:08:17 +08:00
|
|
|
std::string ErrorHandler::getLocation(const Twine &msg) {
|
|
|
|
if (!vsDiagnostics)
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(logName);
|
2019-08-07 16:08:17 +08:00
|
|
|
|
|
|
|
static std::regex regexes[] = {
|
|
|
|
std::regex(
|
2019-08-09 16:29:03 +08: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 22:54:02 +08:00
|
|
|
std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
|
|
|
|
std::regex(
|
|
|
|
R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
|
2019-08-09 16:29:03 +08: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 16:08:17 +08:00
|
|
|
std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
|
2019-07-17 22:54:02 +08:00
|
|
|
std::regex(R"((\S+):(\d+): unclosed quote)"),
|
|
|
|
};
|
|
|
|
|
2019-08-07 16:08:17 +08: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 22:54:02 +08:00
|
|
|
|
2019-08-07 16:08:17 +08: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 22:54:02 +08:00
|
|
|
}
|
|
|
|
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(logName);
|
2016-11-26 04:27:32 +08:00
|
|
|
}
|
|
|
|
|
2021-09-10 00:27:14 +08: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()) {
|
|
|
|
if (lld::errs().colors_enabled()) {
|
|
|
|
os.enable_colors(true);
|
|
|
|
os << c << diagKind << ": " << Colors::RESET;
|
|
|
|
} else {
|
|
|
|
os << diagKind << ": ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
os << msg << '\n';
|
|
|
|
lld::errs() << buf;
|
|
|
|
}
|
|
|
|
|
[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-26 06:28:38 +08:00
|
|
|
void ErrorHandler::log(const Twine &msg) {
|
2020-09-25 03:00:43 +08:00
|
|
|
if (!verbose || disableOutput)
|
2019-08-07 16:08:17 +08:00
|
|
|
return;
|
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
2021-09-10 00:27:14 +08:00
|
|
|
reportDiagnostic(logName, Colors::RESET, "", msg);
|
2017-02-22 07:22:56 +08:00
|
|
|
}
|
|
|
|
|
2021-11-02 22:13:27 +08:00
|
|
|
void ErrorHandler::message(const Twine &msg, llvm::raw_ostream &s) {
|
2020-09-25 03:00:43 +08:00
|
|
|
if (disableOutput)
|
|
|
|
return;
|
2017-02-22 07:22:56 +08:00
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
2021-11-02 22:13:27 +08:00
|
|
|
s << msg << "\n";
|
|
|
|
s.flush();
|
2016-02-26 02:56:01 +08: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-26 06:28:38 +08:00
|
|
|
void ErrorHandler::warn(const Twine &msg) {
|
|
|
|
if (fatalWarnings) {
|
2016-07-04 21:43:12 +08:00
|
|
|
error(msg);
|
2016-11-24 02:34:28 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-03-31 03:13:47 +08:00
|
|
|
|
2016-11-24 02:34:28 +08:00
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
2021-09-10 00:27:14 +08:00
|
|
|
reportDiagnostic(getLocation(msg), Colors::MAGENTA, "warning", msg);
|
2019-08-07 18:11:24 +08:00
|
|
|
sep = getSeparator(msg);
|
2019-08-01 17:58:03 +08:00
|
|
|
}
|
|
|
|
|
2019-08-07 16:08:17 +08:00
|
|
|
void ErrorHandler::error(const Twine &msg) {
|
|
|
|
// If Visual Studio-style error message mode is enabled,
|
|
|
|
// this particular error is printed out as two errors.
|
2019-08-01 17:58:03 +08:00
|
|
|
if (vsDiagnostics) {
|
2019-08-07 16:08:17 +08:00
|
|
|
static std::regex re(R"(^(duplicate symbol: .*))"
|
2019-08-07 19:32:43 +08:00
|
|
|
R"((\n>>> defined at \S+:\d+.*\n>>>.*))"
|
|
|
|
R"((\n>>> defined at \S+:\d+.*\n>>>.*))");
|
2019-08-07 16:08:17 +08: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));
|
2019-08-01 17:58:03 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-23 01:08:09 +08:00
|
|
|
bool exit = false;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mu);
|
|
|
|
|
|
|
|
if (errorLimit == 0 || errorCount < errorLimit) {
|
2021-09-10 00:27:14 +08:00
|
|
|
reportDiagnostic(getLocation(msg), Colors::RED, "error", msg);
|
2020-01-23 01:08:09 +08:00
|
|
|
} else if (errorCount == errorLimit) {
|
2021-09-10 00:27:14 +08:00
|
|
|
reportDiagnostic(logName, Colors::RED, "error", errorLimitExceededMsg);
|
2020-01-23 01:08:09 +08:00
|
|
|
exit = exitEarly;
|
|
|
|
}
|
2016-11-24 02:34:28 +08:00
|
|
|
|
2020-01-23 01:08:09 +08:00
|
|
|
sep = getSeparator(msg);
|
|
|
|
++errorCount;
|
2016-11-24 02:15:37 +08:00
|
|
|
}
|
|
|
|
|
2020-01-23 01:08:09 +08:00
|
|
|
if (exit)
|
|
|
|
exitLld(1);
|
2015-08-06 23:08:23 +08:00
|
|
|
}
|
|
|
|
|
2020-10-19 19:19:52 +08:00
|
|
|
void ErrorHandler::error(const Twine &msg, ErrorTag tag,
|
|
|
|
ArrayRef<StringRef> args) {
|
|
|
|
if (errorHandlingScript.empty()) {
|
|
|
|
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 19:21:23 +08:00
|
|
|
case ErrorTag::SymbolNotFound:
|
|
|
|
scriptArgs.push_back("undefined-symbol");
|
|
|
|
break;
|
2020-10-19 19:19:52 +08: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-26 06:28:38 +08:00
|
|
|
void ErrorHandler::fatal(const Twine &msg) {
|
2017-03-31 03:13:47 +08:00
|
|
|
error(msg);
|
2016-10-27 21:32:32 +08: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-29 02:40:06 +08:00
|
|
|
}
|