diff options
-rw-r--r-- | ELF/Config.h | 2 | ||||
-rw-r--r-- | ELF/Driver.cpp | 4 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 9 | ||||
-rw-r--r-- | ELF/InputFiles.h | 2 | ||||
-rw-r--r-- | ELF/Options.td | 3 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 11 | ||||
-rw-r--r-- | ELF/SymbolTable.h | 2 | ||||
-rw-r--r-- | test/ELF/Inputs/trace-symbols-foo-strong.s | 14 | ||||
-rw-r--r-- | test/ELF/Inputs/trace-symbols-foo-weak.s | 12 | ||||
-rw-r--r-- | test/ELF/trace-symbols.s | 84 |
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 |