diff --git a/include/eld/Config/GeneralOptions.h b/include/eld/Config/GeneralOptions.h index f71109fb55..4b8e2a246a 100644 --- a/include/eld/Config/GeneralOptions.h +++ b/include/eld/Config/GeneralOptions.h @@ -152,6 +152,8 @@ class GeneralOptions { bool traceReloc(std::string const &RelocName) const; + bool tracePlugin(std::string const &PluginName) const; + bool traceLTO(void) const; bool codegenOpts(void) const; @@ -1041,6 +1043,10 @@ class GeneralOptions { bool isSectionTracingRequested() const { return SectionTracingRequested; } + void setPluginTracingRequested() { PluginTracingRequested = true; } + + bool isPluginTracingRequested() const { return PluginTracingRequested; } + // --------------Dynamic Linker------------------------- bool hasDynamicLinker() const { return BDynamicLinker; } @@ -1376,9 +1382,11 @@ class GeneralOptions { std::vector SymbolTrace; std::vector RelocTrace; std::vector SectionTrace; + std::vector PluginTrace; std::vector SymbolsToTrace; std::vector SectionsToTrace; std::vector RelocsToTrace; + std::vector PluginsToTrace; std::vector MergeStrSectionsToTrace; MergeStrTraceType MergeStrTraceValue = MergeStrTraceType::NONE; std::set RelocVerify; @@ -1419,6 +1427,7 @@ class GeneralOptions { llvm::StringRef TrampolineMapFile; // TrampolineMap bool SymbolTracingRequested = false; bool SectionTracingRequested = false; + bool PluginTracingRequested = false; std::vector RequestedTimeRegions; DiagnosticEngine *DiagEngine = nullptr; bool BDynamicLinker = true; diff --git a/include/eld/Driver/GnuLinkerOptions.td b/include/eld/Driver/GnuLinkerOptions.td index a720bed99b..65c19f3e4a 100644 --- a/include/eld/Driver/GnuLinkerOptions.td +++ b/include/eld/Driver/GnuLinkerOptions.td @@ -866,6 +866,7 @@ defm trace "\t\t\t --trace=garbage-collection : trace linker garbage " "collection\n" "\t\t\t --trace=plugin : trace plugin\n" + "\t\t\t --trace=plugin= : trace a single plugin\n" "\t\t\t --trace=threads : trace threads\n" "\t\t\t --trace=assignments : trace symbol assignments\n" "\t\t\t --trace=command-line : trace header info\n" diff --git a/include/eld/PluginAPI/LinkerWrapper.h b/include/eld/PluginAPI/LinkerWrapper.h index b02d3945c6..7004f8e5ef 100644 --- a/include/eld/PluginAPI/LinkerWrapper.h +++ b/include/eld/PluginAPI/LinkerWrapper.h @@ -714,6 +714,11 @@ class DLL_A_EXPORT LinkerWrapper { /// Returns true if user has requested verbose diagnostics. bool isVerbose() const; + /// Returns true if this plugin is being traced, i.e. --trace=plugin + /// was given without a scope, or with a scope (--trace=plugin=) + /// that matches this plugin's name. + bool isTraced() const; + eld::Expected> getAllOutputSections() const; diff --git a/include/eld/Script/Plugin.h b/include/eld/Script/Plugin.h index 3fb51a80ab..e5b8a56ee0 100644 --- a/include/eld/Script/Plugin.h +++ b/include/eld/Script/Plugin.h @@ -61,6 +61,10 @@ class Plugin { std::string getPluginOptions() const { return PluginOptions; } + /// Returns true if diagnostics should be traced for this plugin, honoring + /// both bare --trace=plugin and scoped --trace=plugin=. + bool isTraced() const; + plugin::PluginBase *getLinkerPlugin() const { return UserPluginHandle; } void *getLibraryHandle() const { return PluginLibraryHandle; } @@ -96,9 +100,10 @@ class Plugin { bool registerPlugin(void *Handle); // -------------- Load/Unload/Reset Plugin ------------------------ - static void *loadPlugin(std::string Name, Module *Module); + static void *loadPlugin(std::string Name, Module *Module, bool IsTraced); - static bool unload(std::string Name, void *LibraryHandle, Module *Module); + static bool unload(std::string Name, void *LibraryHandle, Module *Module, + bool IsTraced); void reset(); diff --git a/lib/Config/GeneralOptions.cpp b/lib/Config/GeneralOptions.cpp index a0cd9decdc..7fe841c12a 100644 --- a/lib/Config/GeneralOptions.cpp +++ b/lib/Config/GeneralOptions.cpp @@ -210,6 +210,13 @@ eld::Expected GeneralOptions::setTrace(const char *PTraceType) { std::string Sym = TraceType.substr(Pos + 1).str(); SectionTrace.emplace_back(llvm::Regex(Sym)); SectionsToTrace.emplace_back(Sym); + } else if (TraceType.starts_with("plugin") && TraceType.contains('=')) { + setPluginTracingRequested(); + TraceMe = DiagEngine->getPrinter()->TracePlugin; + size_t Pos = TraceType.find_last_of('='); + std::string PluginName = TraceType.substr(Pos + 1).str(); + PluginTrace.emplace_back(llvm::Regex(PluginName)); + PluginsToTrace.emplace_back(PluginName); } else if (TraceType.starts_with("merge-strings")) { size_t Pos = TraceType.find_last_of('='); std::string Arg = TraceType.substr(Pos + 1).str(); @@ -402,6 +409,20 @@ bool GeneralOptions::traceReloc(std::string const &RelocName) const { }); } +bool GeneralOptions::tracePlugin(std::string const &PluginName) const { + if (!DiagEngine->getPrinter()->tracePlugins()) + return false; + // Bare "--trace=plugin" (no scoped names given): trace every plugin. + if (!PluginTracingRequested) + return true; + StringRef PluginRef(PluginName); + return llvm::any_of(PluginsToTrace, + [&](const std::string &S) { return S == PluginName; }) || + llvm::any_of(PluginTrace, [&](const llvm::Regex &Regex) { + return Regex.match(PluginRef); + }); +} + std::vector GeneralOptions::getLTOOptionsAsString() const { std::vector ReturnValue; if ((LTOOptions & LTOVerbose) == LTOVerbose) diff --git a/lib/Core/LinkerScript.cpp b/lib/Core/LinkerScript.cpp index adcdf6cb0e..48292ff521 100644 --- a/lib/Core/LinkerScript.cpp +++ b/lib/Core/LinkerScript.cpp @@ -78,7 +78,8 @@ void LinkerScript::unloadPlugins(Module *Module) { continue; // Run the cleanup function H.second->cleanup(); - Plugin::unload(H.first, H.second->getLibraryHandle(), Module); + Plugin::unload(H.first, H.second->getLibraryHandle(), Module, + H.second->isTraced()); if (Module->getPrinter()->isVerbose()) Diag->raise(Diag::unloaded_plugin) << H.first; } @@ -574,7 +575,7 @@ bool LinkerScript::loadPlugin(Plugin &P, Module &M) { void *Handle = nullptr; auto &PAL = M.getPluginActivityLog(); if (I == MLibraryToPluginMap.end()) { - Handle = Plugin::loadPlugin(ResolvedPath, &M); + Handle = Plugin::loadPlugin(ResolvedPath, &M, P.isTraced()); MLibraryToPluginMap.insert(std::make_pair(ResolvedPath, &P)); } else { Handle = I->second->getLibraryHandle(); diff --git a/lib/LinkerWrapper/LinkerWrapper.cpp b/lib/LinkerWrapper/LinkerWrapper.cpp index 37dc9dca3f..6366da36e8 100644 --- a/lib/LinkerWrapper/LinkerWrapper.cpp +++ b/lib/LinkerWrapper/LinkerWrapper.cpp @@ -1021,6 +1021,8 @@ bool LinkerWrapper::isVerbose() const { return m_Module.getConfig().getPrinter()->isVerbose(); } +bool LinkerWrapper::isTraced() const { return m_Plugin->isTraced(); } + eld::Expected> LinkerWrapper::getAllOutputSections() const { CHECK_LINK_STATE(*this, "ActBeforeRuleMatching", "BeforeLayout", diff --git a/lib/Plugin/PluginManager.cpp b/lib/Plugin/PluginManager.cpp index 871c9624eb..df46d48ee0 100644 --- a/lib/Plugin/PluginManager.cpp +++ b/lib/Plugin/PluginManager.cpp @@ -111,7 +111,7 @@ bool PluginManager::callVisitSymbolHook(LDSymbol *Sym, llvm::StringRef SymName, void PluginManager::addSymbolVisitor(eld::Plugin *P) { SymbolVisitors.insert(P); - if (DE.getPrinter()->tracePlugins()) + if (P->isTraced()) DE.raise(Diag::trace_plugin_enable_visit_symbol) << P->getPluginName(); } @@ -136,7 +136,7 @@ void PluginManager::setAuxiliarySymbolNameMap( const ObjectFile::AuxiliarySymbolNameMap &AuxSymNameMap, const Plugin *P) { ObjFile->setAuxiliarySymbolNameMap(AuxSymNameMap); AuxSymNameMapProvider[ObjFile] = P; - if (DE.getPrinter()->tracePlugins()) + if (P->isTraced()) DE.raise(Diag::trace_set_aux_sym_name_map) << P->getPluginName() << ObjFile->getInput()->decoratedPath(); } diff --git a/lib/Script/Plugin.cpp b/lib/Script/Plugin.cpp index e5fee646b7..f463745c6f 100644 --- a/lib/Script/Plugin.cpp +++ b/lib/Script/Plugin.cpp @@ -49,6 +49,10 @@ Plugin::Plugin(plugin::Plugin::Type T, std::string LibraryName, ThisModule(Module), ThisConfig(Module.getConfig()), IsDefaultPlugin(DefaultPlugin) {} +bool Plugin::isTraced() const { + return ThisConfig.options().tracePlugin(getPluginType()); +} + std::string Plugin::resolvePath(const LinkerConfig &PConfig) { // Library already loaded! if (PluginLibraryHandle) @@ -79,13 +83,14 @@ std::string Plugin::resolvePath(const LinkerConfig &PConfig) { if (nullptr != NS) { PluginLibraryName = NS->getFullPath(); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::using_plugin) << PluginLibraryName << Name; } return PluginLibraryName; } -void *Plugin::loadPlugin(std::string LibraryName, Module *Module) { +void *Plugin::loadPlugin(std::string LibraryName, Module *Module, + bool IsTraced) { void *LibraryHandle = DynamicLibrary::Load(LibraryName); DiagnosticEngine *DiagEngine = Module->getConfig().getDiagEngine(); if (!LibraryHandle) { @@ -94,7 +99,7 @@ void *Plugin::loadPlugin(std::string LibraryName, Module *Module) { return nullptr; } - if (Module->getPrinter()->tracePlugins()) + if (IsTraced) DiagEngine->raise(Diag::loaded_library) << LibraryName; return LibraryHandle; @@ -151,7 +156,7 @@ bool Plugin::setFunctions() { return false; } - if (ThisModule.getPrinter()->tracePlugins()) { + if (isTraced()) { ThisConfig.raise(Diag::found_register_function) << Register << LibraryName; ThisConfig.raise(Diag::found_function_for_plugintype) << PluginFunc << LibraryName; @@ -159,7 +164,7 @@ bool Plugin::setFunctions() { std::string PluginCleanupFunc = "Cleanup"; void *C = DynamicLibrary::GetFunction(PluginLibraryHandle, PluginCleanupFunc); - if (C && ThisModule.getPrinter()->tracePlugins()) { + if (C && isTraced()) { ThisConfig.raise(Diag::found_cleanup_function) << PluginCleanupFunc << LibraryName; } @@ -182,7 +187,7 @@ bool Plugin::setFunctions() { bool Plugin::getUserPlugin() { std::string LibraryName = DynamicLibrary::getLibraryName(Name); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::registering_all_functions); UserPluginHandle = (*GetPluginFunction)(getPluginType().c_str()); @@ -192,7 +197,7 @@ bool Plugin::getUserPlugin() { return false; } - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::found_plugin_handler) << getPluginType() << LibraryName; @@ -211,7 +216,7 @@ bool Plugin::init(eld::OutputTarWriter *OutputTar) { return false; eld::RegisterTimer T( "Init", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::note_initializing_plugin) << getPluginType() << DynamicLibrary::getLibraryName(Name) << UserPluginHandle->GetName(); @@ -235,14 +240,14 @@ bool Plugin::run(std::vector &Plugins) { return false; eld::RegisterTimer T( "Run", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::running_plugin) << getPluginType() << DynamicLibrary::getLibraryName(Name) << UserPluginHandle->GetName(); Plugins.push_back(this); Running R(this); plugin::Plugin *P = llvm::cast(UserPluginHandle); - plugin::Plugin::Status S = P->Run(ThisModule.getPrinter()->tracePlugins()); + plugin::Plugin::Status S = P->Run(isTraced()); if (S == plugin::Plugin::Status::ERROR || P->GetLastError()) { ThisConfig.raise(Diag::plugin_has_error) << getPluginType() << DynamicLibrary::getLibraryName(Name) @@ -266,11 +271,12 @@ bool Plugin::cleanup() { return true; } -bool Plugin::unload(std::string LibraryName, void *Handle, Module *Module) { +bool Plugin::unload(std::string LibraryName, void *Handle, Module *Module, + bool IsTraced) { if (Handle) { DynamicLibrary::Unload(Handle); - if (Module->getPrinter()->tracePlugins()) + if (IsTraced) Module->getConfig().raise(Diag::unloaded_library) << LibraryName; } @@ -290,7 +296,7 @@ bool Plugin::destroy() { return false; eld::RegisterTimer T( "Destroy", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::plugin_destroy) << getPluginType(); plugin::Plugin *P = llvm::cast(UserPluginHandle); P->Destroy(); @@ -332,7 +338,7 @@ bool Plugin::check() { return false; } - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::note_plugin_version) << PluginMajor << PluginMinor << DynamicLibrary::getLibraryName(Name) << getPluginType(); @@ -522,7 +528,7 @@ void Plugin::callInitHook() { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T("Init", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_init) << getPluginName(); P->Init(PluginOptions); } @@ -531,7 +537,7 @@ void Plugin::callDestroyHook() { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T("Destroy", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_destroy) << getPluginName(); P->Destroy(); } @@ -539,7 +545,7 @@ void Plugin::callDestroyHook() { void Plugin::registerCommandLineOption( const std::string &Option, bool HasValue, const CommandLineOptionSpec::OptionHandlerType &OptionHandler) { - if (ThisModule.getPrinter()->tracePlugins()) { + if (isTraced()) { if (HasValue) ThisConfig.raise(Diag::trace_plugin_register_opt_with_val) << getPluginName() << Option; @@ -568,7 +574,7 @@ void Plugin::callVisitSectionsHook(InputFile &IF) { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T("VisitSections", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_visit_sections) << getPluginName() << IF.getInput()->decoratedPath(); P->VisitSections(plugin::InputFile(&IF)); @@ -579,7 +585,7 @@ void Plugin::callVisitSymbolHook(LDSymbol *Sym, llvm::StringRef SymName, plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T("VisitSymbol", ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_visit_symbol) << getPluginName() << SymName; std::unique_ptr UpSymInfo = std::make_unique(SymInfo); @@ -593,7 +599,7 @@ void Plugin::callActBeforeRuleMatchingHook() { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T(HookName, ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_hook) << getPluginName() << HookName; P->ActBeforeRuleMatching(); } @@ -603,7 +609,7 @@ void Plugin::callActBeforeSectionMergingHook() { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T(HookName, ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_hook) << getPluginName() << HookName; P->ActBeforeSectionMerging(); } @@ -613,7 +619,7 @@ void Plugin::callActBeforePerformingLayoutHook() { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T(HookName, ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_hook) << getPluginName() << HookName; P->ActBeforePerformingLayout(); } @@ -623,7 +629,7 @@ void Plugin::callActBeforeWritingOutputHook() { plugin::LinkerPlugin *P = llvm::cast(UserPluginHandle); RegisterTimer T(HookName, ThisModule.saveString(UserPluginHandle->GetName()), Stats); - if (ThisModule.getPrinter()->tracePlugins()) + if (isTraced()) ThisConfig.raise(Diag::trace_plugin_hook) << getPluginName() << HookName; P->ActBeforeWritingOutput(); } diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index 6deefbde35..a4456b7cbf 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -4626,7 +4626,7 @@ bool GNULDBackend::RunPluginsAndProcessHelper( return false; } - if (m_Module.getPrinter()->tracePlugins()) + if (O->prolog().getPlugin()->isTraced()) config().raise(Diag::allocating_memory) << S->size() << S->name(); MemoryRegion mr(reinterpret_cast(MB.base()), @@ -4639,10 +4639,10 @@ bool GNULDBackend::RunPluginsAndProcessHelper( return false; } } - if (m_Module.getPrinter()->tracePlugins()) + if (O->prolog().getPlugin()->isTraced()) config().raise(Diag::applying_relocations) << S->name(); m_Module.getLinker()->getObjLinker()->relocation(false); - if (m_Module.getPrinter()->tracePlugins()) + if (O->prolog().getPlugin()->isTraced()) config().raise(Diag::syncing_relocations) << S->name(); m_Module.getLinker()->getObjLinker()->syncRelocations( reinterpret_cast(MB.base())); @@ -4668,7 +4668,7 @@ bool GNULDBackend::RunPluginsAndProcessHelper( B.Name = std::string(S->name()); // Add the Memory Block. - if (m_Module.getPrinter()->tracePlugins()) + if (O->prolog().getPlugin()->isTraced()) config().raise(Diag::adding_memory_blocks) << S->name(); // Add Memory Blocks. @@ -4677,7 +4677,7 @@ bool GNULDBackend::RunPluginsAndProcessHelper( else FOP->AddBlocks(std::move(B)); - if (m_Module.getPrinter()->tracePlugins()) + if (O->prolog().getPlugin()->isTraced()) config().raise(Diag::calling_handler) << S->name(); // Run the algorithm. @@ -4689,7 +4689,7 @@ bool GNULDBackend::RunPluginsAndProcessHelper( auto RB = MatchSections ? VAP->GetBlocks() : FOP->GetBlocks(); - if (m_Module.getPrinter()->tracePlugins()) + if (O->prolog().getPlugin()->isTraced()) config().raise(Diag::plugin_returned_blocks) << RB.size() << S->name(); ELFSection *OutputSection = S; diff --git a/test/UnitTests/PluginAPI/CMakeLists.txt b/test/UnitTests/PluginAPI/CMakeLists.txt index 326b9f798f..d26dae90b3 100644 --- a/test/UnitTests/PluginAPI/CMakeLists.txt +++ b/test/UnitTests/PluginAPI/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(INIFileTests) add_subdirectory(ThreadPoolTests) +add_subdirectory(TracePluginTests) diff --git a/test/UnitTests/PluginAPI/TracePluginTests/CMakeLists.txt b/test/UnitTests/PluginAPI/TracePluginTests/CMakeLists.txt new file mode 100644 index 0000000000..93ec47f00a --- /dev/null +++ b/test/UnitTests/PluginAPI/TracePluginTests/CMakeLists.txt @@ -0,0 +1,2 @@ +add_eld_unittest(TracePluginTests TracePluginTest.cpp) +target_link_libraries(TracePluginTests PRIVATE ELDCore ELDConfig ELDScript ELDDiagnostics LW) diff --git a/test/UnitTests/PluginAPI/TracePluginTests/TracePluginTest.cpp b/test/UnitTests/PluginAPI/TracePluginTests/TracePluginTest.cpp new file mode 100644 index 0000000000..af5654bb07 --- /dev/null +++ b/test/UnitTests/PluginAPI/TracePluginTests/TracePluginTest.cpp @@ -0,0 +1,104 @@ +//===- TracePluginTest.cpp -------------------------------------------===// +// Part of the eld Project, under the BSD License +// See https://github.com/qualcomm/eld/LICENSE.txt for license information. +// SPDX-License-Identifier: BSD-3-Clause +//===----------------------------------------------------------------------===// +#include "eld/Config/GeneralOptions.h" +#include "eld/Config/LinkerConfig.h" +#include "eld/Core/LinkerScript.h" +#include "eld/Core/Module.h" +#include "eld/Diagnostics/DiagnosticEngine.h" +#include "eld/PluginAPI/LinkerWrapper.h" +#include "eld/Script/Plugin.h" +#include "gtest/gtest.h" + +using namespace eld; + +namespace { + +class TracePluginTest : public ::testing::Test { +protected: + void SetUp() override { + DiagEngine = make(/*useColor=*/false); + Config = make(DiagEngine); + Script = make(DiagEngine); + Mod = make(*Script, *Config, /*layoutInfo=*/nullptr); + } + + // Constructs a Plugin named `PluginName` along with a standalone + // LinkerWrapper wrapping it. We construct the LinkerWrapper directly + // (rather than via Plugin::getLinkerWrapper(), which requires a real + // dynamically-loaded plugin library to have registered itself first) + // since LinkerWrapper::isTraced() only needs the Plugin* it was built + // with. + eld::Plugin *makePlugin(const std::string &PluginName, + plugin::LinkerWrapper **LWOut = nullptr) { + auto *P = make(plugin::PluginBase::Type::OutputSectionIterator, + /*Name=*/PluginName, /*R=*/PluginName, + /*O=*/"", /*Stats=*/false, + /*DefaultPlugin=*/false, *Mod); + auto *LW = make(P, *Mod); + if (LWOut) + *LWOut = LW; + return P; + } + + DiagnosticEngine *DiagEngine = nullptr; + LinkerConfig *Config = nullptr; + LinkerScript *Script = nullptr; + Module *Mod = nullptr; +}; + +TEST_F(TracePluginTest, NotTracedByDefault) { + plugin::LinkerWrapper *LW = nullptr; + eld::Plugin *P = makePlugin("MyPlugin", &LW); + EXPECT_FALSE(P->isTraced()); + EXPECT_FALSE(LW->isTraced()); +} + +TEST_F(TracePluginTest, UnscopedTraceTracesEveryPlugin) { + ASSERT_TRUE((bool)Config->options().setTrace("plugin")); + + plugin::LinkerWrapper *LW1 = nullptr, *LW2 = nullptr; + eld::Plugin *P1 = makePlugin("PluginOne", &LW1); + eld::Plugin *P2 = makePlugin("PluginTwo", &LW2); + EXPECT_TRUE(P1->isTraced()); + EXPECT_TRUE(P2->isTraced()); + EXPECT_TRUE(LW1->isTraced()); + EXPECT_TRUE(LW2->isTraced()); +} + +TEST_F(TracePluginTest, ScopedTraceOnlyMatchesNamedPlugin) { + ASSERT_TRUE((bool)Config->options().setTrace("plugin=MyPlugin")); + + plugin::LinkerWrapper *MatchingLW = nullptr, *NonMatchingLW = nullptr; + eld::Plugin *Matching = makePlugin("MyPlugin", &MatchingLW); + eld::Plugin *NonMatching = makePlugin("OtherPlugin", &NonMatchingLW); + EXPECT_TRUE(Matching->isTraced()); + EXPECT_TRUE(MatchingLW->isTraced()); + EXPECT_FALSE(NonMatching->isTraced()); + EXPECT_FALSE(NonMatchingLW->isTraced()); +} + +TEST_F(TracePluginTest, ScopedTraceNameIsARegex) { + ASSERT_TRUE((bool)Config->options().setTrace("plugin=My.*")); + + eld::Plugin *Matching = makePlugin("MyPlugin"); + eld::Plugin *NonMatching = makePlugin("OtherPlugin"); + EXPECT_TRUE(Matching->isTraced()); + EXPECT_FALSE(NonMatching->isTraced()); +} + +TEST_F(TracePluginTest, MultipleScopedTracesAreCumulative) { + ASSERT_TRUE((bool)Config->options().setTrace("plugin=PluginOne")); + ASSERT_TRUE((bool)Config->options().setTrace("plugin=PluginTwo")); + + eld::Plugin *P1 = makePlugin("PluginOne"); + eld::Plugin *P2 = makePlugin("PluginTwo"); + eld::Plugin *P3 = makePlugin("PluginThree"); + EXPECT_TRUE(P1->isTraced()); + EXPECT_TRUE(P2->isTraced()); + EXPECT_FALSE(P3->isTraced()); +} + +} // namespace