Change the error message format for undefined symbols.

Previously, undefined symbol errors are one line like this
and wasn't easy to read.

  /ssd/clang/bin/ld.lld: error: /ssd/llvm-project/lld/ELF/Writer.cpp:207: undefined symbol 'lld:🧝:EhFrameSection<llvm::object::ELFType<(llvm::support::endianness)0, true> >::addSection(lld:🧝:InputSectionBase*)'

This patch make it more structured like this.

  bin/ld.lld: error: undefined symbol: lld:🧝:EhFrameSection<llvm::object::ELFType<(llvm::support::endianness)0, true>
  >>> Referenced by Writer.cpp:207 (/ssd/llvm-project/lld/ELF/Writer.cpp:207)
  >>>               Writer.cpp.o in archive lib/liblldELF.a

Discussion thread:
http://lists.llvm.org/pipermail/llvm-dev/2017-March/111459.html

Differential Revision: https://reviews.llvm.org/D31481

llvm-svn: 299097
This commit is contained in:
Rui Ueyama 2017-03-30 19:13:47 +00:00
parent edaec6de73
commit b87602032a
20 changed files with 194 additions and 50 deletions

View File

@ -33,6 +33,18 @@ StringRef elf::Argv0;
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
// Prints "\n" or does nothing, depending on Msg contents of
// the previous call of this function.
static void newline(const Twine &Msg) {
// True if the previous error message contained "\n".
// We want to separate multi-line error messages with a newline.
static bool Flag;
if (Flag)
*ErrorOS << "\n";
Flag = (StringRef(Msg.str()).find('\n') != StringRef::npos);
}
static void print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << Argv0 + ": ";
if (Config->ColorDiagnostics) {
@ -62,13 +74,16 @@ void elf::warn(const Twine &Msg) {
error(Msg);
return;
}
std::lock_guard<std::mutex> Lock(Mu);
newline(Msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
void elf::error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
newline(Msg);
if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
print("error: ", raw_ostream::RED);
@ -96,8 +111,6 @@ void elf::exitLld(int Val) {
}
void elf::fatal(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
print("error: ", raw_ostream::RED);
*ErrorOS << Msg << "\n";
error(Msg);
exitLld(1);
}

View File

@ -92,15 +92,15 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
uint64_t Offset) {
Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
uint64_t Offset) {
if (!DwarfLine)
initializeDwarfLine();
// The offset to CU is 0.
const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
if (!Tbl)
return "";
return None;
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
@ -109,8 +109,18 @@ std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
S->getOffsetInFile() + Offset, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
if (Info.Line == 0)
return "";
return Info.FileName + ":" + std::to_string(Info.Line);
return None;
return Info;
}
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
uint64_t Offset) {
if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
return Info->FileName + ":" + std::to_string(Info->Line);
return "";
}
// Returns "(internal)", "foo.a(bar.o)" or "baz.o".

View File

