[lld] 201d760 - [ELF] Add context-aware diagnostic functions (#112319)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 6 08:26:01 PST 2024
Author: Fangrui Song
Date: 2024-11-06T08:25:58-08:00
New Revision: 201d7607f87afff999b1257d27569a3053b85143
URL: https://github.com/llvm/llvm-project/commit/201d7607f87afff999b1257d27569a3053b85143
DIFF: https://github.com/llvm/llvm-project/commit/201d7607f87afff999b1257d27569a3053b85143.diff
LOG: [ELF] Add context-aware diagnostic functions (#112319)
The current diagnostic functions log/warn/error/fatal lack a context
argument and call the global `lld::errorHandler()`, which prevents
multiple lld instances in one process.
This patch introduces context-aware replacements:
* log => Log(ctx)
* warn => Warn(ctx)
* errorOrWarn => Err(ctx)
* error => ErrAlways(ctx)
* fatal => Fatal(ctx)
Example: `errorOrWarn(toString(f) + "xxx")` => `Err(ctx) << f << "xxx"`.
(`toString(f)` is shortened to `f` as a bonus and may access `ctx`
without accessing the global variable (see `Target.cpp`)).
`ctx.e = &context->e;` can be replaced with a non-global Errorhandler
when `ctx` becomes a local variable.
(For the ELF port, the long term goal is to eliminate `error`. Most can
be straightforwardly converted to `Err(ctx)`.)
Added:
Modified:
lld/Common/ErrorHandler.cpp
lld/ELF/Config.h
lld/ELF/Driver.cpp
lld/ELF/InputFiles.cpp
lld/ELF/InputFiles.h
lld/ELF/Target.cpp
lld/ELF/Target.h
lld/include/lld/Common/ErrorHandler.h
Removed:
################################################################################
diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp
index 4e3a1bc31ade50..21755481665961 100644
--- a/lld/Common/ErrorHandler.cpp
+++ b/lld/Common/ErrorHandler.cpp
@@ -335,3 +335,21 @@ void ErrorHandler::fatal(const Twine &msg) {
error(msg);
exitLld(1);
}
+
+SyncStream::~SyncStream() {
+ os.flush();
+ switch (level) {
+ case DiagLevel::Log:
+ e.log(buf);
+ break;
+ case DiagLevel::Warn:
+ e.warn(buf);
+ break;
+ case DiagLevel::Err:
+ e.error(buf);
+ break;
+ case DiagLevel::Fatal:
+ e.fatal(buf);
+ break;
+ }
+}
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f5d65d26ef4479..aebccc020030d3 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -547,6 +547,8 @@ struct Ctx {
LinkerScript *script;
std::unique_ptr<TargetInfo> target;
+ ErrorHandler *errHandler;
+
// These variables are initialized by Writer and should not be used before
// Writer is initialized.
uint8_t *bufferStart;
@@ -679,6 +681,39 @@ static inline void internalLinkerError(StringRef loc, const Twine &msg) {
llvm::getBugReportMsg());
}
+struct ELFSyncStream : SyncStream {
+ Ctx &ctx;
+ ELFSyncStream(Ctx &ctx, DiagLevel level)
+ : SyncStream(*ctx.errHandler, level), ctx(ctx) {}
+};
+
+template <typename T>
+std::enable_if_t<!std::is_pointer_v<std::remove_reference_t<T>>,
+ const ELFSyncStream &>
+operator<<(const ELFSyncStream &s, T &&v) {
+ s.os << std::forward<T>(v);
+ return s;
+}
+
+// Report a log if --verbose is specified.
+ELFSyncStream Log(Ctx &ctx);
+
+// Report a warning. Upgraded to an error if --fatal-warnings is specified.
+ELFSyncStream Warn(Ctx &ctx);
+
+// Report an error that will suppress the output file generation. Downgraded to
+// a warning if --noinhibit-exec is specified.
+ELFSyncStream Err(Ctx &ctx);
+
+// Report an error regardless of --noinhibit-exec.
+ELFSyncStream ErrAlways(Ctx &ctx);
+
+// Report a fatal error that exits immediately. This should generally be avoided
+// in favor of Err.
+ELFSyncStream Fatal(Ctx &ctx);
+
+uint64_t errCount(Ctx &ctx);
+
} // namespace lld::elf
#endif
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 0d7712f904dab8..aa123e9d11e5cf 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -91,6 +91,15 @@ void elf::errorOrWarn(const Twine &msg) {
error(msg);
}
+ELFSyncStream elf::Log(Ctx &ctx) { return {ctx, DiagLevel::Log}; }
+ELFSyncStream elf::Warn(Ctx &ctx) { return {ctx, DiagLevel::Warn}; }
+ELFSyncStream elf::Err(Ctx &ctx) {
+ return {ctx, ctx.arg.noinhibitExec ? DiagLevel::Warn : DiagLevel::Err};
+}
+ELFSyncStream elf::ErrAlways(Ctx &ctx) { return {ctx, DiagLevel::Err}; }
+ELFSyncStream elf::Fatal(Ctx &ctx) { return {ctx, DiagLevel::Fatal}; }
+uint64_t elf::errCount(Ctx &ctx) { return ctx.errHandler->errorCount; }
+
Ctx::Ctx() : driver(*this) {}
void Ctx::reset() {
@@ -101,6 +110,8 @@ void Ctx::reset() {
script = nullptr;
target.reset();
+ errHandler = nullptr;
+
bufferStart = nullptr;
mainPart = nullptr;
tlsPhdr = nullptr;
@@ -169,6 +180,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
Ctx &ctx = elf::ctx;
LinkerScript script(ctx);
ctx.script = &script;
+ ctx.errHandler = &context->e;
ctx.symAux.emplace_back();
ctx.symtab = std::make_unique<SymbolTable>(ctx);
@@ -179,7 +191,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
ctx.driver.linkerMain(args);
- return errorCount() == 0;
+ return errCount(ctx) == 0;
}
} // namespace elf
} // namespace lld
@@ -366,7 +378,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
files.push_back(createObjFile(ctx, mbref, "", inLib));
break;
default:
- error(path + ": unknown file type");
+ ErrAlways(ctx) << path << ": unknown file type";
}
}
@@ -2780,8 +2792,9 @@ static void readSecurityNotes(Ctx &ctx) {
if (ctx.arg.zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
if (ctx.arg.zBtiReport == "none")
- warn(toString(f) + ": -z force-bti: file does not have "
- "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
+ Warn(ctx) << f
+ << ": -z force-bti: file does not have "
+ "GNU_PROPERTY_AARCH64_FEATURE_1_BTI property";
} else if (ctx.arg.zForceIbt &&
!(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
if (ctx.arg.zCetReport == "none")
@@ -3048,7 +3061,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
oldFilenames.insert(f->getName());
for (InputFile *newFile : newInputFiles)
if (!oldFilenames.contains(newFile->getName()))
- errorOrWarn("input file '" + newFile->getName() + "' added after LTO");
+ Err(ctx) << "input file '" << newFile->getName() << "' added after LTO";
}
// Handle --exclude-libs again because lto.tmp may reference additional
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 0d3db373138874..e9a75b37026fd2 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -66,6 +66,12 @@ std::string lld::toString(const InputFile *f) {
return std::string(f->toStringCache);
}
+const ELFSyncStream &elf::operator<<(const ELFSyncStream &s,
+ const InputFile *f) {
+ s << toString(f);
+ return s;
+}
+
static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
unsigned char size;
unsigned char endian;
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index f80413b215047d..e00e2c83d017c2 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -386,6 +386,8 @@ ELFFileBase *createObjFile(Ctx &, MemoryBufferRef mb,
std::string replaceThinLTOSuffix(Ctx &, StringRef path);
+const ELFSyncStream &operator<<(const ELFSyncStream &, const InputFile *);
+
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 96d132a2a8f369..5d487b1673d925 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -45,6 +45,15 @@ std::string lld::toString(RelType type) {
return std::string(s);
}
+const ELFSyncStream &elf::operator<<(const ELFSyncStream &s, RelType type) {
+ StringRef buf = getELFRelocationTypeName(s.ctx.arg.emachine, type);
+ if (buf == "Unknown")
+ s << "Unknown (" << type << ')';
+ else
+ s << buf;
+ return s;
+}
+
void elf::setTarget(Ctx &ctx) {
switch (ctx.arg.emachine) {
case EM_386:
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 27986b0a127e8e..250a29d6184313 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -327,6 +327,8 @@ inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
*bufLoc = val;
return val;
}
+
+const ELFSyncStream &operator<<(const ELFSyncStream &, RelType);
} // namespace elf
} // namespace lld
diff --git a/lld/include/lld/Common/ErrorHandler.h b/lld/include/lld/Common/ErrorHandler.h
index 0b69bb6202b32c..b9858b0e26ece9 100644
--- a/lld/include/lld/Common/ErrorHandler.h
+++ b/lld/include/lld/Common/ErrorHandler.h
@@ -73,11 +73,11 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include <mutex>
namespace llvm {
class DiagnosticInfo;
-class raw_ostream;
}
namespace lld {
@@ -152,6 +152,21 @@ void message(const Twine &msg, llvm::raw_ostream &s = outs());
void warn(const Twine &msg);
uint64_t errorCount();
+enum class DiagLevel { Log, Warn, Err, Fatal };
+
+// A class that synchronizes thread writing to the same stream similar
+// std::osyncstream.
+class SyncStream {
+ ErrorHandler &e;
+ DiagLevel level;
+ std::string buf;
+
+public:
+ mutable llvm::raw_string_ostream os{buf};
+ SyncStream(ErrorHandler &e, DiagLevel level) : e(e), level(level) {}
+ ~SyncStream();
+};
+
[[noreturn]] void exitLld(int val);
void diagnosticHandler(const llvm::DiagnosticInfo &di);
More information about the llvm-commits
mailing list