[lld-macho] Print the name of functions containing undefined references

The error used to look like this:

  ld64.lld: error: undefined symbol: _foo
  >>> referenced by /path/to/bar.o

Now it displays the name of the function that contains the undefined
reference as well:

  ld64.lld: error: undefined symbol: _foo
  >>> referenced by /path/to/bar.o:(symbol _baz+0x4)

Differential Revision: https://reviews.llvm.org/D127696
This commit is contained in:
Daniel Bertalan 2022-06-14 09:41:28 -04:00 committed by Nico Weber
parent cbcce82ef6
commit f2e92cf60e
5 changed files with 70 additions and 40 deletions

View file

@ -302,50 +302,78 @@ static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
}
void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
// Try to find a definition for an undefined symbol.
// Returns true if a definition was found and no diagnostics are needed.
static bool recoverFromUndefinedSymbol(const Undefined &sym) {
// Handle start/end symbols.
StringRef name = sym.getName();
if (name.consume_front("section$start$"))
return handleSectionBoundarySymbol(sym, name, Boundary::Start);
if (name.consume_front("section$end$"))
return handleSectionBoundarySymbol(sym, name, Boundary::End);
if (name.consume_front("segment$start$"))
return handleSegmentBoundarySymbol(sym, name, Boundary::Start);
if (name.consume_front("segment$end$"))
return handleSegmentBoundarySymbol(sym, name, Boundary::End);
if (name.consume_front("section$start$")) {
handleSectionBoundarySymbol(sym, name, Boundary::Start);
return true;
}
if (name.consume_front("section$end$")) {
handleSectionBoundarySymbol(sym, name, Boundary::End);
return true;
}
if (name.consume_front("segment$start$")) {
handleSegmentBoundarySymbol(sym, name, Boundary::Start);
return true;
}
if (name.consume_front("segment$end$")) {
handleSegmentBoundarySymbol(sym, name, Boundary::End);
return true;
}
// Handle -U.
if (config->explicitDynamicLookups.count(sym.getName())) {
symtab->addDynamicLookup(sym.getName());
return;
return true;
}
// Handle -undefined.
auto message = [source, &sym]() {
std::string message = "undefined symbol";
if (config->archMultiple)
message += (" for arch " + getArchitectureName(config->arch())).str();
message += ": " + toString(sym);
if (!source.empty())
message += "\n>>> referenced by " + source.str();
else
message += "\n>>> referenced by " + toString(sym.getFile());
return message;
};
switch (config->undefinedSymbolTreatment) {
case UndefinedSymbolTreatment::error:
error(message());
break;
case UndefinedSymbolTreatment::warning:
warn(message());
LLVM_FALLTHROUGH;
case UndefinedSymbolTreatment::dynamic_lookup:
case UndefinedSymbolTreatment::suppress:
if (config->undefinedSymbolTreatment ==
UndefinedSymbolTreatment::dynamic_lookup ||
config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) {
symtab->addDynamicLookup(sym.getName());
break;
case UndefinedSymbolTreatment::unknown:
llvm_unreachable("unknown -undefined TREATMENT");
return true;
}
// We do not return true here, as we still need to print diagnostics.
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning)
symtab->addDynamicLookup(sym.getName());
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();
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");
}
void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
if (recoverFromUndefinedSymbol(sym))
return;
printUndefinedDiagnostic(sym.getName(), source);
}
void lld::macho::treatUndefinedSymbol(const Undefined &sym,
const InputSection *isec,
uint64_t offset) {
if (recoverFromUndefinedSymbol(sym))
return;
// TODO: Get source file/line from debug information.
printUndefinedDiagnostic(toString(sym), isec->getLocation(offset));
}
std::unique_ptr<SymbolTable> macho::symtab;

View file

@ -69,7 +69,9 @@ private:
std::vector<Symbol *> symVector;
};
void treatUndefinedSymbol(const Undefined &, StringRef source = "");
void treatUndefinedSymbol(const Undefined &, StringRef source);
void treatUndefinedSymbol(const Undefined &, const InputSection *,
uint64_t offset);
extern std::unique_ptr<SymbolTable> symtab;

View file

@ -273,7 +273,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
r.referent = s = sym;
}
if (auto *undefined = dyn_cast<Undefined>(s)) {
treatUndefinedSymbol(*undefined);
treatUndefinedSymbol(*undefined, isec, r.offset);
// treatUndefinedSymbol() can replace s with a DylibSymbol; re-check.
if (isa<Undefined>(s))
continue;

View file

@ -659,7 +659,7 @@ void Writer::scanRelocations() {
}
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
if (auto *undefined = dyn_cast<Undefined>(sym))
treatUndefinedSymbol(*undefined);
treatUndefinedSymbol(*undefined, isec, r.offset);
// treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check.
if (!isa<Undefined>(sym) && validateSymbolRelocation(sym, isec, r))
prepareSymbolRelocation(sym, isec, r);

View file

@ -4,13 +4,13 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
# RUN: llvm-ar crs %t/foo.a %t/foo.o
# RUN: not %lld --icf=all -o /dev/null %t/main.o 2>&1 | \
# RUN: FileCheck %s -DSYM=_foo -DFILENAME=%t/main.o
# RUN: FileCheck %s -DSYM=_foo -DLOC='%t/main.o:(symbol _main+0x1)'
# RUN: not %lld -o /dev/null %t/main.o %t/foo.a 2>&1 | \
# RUN: FileCheck %s -DSYM=_bar -DFILENAME='%t/foo.a(foo.o)'
# RUN: FileCheck %s -DSYM=_bar -DLOC='%t/foo.a(foo.o):(symbol _foo+0x1)'
# RUN: not %lld -o /dev/null %t/main.o -force_load %t/foo.a 2>&1 | \
# RUN: FileCheck %s -DSYM=_bar -DFILENAME='%t/foo.a(foo.o)'
# RUN: FileCheck %s -DSYM=_bar -DLOC='%t/foo.a(foo.o):(symbol _foo+0x1)'
# CHECK: error: undefined symbol: [[SYM]]
# CHECK-NEXT: >>> referenced by [[FILENAME]]
# CHECK-NEXT: >>> referenced by [[LOC]]
#--- foo.s
.globl _foo