Skip to content

Commit dccc00a

Browse files
committed
[ELF] Add context-aware diagnostic functions
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)`.) Pull Request: #112319
1 parent ac9ee61 commit dccc00a

File tree

8 files changed

+102
-5
lines changed

8 files changed

+102
-5
lines changed

lld/Common/ErrorHandler.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,21 @@ void ErrorHandler::fatal(const Twine &msg) {
335335
error(msg);
336336
exitLld(1);
337337
}
338+
339+
SyncStream::~SyncStream() {
340+
os.flush();
341+
switch (level) {
342+
case DiagLevel::Log:
343+
e.log(buf);
344+
break;
345+
case DiagLevel::Warn:
346+
e.warn(buf);
347+
break;
348+
case DiagLevel::Err:
349+
e.error(buf);
350+
break;
351+
case DiagLevel::Fatal:
352+
e.fatal(buf);
353+
break;
354+
}
355+
}

lld/ELF/Config.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,8 @@ struct Ctx {
547547
LinkerScript *script;
548548
std::unique_ptr<TargetInfo> target;
549549

550+
ErrorHandler *errHandler;
551+
550552
// These variables are initialized by Writer and should not be used before
551553
// Writer is initialized.
552554
uint8_t *bufferStart;
@@ -679,6 +681,37 @@ static inline void internalLinkerError(StringRef loc, const Twine &msg) {
679681
llvm::getBugReportMsg());
680682
}
681683

684+
struct ELFSyncStream : SyncStream {
685+
Ctx &ctx;
686+
ELFSyncStream(Ctx &ctx, DiagLevel level)
687+
: SyncStream(*ctx.errHandler, level), ctx(ctx) {}
688+
};
689+
690+
template <typename T>
691+
std::enable_if_t<!std::is_pointer_v<std::remove_reference_t<T>>,
692+
const ELFSyncStream &>
693+
operator<<(const ELFSyncStream &s, T &&v) {
694+
s.os << std::forward<T>(v);
695+
return s;
696+
}
697+
698+
// Report a log if --verbose is specified.
699+
ELFSyncStream Log(Ctx &ctx);
700+
701+
// Report a warning. Upgraded to an error if --fatal-warnings is specified.
702+
ELFSyncStream Warn(Ctx &ctx);
703+
704+
// Report an error that will suppress the output file generation. Downgraded to
705+
// a warning if --noinhibit-exec is specified.
706+
ELFSyncStream Err(Ctx &ctx);
707+
708+
// Report an error regardless of --noinhibit-exec.
709+
ELFSyncStream ErrAlways(Ctx &ctx);
710+
711+
// Report a fatal error that exits immediately. This should generally be avoided
712+
// in favor of Err.
713+
ELFSyncStream Fatal(Ctx &ctx);
714+
682715
} // namespace lld::elf
683716

684717
#endif

lld/ELF/Driver.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ void elf::errorOrWarn(const Twine &msg) {
9191
error(msg);
9292
}
9393

94+
ELFSyncStream elf::Log(Ctx &ctx) { return {ctx, DiagLevel::Log}; }
95+
ELFSyncStream elf::Warn(Ctx &ctx) { return {ctx, DiagLevel::Warn}; }
96+
ELFSyncStream elf::Err(Ctx &ctx) {
97+
return {ctx, ctx.arg.noinhibitExec ? DiagLevel::Warn : DiagLevel::Err};
98+
}
99+
ELFSyncStream elf::ErrAlways(Ctx &ctx) { return {ctx, DiagLevel::Err}; }
100+
ELFSyncStream elf::Fatal(Ctx &ctx) { return {ctx, DiagLevel::Fatal}; }
101+
94102
Ctx::Ctx() : driver(*this) {}
95103

96104
void Ctx::reset() {
@@ -101,6 +109,8 @@ void Ctx::reset() {
101109
script = nullptr;
102110
target.reset();
103111

112+
errHandler = nullptr;
113+
104114
bufferStart = nullptr;
105115
mainPart = nullptr;
106116
tlsPhdr = nullptr;
@@ -169,6 +179,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
169179
Ctx &ctx = elf::ctx;
170180
LinkerScript script(ctx);
171181
ctx.script = &script;
182+
ctx.errHandler = &context->e;
172183
ctx.symAux.emplace_back();
173184
ctx.symtab = std::make_unique<SymbolTable>(ctx);
174185

@@ -366,7 +377,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
366377
files.push_back(createObjFile(ctx, mbref, "", inLib));
367378
break;
368379
default:
369-
error(path + ": unknown file type");
380+
ErrAlways(ctx) << path << ": unknown file type";
370381
}
371382
}
372383

@@ -2780,8 +2791,9 @@ static void readSecurityNotes(Ctx &ctx) {
27802791
if (ctx.arg.zForceBti && !(features & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)) {
27812792
features |= GNU_PROPERTY_AARCH64_FEATURE_1_BTI;
27822793
if (ctx.arg.zBtiReport == "none")
2783-
warn(toString(f) + ": -z force-bti: file does not have "
2784-
"GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
2794+
Warn(ctx) << f
2795+
<< ": -z force-bti: file does not have "
2796+
"GNU_PROPERTY_AARCH64_FEATURE_1_BTI property";
27852797
} else if (ctx.arg.zForceIbt &&
27862798
!(features & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
27872799
if (ctx.arg.zCetReport == "none")
@@ -3048,7 +3060,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
30483060
oldFilenames.insert(f->getName());
30493061
for (InputFile *newFile : newInputFiles)
30503062
if (!oldFilenames.contains(newFile->getName()))
3051-
errorOrWarn("input file '" + newFile->getName() + "' added after LTO");
3063+
Err(ctx) << "input file '" << newFile->getName() << "' added after LTO";
30523064
}
30533065

30543066
// Handle --exclude-libs again because lto.tmp may reference additional

lld/ELF/InputFiles.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ std::string lld::toString(const InputFile *f) {
6666
return std::string(f->toStringCache);
6767
}
6868

69+
const ELFSyncStream &elf::operator<<(const ELFSyncStream &s,
70+
const InputFile *f) {
71+
s << toString(f);
72+
return s;
73+
}
74+
6975
static ELFKind getELFKind(MemoryBufferRef mb, StringRef archiveName) {
7076
unsigned char size;
7177
unsigned char endian;

lld/ELF/InputFiles.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ ELFFileBase *createObjFile(Ctx &, MemoryBufferRef mb,
386386

387387
std::string replaceThinLTOSuffix(Ctx &, StringRef path);
388388

389+
const ELFSyncStream &operator<<(const ELFSyncStream &, const InputFile *);
390+
389391
} // namespace elf
390392
} // namespace lld
391393

lld/ELF/Target.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ std::string lld::toString(RelType type) {
4545
return std::string(s);
4646
}
4747

48+
const ELFSyncStream &elf::operator<<(const ELFSyncStream &s, RelType type) {
49+
StringRef buf = getELFRelocationTypeName(s.ctx.arg.emachine, type);
50+
if (buf == "Unknown")
51+
s << ("Unknown (" + Twine(type) + ")").str();
52+
else
53+
s << buf;
54+
return s;
55+
}
56+
4857
void elf::setTarget(Ctx &ctx) {
4958
switch (ctx.arg.emachine) {
5059
case EM_386:

lld/ELF/Target.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
327327
*bufLoc = val;
328328
return val;
329329
}
330+
331+
const ELFSyncStream &operator<<(const ELFSyncStream &, RelType);
330332
} // namespace elf
331333
} // namespace lld
332334

lld/include/lld/Common/ErrorHandler.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@
7373
#include "llvm/ADT/STLExtras.h"
7474
#include "llvm/Support/Error.h"
7575
#include "llvm/Support/FileOutputBuffer.h"
76+
#include "llvm/Support/raw_ostream.h"
7677
#include <mutex>
7778

7879
namespace llvm {
7980
class DiagnosticInfo;
80-
class raw_ostream;
8181
}
8282

8383
namespace lld {
@@ -152,6 +152,21 @@ void message(const Twine &msg, llvm::raw_ostream &s = outs());
152152
void warn(const Twine &msg);
153153
uint64_t errorCount();
154154

155+
enum class DiagLevel { Log, Warn, Err, Fatal };
156+
157+
// A class that synchronizes thread writing to the same stream similar
158+
// std::osyncstream.
159+
class SyncStream {
160+
ErrorHandler &e;
161+
DiagLevel level;
162+
std::string buf;
163+
164+
public:
165+
mutable llvm::raw_string_ostream os{buf};
166+
SyncStream(ErrorHandler &e, DiagLevel level) : e(e), level(level) {}
167+
~SyncStream();
168+
};
169+
155170
[[noreturn]] void exitLld(int val);
156171

157172
void diagnosticHandler(const llvm::DiagnosticInfo &di);

0 commit comments

Comments
 (0)