@ -30,6 +30,7 @@
namespace llvm {
class DWARFDebugLine;
class TarWriter;
struct DILineInfo;
namespace lto {
class InputFile;
}
@ -175,6 +176,7 @@ public:
// Returns source line information for a given offset.
// If no information is available, returns "".
std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
// MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support

View File

@ -22,6 +22,7 @@
#include "llvm/Object/Decompressor.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Path.h"
#include <mutex>
using namespace llvm;
@ -29,6 +30,7 @@ using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
using namespace llvm::sys;
using namespace lld;
using namespace lld::elf;
@ -215,6 +217,62 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
}
// Returns a source location string. This function is intended to be
// used for constructing an error message. The returned message looks
// like this:
//
// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42)
//
// Returns an empty string if there's no way to get line info.
template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) {
// Synthetic sections don't have input files.
elf::ObjectFile<ELFT> *File = getFile<ELFT>();
if (!File)
return "";
Optional<DILineInfo> Info = File->getDILineInfo(this, Offset);
// File->SourceFile contains STT_FILE symbol, and that is a last resort.
if (!Info)
return File->SourceFile;
std::string Path = Info->FileName;
std::string Filename = path::filename(Path);
std::string Lineno = ":" + std::to_string(Info->Line);
if (Filename == Path)
return Filename + Lineno;
return Filename + Lineno + " (" + Path + Lineno + ")";
}
// Returns a filename string along with an optional section name. This
// function is intended to be used for constructing an error
// message. The returned message looks like this:
//
// path/to/foo.o:(function bar)
//
// or
//
// path/to/foo.o:(function bar) in archive path/to/bar.a
template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) {
// Synthetic sections don't have input files.
elf::ObjectFile<ELFT> *File = getFile<ELFT>();
std::string Filename = File ? File->getName() : "(internal)";
std::string Archive;
if (!File->ArchiveName.empty())
Archive = (" in archive " + File->ArchiveName).str();
// Find a symbol that encloses a given location.
for (SymbolBody *B : getFile<ELFT>()->getSymbols())
if (auto *D = dyn_cast<DefinedRegular>(B))
if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size)
return Filename + ":(" + toString(*D) + ")" + Archive;
// If there's no symbol, print out the offset in the section.
return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive)
.str();
}
InputSectionBase InputSectionBase::Discarded;
InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
@ -833,6 +891,16 @@ template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t);
template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t);
template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t);
template std::string InputSectionBase::getSrcMsg<ELF32LE>(uint64_t);
template std::string InputSectionBase::getSrcMsg<ELF32BE>(uint64_t);
template std::string InputSectionBase::getSrcMsg<ELF64LE>(uint64_t);
template std::string InputSectionBase::getSrcMsg<ELF64BE>(uint64_t);
template std::string InputSectionBase::getObjMsg<ELF32LE>(uint64_t);
template std::string InputSectionBase::getObjMsg<ELF32BE>(uint64_t);
template std::string InputSectionBase::getObjMsg<ELF64LE>(uint64_t);
template std::string InputSectionBase::getObjMsg<ELF64BE>(uint64_t);
template void InputSection::writeTo<ELF32LE>(uint8_t *);
template void InputSection::writeTo<ELF32BE>(uint8_t *);
template void InputSection::writeTo<ELF64LE>(uint8_t *);

View File

@ -163,6 +163,8 @@ public:
// Returns a source location string. Used to construct an error message.
template <class ELFT> std::string getLocation(uint64_t Offset);
template <class ELFT> std::string getSrcMsg(uint64_t Offset);
template <class ELFT> std::string getObjMsg(uint64_t Offset);
template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);

View File

