Skip to content

Commit f2e92cf

Browse files
BertalanDnico
authored andcommitted
[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
1 parent cbcce82 commit f2e92cf

File tree

5 files changed

+70
-40
lines changed

5 files changed

+70
-40
lines changed

lld/MachO/SymbolTable.cpp

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -302,50 +302,78 @@ static void handleSegmentBoundarySymbol(const Undefined &sym, StringRef segName,
302302
seg->segmentEndSymbols.push_back(createBoundarySymbol(sym));
303303
}
304304

305-
void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
305+
// Try to find a definition for an undefined symbol.
306+
// Returns true if a definition was found and no diagnostics are needed.
307+
static bool recoverFromUndefinedSymbol(const Undefined &sym) {
306308
// Handle start/end symbols.
307309
StringRef name = sym.getName();
308-
if (name.consume_front("section$start$"))
309-
return handleSectionBoundarySymbol(sym, name, Boundary::Start);
310-
if (name.consume_front("section$end$"))
311-
return handleSectionBoundarySymbol(sym, name, Boundary::End);
312-
if (name.consume_front("segment$start$"))
313-
return handleSegmentBoundarySymbol(sym, name, Boundary::Start);
314-
if (name.consume_front("segment$end$"))
315-
return handleSegmentBoundarySymbol(sym, name, Boundary::End);
310+
if (name.consume_front("section$start$")) {
311+
handleSectionBoundarySymbol(sym, name, Boundary::Start);
312+
return true;
313+
}
314+
if (name.consume_front("section$end$")) {
315+
handleSectionBoundarySymbol(sym, name, Boundary::End);
316+
return true;
317+
}
318+
if (name.consume_front("segment$start$")) {
319+
handleSegmentBoundarySymbol(sym, name, Boundary::Start);
320+
return true;
321+
}
322+
if (name.consume_front("segment$end$")) {
323+
handleSegmentBoundarySymbol(sym, name, Boundary::End);
324+
return true;
325+
}
316326

317327
// Handle -U.
318328
if (config->explicitDynamicLookups.count(sym.getName())) {
319329
symtab->addDynamicLookup(sym.getName());
320-
return;
330+
return true;
321331
}
322332

323333
// Handle -undefined.
324-
auto message = [source, &sym]() {
325-
std::string message = "undefined symbol";
326-
if (config->archMultiple)
327-
message += (" for arch " + getArchitectureName(config->arch())).str();
328-
message += ": " + toString(sym);
329-
if (!source.empty())
330-
message += "\n>>> referenced by " + source.str();
331-
else
332-
message += "\n>>> referenced by " + toString(sym.getFile());
333-
return message;
334-
};
335-
switch (config->undefinedSymbolTreatment) {
336-
case UndefinedSymbolTreatment::error:
337-
error(message());
338-
break;
339-
case UndefinedSymbolTreatment::warning:
340-
warn(message());
341-
LLVM_FALLTHROUGH;
342-
case UndefinedSymbolTreatment::dynamic_lookup:
343-
case UndefinedSymbolTreatment::suppress:
334+
if (config->undefinedSymbolTreatment ==
335+
UndefinedSymbolTreatment::dynamic_lookup ||
336+
config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) {
344337
symtab->addDynamicLookup(sym.getName());
345-
break;
346-
case UndefinedSymbolTreatment::unknown:
347-
llvm_unreachable("unknown -undefined TREATMENT");
338+
return true;
348339
}
340+
341+
// We do not return true here, as we still need to print diagnostics.
342+
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning)
343+
symtab->addDynamicLookup(sym.getName());
344+
345+
return false;
346+
}
347+
348+
static void printUndefinedDiagnostic(StringRef name, StringRef source) {
349+
std::string message = "undefined symbol";
350+
if (config->archMultiple)
351+
message += (" for arch " + getArchitectureName(config->arch())).str();
352+
message += (": " + name + "\n>>> referenced by " + source).str();
353+
354+
if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error)
355+
error(message);
356+
else if (config->undefinedSymbolTreatment ==
357+
UndefinedSymbolTreatment::warning)
358+
warn(message);
359+
else
360+
assert(false && "diagnostics make sense for -undefined error|warning only");
361+
}
362+
363+
void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) {
364+
if (recoverFromUndefinedSymbol(sym))
365+
return;
366+
printUndefinedDiagnostic(sym.getName(), source);
367+
}
368+
369+
void lld::macho::treatUndefinedSymbol(const Undefined &sym,
370+
const InputSection *isec,
371+
uint64_t offset) {
372+
if (recoverFromUndefinedSymbol(sym))
373+
return;
374+
375+
// TODO: Get source file/line from debug information.
376+
printUndefinedDiagnostic(toString(sym), isec->getLocation(offset));
349377
}
350378

