Index: ELF/Error.h =================================================================== --- ELF/Error.h +++ ELF/Error.h @@ -37,8 +37,10 @@ void log(const Twine &Msg); void warn(const Twine &Msg); +void warn(const Twine &Source, const Twine &Msg); void error(const Twine &Msg); +void error(const Twine &Source, const Twine &Msg); void error(std::error_code EC, const Twine &Prefix); template void error(const ErrorOr &V, const Twine &Prefix) { Index: ELF/Error.cpp =================================================================== --- ELF/Error.cpp +++ ELF/Error.cpp @@ -27,15 +27,24 @@ outs() << Argv0 << ": " << Msg << "\n"; } -void elf::warn(const Twine &Msg) { +static void output(const Twine &Type, const Twine &Source, const Twine &Msg) { + *elf::ErrorOS << elf::Argv0 << ": " << Source << ": " << Type << ": " << Msg + << "\n"; +} + +void elf::warn(const Twine &Msg) { warn(Twine(), Msg); } + +void elf::warn(const Twine &Source, const Twine &Msg) { if (Config->FatalWarnings) - error(Msg); + error(Source, Msg); else - *ErrorOS << Argv0 << ": warning: " << Msg << "\n"; + output("warning", Source, Msg); } -void elf::error(const Twine &Msg) { - *ErrorOS << Argv0 << ": error: " << Msg << "\n"; +void elf::error(const Twine &Msg) { error(Twine(), Msg); } + +void elf::error(const Twine &Source, const Twine &Msg) { + output("error", Source, Msg); HasError = true; } @@ -44,7 +53,7 @@ } void elf::fatal(const Twine &Msg) { - *ErrorOS << Argv0 << ": error: " << Msg << "\n"; + output("error", Twine(), Msg); exit(1); } Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -175,6 +175,9 @@ // R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations. uint32_t getMipsGp0() const; + // Gets symbol which encloses given offset and belongs to given section + DefinedRegular *getSymbolAt(InputSectionBase *S, uintX_t Offset); + // The number is the offset in the string table. It will be used as the // st_name of the symbol. std::vector *, unsigned>> KeptLocalSyms; @@ -183,6 +186,11 @@ // using this buffer. llvm::BumpPtrAllocator Alloc; + // Name of source file obtained from STT_FILE symbol value, + // or empty string if there is no such symbol in object file + // symbol table. + StringRef SourceFile; + private: void initializeSections(llvm::DenseSet &ComdatGroups); void initializeSymbols(); Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -402,6 +402,18 @@ SymbolBodies.push_back(createSymbolBody(&Sym)); } +// Find symbol that encloses given offset. Used for error reporting. +template +DefinedRegular * +elf::ObjectFile::getSymbolAt(InputSectionBase *S, uintX_t Offset) { + for (SymbolBody *B : SymbolBodies) + if (auto *D = dyn_cast>(B)) + if (D->Value <= Offset && D->Value + D->Size > Offset && D->Section == S) + return D; + + return nullptr; +} + template InputSectionBase * elf::ObjectFile::getSection(const Elf_Sym &Sym) const { @@ -431,6 +443,8 @@ int Binding = Sym->getBinding(); InputSectionBase *Sec = getSection(*Sym); if (Binding == STB_LOCAL) { + if (Sym->getType() == STT_FILE) + SourceFile = check(Sym->getName(this->StringTable)); if (Sym->st_shndx == SHN_UNDEF) return new (this->Alloc) Undefined(Sym->st_name, Sym->st_other, Sym->getType(), this); Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -522,7 +522,31 @@ return Addend; } -static void reportUndefined(SymbolBody &Sym) { +template +static std::string getLocation(SymbolBody &Sym, InputSectionBase &S, + typename ELFT::uint Offset) { + ObjectFile *File = S.getFile(); + std::string SrcFile = File->SourceFile; + + // If don't have STT_FILE typed symbol in object file then + // use object file name. + if (SrcFile.empty()) + SrcFile = Sym.File ? getFilename(Sym.File) : getFilename(File); + + DefinedRegular *Encl = File->getSymbolAt(&S, Offset); + if (Encl && Encl->Type == STT_FUNC) { + StringRef Func = getSymbolName(*File, *Encl); + return SrcFile + " (function " + + (Config->Demangle ? demangle(Func) : Func.str()) + ")"; + } + + return (SrcFile + " (" + S.Name + "+0x" + Twine::utohexstr(Offset) + ")") + .str(); +} + +template +static void reportUndefined(SymbolBody &Sym, InputSectionBase &S, + typename ELFT::uint Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore) return; @@ -530,15 +554,15 @@ Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef) return; - std::string Msg = "undefined symbol: "; - Msg += Config->Demangle ? demangle(Sym.getName()) : Sym.getName().str(); + std::string Location = getLocation(Sym, S, Offset); + std::string Msg = + "undefined symbol '" + + (Config->Demangle ? demangle(Sym.getName()) : Sym.getName().str()) + "'"; - if (Sym.File) - Msg += " in " + getFilename(Sym.File); if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn) - warn(Msg); + warn(Location, Msg); else - error(Msg); + error(Location, Msg); } // The reason we have to do this early scan is as follows @@ -583,7 +607,7 @@ // We only report undefined symbols if they are referenced somewhere in the // code. if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak()) - reportUndefined(Body); + reportUndefined(Body, C, RI.r_offset); RelExpr Expr = Target->getRelExpr(Type, Body); bool Preemptible = isPreemptible(Body, Type); Index: test/ELF/libsearch.s =================================================================== --- test/ELF/libsearch.s +++ test/ELF/libsearch.s @@ -22,7 +22,7 @@ // Should not link because of undefined symbol _bar // RUN: not ld.lld -o %t3 %t.o %tbar.o 2>&1 \ // RUN: | FileCheck --check-prefix=UNDEFINED %s -// UNDEFINED: undefined symbol: _bar +// UNDEFINED: (.bar+0x0): error: undefined symbol '_bar' // Should fail if cannot find specified library (without -L switch) // RUN: not ld.lld -o %t3 %t.o -lls 2>&1 \ Index: test/ELF/linkerscript/edata-etext.s =================================================================== --- test/ELF/linkerscript/edata-etext.s +++ test/ELF/linkerscript/edata-etext.s @@ -2,9 +2,9 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS { }" > %t.script # RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s -# CHECK: undefined symbol: _edata -# CHECK: undefined symbol: _etext -# CHECK: undefined symbol: _end +# CHECK: (.text+0x0): error: undefined symbol '_edata' +# CHECK: (.text+0x8): error: undefined symbol '_etext' +# CHECK: (.text+0x10): error: undefined symbol '_end' .global _start,_end,_etext,_edata .text Index: test/ELF/linkerscript/ehdr_start.s =================================================================== --- test/ELF/linkerscript/ehdr_start.s +++ test/ELF/linkerscript/ehdr_start.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: echo "SECTIONS { }" > %t.script # RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s -# CHECK: undefined symbol: __ehdr_start +# CHECK: (.text+0x0): error: undefined symbol '__ehdr_start' .text .global _start, __ehdr_start Index: test/ELF/lto/combined-lto-object-name.ll =================================================================== --- test/ELF/lto/combined-lto-object-name.ll +++ test/ELF/lto/combined-lto-object-name.ll @@ -11,4 +11,4 @@ ret void } -; CHECK: undefined symbol: foo in {{.*}}combined-lto-object-name.ll.tmp.o +; CHECK: ld-temp.o (function _start): error: undefined symbol 'foo' Index: test/ELF/sysroot.s =================================================================== --- test/ELF/sysroot.s +++ test/ELF/sysroot.s @@ -9,7 +9,7 @@ // Should not link because of undefined symbol _bar // RUN: not ld.lld -o %t/r %t/m.o 2>&1 \ // RUN: | FileCheck --check-prefix=UNDEFINED %s -// UNDEFINED: undefined symbol: _bar +// UNDEFINED: (.text+0x1): error: undefined symbol '_bar' // We need to be sure that there is no suitable library in the /lib directory // RUN: not ld.lld -o %t/r %t/m.o -L/lib -l:libls.a 2>&1 \ Index: test/ELF/tls-static.s =================================================================== --- test/ELF/tls-static.s +++ test/ELF/tls-static.s @@ -10,4 +10,4 @@ _start: call __tls_get_addr -// CHECK: undefined symbol: __tls_get_addr +// CHECK: (.text+0x1): error: undefined symbol '__tls_get_addr' Index: test/ELF/undef-shared.s =================================================================== --- test/ELF/undef-shared.s +++ test/ELF/undef-shared.s @@ -1,15 +1,15 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s -# CHECK: undefined symbol: hidden in {{.*}} +# CHECK: {{.*}} (.data+0x0): error: undefined symbol 'hidden' .global hidden .hidden hidden -# CHECK: undefined symbol: internal in {{.*}} +# CHECK: {{.*}} (.data+0x8): error: undefined symbol 'internal' .global internal .internal internal -# CHECK: undefined symbol: protected in {{.*}} +# CHECK: {{.*}} (.data+0x10): error: undefined symbol 'protected' .global protected .protected protected Index: test/ELF/undef.s =================================================================== --- test/ELF/undef.s +++ test/ELF/undef.s @@ -4,14 +4,16 @@ # RUN: llvm-ar rc %t2.a %t2.o # RUN: not ld.lld %t.o %t2.a -o %t.exe 2>&1 | FileCheck %s # RUN: not ld.lld -pie %t.o %t2.a -o %t.exe 2>&1 | FileCheck %s -# CHECK: undefined symbol: foo in -# CHECK: undefined symbol: bar in -# CHECK: undefined symbol: foo(int) in -# CHECK: undefined symbol: zed2 in {{.*}}2.a({{.*}}.o) +# CHECK: undef.s (.text+0x1): error: undefined symbol 'foo' +# CHECK: undef.s (.text+0x6): error: undefined symbol 'bar' +# CHECK: undef.s (.text+0x10): error: undefined symbol 'foo(int)' +# CHECK: {{.*}}2.a({{.*}}.o) (.text+0x0): error: undefined symbol 'zed2' # RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \ # RUN: FileCheck -check-prefix=NO-DEMANGLE %s -# NO-DEMANGLE: undefined symbol: _Z3fooi in +# NO-DEMANGLE: undef.s (.text+0x10): error: undefined symbol '_Z3fooi' + +.file "undef.s" .globl _start _start: Index: test/ELF/unresolved-symbols.s =================================================================== --- test/ELF/unresolved-symbols.s +++ test/ELF/unresolved-symbols.s @@ -6,7 +6,7 @@ ## Check that %t2.o contains undefined symbol undef. # RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | \ # RUN: FileCheck -check-prefix=UNDCHECK %s -# UNDCHECK: undefined symbol: undef in {{.*}}2.o +# UNDCHECK: {{.*}}2.o (.text+0x1): error: undefined symbol 'undef' ## Error out if unknown option value was set. # RUN: not ld.lld %t1.o %t2.o -o %t --unresolved-symbols=xxx 2>&1 | \ @@ -19,7 +19,7 @@ # RUN: llvm-readobj %t1_1 > /dev/null 2>&1 # RUN: not ld.lld %t2.o -o %t1_2 --unresolved-symbols=ignore-all --no-undefined 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s -# ERRUND: undefined symbol: undef +# ERRUND: (.text+0x1): error: undefined symbol 'undef ## Also ignore all should not produce error for symbols from DSOs. # RUN: ld.lld %t1.o %t.so -o %t1_3 --unresolved-symbols=ignore-all # RUN: llvm-readobj %t1_3 > /dev/null 2>&1 Index: test/ELF/verneed-local.s =================================================================== --- test/ELF/verneed-local.s +++ test/ELF/verneed-local.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: not ld.lld %t.o %S/Inputs/verneed1.so -o %t 2>&1 | FileCheck %s -# CHECK: undefined symbol: f3 in +# CHECK: (.text+0x1): error: undefined symbol 'f3' .globl _start _start: call f3 Index: test/ELF/zdefs.s =================================================================== --- test/ELF/zdefs.s +++ test/ELF/zdefs.s @@ -2,6 +2,6 @@ # RUN: ld.lld -shared %t.o -o %t1.so # RUN: not ld.lld -z defs -shared %t.o -o %t1.so 2>&1 | FileCheck -check-prefix=ERR %s -# ERR: undefined symbol: foo +# ERR: (.text+0x1): error: undefined symbol 'foo' callq foo@PLT