@ -616,14 +616,20 @@ static void reportUndefined(SymbolBody &Sym, InputSectionBase &S,
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return;
std::string Msg = S.getLocation<ELFT>(Offset) + ": undefined symbol '" +
toString(Sym) + "'";
std::string Msg =
"undefined symbol: " + toString(Sym) + "\n>>> referenced by ";
std::string Src = S.getSrcMsg<ELFT>(Offset);
if (!Src.empty())
Msg += Src + "\n>>> ";
Msg += S.getObjMsg<ELFT>(Offset);
if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll ||
(Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) {
warn(Msg);
} else {
error(Msg);
if (Config->ArchiveWithoutSymbolsSeen) {
message("At least one archive listed no symbols in its index."
" This can happen when creating archives with a version"

View File

@ -22,7 +22,8 @@
// 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: error: {{.*}}:(.bar+0x0): undefined symbol '_bar'
// UNDEFINED: error: undefined symbol: _bar
// UNDEFINED: >>> referenced by {{.*}}:(.bar+0x0)
// Should fail if cannot find specified library (without -L switch)
// RUN: not ld.lld -o %t3 %t.o -lls 2>&1 \

View File

@ -2,9 +2,12 @@
# 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: error: {{.*}}:(.text+0x0): undefined symbol '_edata'
# CHECK: error: {{.*}}:(.text+0x8): undefined symbol '_etext'
# CHECK: error: {{.*}}:(.text+0x10): undefined symbol '_end'
# CHECK: error: undefined symbol: _edata
# CHECK: >>> referenced by {{.*}}:(.text+0x0)
# CHECK: error: undefined symbol: _etext
# CHECK: >>> referenced by {{.*}}:(.text+0x8)
# CHECK: error: undefined symbol: _end
# CHECK: >>> referenced by {{.*}}:(.text+0x10)
.global _start,_end,_etext,_edata
.text

View File

@ -3,7 +3,8 @@
# 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: error: {{.*}}:(.text+0x0): undefined symbol '__ehdr_start'
# CHECK: error: undefined symbol: __ehdr_start
# CHECK: >>> referenced by {{.*}}:(.text+0x0)
.text
.global _start, __ehdr_start

View File

@ -22,10 +22,10 @@
; RUN: not ld.lld -emain -m elf_x86_64 %t.o -o %t %T/archive-no-index/libfoo.a \
; RUN: 2>&1 | FileCheck --check-prefix=NO-NOTE %s
; NOTE: undefined symbol 'f'
; NOTE: undefined symbol: f
; NOTE: archive listed no symbols
; NO-NOTE: undefined symbol 'f'
; NO-NOTE: undefined symbol: f
; NO-NOTE-NOT: archive listed no symbols
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -11,4 +11,6 @@ define void @_start() {
ret void
}
; CHECK: error: ld-temp.o:(function _start): undefined symbol 'foo'
; CHECK: error: undefined symbol: foo
; CHECK: >>> referenced by ld-temp.o
; CHECK: {{.*}}:(_start)

View File

@ -9,7 +9,8 @@
// 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: error: {{.*}}:(.text+0x1): undefined symbol '_bar'
// UNDEFINED: error: undefined symbol: _bar
// UNDEFINED: >>> referenced by {{.*}}:(.text+0x1)
// 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 \

View File

@ -10,4 +10,5 @@
_start:
call __tls_get_addr
// CHECK: error: {{.*}}:(.text+0x1): undefined symbol '__tls_get_addr'
// CHECK: error: undefined symbol: __tls_get_addr
// CHECK: >>> referenced by {{.*}}:(.text+0x1)

View File

@ -1,15 +1,18 @@
# 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: error: {{.*}}:(.data+0x0): undefined symbol 'hidden'
# CHECK: error: undefined symbol: hidden
# CHECK: >>> referenced by {{.*}}:(.data+0x0)
.global hidden
.hidden hidden
# CHECK: error: {{.*}}:(.data+0x8): undefined symbol 'internal'
# CHECK: error: undefined symbol: internal
# CHECK: >>> referenced by {{.*}}:(.data+0x8)
.global internal
.internal internal
# CHECK: error: {{.*}}:(.data+0x10): undefined symbol 'protected'
# CHECK: error: undefined symbol: protected
# CHECK: >>> referenced by {{.*}}:(.data+0x10)
.global protected
.protected protected

View File

@ -5,17 +5,37 @@
# RUN: llvm-ar rc %t2.a %t2.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: dir{{/|\\}}undef-debug.s:3: undefined symbol 'zed3'
# CHECK: error: dir{{/|\\}}undef-debug.s:7: undefined symbol 'zed4'
# CHECK: error: dir{{/|\\}}undef-debug.s:11: undefined symbol 'zed5'
# CHECK: error: undefined symbol: foo
# CHECK: >>> referenced by undef.s
# CHECK: {{.*}}:(.text+0x1)
# CHECK: error: undefined symbol: bar
# CHECK: >>> referenced by undef.s
# CHECK: >>> {{.*}}:(.text+0x6)
# CHECK: error: undefined symbol: foo(int)
# CHECK: >>> referenced by undef.s
# CHECK: >>> {{.*}}:(.text+0x10)
# CHECK: error: undefined symbol: zed2
# CHECK: >>> referenced by {{.*}}.o:(.text+0x0) in archive {{.*}}2.a
# CHECK: error: undefined symbol: zed3
# CHECK: >>> referenced by undef-debug.s:3 (dir{{/|\\}}undef-debug.s:3)
# CHECK: >>> {{.*}}.o:(.text+0x0)
# CHECK: error: undefined symbol: zed4
# CHECK: >>> referenced by undef-debug.s:7 (dir{{/|\\}}undef-debug.s:7)
# CHECK: >>> {{.*}}.o:(.text.1+0x0)
# CHECK: error: undefined symbol: zed5
# CHECK: >>> referenced by undef-debug.s:11 (dir{{/|\\}}undef-debug.s:11)
# CHECK: >>> {{.*}}.o:(.text.2+0x0)
# RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \
# RUN: FileCheck -check-prefix=NO-DEMANGLE %s
# NO-DEMANGLE: error: undef.s:(.text+0x10): undefined symbol '_Z3fooi'
# NO-DEMANGLE: error: undefined symbol: _Z3fooi
.file "undef.s"

View File

@ -6,7 +6,8 @@
## 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: error: {{.*}}2.o:(.text+0x1): undefined symbol 'undef'
# UNDCHECK: error: undefined symbol: undef
# UNDCHECK: >>> referenced by {{.*}}2.o:(.text+0x1)
## 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 +20,9 @@
# 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: error: {{.*}}:(.text+0x1): undefined symbol 'undef'
# ERRUND: error: undefined symbol: undef
# ERRUND: >>> referenced by {{.*}}:(.text+0x1)
## 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
@ -56,8 +59,7 @@
# RUN: llvm-readobj %t6_1 > /dev/null 2>&1
# RUN: not ld.lld %t2.o -o %t7 --unresolved-symbols=report-all 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | \
# RUN: FileCheck -check-prefix=ERRUND %s
# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | FileCheck -check-prefix=ERRUND %s
.globl _start
_start:

View File

@ -2,7 +2,8 @@
# 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: error: {{.*}}:(.text+0x1): undefined symbol 'f3'
# CHECK: error: undefined symbol: f3
# CHECK: >>> referenced by {{.*}}:(.text+0x1)
.globl _start
_start:
call f3

View File

@ -2,13 +2,13 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: not ld.lld -shared %t.o -o %t.so -z defs --warn-unresolved-symbols 2>&1| FileCheck %s
# CHECK: warning: {{.*}}: undefined symbol 'foo'
# CHECK: error: {{.*}}: undefined symbol 'bar'
# CHECK: error: {{.*}}: undefined symbol 'zed'
# CHECK: warning: undefined symbol: foo
# CHECK: error: undefined symbol: bar
# CHECK: error: undefined symbol: zed
.data
.quad foo
.hidden bar
.quad bar
.protected zed
.quad zed
.data
.quad foo
.hidden bar
.quad bar
.protected zed
.quad zed

View File

@ -31,10 +31,17 @@
# RUN: ld.lld -shared %t1.o -o %t10.so --warn-unresolved-symbols 2>&1 | \
# RUN: FileCheck -allow-empty -check-prefix=NOWARN %s
# ERRUND: error: {{.*}}:(.text+0x1): undefined symbol 'undef'
# WARNUND: warning: {{.*}}:(.text+0x1): undefined symbol 'undef'
# NOERR-NOT: error: {{.*}}:(.text+0x1): undefined symbol 'undef'
# NOWARN-NOT: warning: {{.*}}:(.text+0x1): undefined symbol 'undef'
# ERRUND: error: undefined symbol: undef
# ERRUND: >>> referenced by {{.*}}:(.text+0x1)
# WARNUND: warning: undefined symbol: undef
# WARNUND: >>> referenced by {{.*}}:(.text+0x1)
# NOERR-NOT: error: undefined symbol: undef
# NOERR-NOT: >>> referenced by {{.*}}:(.text+0x1)
# NOWARN-NOT: warning: undefined symbol: undef
# NOWARN-NOT: >>> referenced by {{.*}}:(.text+0x1)
.globl _start
_start:

View File

@ -2,6 +2,7 @@
# 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: error: {{.*}}:(.text+0x1): undefined symbol 'foo'
# ERR: error: undefined symbol: foo
# ERR: >>> referenced by {{.*}}:(.text+0x1)
callq foo@PLT