351379
std::unique_ptr<SymbolTable> macho::symtab;

lld/MachO/SymbolTable.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ class SymbolTable {
6969
std::vector<Symbol *> symVector;
7070
};
7171

72-
void treatUndefinedSymbol(const Undefined &, StringRef source = "");
72+
void treatUndefinedSymbol(const Undefined &, StringRef source);
73+
void treatUndefinedSymbol(const Undefined &, const InputSection *,
74+
uint64_t offset);
7375

7476
extern std::unique_ptr<SymbolTable> symtab;
7577

lld/MachO/UnwindInfoSection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ void UnwindInfoSectionImpl::prepareRelocations(ConcatInputSection *isec) {
273273
r.referent = s = sym;
274274
}
275275
if (auto *undefined = dyn_cast<Undefined>(s)) {
276-
treatUndefinedSymbol(*undefined);
276+
treatUndefinedSymbol(*undefined, isec, r.offset);
277277
// treatUndefinedSymbol() can replace s with a DylibSymbol; re-check.
278278
if (isa<Undefined>(s))
279279
continue;

lld/MachO/Writer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ void Writer::scanRelocations() {
659659
}
660660
if (auto *sym = r.referent.dyn_cast<Symbol *>()) {
661661
if (auto *undefined = dyn_cast<Undefined>(sym))
662-
treatUndefinedSymbol(*undefined);
662+
treatUndefinedSymbol(*undefined, isec, r.offset);
663663
// treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check.
664664
if (!isa<Undefined>(sym) && validateSymbolRelocation(sym, isec, r))
665665
prepareSymbolRelocation(sym, isec, r);

lld/test/MachO/invalid/undefined-symbol.s

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
55
# RUN: llvm-ar crs %t/foo.a %t/foo.o
66
# RUN: not %lld --icf=all -o /dev/null %t/main.o 2>&1 | \
7-
# RUN: FileCheck %s -DSYM=_foo -DFILENAME=%t/main.o
7+
# RUN: FileCheck %s -DSYM=_foo -DLOC='%t/main.o:(symbol _main+0x1)'
88
# RUN: not %lld -o /dev/null %t/main.o %t/foo.a 2>&1 | \
9-
# RUN: FileCheck %s -DSYM=_bar -DFILENAME='%t/foo.a(foo.o)'
9+
# RUN: FileCheck %s -DSYM=_bar -DLOC='%t/foo.a(foo.o):(symbol _foo+0x1)'
1010
# RUN: not %lld -o /dev/null %t/main.o -force_load %t/foo.a 2>&1 | \
11-
# RUN: FileCheck %s -DSYM=_bar -DFILENAME='%t/foo.a(foo.o)'
11+
# RUN: FileCheck %s -DSYM=_bar -DLOC='%t/foo.a(foo.o):(symbol _foo+0x1)'
1212
# CHECK: error: undefined symbol: [[SYM]]
13-
# CHECK-NEXT: >>> referenced by [[FILENAME]]
13+
# CHECK-NEXT: >>> referenced by [[LOC]]
1414

1515
#--- foo.s
1616
.globl _foo

0 commit comments

Comments
 (0)