aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2016-06-23 07:00:17 +0000
committerRui Ueyama <ruiu@google.com>2016-06-23 07:00:17 +0000
commit8319c3a03c80e5552852b6d2bccfd07392b56f4f (patch)
tree3514553c7c59737e74dd5bc09b50453982bd06e9
parent1c48a2e94ee309c66ab6375c0c24bd1ce2e42016 (diff)
Implement --trace-symbol=symbol option.
Patch by Shridhar Joshi. This option provides names of all the link time modules which define and reference symbols requested by user. This helps to speed up application development by detecting references causing undefined symbols. It also helps in detecting symbols being resolved to wrong (unintended) definitions in case of applications containing multiple definitions for same symbols with different types, bindings. Implements PR28226. git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@273536 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--ELF/Config.h2
-rw-r--r--ELF/Driver.cpp4
-rw-r--r--ELF/InputFiles.cpp9
-rw-r--r--ELF/InputFiles.h2
-rw-r--r--ELF/Options.td3
-rw-r--r--ELF/SymbolTable.cpp11
-rw-r--r--ELF/SymbolTable.h2
-rw-r--r--test/ELF/Inputs/trace-symbols-foo-strong.s14
-rw-r--r--test/ELF/Inputs/trace-symbols-foo-weak.s12
-rw-r--r--test/ELF/trace-symbols.s84
10 files changed, 143 insertions, 0 deletions
diff --git a/ELF/Config.h b/ELF/Config.h
index bab9b899d..d36790d7b 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -12,6 +12,7 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Support/ELF.h"
#include <vector>
@@ -59,6 +60,7 @@ struct Configuration {
llvm::StringRef OutputFile;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
+ llvm::StringSet<> TraceSymbol;
std::string RPath;
std::vector<Version> SymbolVersions;
std::vector<llvm::StringRef> DynamicList;
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index c99b22988..36bb7285e 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -417,6 +417,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
parseVersionScript(*Buffer);
}
+
+ for (auto *Arg : Args.filtered(OPT_trace_symbol))
+ Config->TraceSymbol.insert(Arg->getValue());
}
void LinkerDriver::createFiles(opt::InputArgList &Args) {
@@ -499,6 +502,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Symtab.scanShlibUndefined();
Symtab.scanDynamicList();
Symtab.scanVersionScript();
+ Symtab.traceDefined();
Symtab.addCombinedLtoObject();
if (HasError)
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index df0c6855b..feae964d6 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -313,6 +313,14 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
return new (IAlloc.Allocate()) InputSection<ELFT>(this, &Sec);
}
+// Print the module names which reference the notified
+// symbols provided through -y or --trace-symbol option.
+template <class ELFT>
+void elf::ObjectFile<ELFT>::traceUndefined(StringRef Name) {
+ if (!Config->TraceSymbol.empty() && Config->TraceSymbol.count(Name))
+ outs() << getFilename(this) << ": reference to " << Name << "\n";
+}
+
template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
this->initStringTable();
Elf_Sym_Range Syms = this->getElfSymbols(false);
@@ -350,6 +358,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
switch (Sym->st_shndx) {
case SHN_UNDEF:
+ traceUndefined(Name);
return elf::Symtab<ELFT>::X
->addUndefined(Name, Binding, Sym->st_other, Sym->getType(),
/*CanOmitFromDynSym*/ false, this)
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 0dec96420..d009d94f3 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -140,6 +140,8 @@ public:
const Elf_Shdr *getSymbolTable() const { return this->Symtab; };
+ void traceUndefined(StringRef Name);
+
// 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.
diff --git a/ELF/Options.td b/ELF/Options.td
index c9a6bad36..1cf99c67e 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -142,6 +142,8 @@ def threads: F<"threads">, HelpText<"Enable use of threads">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
+def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
+
def undefined: J<"undefined=">,
HelpText<"Force undefined symbol during linking">;
@@ -194,6 +196,7 @@ def alias_soname_soname: S<"soname">, Alias<soname>;
def alias_strip_all: F<"s">, Alias<strip_all>;
def alias_strip_debug_S: F<"S">, Alias<strip_debug>;
def alias_trace: F<"t">, Alias<trace>;
+def alias_trace_symbol_y : JS<"y">, Alias<trace_symbol>;
def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
def alias_wrap_wrap: J<"wrap=">, Alias<wrap>;
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index 65863c1f2..eaf09ec4c 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -541,6 +541,17 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() {
}
}
+// Print the module names which define the notified
+// symbols provided through -y or --trace-symbol option.
+template <class ELFT> void SymbolTable<ELFT>::traceDefined() {
+ for (const auto &Symbol : Config->TraceSymbol)
+ if (SymbolBody *B = find(Symbol.getKey()))
+ if (B->isDefined() || B->isCommon())
+ if (InputFile *File = B->getSourceFile<ELFT>())
+ outs() << getFilename(File) << ": definition of "
+ << B->getName() << "\n";
+}
+
template class elf::SymbolTable<ELF32LE>;
template class elf::SymbolTable<ELF32BE>;
template class elf::SymbolTable<ELF64LE>;
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 218fbec3e..45741d99e 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -82,6 +82,8 @@ public:
void scanShlibUndefined();
void scanDynamicList();
void scanVersionScript();
+ void traceDefined();
+
SymbolBody *find(StringRef Name);
void wrap(StringRef Name);
diff --git a/test/ELF/Inputs/trace-symbols-foo-strong.s b/test/ELF/Inputs/trace-symbols-foo-strong.s
new file mode 100644
index 000000000..874642978
--- /dev/null
+++ b/test/ELF/Inputs/trace-symbols-foo-strong.s
@@ -0,0 +1,14 @@
+.text
+.globl foo
+.type foo, @function
+foo:
+nop
+
+.globl bar
+.type bar, @function
+bar:
+nop
+
+.global func2
+.type func2, @function
+func2:
diff --git a/test/ELF/Inputs/trace-symbols-foo-weak.s b/test/ELF/Inputs/trace-symbols-foo-weak.s
new file mode 100644
index 000000000..d071ebecc
--- /dev/null
+++ b/test/ELF/Inputs/trace-symbols-foo-weak.s
@@ -0,0 +1,12 @@
+.comm common,4,4
+.text
+.weak foo
+.type foo, @function
+foo:
+callq bar@PLT
+
+.globl func1
+.type func1, @function
+func1:
+call func2@PLT
+
diff --git a/test/ELF/trace-symbols.s b/test/ELF/trace-symbols.s
new file mode 100644
index 000000000..bd0a19cda
--- /dev/null
+++ b/test/ELF/trace-symbols.s
@@ -0,0 +1,84 @@
+# Test -y symbol and -trace-symbol=symbol
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/trace-symbols-foo-weak.s -o %t1
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+# RUN: %p/Inputs/trace-symbols-foo-strong.s -o %t2
+# RUN: ld.lld -shared %t1 -o %t1.so
+# RUN: ld.lld -shared %t2 -o %t2.so
+# RUN: ar -r %t1.a %t1
+# RUN: ar -r %t2.a %t2
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTRFOO %s
+# OBJECTRFOO: trace-symbols.s.tmp: reference to foo
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN: %t %t1 %t2 -o %t3 2>&1 | not FileCheck -check-prefix=OBJECTDCOMMON %s
+# OBJECTDCOMMON: trace-symbols.s.tmp1: definition of common
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN: %t %t1 %t2 -o %t3 2>&1 | not FileCheck -check-prefix=OBJECTD1FOO %s
+# RUN: ld.lld -y foo -y common %t %t2 %t1 -o %t3 2>&1 | not FileCheck \
+# RUN: -check-prefix=OBJECTD1FOO %s
+# OBJECTD1FOO: trace-symbols.s.tmp1: definition of foo
+
+# RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \
+# RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common --trace-symbol=hsymbol \
+# RUN: %t %t2 %t1 -o %t4 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN: FileCheck -check-prefix=OBJECTD2FOO %s
+# RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \
+# RUN: FileCheck -check-prefix=OBJECTD2FOO %s
+# OBJECTD2FOO: trace-symbols.s.tmp2: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN: FileCheck -check-prefix=SHLIBDCOMMON %s
+# SHLIBDCOMMON: trace-symbols.s.tmp1.so: definition of common
+
+# RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \
+# RUN: not FileCheck -check-prefix=SHLIBD1FOO %s
+# RUN: ld.lld -y foo -y common %t %t1.so %t2.so -o %t3 2>&1 | \
+# RUN: FileCheck -check-prefix=SHLIBD1FOO %s
+# RUN: ld.lld -y foo %t %t1.so %t2.a -o %t3 | \
+# RUN: FileCheck -check-prefix=SHLIBD1FOO %s
+# SHLIBD1FOO: trace-symbols.s.tmp1.so: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t2.so %t1.so -o %t3 2>&1 | \
+# RUN: FileCheck -check-prefix=SHLIBD2FOO %s
+# RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \
+# RUN: not FileCheck -check-prefix=SHLIBD2FOO %s
+# SHLIBD2FOO: trace-symbols.s.tmp2.so: definition of foo
+
+# RUN: ld.lld -y foo -y common %t %t2 %t1.a -o %t3 2>&1 | \
+# RUN: not FileCheck -check-prefix=ARCHIVEDCOMMON %s
+# ARCHIVEDCOMMON: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of \
+# common
+
+# RUN: ld.lld -y foo %t %t1.a %t2.so -o %t3 | \
+# RUN: FileCheck -check-prefix=ARCHIVED1FOO %s
+# ARCHIVED1FOO: trace-symbols.s.tmp1.a(trace-symbols.s.tmp1): definition of foo
+
+# RUN: ld.lld -y foo %t %t1.a %t2.a -o %t3 | \
+# RUN: FileCheck -check-prefix=ARCHIVED2FOO %s
+# ARCHIVED2FOO: trace-symbols.s.tmp2.a(trace-symbols.s.tmp2): definition of foo
+
+# RUN: ld.lld -y bar %t %t1.so %t2.so -o %t3 | \
+# RUN: FileCheck -check-prefix=SHLIBDBAR %s
+# SHLIBDBAR: trace-symbols.s.tmp2.so: definition of bar
+
+# RUN: ld.lld -y foo -y bar %t %t1.so %t2.so -o %t3 | \
+# RUN: not FileCheck -check-prefix=SHLIBRBAR %s
+# SHLIBRBAR: trace-symbols.s.tmp1.so: reference to bar
+
+# RUN: ld.lld -y foo -y bar %t -u bar --start-lib %t1 %t2 --end-lib -o %t3 | \
+# RUN: FileCheck -check-prefix=STARTLIB %s
+# STARTLIB: trace-symbols.s.tmp1: reference to bar
+
+.hidden hsymbol
+.globl _start
+.type _start, @function
+_start:
+call foo