-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[ELF] Add context-aware diagnostic functions #112319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the intention that all errors are now errorOrWarn, it looks we currently have error and errorOrWarn. I can see error being useful for conditions where the output file is always going to be broken, but we can complete the link with diagnostics. The errorOrWarn can be for when the output is likely broken, or some standard has been broken. FatalError can be used if we're going crash if we keep going. This isn't a strong distinction so I can see it being worthwhile to merge so that more diagnostics can become warnings if needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree with the above. I think we should add a comment before these 4 functions, to explain in which situation they should be used, and what are the expectations. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We prefer I agree that we need a replacement for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If Alternatives: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adopted Sorry that I just realized that I did not update this yet. |
||
|
||
// 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is great, it looks much better! |
||
<< ": -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 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the plan to replace these error methods with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For ELF, the intention is yes. Perhaps this "deprecation" notice can be added once another port decides to follow ELF? |
||
|
||
enum class DiagLevel { Log, Warn, Err, Fatal }; | ||
|
||
// A class that synchronizes thread writing to the same stream similar | ||
// std::osyncstream. | ||
class SyncStream { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious what the "Sync" part means here? Can we come up with a more meaningful name? Something that signifies this relates to logging/error output maybe? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name |
||
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); | ||
|
Uh oh!
There was an error while loading. Please reload this page.