diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -21,6 +21,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/GlobPattern.h" #include +#include #include namespace lld { @@ -125,6 +126,7 @@ std::pair thinLTOObjectSuffixReplace; std::pair thinLTOPrefixReplace; std::string rpath; + std::unordered_set traceSymbolsFromFile; std::vector versionDefinitions; std::vector auxiliaryList; std::vector filterList; @@ -206,6 +208,7 @@ bool sysvHash = false; bool target1Rel; bool trace; + bool traceAllSymbols; bool thinLTOEmitImportsFiles; bool thinLTOIndexOnly; bool timeTraceEnabled; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -803,6 +803,15 @@ return {false, false}; } +static std::unordered_set +getTraceSymbolsFromFile(opt::InputArgList &args) { + std::vector v = + args::getStrings(args, OPT_trace_symbols_from_file); + std::unordered_set traceSymbolsFromFile( + std::make_move_iterator(v.begin()), std::make_move_iterator(v.end())); + return traceSymbolsFromFile; +} + static void readCallGraph(MemoryBufferRef mb) { // Build a map from symbol name to section DenseMap map; @@ -1084,6 +1093,9 @@ config->timeTraceGranularity = args::getInteger(args, OPT_time_trace_granularity, 500); config->trace = args.hasArg(OPT_trace); + config->traceAllSymbols = args.hasArg(OPT_trace_all_symbols); + config->traceSymbolsFromFile = getTraceSymbolsFromFile(args); + config->undefined = args::getStrings(args, OPT_undefined); config->undefinedVersion = args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -419,6 +419,11 @@ def trace: F<"trace">, HelpText<"Print the names of the input files">; +def trace_all_symbols: F<"trace-all-symbols">, HelpText<"Trace references to all symbols">; + +defm trace_symbols_from_file: Eq<"trace-symbols-from-file", + "Trace symbols referenced or defined in a file">; + defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; defm undefined: Eq<"undefined", "Force undefined symbol during linking">, diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -142,6 +142,7 @@ // True if this symbol is specified by --trace-symbol option. uint8_t traced : 1; + inline bool needToTraceSymbol(); inline void replace(const Symbol &newSym); bool includeInDynsym() const; @@ -525,6 +526,18 @@ llvm_unreachable("unknown symbol kind"); } +// The symbol table is initialized after the file is parsed, but +// symbol tracing information is printed during parsing. If we +// want to print tracing information of symbols in a file, we need +// to check that the symbol is in the file the first time it is +// processed. +bool Symbol::needToTraceSymbol() { + return traced || config->traceAllSymbols || + (this->file != nullptr && + config->traceSymbolsFromFile.find(this->file->getName()) != + config->traceSymbolsFromFile.end()); +} + // replace() replaces "this" object with a given symbol by memcpy'ing // it over to "this". This function is called as a result of name // resolution, e.g. to replace an undefind symbol with a defined symbol. @@ -566,9 +579,10 @@ if (nameData == old.nameData && nameSize == 0 && old.nameSize != 0) nameSize = old.nameSize; - // Print out a log message if --trace-symbol was specified. + // Print out a log message if --trace-symbol or --trace-all-symbols + // was specified. // This is for debugging. - if (traced) + if (needToTraceSymbol()) printTraceSymbol(this); } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -458,7 +458,7 @@ return; } - if (traced) + if (needToTraceSymbol()) printTraceSymbol(&other); if (isLazy()) { diff --git a/lld/test/ELF/trace-all-symbols.s b/lld/test/ELF/trace-all-symbols.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/trace-all-symbols.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# Test --trace-all-symbols + +# 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: rm -f %t1.a +# RUN: llvm-ar rcs %t1.a %t1 +# RUN: rm -f %t2.a +# RUN: llvm-ar rcs %t2.a %t2 + +# RUN: ld.lld --trace-all-symbols %t %t1 %t2 -o %t3 | FileCheck %s +# CHECK-DAG: trace-all-symbols.s.tmp: definition of _start +# CHECK-DAG: trace-all-symbols.s.tmp: reference to foo +# CHECK-DAG: trace-all-symbols.s.tmp1: reference to bar +# CHECK-DAG: trace-all-symbols.s.tmp1: common definition of common +# CHECK-DAG: trace-all-symbols.s.tmp1: definition of foo +# CHECK-DAG: trace-all-symbols.s.tmp1: definition of func1 +# CHECK-DAG: trace-all-symbols.s.tmp1: reference to func2 +# CHECK-DAG: trace-all-symbols.s.tmp2: definition of bar +# CHECK-DAG: trace-all-symbols.s.tmp2: definition of foo +# CHECK-DAG: trace-all-symbols.s.tmp2: definition of func2 +# CHECK-DAG: trace-all-symbols.s.tmp1: definition of common + +.hidden hsymbol +.globl _start +.type _start, @function +_start: +call foo diff --git a/lld/test/ELF/trace-file.s b/lld/test/ELF/trace-file.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/trace-file.s @@ -0,0 +1,48 @@ +# REQUIRES: x86 +# Test --trace-symbols-from-file=file 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: rm -f %t1.a +# RUN: llvm-ar rcs %t1.a %t1 +# RUN: rm -f %t2.a +# RUN: llvm-ar rcs %t2.a %t2 + +# RUN: ld.lld --trace-symbols-from-file=%t %t %t1 %t2 -o %t3 | FileCheck --check-prefix=FILE0 %s +# FILE0-DAG: trace-file.s.tmp: definition of _start +# FILE0-DAG: trace-file.s.tmp: reference to foo + +# RUN: ld.lld --trace-symbols-from-file=%t1 %t %t1 %t2 -o %t3 | FileCheck --check-prefix=FILE1 %s +# FILE1-DAG: trace-file.s.tmp1: reference to bar +# FILE1-DAG: trace-file.s.tmp1: common definition of common +# FILE1-DAG: trace-file.s.tmp1: definition of foo +# FILE1-DAG: trace-file.s.tmp1: definition of func1 +# FILE1-DAG: trace-file.s.tmp1: reference to func2 +# FILE1-DAG: trace-file.s.tmp1: definition of common + +# RUN: ld.lld --trace-symbols-from-file=%t --trace-symbols-from-file=%t1 %t %t1 %t2 -o %t3 | FileCheck --check-prefix=FILE0AND1 %s +# FILE0AND1-DAG: trace-file.s.tmp: definition of _start +# FILE0AND1-DAG: trace-file.s.tmp: reference to foo +# FILE0AND1-DAG: trace-file.s.tmp1: reference to bar +# FILE0AND1-DAG: trace-file.s.tmp1: common definition of common +# FILE0AND1-DAG: trace-file.s.tmp1: definition of foo +# FILE0AND1-DAG: trace-file.s.tmp1: definition of func1 +# FILE0AND1-DAG: trace-file.s.tmp1: reference to func2 +# FILE0AND1-DAG: trace-file.s.tmp1: definition of common + +# RUN: ld.lld --trace-symbols-from-file=%t --trace-symbol=foo %t %t1 %t2 -o %t3 | FileCheck --check-prefix=FILE0FOO %s +# FILE0FOO-DAG: trace-file.s.tmp: definition of _start +# FILE0FOO-DAG: trace-file.s.tmp: reference to foo +# FILE0FOO-DAG: trace-file.s.tmp1: definition of foo +# FILE0FOO-DAG: trace-file.s.tmp2: definition of foo + +.hidden hsymbol +.globl _start +.type _start, @function +_start: +call foo