forked from OSchip/llvm-project
[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:
parent
cbcce82ef6
commit
f2e92cf60e
|
@ -302,50 +302,78 @@ static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
|
||||||
seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
|
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.
|
// Handle start/end symbols.
|
||||||
StringRef name = sym.getName();
|
StringRef name = sym.getName();
|
||||||
if (name.consume_front("section$start$"))
|
if (name.consume_front("section$start$")) {
|
||||||
return handleSectionBoundarySymbol(sym, name, Boundary::Start);
|
handleSectionBoundarySymbol(sym, name, Boundary::Start);
|
||||||
if (name.consume_front("section$end$"))
|
return true;
|
||||||
return handleSectionBoundarySymbol(sym, name, Boundary::End);
|
}
|
||||||
if (name.consume_front("segment$start$"))
|
if (name.consume_front("section$end$")) {
|
||||||
return handleSegmentBoundarySymbol(sym, name, Boundary::Start);
|
handleSectionBoundarySymbol(sym, name, Boundary::End);
|
||||||
if (name.consume_front("segment$end$"))
|
return true;
|
||||||
return handleSegmentBoundarySymbol(sym, name, Boundary::End);
|
}
|
||||||
|
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.
|
// Handle -U.
|
||||||
if (config->explicitDynamicLookups.count(sym.getName())) {
|
if (config->explicitDynamicLookups.count(sym.getName())) {
|
||||||
symtab->addDynamicLookup(sym.getName());
|
symtab->addDynamicLookup(sym.getName());
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle -undefined.
|
// Handle -undefined.
|
||||||
auto message = [source, &sym]() {
|
if (config->undefinedSymbolTreatment ==
|
||||||
std::string message = "undefined symbol";
|
UndefinedSymbolTreatment::dynamic_lookup ||
|
||||||
if (config->archMultiple)
|
config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) {
|
||||||
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:
|
|
||||||
symtab->addDynamicLookup(sym.getName());
|
symtab->addDynamicLookup(sym.getName());
|
||||||
break;
|
return true;
|
||||||
case UndefinedSymbolTreatment::unknown:
|
|
||||||
llvm_unreachable("unknown -undefined TREATMENT");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
std::unique_ptr<SymbolTable> macho::symtab;
|
||||||
|
|
|
@ -69,7 +69,9 @@ private:
|
||||||
std::vector<Symbol *> symVector;
|
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;
|
extern std::unique_ptr<SymbolTable> symtab;
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
|
||||||
r.referent = s = sym;
|
r.referent = s = sym;
|
||||||
}
|
}
|
||||||
if (auto *undefined = dyn_cast<Undefined>(s)) {
|
if (auto *undefined = dyn_cast<Undefined>(s)) {
|
||||||
treatUndefinedSymbol(*undefined);
|
treatUndefinedSymbol(*undefined, isec, r.offset);
|
||||||
// treatUndefinedSymbol() can replace s with a DylibSymbol; re-check.
|
// treatUndefinedSymbol() can replace s with a DylibSymbol; re-check.
|
||||||
if (isa<Undefined>(s))
|
if (isa<Undefined>(s))
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -659,7 +659,7 @@ void Writer::scanRelocations() {
|
||||||
}
|
}
|
||||||
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
|
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
|
||||||
if (auto *undefined = dyn_cast<Undefined>(sym))
|
if (auto *undefined = dyn_cast<Undefined>(sym))
|
||||||
treatUndefinedSymbol(*undefined);
|
treatUndefinedSymbol(*undefined, isec, r.offset);
|
||||||
// treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check.
|
// treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check.
|
||||||
if (!isa<Undefined>(sym) && validateSymbolRelocation(sym, isec, r))
|
if (!isa<Undefined>(sym) && validateSymbolRelocation(sym, isec, r))
|
||||||
prepareSymbolRelocation(sym, isec, r);
|
prepareSymbolRelocation(sym, isec, r);
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
|
# 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: llvm-ar crs %t/foo.a %t/foo.o
|
||||||
# RUN: not %lld --icf=all -o /dev/null %t/main.o 2>&1 | \
|
# 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: 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: 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: error: undefined symbol: [[SYM]]
|
||||||
# CHECK-NEXT: >>> referenced by [[FILENAME]]
|
# CHECK-NEXT: >>> referenced by [[LOC]]
|
||||||
|
|
||||||
#--- foo.s
|
#--- foo.s
|
||||||
.globl _foo
|
.globl _foo
|
||||||
|
|
Loading…
Reference in New Issue