Reland "[lld-macho] Group undefined symbol diagnostics by symbol".

This reverts commit 36e7c9a450.

This relands d61341768c with the fix described in
https://reviews.llvm.org/D127753#3587390
This commit is contained in:
Daniel Bertalan 2022-06-15 19:17:07 -04:00 committed by Nico Weber
parent 20d5a86134
commit 0eec7e2a89
5 changed files with 104 additions and 22 deletions

View file

@ -558,6 +558,7 @@ static std::string maybeReportDiscarded(Undefined &sym) {
return msg;
}
namespace {
// Undefined diagnostics are collected in a vector and emitted once all of
// them are known, so that some postprocessing on the list of undefined symbols
// can happen before lld emits diagnostics.
@ -571,7 +572,8 @@ struct UndefinedDiag {
bool isWarning;
};
static std::vector<UndefinedDiag> undefs;
std::vector<UndefinedDiag> undefs;
}
// Check whether the definition name def is a mangled function name that matches
// the reference name ref.

View file

@ -345,35 +345,82 @@ static bool recoverFromUndefinedSymbol(const Undefined &sym) {
return false;
}
static void printUndefinedDiagnostic(StringRef name, StringRef source) {
std::string message = "undefined symbol";
if (config->archMultiple)
message += (" for arch " + getArchitectureName(config->arch())).str();
message += (": " + name + "\n>>> referenced by " + source).str();
namespace {
struct UndefinedDiag {
struct SectionAndOffset {
const InputSection *isec;
uint64_t offset;
};
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error)
error(message);
else if (config->undefinedSymbolTreatment ==
UndefinedSymbolTreatment::warning)
warn(message);
else
assert(false && "diagnostics make sense for -undefined error|warning only");
std::vector<SectionAndOffset> codeReferences;
std::vector<std::string> otherReferences;
};
MapVector<const Undefined *, UndefinedDiag> undefs;
}
void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
if (recoverFromUndefinedSymbol(sym))
return;
printUndefinedDiagnostic(sym.getName(), source);
void macho::reportPendingUndefinedSymbols() {
for (const auto &undef : undefs) {
const UndefinedDiag &locations = undef.second;
std::string message = "undefined symbol";
if (config->archMultiple)
message += (" for arch " + getArchitectureName(config->arch())).str();
message += ": " + toString(*undef.first);
const size_t maxUndefinedReferences = 3;
size_t i = 0;
for (const std::string &loc : locations.otherReferences) {
if (i >= maxUndefinedReferences)
break;
message += "\n>>> referenced by " + loc;
++i;
}
for (const UndefinedDiag::SectionAndOffset &loc :
locations.codeReferences) {
if (i >= maxUndefinedReferences)
break;
// TODO: Get source file/line from debug information.
message += "\n>>> referenced by " + loc.isec->getLocation(loc.offset);
++i;
}
size_t totalReferences =
locations.otherReferences.size() + locations.codeReferences.size();
if (totalReferences > i)
message +=
("\n>>> referenced " + Twine(totalReferences - i) + " more times")
.str();
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error)
error(message);
else if (config->undefinedSymbolTreatment ==
UndefinedSymbolTreatment::warning)
warn(message);
else
assert(false &&
"diagnostics make sense for -undefined error|warning only");
}
// This function is called multiple times during execution. Clear the printed
// diagnostics to avoid printing the same things again the next time.
undefs.clear();
}
void lld::macho::treatUndefinedSymbol(const Undefined &sym,
const InputSection *isec,
uint64_t offset) {
void macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
if (recoverFromUndefinedSymbol(sym))
return;
// TODO: Get source file/line from debug information.
printUndefinedDiagnostic(toString(sym), isec->getLocation(offset));
undefs[&sym].otherReferences.push_back(source.str());
}
void macho::treatUndefinedSymbol(const Undefined &sym, const InputSection *isec,
uint64_t offset) {
if (recoverFromUndefinedSymbol(sym))
return;
undefs[&sym].codeReferences.push_back({isec, offset});
}
std::unique_ptr<SymbolTable> macho::symtab;

View file

@ -69,6 +69,9 @@ private:
std::vector<Symbol *> symVector;
};
void reportPendingUndefinedSymbols();
// Call reportPendingUndefinedSymbols() to emit diagnostics.
void treatUndefinedSymbol(const Undefined &, StringRef source);
void treatUndefinedSymbol(const Undefined &, const InputSection *,
uint64_t offset);

View file

@ -1133,6 +1133,7 @@ void Writer::writeCodeSignature() {
void Writer::writeOutputFile() {
TimeTraceScope timeScope("Write output file");
openFile();
reportPendingUndefinedSymbols();
if (errorCount())
return;
writeSections();
@ -1155,6 +1156,7 @@ template <class LP> void Writer::run() {
scanRelocations();
// Do not proceed if there was an undefined symbol.
reportPendingUndefinedSymbols();
if (errorCount())
return;

View file

@ -0,0 +1,28 @@
# REQUIRES: aarch64
# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
# RUN: not %lld -arch arm64 %t.o -o /dev/null 2>&1 | FileCheck -DFILE=%t.o %s
# CHECK: error: undefined symbol: _undef
# CHECK-NEXT: >>> referenced by [[FILE]]:(symbol _main+0x0)
# CHECK-NEXT: >>> referenced by [[FILE]]:(symbol _foo+0x0)
# CHECK-NEXT: >>> referenced by [[FILE]]:(symbol _bar+0x0)
# CHECK-NEXT: >>> referenced 1 more times
.globl _main
_main:
b _undef
.globl _foo
_foo:
b _undef
.global _bar
_bar:
b _undef
.globl _baz
_baz:
b _undef
.subsections_via_symbols