Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -64,6 +64,7 @@ std::vector SearchPaths; std::vector Undefined; std::vector VersionScriptGlobals; + std::vector TraceSymbolList; std::vector BuildIdVector; bool AllowMultipleDefinition; bool AsNeeded = false; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -417,6 +417,12 @@ if (Optional Buffer = readFile(Arg->getValue())) parseVersionScript(*Buffer); } + for (auto *Arg : Args.filtered(OPT_y)) { + Config->TraceSymbolList.push_back(Arg->getValue()); + } + for (auto *Arg : Args.filtered(OPT_trace_symbol)) { + Config->TraceSymbolList.push_back(Arg->getValue()); + } } void LinkerDriver::createFiles(opt::InputArgList &Args) { Index: ELF/Error.h =================================================================== --- ELF/Error.h +++ ELF/Error.h @@ -52,6 +52,8 @@ fatal(EO.getError().message(), Prefix); } +void info(const Twine &Msg); + } // namespace elf } // namespace lld Index: ELF/Error.cpp =================================================================== --- ELF/Error.cpp +++ ELF/Error.cpp @@ -50,5 +50,9 @@ fatal(EC.message()); } +void info(const Twine &Msg) { + llvm::outs() << Msg << "\n"; +} + } // namespace elf } // namespace lld Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -51,6 +51,8 @@ StringRef getName() const { return MB.getBufferIdentifier(); } MemoryBufferRef MB; + void notify(StringRef &Name, bool isDefined); + // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -313,6 +313,28 @@ return new (IAlloc.Allocate()) InputSection(this, &Sec); } +// print the module names which references and defines the +// notified symbols provided through -y or trace-symbol option +void InputFile::notify(StringRef &Name, bool isDefined) { + if (!Config->TraceSymbolList.empty()) { + for (StringRef S : Config->TraceSymbolList) { + if (!S.compare(Name)) { + std::string Msg; + if (!ArchiveName.empty()) + Msg += ArchiveName.str() + "(" + this->getName().str() + ")"; + else + Msg += this->getName().str(); + if (isDefined) + Msg += ": definition of " + Name.str(); + else + Msg += ": reference to " + Name.str(); + info(Msg); + break; + } + } + } +} + template void elf::ObjectFile::initializeSymbols() { this->initStringTable(); Elf_Sym_Range Syms = this->getElfSymbols(false); @@ -350,11 +372,13 @@ switch (Sym->st_shndx) { case SHN_UNDEF: + InputFile::notify(Name, false); return elf::Symtab::X ->addUndefined(Name, Binding, Sym->st_other, Sym->getType(), /*CanOmitFromDynSym*/ false, this) ->body(); case SHN_COMMON: + InputFile::notify(Name, true); return elf::Symtab::X ->addCommon(Name, Sym->st_size, Sym->st_value, Binding, Sym->st_other, Sym->getType(), this) @@ -525,10 +549,14 @@ StringRef Name = check(Sym.getName(this->StringTable)); if (Sym.isUndefined()) { + InputFile::notify(Name, false); Undefs.push_back(Name); continue; } + if (Sym.isDefined()) + InputFile::notify(Name, true); + if (Versym) { // Ignore local symbols and non-default versions. if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN)) Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -122,6 +122,12 @@ def z : JoinedOrSeparate<["-"], "z">, MetaVarName<"