aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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