[lld] r285186 - [ELF] Better error reporting for undefined symbols
Eugene Leviant via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 26 04:07:10 PDT 2016
Author: evgeny777
Date: Wed Oct 26 06:07:09 2016
New Revision: 285186
URL: http://llvm.org/viewvc/llvm-project?rev=285186&view=rev
Log:
[ELF] Better error reporting for undefined symbols
This patch make lld show following details for undefined symbol errors:
- file (line)
- file (function name)
- file (section name + offset)
Differential revision: https://reviews.llvm.org/D25826
Added:
lld/trunk/test/ELF/Inputs/undef-debug.s
Modified:
lld/trunk/ELF/InputFiles.cpp
lld/trunk/ELF/InputFiles.h
lld/trunk/ELF/Relocations.cpp
lld/trunk/test/ELF/libsearch.s
lld/trunk/test/ELF/linkerscript/edata-etext.s
lld/trunk/test/ELF/linkerscript/ehdr_start.s
lld/trunk/test/ELF/lto/combined-lto-object-name.ll
lld/trunk/test/ELF/sysroot.s
lld/trunk/test/ELF/tls-static.s
lld/trunk/test/ELF/undef-shared.s
lld/trunk/test/ELF/undef.s
lld/trunk/test/ELF/unresolved-symbols.s
lld/trunk/test/ELF/verneed-local.s
lld/trunk/test/ELF/zdefs.s
Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Wed Oct 26 06:07:09 2016
@@ -18,6 +18,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/Analysis.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/LTO/LTO.h"
@@ -35,6 +36,39 @@ using namespace lld::elf;
std::vector<InputFile *> InputFile::Pool;
+template <class ELFT> DIHelper<ELFT>::DIHelper(elf::InputFile *F) {
+ Expected<std::unique_ptr<object::ObjectFile>> Obj =
+ object::ObjectFile::createObjectFile(F->MB);
+ if (!Obj)
+ return;
+
+ DWARFContextInMemory Dwarf(*Obj.get());
+ DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs));
+ DataExtractor LineData(Dwarf.getLineSection().Data,
+ ELFT::TargetEndianness == support::little,
+ ELFT::Is64Bits ? 8 : 4);
+ // The second parameter is offset in .debug_line section
+ // for compilation unit (CU) of interest. We have only one
+ // CU (object file), so offset is always 0.
+ DwarfLine->getOrParseLineTable(LineData, 0);
+}
+
+template <class ELFT> std::string DIHelper<ELFT>::getLineInfo(uintX_t Offset) {
+ if (!DwarfLine)
+ return "";
+
+ DILineInfo LineInfo;
+ DILineInfoSpecifier Spec;
+ // The offset to CU is 0 (see DIHelper constructor).
+ const DWARFDebugLine::LineTable *LineTbl = DwarfLine->getLineTable(0);
+ if (!LineTbl)
+ return "";
+ LineTbl->getFileLineInfoForAddress(Offset, nullptr, Spec.FLIKind, LineInfo);
+ return LineInfo.Line != 0
+ ? LineInfo.FileName + " (" + std::to_string(LineInfo.Line) + ")"
+ : "";
+}
+
// Deletes all InputFile instances created so far.
void InputFile::freePool() {
// Files are freed in reverse order so that files created
@@ -132,6 +166,13 @@ ArrayRef<SymbolBody *> elf::ObjectFile<E
return makeArrayRef(this->SymbolBodies).slice(1);
}
+template <class ELFT> DIHelper<ELFT> *elf::ObjectFile<ELFT>::getDIHelper() {
+ if (!DIH)
+ DIH.reset(new DIHelper<ELFT>(this));
+
+ return DIH.get();
+}
+
template <class ELFT> uint32_t elf::ObjectFile<ELFT>::getMipsGp0() const {
if (ELFT::Is64Bits && MipsOptions && MipsOptions->Reginfo)
return MipsOptions->Reginfo->ri_gp_value;
@@ -432,6 +473,8 @@ SymbolBody *elf::ObjectFile<ELFT>::creat
int Binding = Sym->getBinding();
InputSectionBase<ELFT> *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);
@@ -897,3 +940,8 @@ template InputFile *BinaryFile::createEL
template InputFile *BinaryFile::createELF<ELF32BE>();
template InputFile *BinaryFile::createELF<ELF64LE>();
template InputFile *BinaryFile::createELF<ELF64BE>();
+
+template class elf::DIHelper<ELF32LE>;
+template class elf::DIHelper<ELF32BE>;
+template class elf::DIHelper<ELF64LE>;
+template class elf::DIHelper<ELF64BE>;
Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed Oct 26 06:07:09 2016
@@ -29,6 +29,7 @@
#include <map>
namespace llvm {
+class DWARFDebugLine;
namespace lto {
class InputFile;
}
@@ -43,6 +44,21 @@ class InputFile;
class Lazy;
class SymbolBody;
+// Debugging information helper class. The main purpose is to
+// retrieve source file and line for error reporting. Linker may
+// find reasonable number of errors in a single object file, so
+// we cache debugging information in order to parse it only once
+// for each object file we link.
+template <class ELFT> class DIHelper {
+public:
+ typedef typename ELFT::uint uintX_t;
+
+ DIHelper(InputFile *F);
+ std::string getLineInfo(uintX_t Offset);
+private:
+ std::unique_ptr<llvm::DWARFDebugLine> DwarfLine;
+};
+
// The root class of input files.
class InputFile {
public:
@@ -171,6 +187,10 @@ public:
const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
+ // DI helper allows manipilating debugging information for this
+ // object file. Used for error reporting.
+ DIHelper<ELFT> *getDIHelper();
+
// Get MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
// R_MIPS_GPREL16 / R_MIPS_GPREL32 relocations.
@@ -184,6 +204,11 @@ public:
// 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<llvm::CachedHashStringRef> &ComdatGroups);
@@ -211,6 +236,7 @@ private:
llvm::SpecificBumpPtrAllocator<InputSection<ELFT>> IAlloc;
llvm::SpecificBumpPtrAllocator<MergeInputSection<ELFT>> MAlloc;
llvm::SpecificBumpPtrAllocator<EhInputSection<ELFT>> EHAlloc;
+ std::unique_ptr<DIHelper<ELFT>> DIH;
};
// LazyObjectFile is analogous to ArchiveFile in the sense that
Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Wed Oct 26 06:07:09 2016
@@ -522,7 +522,48 @@ static typename ELFT::uint computeAddend
return Addend;
}
-static void reportUndefined(SymbolBody &Sym) {
+// Find symbol that encloses given offset. Used for error reporting.
+template <class ELFT>
+static DefinedRegular<ELFT> *getSymbolAt(InputSectionBase<ELFT> *S,
+ typename ELFT::uint Offset) {
+ for (SymbolBody *B : S->getFile()->getSymbols())
+ if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B))
+ if (D->Value <= Offset && D->Value + D->Size > Offset && D->Section == S)
+ return D;
+
+ return nullptr;
+}
+
+template <class ELFT>
+static std::string getLocation(SymbolBody &Sym, InputSectionBase<ELFT> &S,
+ typename ELFT::uint Offset) {
+ ObjectFile<ELFT> *File = S.getFile();
+
+ // First check if we can get desired values from debugging information.
+ std::string LineInfo = File->getDIHelper()->getLineInfo(Offset);
+ if (!LineInfo.empty())
+ return LineInfo;
+
+ // If don't have STT_FILE typed symbol in object file then
+ // use object file name.
+ std::string SrcFile = File->SourceFile;
+ if (SrcFile.empty())
+ SrcFile = Sym.File ? getFilename(Sym.File) : getFilename(File);
+
+ DefinedRegular<ELFT> *Encl = 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 <class ELFT>
+static void reportUndefined(SymbolBody &Sym, InputSectionBase<ELFT> &S,
+ typename ELFT::uint Offset) {
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
return;
@@ -530,11 +571,10 @@ static void reportUndefined(SymbolBody &
Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
return;
- std::string Msg = "undefined symbol: ";
- Msg += Config->Demangle ? demangle(Sym.getName()) : Sym.getName().str();
+ std::string Msg =
+ getLocation(Sym, S, Offset) + ": 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);
else
@@ -583,7 +623,7 @@ static void scanRelocs(InputSectionBase<
// 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);
Added: lld/trunk/test/ELF/Inputs/undef-debug.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/undef-debug.s?rev=285186&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/undef-debug.s (added)
+++ lld/trunk/test/ELF/Inputs/undef-debug.s Wed Oct 26 06:07:09 2016
@@ -0,0 +1,3 @@
+.file 1 "undef-debug.s"
+.loc 1 3
+ .quad zed3
Modified: lld/trunk/test/ELF/libsearch.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/libsearch.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/libsearch.s (original)
+++ lld/trunk/test/ELF/libsearch.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.bar+0x0): undefined symbol '_bar'
// Should fail if cannot find specified library (without -L switch)
// RUN: not ld.lld -o %t3 %t.o -lls 2>&1 \
Modified: lld/trunk/test/ELF/linkerscript/edata-etext.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/edata-etext.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/edata-etext.s (original)
+++ lld/trunk/test/ELF/linkerscript/edata-etext.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.text+0x0): undefined symbol '_edata'
+# CHECK: error: {{.*}} (.text+0x8): undefined symbol '_etext'
+# CHECK: error: {{.*}} (.text+0x10): undefined symbol '_end'
.global _start,_end,_etext,_edata
.text
Modified: lld/trunk/test/ELF/linkerscript/ehdr_start.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/ehdr_start.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/ehdr_start.s (original)
+++ lld/trunk/test/ELF/linkerscript/ehdr_start.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.text+0x0): undefined symbol '__ehdr_start'
.text
.global _start, __ehdr_start
Modified: lld/trunk/test/ELF/lto/combined-lto-object-name.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/combined-lto-object-name.ll?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/lto/combined-lto-object-name.ll (original)
+++ lld/trunk/test/ELF/lto/combined-lto-object-name.ll Wed Oct 26 06:07:09 2016
@@ -11,4 +11,4 @@ define void @_start() {
ret void
}
-; CHECK: undefined symbol: foo in {{.*}}combined-lto-object-name.ll.tmp.o
+; CHECK: error: ld-temp.o (function _start): undefined symbol 'foo'
Modified: lld/trunk/test/ELF/sysroot.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/sysroot.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/sysroot.s (original)
+++ lld/trunk/test/ELF/sysroot.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.text+0x1): 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 \
Modified: lld/trunk/test/ELF/tls-static.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/tls-static.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/tls-static.s (original)
+++ lld/trunk/test/ELF/tls-static.s Wed Oct 26 06:07:09 2016
@@ -10,4 +10,4 @@
_start:
call __tls_get_addr
-// CHECK: undefined symbol: __tls_get_addr
+// CHECK: error: {{.*}} (.text+0x1): undefined symbol '__tls_get_addr'
Modified: lld/trunk/test/ELF/undef-shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/undef-shared.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/undef-shared.s (original)
+++ lld/trunk/test/ELF/undef-shared.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.data+0x0): undefined symbol 'hidden'
.global hidden
.hidden hidden
-# CHECK: undefined symbol: internal in {{.*}}
+# CHECK: error: {{.*}} (.data+0x8): undefined symbol 'internal'
.global internal
.internal internal
-# CHECK: undefined symbol: protected in {{.*}}
+# CHECK: error: {{.*}} (.data+0x10): undefined symbol 'protected'
.global protected
.protected protected
Modified: lld/trunk/test/ELF/undef.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/undef.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/undef.s (original)
+++ lld/trunk/test/ELF/undef.s Wed Oct 26 06:07:09 2016
@@ -1,17 +1,21 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug.s -o %t3.o
# 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)
+# RUN: not ld.lld %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s
+# RUN: not ld.lld -pie %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: error: undef.s (.text+0x1): undefined symbol 'foo'
+# CHECK: error: undef.s (.text+0x6): undefined symbol 'bar'
+# CHECK: error: undef.s (.text+0x10): undefined symbol 'foo(int)'
+# CHECK: error: {{.*}}2.a({{.*}}.o) (.text+0x0): undefined symbol 'zed2'
+# CHECK: error: undef-debug.s (3): undefined symbol 'zed3'
# 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: error: undef.s (.text+0x10): undefined symbol '_Z3fooi'
+
+.file "undef.s"
.globl _start
_start:
Modified: lld/trunk/test/ELF/unresolved-symbols.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/unresolved-symbols.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/unresolved-symbols.s (original)
+++ lld/trunk/test/ELF/unresolved-symbols.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}}2.o (.text+0x1): 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: error: {{.*}} (.text+0x1): 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
Modified: lld/trunk/test/ELF/verneed-local.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/verneed-local.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/verneed-local.s (original)
+++ lld/trunk/test/ELF/verneed-local.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.text+0x1): undefined symbol 'f3'
.globl _start
_start:
call f3
Modified: lld/trunk/test/ELF/zdefs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/zdefs.s?rev=285186&r1=285185&r2=285186&view=diff
==============================================================================
--- lld/trunk/test/ELF/zdefs.s (original)
+++ lld/trunk/test/ELF/zdefs.s Wed Oct 26 06:07:09 2016
@@ -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: error: {{.*}} (.text+0x1): undefined symbol 'foo'
callq foo at PLT
More information about the llvm-commits
mailing list