forked from OSchip/llvm-project
[ELF] Print symbols with non-default versions for better "undefined symbol" diagnostics
When reporting an "undefined symbol" diagnostic: * We don't print @ for the reference. * We don't print @ or @@ for the definition. https://bugs.llvm.org/show_bug.cgi?id=45318 This can lead to confusing diagnostics: ``` // foo may be foo@v2 ld.lld: error: undefined symbol: foo >>> referenced by t1.o:(.text+0x1) // foo may be foo@v1 or foo@@v1 >>> did you mean: foo >>> defined in: t.so ``` There are 2 ways a symbol in symtab may get truncated: * A @@ definition may be truncated *early* by SymbolTable::insert(). The name ends with a '\0'. * A @ definition/reference may be truncated *later* by Symbol::parseSymbolVersion(). The name ends with a '@'. This patch detects the second case and improves the diagnostics. The first case is not improved but the second case is sufficient to make diagnostics not confusing. Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D76999
This commit is contained in:
parent
f527e6f2e1
commit
f2036a15d3
|
@ -31,7 +31,18 @@ static std::string demangle(StringRef symName) {
|
|||
return std::string(symName);
|
||||
}
|
||||
|
||||
std::string toString(const elf::Symbol &b) { return demangle(b.getName()); }
|
||||
std::string toString(const elf::Symbol &sym) {
|
||||
StringRef name = sym.getName();
|
||||
std::string ret = demangle(name);
|
||||
|
||||
// If sym has a non-default version, its name may have been truncated at '@'
|
||||
// by Symbol::parseSymbolVersion(). Add the trailing part. This check is safe
|
||||
// because every symbol name ends with '\0'.
|
||||
if (name.data()[name.size()] == '@')
|
||||
ret += name.data() + name.size();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string toELFString(const Archive::Symbol &b) {
|
||||
return demangle(b.getName());
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "llvm/Object/ELF.h"
|
||||
|
||||
namespace lld {
|
||||
// Returns a string representation for a symbol for diagnostics.
|
||||
std::string toString(const elf::Symbol &);
|
||||
|
||||
// There are two different ways to convert an Archive::Symbol to a string:
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
# REQUIRES: x86
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
|
||||
# RUN: echo 'v1 {bar;};' > %t.ver
|
||||
# RUN: ld.lld -shared --version-script %t.ver %t.o -o %t.so
|
||||
|
||||
## For an unversioned undefined symbol, check we can suggest the symbol with the
|
||||
## default version.
|
||||
# RUN: echo 'call bat' | llvm-mc -filetype=obj -triple=x86_64 - -o %tdef1.o
|
||||
# RUN: not ld.lld %t.so %tdef1.o -o /dev/null 2>&1 | FileCheck --check-prefix=DEFAULT1 %s
|
||||
|
||||
# DEFAULT1: error: undefined symbol: bat
|
||||
# DEFAULT1-NEXT: >>> referenced by {{.*}}.o:(.text+0x1)
|
||||
# DEFAULT1-NEXT: >>> did you mean: bar{{$}}
|
||||
# DEFAULT1-NEXT: >>> defined in: {{.*}}.so
|
||||
|
||||
## For a versioned undefined symbol, check we can suggest the symbol with the
|
||||
## default version.
|
||||
# RUN: echo '.symver bar.v2,bar@v2; call bar.v2' | llvm-mc -filetype=obj -triple=x86_64 - -o %tdef2.o
|
||||
# RUN: not ld.lld %t.so %tdef2.o -o /dev/null 2>&1 | FileCheck --check-prefix=DEFAULT2 %s
|
||||
|
||||
# DEFAULT2: error: undefined symbol: bar@v2
|
||||
# DEFAULT2-NEXT: >>> referenced by {{.*}}.o:(.text+0x1)
|
||||
# DEFAULT2-NEXT: >>> did you mean: bar{{$}}
|
||||
# DEFAULT2-NEXT: >>> defined in: {{.*}}.so
|
||||
|
||||
## For an unversioned undefined symbol, check we can suggest a symbol with
|
||||
## a non-default version.
|
||||
# RUN: echo 'call foo; call _Z3fooi' | llvm-mc -filetype=obj -triple=x86_64 - -o %thidden1.o
|
||||
# RUN: not ld.lld %t.so %thidden1.o -o /dev/null 2>&1 | FileCheck --check-prefix=HIDDEN1 %s
|
||||
|
||||
# HIDDEN1: error: undefined symbol: foo
|
||||
# HIDDEN1-NEXT: >>> referenced by {{.*}}.o:(.text+0x1)
|
||||
# HIDDEN1-NEXT: >>> did you mean: foo@v1
|
||||
# HIDDEN1-NEXT: >>> defined in: {{.*}}.so
|
||||
# HIDDEN1-EMPTY:
|
||||
# HIDDEN1-NEXT: error: undefined symbol: foo(int)
|
||||
# HIDDEN1-NEXT: >>> referenced by {{.*}}.o:(.text+0x6)
|
||||
# HIDDEN1-NEXT: >>> did you mean: foo(int)@v1
|
||||
# HIDDEN1-NEXT: >>> defined in: {{.*}}.so
|
||||
|
||||
## For a versioned undefined symbol, check we can suggest a symbol with
|
||||
## a different version.
|
||||
# RUN: echo '.symver foo.v2,foo@v2; call foo.v2' | llvm-mc -filetype=obj -triple=x86_64 - -o %thidden2.o
|
||||
# RUN: not ld.lld %t.so %thidden2.o -o /dev/null 2>&1 | FileCheck --check-prefix=HIDDEN2 %s
|
||||
|
||||
# HIDDEN2: error: undefined symbol: foo@v2
|
||||
# HIDDEN2-NEXT: >>> referenced by {{.*}}.o:(.text+0x1)
|
||||
# HIDDEN2-NEXT: >>> did you mean: foo@v1
|
||||
# HIDDEN2-NEXT: >>> defined in: {{.*}}.so
|
||||
|
||||
## %t.so exports bar@@v1 and two VERSYM_HIDDEN symbols: foo@v1 and _Z3fooi@v1.
|
||||
.globl foo.v1, _Z3fooi.v1, bar
|
||||
.symver foo.v1,foo@v1
|
||||
.symver _Z3fooi.v1,_Z3fooi@v1
|
||||
foo.v1:
|
||||
_Z3fooi.v1:
|
||||
bar:
|
Loading…
Reference in New Issue