From 583620a0949a4b479b2dac62480310edd750367c Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Mon, 4 Aug 2025 10:26:38 +0530 Subject: [PATCH 01/10] [WIP][LLVM] Test: Validate Auto Shared Library Resolver Correctness --- .../cling/Interpreter/DynamicLibraryManager.h | 16 +++++++++----- .../lib/Interpreter/DynamicLibraryManager.cpp | 5 +++++ .../DynamicLibraryManagerSymbol.cpp | 21 ++++++++++++++++++- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h index de5bb2da8e8ee..bc203ef6ade8d 100644 --- a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +++ b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h @@ -10,6 +10,7 @@ #ifndef CLING_DYNAMIC_LIBRARY_MANAGER_H #define CLING_DYNAMIC_LIBRARY_MANAGER_H +#include "llvm/ExecutionEngine/Orc/Shared/DynamicLoader.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" @@ -66,6 +67,8 @@ namespace cling { Dyld* m_Dyld = nullptr; + std::unique_ptr m_DyldController; + ///\brief Concatenates current include paths and the system include paths /// and performs a lookup for the filename. /// See more information for RPATH and RUNPATH: https://en.wikipedia.org/wiki/Rpath @@ -123,11 +126,14 @@ namespace cling { void addSearchPath(llvm::StringRef dir, bool isUser = true, bool prepend = false) { if (!dir.empty()) { - for (auto & item : m_SearchPaths) - if (dir == item.Path) - return; - auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); - m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); + // for (auto & item : m_SearchPaths) + // if (dir == item.Path) + // return; + // auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); + // m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); + m_DyldController->addScanPath(dir.str(), + isUser ? llvm::orc::PathType::User + : llvm::orc::PathType::System); } } diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp index 320dde689c7fd..708a75ee59f66 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp @@ -44,6 +44,9 @@ namespace cling { #endif }; + m_DyldController = llvm::orc::LibraryResolutionDriver::create( + llvm::orc::LibraryResolver::Setup::create({})); + // Behaviour is to not add paths that don't exist...In an interpreted env // does this make sense? Path could pop into existance at any time. for (const char* Var : kSysLibraryEnv) { @@ -393,6 +396,7 @@ namespace cling { if (!insRes.second) return kLoadLibAlreadyLoaded; m_LoadedLibraries.insert(canonicalLoadedLib); + m_DyldController->markLibraryLoaded(canonicalLoadedLib); return kLoadLibSuccess; } @@ -424,6 +428,7 @@ namespace cling { m_DyLibs.erase(dyLibHandle); m_LoadedLibraries.erase(canonicalLoadedLib); + m_DyldController->markLibraryUnLoaded(canonicalLoadedLib); } bool DynamicLibraryManager::isLibraryLoaded(llvm::StringRef fullPath) const { diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index 5d523776aa003..40c97ac622a2a 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1357,7 +1357,26 @@ namespace cling { DynamicLibraryManager::searchLibrariesForSymbol(StringRef mangledName, bool searchSystem/* = true*/) const { assert(m_Dyld && "Must call initialize dyld before!"); - return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem); + std::string res = ""; + std::vector sym; + sym.push_back(mangledName.str()); + llvm::orc::SearchPolicy policy = { + {{llvm::orc::LibraryManager::State::Queried, llvm::orc::PathType::User}, + {llvm::orc::LibraryManager::State::Unloaded, + llvm::orc::PathType::User}, + {llvm::orc::LibraryManager::State::Queried, + llvm::orc::PathType::System}, + {llvm::orc::LibraryManager::State::Unloaded, + llvm::orc::PathType::System}}}; + m_DyldController->resolveSymbols( + sym, + [&](llvm::orc::LibraryResolver::SymbolQuery& Q) { + if (auto s = Q.getResolvedLib(mangledName)) + res = *s; + }, + policy); + return res; + // return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem); } std::string DynamicLibraryManager::getSymbolLocation(void *func) { From 1d6af3875215c1abe90f5ce1236989579392f6a1 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Sat, 9 Aug 2025 17:22:32 +0530 Subject: [PATCH 02/10] Fix lookup failure --- .../include/cling/Interpreter/DynamicLibraryManager.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h index bc203ef6ade8d..e7fc0e878cacb 100644 --- a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +++ b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h @@ -126,11 +126,11 @@ namespace cling { void addSearchPath(llvm::StringRef dir, bool isUser = true, bool prepend = false) { if (!dir.empty()) { - // for (auto & item : m_SearchPaths) - // if (dir == item.Path) - // return; - // auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); - // m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); + for (auto & item : m_SearchPaths) + if (dir == item.Path) + return; + auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); + m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); m_DyldController->addScanPath(dir.str(), isUser ? llvm::orc::PathType::User : llvm::orc::PathType::System); From b2a68c7389f54fb58da238c03a35efcb0ae8f3d0 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Tue, 16 Sep 2025 14:35:03 +0530 Subject: [PATCH 03/10] Update changes with the llvms PR --- .../cling/Interpreter/DynamicLibraryManager.h | 8 ++-- .../lib/Interpreter/DynamicLibraryManager.cpp | 10 +++-- .../DynamicLibraryManagerSymbol.cpp | 41 ++++++++++++++----- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h index e7fc0e878cacb..06406bcc1c2e3 100644 --- a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +++ b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h @@ -10,7 +10,7 @@ #ifndef CLING_DYNAMIC_LIBRARY_MANAGER_H #define CLING_DYNAMIC_LIBRARY_MANAGER_H -#include "llvm/ExecutionEngine/Orc/Shared/DynamicLoader.h" +#include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" @@ -131,9 +131,9 @@ namespace cling { return; auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); - m_DyldController->addScanPath(dir.str(), - isUser ? llvm::orc::PathType::User - : llvm::orc::PathType::System); + // m_DyldController->addScanPath(dir.str(), + // isUser ? llvm::orc::PathType::User + // : llvm::orc::PathType::System); } } diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp index 708a75ee59f66..b4648cf9ed3b3 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp @@ -44,8 +44,8 @@ namespace cling { #endif }; - m_DyldController = llvm::orc::LibraryResolutionDriver::create( - llvm::orc::LibraryResolver::Setup::create({})); + // m_DyldController = llvm::orc::LibraryResolutionDriver::create( + // llvm::orc::LibraryResolver::Setup::create({})); // Behaviour is to not add paths that don't exist...In an interpreted env // does this make sense? Path could pop into existance at any time. @@ -396,7 +396,8 @@ namespace cling { if (!insRes.second) return kLoadLibAlreadyLoaded; m_LoadedLibraries.insert(canonicalLoadedLib); - m_DyldController->markLibraryLoaded(canonicalLoadedLib); + if (m_DyldController) + m_DyldController->markLibraryLoaded(canonicalLoadedLib); return kLoadLibSuccess; } @@ -428,7 +429,8 @@ namespace cling { m_DyLibs.erase(dyLibHandle); m_LoadedLibraries.erase(canonicalLoadedLib); - m_DyldController->markLibraryUnLoaded(canonicalLoadedLib); + if (m_DyldController) + m_DyldController->markLibraryUnLoaded(canonicalLoadedLib); } bool DynamicLibraryManager::isLibraryLoaded(llvm::StringRef fullPath) const { diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index 40c97ac622a2a..3d1e84d0b4cca 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1335,28 +1335,43 @@ namespace cling { } DynamicLibraryManager::~DynamicLibraryManager() { - static_assert(sizeof(Dyld) > 0, "Incomplete type"); - delete m_Dyld; + // static_assert(sizeof(Dyld) > 0, "Incomplete type"); + // delete m_Dyld; } void DynamicLibraryManager::initializeDyld( std::function shouldPermanentlyIgnore) { //assert(!m_Dyld && "Already initialized!"); - if (m_Dyld) - delete m_Dyld; + if (m_DyldController) + m_DyldController.reset(); + + llvm::orc::LibraryResolver::Setup S = + llvm::orc::LibraryResolver::Setup::create({}); + S.shouldScan = shouldPermanentlyIgnore; + m_DyldController = llvm::orc::LibraryResolutionDriver::create(S); + + for (const auto& info : m_SearchPaths) { + m_DyldController->addScanPath(info.Path, + info.IsUser ? llvm::orc::PathType::User + : llvm::orc::PathType::System); + } + + for (const auto& lib : m_LoadedLibraries) { + m_DyldController->markLibraryLoaded(lib.first()); + } - std::string exeP = GetExecutablePath(); - auto ObjF = - cantFail(llvm::object::ObjectFile::createObjectFile(exeP)); + // std::string exeP = GetExecutablePath(); + // auto ObjF = + // cantFail(llvm::object::ObjectFile::createObjectFile(exeP)); - m_Dyld = new Dyld(*this, shouldPermanentlyIgnore, - ObjF.getBinary()->getFileFormatName()); + // m_Dyld = new Dyld(*this, shouldPermanentlyIgnore, + // ObjF.getBinary()->getFileFormatName()); } std::string DynamicLibraryManager::searchLibrariesForSymbol(StringRef mangledName, bool searchSystem/* = true*/) const { - assert(m_Dyld && "Must call initialize dyld before!"); + assert(m_DyldController && "Must call initialize dyld before!"); std::string res = ""; std::vector sym; sym.push_back(mangledName.str()); @@ -1368,13 +1383,17 @@ namespace cling { llvm::orc::PathType::System}, {llvm::orc::LibraryManager::State::Unloaded, llvm::orc::PathType::System}}}; + llvm::orc::SearchConfig config; + config.policy = policy; + config.options.FilterFlags = + llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; m_DyldController->resolveSymbols( sym, [&](llvm::orc::LibraryResolver::SymbolQuery& Q) { if (auto s = Q.getResolvedLib(mangledName)) res = *s; }, - policy); + config); return res; // return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem); } From a4a1011c72107390e2e6c94df7a6cb1060bfd944 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Tue, 16 Sep 2025 18:02:06 +0530 Subject: [PATCH 04/10] Fix should scan call issue --- .../cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index 3d1e84d0b4cca..ba3d9792c96a9 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1347,7 +1347,9 @@ namespace cling { llvm::orc::LibraryResolver::Setup S = llvm::orc::LibraryResolver::Setup::create({}); - S.shouldScan = shouldPermanentlyIgnore; + S.shouldScan = [&](llvm::StringRef lib) -> bool { + return !shouldPermanentlyIgnore(lib); + }; m_DyldController = llvm::orc::LibraryResolutionDriver::create(S); for (const auto& info : m_SearchPaths) { From 369ebe3e39364f3aab4866078c9c05e085392973 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Wed, 17 Sep 2025 19:59:24 +0530 Subject: [PATCH 05/10] Fix initialization setup issue --- .../cling/Interpreter/DynamicLibraryManager.h | 7 ++++--- .../Interpreter/DynamicLibraryManagerSymbol.cpp | 17 +++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h index 06406bcc1c2e3..385e6a7c7cd37 100644 --- a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +++ b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h @@ -131,9 +131,10 @@ namespace cling { return; auto pos = prepend ? m_SearchPaths.begin() : m_SearchPaths.end(); m_SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser}); - // m_DyldController->addScanPath(dir.str(), - // isUser ? llvm::orc::PathType::User - // : llvm::orc::PathType::System); + if (m_DyldController) + m_DyldController->addScanPath(dir.str(), + isUser ? llvm::orc::PathType::User + : llvm::orc::PathType::System); } } diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index ba3d9792c96a9..60d757871bb8f 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1341,14 +1341,20 @@ namespace cling { void DynamicLibraryManager::initializeDyld( std::function shouldPermanentlyIgnore) { - //assert(!m_Dyld && "Already initialized!"); + // assert(!m_Dyld && "Already initialized!"); + // if (m_Dyld) + // delete m_Dyld; if (m_DyldController) m_DyldController.reset(); llvm::orc::LibraryResolver::Setup S = llvm::orc::LibraryResolver::Setup::create({}); - S.shouldScan = [&](llvm::StringRef lib) -> bool { - return !shouldPermanentlyIgnore(lib); + S.shouldScan = [&, shouldPermanentlyIgnore](llvm::StringRef lib) -> bool { + if (shouldPermanentlyIgnore) { + return !shouldPermanentlyIgnore(lib) || !isLibraryLoaded(lib); + } + // fallback behavior if no callback provided + return !isLibraryLoaded(lib); }; m_DyldController = llvm::orc::LibraryResolutionDriver::create(S); @@ -1377,7 +1383,8 @@ namespace cling { std::string res = ""; std::vector sym; sym.push_back(mangledName.str()); - llvm::orc::SearchPolicy policy = { + llvm::orc::SearchConfig config; + config.policy = { {{llvm::orc::LibraryManager::State::Queried, llvm::orc::PathType::User}, {llvm::orc::LibraryManager::State::Unloaded, llvm::orc::PathType::User}, @@ -1385,8 +1392,6 @@ namespace cling { llvm::orc::PathType::System}, {llvm::orc::LibraryManager::State::Unloaded, llvm::orc::PathType::System}}}; - llvm::orc::SearchConfig config; - config.policy = policy; config.options.FilterFlags = llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; m_DyldController->resolveSymbols( From 71e8c0cd2aa2493b7e2d2d92b815142d36075fe8 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Tue, 4 Nov 2025 16:07:07 +0530 Subject: [PATCH 06/10] Rebase and update code with llvm side current changes --- .../DynamicLibraryManagerSymbol.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index 60d757871bb8f..c5557049a694c 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1349,7 +1349,8 @@ namespace cling { llvm::orc::LibraryResolver::Setup S = llvm::orc::LibraryResolver::Setup::create({}); - S.shouldScan = [&, shouldPermanentlyIgnore](llvm::StringRef lib) -> bool { + S.ShouldScanCall = [&, + shouldPermanentlyIgnore](llvm::StringRef lib) -> bool { if (shouldPermanentlyIgnore) { return !shouldPermanentlyIgnore(lib) || !isLibraryLoaded(lib); } @@ -1384,15 +1385,15 @@ namespace cling { std::vector sym; sym.push_back(mangledName.str()); llvm::orc::SearchConfig config; - config.policy = { - {{llvm::orc::LibraryManager::State::Queried, llvm::orc::PathType::User}, - {llvm::orc::LibraryManager::State::Unloaded, - llvm::orc::PathType::User}, - {llvm::orc::LibraryManager::State::Queried, - llvm::orc::PathType::System}, - {llvm::orc::LibraryManager::State::Unloaded, - llvm::orc::PathType::System}}}; - config.options.FilterFlags = + config.Policy = {{{llvm::orc::LibraryManager::LibState::Queried, + llvm::orc::PathType::User}, + {llvm::orc::LibraryManager::LibState::Unloaded, + llvm::orc::PathType::User}, + {llvm::orc::LibraryManager::LibState::Queried, + llvm::orc::PathType::System}, + {llvm::orc::LibraryManager::LibState::Unloaded, + llvm::orc::PathType::System}}}; + config.Options.FilterFlags = llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; m_DyldController->resolveSymbols( sym, From 69ebe90dc2619842e17134bca54e1919a6540e04 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Fri, 5 Dec 2025 12:06:33 +0530 Subject: [PATCH 07/10] Improve caching and simplify resolution logic --- .../Interpreter/DynamicLibraryManagerSymbol.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index c5557049a694c..ab0575c7bb1dc 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1385,16 +1385,14 @@ namespace cling { std::vector sym; sym.push_back(mangledName.str()); llvm::orc::SearchConfig config; - config.Policy = {{{llvm::orc::LibraryManager::LibState::Queried, - llvm::orc::PathType::User}, - {llvm::orc::LibraryManager::LibState::Unloaded, - llvm::orc::PathType::User}, - {llvm::orc::LibraryManager::LibState::Queried, - llvm::orc::PathType::System}, - {llvm::orc::LibraryManager::LibState::Unloaded, - llvm::orc::PathType::System}}}; + config.Policy = { + {{llvm::orc::LibState::Queried, llvm::orc::PathType::User}, + {llvm::orc::LibState::Unloaded, llvm::orc::PathType::User}, + {llvm::orc::LibState::Queried, llvm::orc::PathType::System}, + {llvm::orc::LibState::Unloaded, llvm::orc::PathType::System}}}; config.Options.FilterFlags = llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; + m_DyldController->resolveSymbols( sym, [&](llvm::orc::LibraryResolver::SymbolQuery& Q) { @@ -1402,6 +1400,7 @@ namespace cling { res = *s; }, config); + return res; // return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem); } From 657bd8d022e19cd4fbdbddce3f06b3d3530c7cbf Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Tue, 16 Dec 2025 10:55:54 +0530 Subject: [PATCH 08/10] Improve search logic --- .../cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index ab0575c7bb1dc..f03ed3cc65a44 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -1392,7 +1392,6 @@ namespace cling { {llvm::orc::LibState::Unloaded, llvm::orc::PathType::System}}}; config.Options.FilterFlags = llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; - m_DyldController->resolveSymbols( sym, [&](llvm::orc::LibraryResolver::SymbolQuery& Q) { @@ -1400,7 +1399,6 @@ namespace cling { res = *s; }, config); - return res; // return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem); } From 143f23c469fc80af5983207e1e0d855e2e8d5e5c Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Wed, 24 Dec 2025 16:42:22 +0530 Subject: [PATCH 09/10] Refactor searchSymbolsInLibraries call to accept symbol list; remove legacy code --- .../cling/Interpreter/DynamicLibraryManager.h | 5 + .../DynamicLibraryManagerSymbol.cpp | 1158 +---------------- 2 files changed, 27 insertions(+), 1136 deletions(-) diff --git a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h index 385e6a7c7cd37..821df100ea361 100644 --- a/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +++ b/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h @@ -196,6 +196,11 @@ namespace cling { std::string searchLibrariesForSymbol(llvm::StringRef mangledName, bool searchSystem = true) const; + void + searchLibrariesForSymbol(llvm::ArrayRef Symbols, + llvm::orc::LibraryResolver::OnSearchComplete OnCompletion, + bool searchSystem = true) const; + void dump(llvm::raw_ostream* S = nullptr) const; /// On a success returns to full path to a shared object that holds the diff --git a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp index f03ed3cc65a44..f149436128ee3 100644 --- a/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp +++ b/interpreter/cling/lib/Interpreter/DynamicLibraryManagerSymbol.cpp @@ -17,19 +17,9 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringMap.h" -#include "llvm/BinaryFormat/MachO.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/ELF.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/MachO.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/WithColor.h" #include #include @@ -77,200 +67,10 @@ #include // For VirtualQuery #endif -// FIXME: Implement debugging output stream in cling. -constexpr unsigned DEBUG = 0; - namespace { using BasePath = std::string; -// This is a GNU implementation of hash used in bloom filter! -static uint32_t GNUHash(llvm::StringRef S) { - uint32_t H = 5381; - for (uint8_t C : S) - H = (H << 5) + H + C; - return H; -} - -constexpr uint32_t log2u(std::uint32_t n) { - return (n > 1) ? 1 + log2u(n >> 1) : 0; -} - -struct BloomFilter { - - // https://hur.st/bloomfilter - // - // n = ceil(m / (-k / log(1 - exp(log(p) / k)))) - // p = pow(1 - exp(-k / (m / n)), k) - // m = ceil((n * log(p)) / log(1 / pow(2, log(2)))); - // k = round((m / n) * log(2)); - // - // n = symbolsCount - // p = 0.02 - // k = 2 (k1=GNUHash and k2=GNUHash >> bloomShift) - // m = ceil((symbolsCount * log(p)) / log(1 / pow(2, log(2)))); - // bloomShift = min(5 for bits=32 or 6 for bits=64, log2(symbolsCount)) - // bloomSize = ceil((-1.44 * n * log2f(p)) / bits) - - const int m_Bits = 8 * sizeof(uint64_t); - const float m_P = 0.02; - - bool m_IsInitialized = false; - uint32_t m_SymbolsCount = 0; - uint32_t m_BloomSize = 0; - uint32_t m_BloomShift = 0; - std::vector m_BloomTable; - - bool TestHash(uint32_t hash) const { - // This function is superhot. No branches here, breaks inlining and makes - // overall performance around 4x slower. - assert(m_IsInitialized && "Not yet initialized!"); - uint32_t hash2 = hash >> m_BloomShift; - uint32_t n = (hash >> log2u(m_Bits)) % m_BloomSize; - uint64_t mask = ((1ULL << (hash % m_Bits)) | (1ULL << (hash2 % m_Bits))); - return (mask & m_BloomTable[n]) == mask; - } - - void AddHash(uint32_t hash) { - assert(m_IsInitialized && "Not yet initialized!"); - uint32_t hash2 = hash >> m_BloomShift; - uint32_t n = (hash >> log2u(m_Bits)) % m_BloomSize; - uint64_t mask = ((1ULL << (hash % m_Bits)) | (1ULL << (hash2 % m_Bits))); - m_BloomTable[n] |= mask; - } - - void ResizeTable(uint32_t newSymbolsCount) { - assert(m_SymbolsCount == 0 && "Not supported yet!"); - m_SymbolsCount = newSymbolsCount; - m_BloomSize = ceil((-1.44f * m_SymbolsCount * log2f(m_P)) / m_Bits); - m_BloomShift = std::min(6u, log2u(m_SymbolsCount)); - m_BloomTable.resize(m_BloomSize); - } - -}; - -/// An efficient representation of a full path to a library which does not -/// duplicate common path patterns reducing the overall memory footprint. -/// -/// For example, `/home/.../lib/libA.so`, m_Path will contain a pointer -/// to `/home/.../lib/` -/// will be stored and .second `libA.so`. -/// This approach reduces the duplicate paths as at one location there may be -/// plenty of libraries. -struct LibraryPath { - const BasePath& m_Path; - std::string m_LibName; - BloomFilter m_Filter; - llvm::StringSet<> m_Symbols; - //std::vector m_LibDeps; - - LibraryPath(const BasePath& Path, const std::string& LibName) - : m_Path(Path), m_LibName(LibName) { - } - - bool operator==(const LibraryPath &other) const { - return (&m_Path == &other.m_Path || m_Path == other.m_Path) && - m_LibName == other.m_LibName; - } - - const std::string GetFullName() const { - llvm::SmallString<512> Vec(m_Path); - llvm::sys::path::append(Vec, llvm::StringRef(m_LibName)); - return Vec.str().str(); - } - - void AddBloom(llvm::StringRef symbol) { - m_Filter.AddHash(GNUHash(symbol)); - } - - llvm::StringRef AddSymbol(const std::string& symbol) { - auto it = m_Symbols.insert(symbol); - return it.first->getKey(); - } - - bool hasBloomFilter() const { - return m_Filter.m_IsInitialized; - } - - bool isBloomFilterEmpty() const { - assert(m_Filter.m_IsInitialized && "Bloom filter not initialized!"); - return m_Filter.m_SymbolsCount == 0; - } - - void InitializeBloomFilter(uint32_t newSymbolsCount) { - assert(!m_Filter.m_IsInitialized && - "Cannot re-initialize non-empty filter!"); - m_Filter.m_IsInitialized = true; - m_Filter.ResizeTable(newSymbolsCount); - } - - bool MayExistSymbol(uint32_t hash) const { - // The library had no symbols and the bloom filter is empty. - if (isBloomFilterEmpty()) - return false; - - return m_Filter.TestHash(hash); - } - - bool ExistSymbol(llvm::StringRef symbol) const { - return m_Symbols.find(symbol) != m_Symbols.end(); - } -}; - - -/// A helper class keeping track of loaded libraries. It implements a fast -/// search O(1) while keeping deterministic iterability in a memory efficient -/// way. The underlying set uses a custom hasher for better efficiency given the -/// specific problem where the library names (m_LibName) are relatively short -/// strings and the base paths (m_Path) are repetitive long strings. -class LibraryPaths { - struct LibraryPathHashFn { - size_t operator()(const LibraryPath& item) const { - return std::hash()(item.m_Path.length()) ^ - std::hash()(item.m_LibName); - } - }; - - std::vector m_Libs; - std::unordered_set m_LibsH; -public: - bool HasRegisteredLib(const LibraryPath& Lib) const { - return m_LibsH.count(Lib); - } - - const LibraryPath* GetRegisteredLib(const LibraryPath& Lib) const { - auto search = m_LibsH.find(Lib); - if (search != m_LibsH.end()) - return &(*search); - return nullptr; - } - - const LibraryPath* RegisterLib(const LibraryPath& Lib) { - auto it = m_LibsH.insert(Lib); - assert(it.second && "Already registered!"); - m_Libs.push_back(&*it.first); - return &*it.first; - } - - void UnregisterLib(const LibraryPath& Lib) { - auto found = m_LibsH.find(Lib); - if (found == m_LibsH.end()) - return; - - m_Libs.erase(std::find(m_Libs.begin(), m_Libs.end(), &*found)); - m_LibsH.erase(found); - } - - size_t size() const { - assert(m_Libs.size() == m_LibsH.size()); - return m_Libs.size(); - } - - const std::vector& GetLibraries() const { - return m_Libs; - } -}; - #ifndef _WIN32 // Cached version of system function lstat static inline mode_t cached_lstat(const char *path) { @@ -408,931 +208,9 @@ std::string cached_realpath(llvm::StringRef path, llvm::StringRef base_path = "" return result.str().str(); } -using namespace llvm; -using namespace llvm::object; - -template -static Expected getDynamicStrTab(const ELFFile* Elf) { - auto DynamicEntriesOrError = Elf->dynamicEntries(); - if (!DynamicEntriesOrError) - return DynamicEntriesOrError.takeError(); - - for (const typename ELFT::Dyn& Dyn : *DynamicEntriesOrError) { - if (Dyn.d_tag == ELF::DT_STRTAB) { - auto MappedAddrOrError = Elf->toMappedAddr(Dyn.getPtr()); - if (!MappedAddrOrError) - return MappedAddrOrError.takeError(); - return StringRef(reinterpret_cast(*MappedAddrOrError)); - } - } - - // If the dynamic segment is not present, we fall back on the sections. - auto SectionsOrError = Elf->sections(); - if (!SectionsOrError) - return SectionsOrError.takeError(); - - for (const typename ELFT::Shdr &Sec : *SectionsOrError) { - if (Sec.sh_type == ELF::SHT_DYNSYM) - return Elf->getStringTableForSymtab(Sec); - } - - return createError("dynamic string table not found"); -} - -static llvm::StringRef GetGnuHashSection(llvm::object::ObjectFile *file) { - for (auto S : file->sections()) { - llvm::StringRef name = llvm::cantFail(S.getName()); - if (name == ".gnu.hash") { - return llvm::cantFail(S.getContents()); - } - } - return ""; -} - -/// Bloom filter is a stochastic data structure which can tell us if a symbol -/// name does not exist in a library with 100% certainty. If it tells us it -/// exists this may not be true: -/// https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2 -/// -/// ELF has this optimization in the new linkers by default, It is stored in the -/// gnu.hash section of the object file. -/// -///\returns true if the symbol may be in the library. -static bool MayExistInElfObjectFile(llvm::object::ObjectFile *soFile, - uint32_t hash) { - assert(soFile->isELF() && "Not ELF"); - - // Compute the platform bitness -- either 64 or 32. - const unsigned bits = 8 * soFile->getBytesInAddress(); - - llvm::StringRef contents = GetGnuHashSection(soFile); - if (contents.size() < 16) - // We need to search if the library doesn't have .gnu.hash section! - return true; - const char* hashContent = contents.data(); - - // See https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/ for .gnu.hash - // table layout. - uint32_t maskWords = *reinterpret_cast(hashContent + 8); - uint32_t shift2 = *reinterpret_cast(hashContent + 12); - uint32_t hash2 = hash >> shift2; - uint32_t n = (hash / bits) % maskWords; - - const char *bloomfilter = hashContent + 16; - const char *hash_pos = bloomfilter + n*(bits/8); // * (Bits / 8) - uint64_t word = *reinterpret_cast(hash_pos); - uint64_t bitmask = ( (1ULL << (hash % bits)) | (1ULL << (hash2 % bits))); - return (bitmask & word) == bitmask; -} - } // anon namespace -// This function isn't referenced outside its translation unit, but it -// can't use the "static" keyword because its address is used for -// GetMainExecutable (since some platforms don't support taking the -// address of main, and some platforms can't implement GetMainExecutable -// without being given the address of a function in the main executable). -std::string GetExecutablePath() { - // This just needs to be some symbol in the binary; C++ doesn't - // allow taking the address of ::main however. - return cling::DynamicLibraryManager::getSymbolLocation(&GetExecutablePath); -} - namespace cling { - class Dyld { - struct BasePathHashFunction { - size_t operator()(const BasePath& item) const { - return std::hash()(item); - } - }; - - struct BasePathEqFunction { - size_t operator()(const BasePath& l, const BasePath& r) const { - return &l == &r || l == r; - } - }; - /// A memory efficient llvm::VectorSet. The class provides O(1) search - /// complexity. It is tuned to compare BasePaths first by checking the - /// address and then the representation which models the base path reuse. - class BasePaths { - public: - std::unordered_set m_Paths; - public: - const BasePath& RegisterBasePath(const std::string& Path, - bool* WasInserted = nullptr) { - auto it = m_Paths.insert(Path); - if (WasInserted) - *WasInserted = it.second; - - return *it.first; - } - - bool Contains(StringRef Path) { - return m_Paths.count(Path.str()); - } - }; - - bool m_FirstRun = true; - bool m_FirstRunSysLib = true; - bool m_UseBloomFilter = true; - bool m_UseHashTable = true; - - const cling::DynamicLibraryManager& m_DynamicLibraryManager; - - /// The basename of `/home/.../lib/libA.so`, - /// m_BasePaths will contain `/home/.../lib/` - BasePaths m_BasePaths; - - LibraryPaths m_Libraries; - LibraryPaths m_SysLibraries; - /// Contains a set of libraries which we gave to the user via ResolveSymbol - /// call and next time we should check if the user loaded them to avoid - /// useless iterations. - LibraryPaths m_QueriedLibraries; - - using PermanentlyIgnoreCallbackProto = std::function; - const PermanentlyIgnoreCallbackProto m_ShouldPermanentlyIgnoreCallback; - const llvm::StringRef m_ExecutableFormat; - - /// Scan for shared objects which are not yet loaded. They are a our symbol - /// resolution candidate sources. - /// NOTE: We only scan not loaded shared objects. - /// \param[in] searchSystemLibraries - whether to decent to standard system - /// locations for shared objects. - void ScanForLibraries(bool searchSystemLibraries = false); - - /// Builds a bloom filter lookup optimization. - void BuildBloomFilter(LibraryPath* Lib, llvm::object::ObjectFile *BinObjFile, - unsigned IgnoreSymbolFlags = 0) const; - - - /// Looks up symbols from a an object file, representing the library. - ///\param[in] Lib - full path to the library. - ///\param[in] mangledName - the mangled name to look for. - ///\param[in] IgnoreSymbolFlags - The symbols to ignore upon a match. - ///\returns true on success. - bool ContainsSymbol(const LibraryPath* Lib, StringRef mangledName, - unsigned IgnoreSymbolFlags = 0) const; - - bool ShouldPermanentlyIgnore(StringRef FileName) const; - void dumpDebugInfo() const; - public: - Dyld(const cling::DynamicLibraryManager &DLM, - PermanentlyIgnoreCallbackProto shouldIgnore, - llvm::StringRef execFormat) - : m_DynamicLibraryManager(DLM), - m_ShouldPermanentlyIgnoreCallback(shouldIgnore), - m_ExecutableFormat(execFormat) { } - - ~Dyld(){}; - - std::string searchLibrariesForSymbol(StringRef mangledName, - bool searchSystem); - }; - - std::string RPathToStr(llvm::SmallVector V) { - std::string result; - for (auto item : V) - result += item.str() + ","; - if (!result.empty()) - result.pop_back(); - return result; - } - - void CombinePaths(std::string& P1, const char* P2) { - if (!P2 || !P2[0]) return; - if (!P1.empty()) - P1 += llvm::sys::EnvPathSeparator; - P1 += P2; - } - - template - void HandleDynTab(const ELFFile* Elf, llvm::StringRef FileName, - llvm::SmallVector& RPath, - llvm::SmallVector& RunPath, - std::vector& Deps, - bool& isPIEExecutable) { - const char *Data = ""; - if (Expected StrTabOrErr = getDynamicStrTab(Elf)) - Data = StrTabOrErr.get().data(); - - isPIEExecutable = false; - - auto DynamicEntriesOrError = Elf->dynamicEntries(); - if (!DynamicEntriesOrError) { - cling::errs() << "Dyld: failed to read dynamic entries in" - << "'" << FileName.str() << "'\n"; - return; - } - - for (const typename ELFT::Dyn& Dyn : *DynamicEntriesOrError) { - switch (Dyn.d_tag) { - case ELF::DT_NEEDED: - Deps.push_back(Data + Dyn.d_un.d_val); - break; - case ELF::DT_RPATH: - SplitPaths(Data + Dyn.d_un.d_val, RPath, utils::kAllowNonExistant, platform::kEnvDelim, false); - break; - case ELF::DT_RUNPATH: - SplitPaths(Data + Dyn.d_un.d_val, RunPath, utils::kAllowNonExistant, platform::kEnvDelim, false); - break; - case ELF::DT_FLAGS_1: - // Check if this is not a pie executable. - if (Dyn.d_un.d_val & llvm::ELF::DF_1_PIE) - isPIEExecutable = true; - break; - // (Dyn.d_tag == ELF::DT_NULL) continue; - // (Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER) - } - } - } - - void Dyld::ScanForLibraries(bool searchSystemLibraries/* = false*/) { - - const auto &searchPaths = m_DynamicLibraryManager.getSearchPaths(); - - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries: system=" << (searchSystemLibraries?"true":"false") << "\n"; - for (const DynamicLibraryManager::SearchPathInfo &Info : searchPaths) - cling::errs() << ">>>" << Info.Path << ", " << (Info.IsUser?"user\n":"system\n"); - } - - llvm::SmallSet ScannedPaths; - - for (const DynamicLibraryManager::SearchPathInfo &Info : searchPaths) { - if (Info.IsUser != searchSystemLibraries) { - // Examples which we should handle. - // File Real - // /lib/1/1.so /lib/1/1.so // file - // /lib/1/2.so->/lib/1/1.so /lib/1/1.so // file local link - // /lib/1/3.so->/lib/3/1.so /lib/3/1.so // file external link - // /lib/2->/lib/1 // path link - // /lib/2/1.so /lib/1/1.so // path link, file - // /lib/2/2.so->/lib/1/1.so /lib/1/1.so // path link, file local link - // /lib/2/3.so->/lib/3/1.so /lib/3/1.so // path link, file external link - // - // /lib/3/1.so - // /lib/3/2.so->/system/lib/s.so - // /lib/3/3.so - // /system/lib/1.so - // - // libL.so NEEDED/RPATH libR.so /lib/some-rpath/libR.so // needed/dependedt library in libL.so RPATH/RUNPATH or other (in)direct dep - // - // Paths = /lib/1 : /lib/2 : /lib/3 - - // m_BasePaths = ["/lib/1", "/lib/3", "/system/lib"] - // m_*Libraries = [<0,"1.so">, <1,"1.so">, <2,"s.so">, <1,"3.so">] - - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries Iter:" << Info.Path << " -> "; - } - std::string RealPath = cached_realpath(Info.Path); - - llvm::StringRef DirPath(RealPath); - if (DEBUG > 7) { - cling::errs() << RealPath << "\n"; - } - - if (!llvm::sys::fs::is_directory(DirPath) || DirPath.empty()) - continue; - - // Already searched? - const BasePath &ScannedBPath = m_BasePaths.RegisterBasePath(RealPath); - if (ScannedPaths.count(&ScannedBPath)) { - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries Already scanned: " << RealPath << "\n"; - } - continue; - } - - // FileName must be always full/absolute/resolved file name. - std::function HandleLib = - [&](llvm::StringRef FileName, unsigned level) { - - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries HandleLib:" << FileName.str() - << ", level=" << level << " -> "; - } - - llvm::StringRef FileRealPath = llvm::sys::path::parent_path(FileName); - llvm::StringRef FileRealName = llvm::sys::path::filename(FileName); - const BasePath& BaseP = - m_BasePaths.RegisterBasePath(FileRealPath.str()); - LibraryPath LibPath(BaseP, FileRealName.str()); //bp, str - - if (m_SysLibraries.GetRegisteredLib(LibPath) || - m_Libraries.GetRegisteredLib(LibPath)) { - if (DEBUG > 7) { - cling::errs() << "Already handled!!!\n"; - } - return; - } - - if (ShouldPermanentlyIgnore(FileName)) { - if (DEBUG > 7) { - cling::errs() << "PermanentlyIgnored!!!\n"; - } - return; - } - - if (searchSystemLibraries) - m_SysLibraries.RegisterLib(LibPath); - else - m_Libraries.RegisterLib(LibPath); - - // Handle lib dependencies - llvm::SmallVector RPath; - llvm::SmallVector RunPath; - std::vector Deps; - auto ObjFileOrErr = - llvm::object::ObjectFile::createObjectFile(FileName); - if (llvm::Error Err = ObjFileOrErr.takeError()) { - // Note: It is important to always call handleAllErrors, otherwise - // the destructor of llvm::Error will abort the program "due to an - // unhandled Error" - std::string Message; - handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) { - Message += EIB.message() + "; "; - }); - if (DEBUG > 1) { - cling::errs() - << "Dyld::ScanForLibraries: Failed to read object file " - << FileName.str() << " Errors: " << Message << "\n"; - } - return; - } - llvm::object::ObjectFile *BinObjF = ObjFileOrErr.get().getBinary(); - if (BinObjF->isELF()) { - bool isPIEExecutable = false; - - if (const auto* ELF = dyn_cast(BinObjF)) - HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps, - isPIEExecutable); - else if (const auto* ELF = dyn_cast(BinObjF)) - HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps, - isPIEExecutable); - else if (const auto* ELF = dyn_cast(BinObjF)) - HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps, - isPIEExecutable); - else if (const auto* ELF = dyn_cast(BinObjF)) - HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps, - isPIEExecutable); - - if ((level == 0) && isPIEExecutable) { - if (searchSystemLibraries) - m_SysLibraries.UnregisterLib(LibPath); - else - m_Libraries.UnregisterLib(LibPath); - return; - } - } else if (BinObjF->isMachO()) { - MachOObjectFile *Obj = (MachOObjectFile*)BinObjF; - for (const auto &Command : Obj->load_commands()) { - if (Command.C.cmd == MachO::LC_LOAD_DYLIB) { - //Command.C.cmd == MachO::LC_ID_DYLIB || - //Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || - //Command.C.cmd == MachO::LC_REEXPORT_DYLIB || - //Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB || - //Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB || - MachO::dylib_command dylibCmd = - Obj->getDylibIDLoadCommand(Command); - Deps.push_back(StringRef(Command.Ptr + dylibCmd.dylib.name)); - } - else if (Command.C.cmd == MachO::LC_RPATH) { - MachO::rpath_command rpathCmd = Obj->getRpathCommand(Command); - SplitPaths(Command.Ptr + rpathCmd.path, RPath, utils::kAllowNonExistant, platform::kEnvDelim, false); - } - } - } else if (BinObjF->isCOFF()) { - // TODO: COFF support - } - - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries: Deps Info:\n"; - cling::errs() << "Dyld::ScanForLibraries: RPATH=" << RPathToStr(RPath) << "\n"; - cling::errs() << "Dyld::ScanForLibraries: RUNPATH=" << RPathToStr(RunPath) << "\n"; - int x = 0; - for (StringRef dep : Deps) - cling::errs() << "Dyld::ScanForLibraries: Deps[" << x++ << "]=" << dep.str() << "\n"; - } - - // Heuristics for workaround performance problems: - // (H1) If RPATH and RUNPATH == "" -> skip handling Deps - if (RPath.empty() && RunPath.empty()) { - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries: Skip all deps by Heuristic1: " << FileName.str() << "\n"; - } - return; - }; - // (H2) If RPATH subset of LD_LIBRARY_PATH && - // RUNPATH subset of LD_LIBRARY_PATH -> skip handling Deps - if (std::all_of(RPath.begin(), RPath.end(), [&](StringRef item){ return std::any_of(searchPaths.begin(), searchPaths.end(), [&](DynamicLibraryManager::SearchPathInfo item1){ return item==item1.Path; }); }) && - std::all_of(RunPath.begin(), RunPath.end(), [&](StringRef item){ return std::any_of(searchPaths.begin(), searchPaths.end(), [&](DynamicLibraryManager::SearchPathInfo item1){ return item==item1.Path; }); }) ) { - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries: Skip all deps by Heuristic2: " << FileName.str() << "\n"; - } - return; - } - - // Handle dependencies - for (StringRef dep : Deps) { - std::string dep_full = - m_DynamicLibraryManager.lookupLibrary(dep, RPath, RunPath, FileName, false); - HandleLib(dep_full, level + 1); - } - - }; - - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries: Iterator: " << DirPath << "\n"; - } - std::error_code EC; - for (llvm::sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd; - DirIt != DirEnd && !EC; DirIt.increment(EC)) { - - if (DEBUG > 7) { - cling::errs() << "Dyld::ScanForLibraries: Iterator >>> " << - DirIt->path() << ", type=" << (short)(DirIt->type()) << "\n"; - } - - const llvm::sys::fs::file_type ft = DirIt->type(); - if (ft == llvm::sys::fs::file_type::regular_file) { - HandleLib(DirIt->path(), 0); - } else if (ft == llvm::sys::fs::file_type::symlink_file) { - std::string DepFileName_str = cached_realpath(DirIt->path()); - llvm::StringRef DepFileName = DepFileName_str; - assert(!llvm::sys::fs::is_symlink_file(DepFileName)); - if (!llvm::sys::fs::is_directory(DepFileName)) - HandleLib(DepFileName, 0); - } - } - - // Register the DirPath as fully scanned. - ScannedPaths.insert(&ScannedBPath); - } - } - } - - void Dyld::BuildBloomFilter(LibraryPath* Lib, - llvm::object::ObjectFile *BinObjFile, - unsigned IgnoreSymbolFlags /*= 0*/) const { - assert(m_UseBloomFilter && "Bloom filter is disabled"); - assert(!Lib->hasBloomFilter() && "Already built!"); - - using namespace llvm; - using namespace llvm::object; - - if (DEBUG > 7) { - cling::errs()<< "Dyld::BuildBloomFilter: Start building Bloom filter for: " - << Lib->GetFullName() << "\n"; - } - - // If BloomFilter is empty then build it. - // Count Symbols and generate BloomFilter - uint32_t SymbolsCount = 0; - std::list symbols; - for (const llvm::object::SymbolRef &S : BinObjFile->symbols()) { - uint32_t Flags = llvm::cantFail(S.getFlags()); - // Do not insert in the table symbols flagged to ignore. - if (Flags & IgnoreSymbolFlags) - continue; - - // Note, we are at last resort and loading library based on a weak - // symbol is allowed. Otherwise, the JIT will issue an unresolved - // symbol error. - // - // There are other weak symbol kinds (marked as 'V') to denote - // typeinfo and vtables. It is unclear whether we should load such - // libraries or from which library we should resolve the symbol. - // We seem to not have a way to differentiate it from the symbol API. - - llvm::Expected SymNameErr = S.getName(); - if (!SymNameErr) { - cling::errs()<< "Dyld::BuildBloomFilter: Failed to read symbol " - << SymNameErr.get() << "\n"; - continue; - } - - if (SymNameErr.get().empty()) - continue; - - ++SymbolsCount; - symbols.push_back(SymNameErr.get()); - } - - if (BinObjFile->isELF()) { - // ELF file format has .dynstr section for the dynamic symbol table. - const auto *ElfObj = cast(BinObjFile); - - for (const object::SymbolRef &S : ElfObj->getDynamicSymbolIterators()) { - uint32_t Flags = llvm::cantFail(S.getFlags()); - // DO NOT insert to table if symbol was undefined - if (Flags & llvm::object::SymbolRef::SF_Undefined) - continue; - - // Note, we are at last resort and loading library based on a weak - // symbol is allowed. Otherwise, the JIT will issue an unresolved - // symbol error. - // - // There are other weak symbol kinds (marked as 'V') to denote - // typeinfo and vtables. It is unclear whether we should load such - // libraries or from which library we should resolve the symbol. - // We seem to not have a way to differentiate it from the symbol API. - - llvm::Expected SymNameErr = S.getName(); - if (!SymNameErr) { - cling::errs() << "Dyld::BuildBloomFilter: Failed to read symbol " - <isCOFF()) { // On Windows, the symbols are present in COFF format. - llvm::object::COFFObjectFile* CoffObj = cast(BinObjFile); - - // In COFF, the symbols are not present in the SymbolTable section - // of the Object file. They are present in the ExportDirectory section. - for (auto I=CoffObj->export_directory_begin(), - E=CoffObj->export_directory_end(); I != E; I = ++I) { - // All the symbols are already flagged as exported. - // We cannot really ignore symbols based on flags as we do on unix. - StringRef Name; - if (I->getSymbolName(Name)) - continue; - if (Name.empty()) - continue; - - ++SymbolsCount; - symbols.push_back(Name); - } - } - - Lib->InitializeBloomFilter(SymbolsCount); - - if (!SymbolsCount) { - if (DEBUG > 7) - cling::errs() << "Dyld::BuildBloomFilter: No symbols!\n"; - return; - } - - if (DEBUG > 7) { - cling::errs() << "Dyld::BuildBloomFilter: Symbols:\n"; - for (auto it : symbols) - cling::errs() << "Dyld::BuildBloomFilter" << "- " << it << "\n"; - } - - // Generate BloomFilter - for (const auto &S : symbols) { - if (m_UseHashTable) - Lib->AddBloom(Lib->AddSymbol(S.str())); - else - Lib->AddBloom(S); - } - } - - bool Dyld::ContainsSymbol(const LibraryPath* Lib, - StringRef mangledName, - unsigned IgnoreSymbolFlags /*= 0*/) const { - const std::string library_filename = Lib->GetFullName(); - - if (DEBUG > 7) { - cling::errs() << "Dyld::ContainsSymbol: Find symbol: lib=" - << library_filename << ", mangled=" - << mangledName.str() << "\n"; - } - - auto ObjF = llvm::object::ObjectFile::createObjectFile(library_filename); - if (llvm::Error Err = ObjF.takeError()) { - // Note: It is important to always call handleAllErrors, otherwise the - // destructor of llvm::Error will abort the program "due to an unhandled - // Error" - std::string Message; - handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) { - Message += EIB.message() + "; "; - }); - if (DEBUG > 1) { - cling::errs() << "Dyld::ContainsSymbol: Failed to read object file " - << library_filename << " Errors: " << Message << "\n"; - } - return false; - } - - llvm::object::ObjectFile *BinObjFile = ObjF.get().getBinary(); - - uint32_t hashedMangle = GNUHash(mangledName); - // Check for the gnu.hash section if ELF. - // If the symbol doesn't exist, exit early. - if (BinObjFile->isELF() && - !MayExistInElfObjectFile(BinObjFile, hashedMangle)) { - if (DEBUG > 7) - cling::errs() << "Dyld::ContainsSymbol: ELF BloomFilter: Skip symbol <" << mangledName.str() << ">.\n"; - return false; - } - - if (m_UseBloomFilter) { - // Use our bloom filters and create them if necessary. - if (!Lib->hasBloomFilter()) - BuildBloomFilter(const_cast(Lib), BinObjFile, - IgnoreSymbolFlags); - - // If the symbol does not exist, exit early. In case it may exist, iterate. - if (!Lib->MayExistSymbol(hashedMangle)) { - if (DEBUG > 7) - cling::errs() << "Dyld::ContainsSymbol: BloomFilter: Skip symbol <" << mangledName.str() << ">.\n"; - return false; - } - if (DEBUG > 7) - cling::errs() << "Dyld::ContainsSymbol: BloomFilter: Symbol <" << mangledName.str() << "> May exist." - << " Search for it. "; - } - - if (m_UseHashTable) { - bool result = Lib->ExistSymbol(mangledName); - if (DEBUG > 7) - cling::errs() << "Dyld::ContainsSymbol: HashTable: Symbol " - << (result ? "Exist" : "Not exist") << "\n"; - return result; - } - - auto ForeachSymbol = - [&library_filename](llvm::iterator_range range, - unsigned IgnoreSymbolFlags, llvm::StringRef mangledName) -> bool { - for (const llvm::object::SymbolRef &S : range) { - uint32_t Flags = llvm::cantFail(S.getFlags()); - // Do not insert in the table symbols flagged to ignore. - if (Flags & IgnoreSymbolFlags) - continue; - - // Note, we are at last resort and loading library based on a weak - // symbol is allowed. Otherwise, the JIT will issue an unresolved - // symbol error. - // - // There are other weak symbol kinds (marked as 'V') to denote - // typeinfo and vtables. It is unclear whether we should load such - // libraries or from which library we should resolve the symbol. - // We seem to not have a way to differentiate it from the symbol API. - - llvm::Expected SymNameErr = S.getName(); - if (!SymNameErr) { - cling::errs() << "Dyld::ContainsSymbol: Failed to read symbol " - << mangledName.str() << "\n"; - continue; - } - - if (SymNameErr.get().empty()) - continue; - - if (SymNameErr.get() == mangledName) { - if (DEBUG > 1) { - cling::errs() << "Dyld::ContainsSymbol: Symbol " - << mangledName.str() << " found in " - << library_filename << "\n"; - return true; - } - } - } - return false; - }; - - // If no hash symbol then iterate to detect symbol - // We Iterate only if BloomFilter and/or SymbolHashTable are not supported. - - if (DEBUG > 7) - cling::errs() << "Dyld::ContainsSymbol: Iterate all for <" - << mangledName.str() << ">"; - - // Symbol may exist. Iterate. - if (ForeachSymbol(BinObjFile->symbols(), IgnoreSymbolFlags, mangledName)) { - if (DEBUG > 7) - cling::errs() << " -> found.\n"; - return true; - } - - - if (!BinObjFile->isELF()) { - if (DEBUG > 7) - cling::errs() << " -> not found.\n"; - return false; - } - - // ELF file format has .dynstr section for the dynamic symbol table. - const auto *ElfObj = - llvm::cast(BinObjFile); - - bool result = ForeachSymbol(ElfObj->getDynamicSymbolIterators(), - IgnoreSymbolFlags, mangledName); - if (DEBUG > 7) - cling::errs() << (result ? " -> found.\n" : " -> not found.\n"); - return result; - } - - bool Dyld::ShouldPermanentlyIgnore(StringRef FileName) const { - assert(!m_ExecutableFormat.empty() && "Failed to find the object format!"); - - if (!cling::DynamicLibraryManager::isSharedLibrary(FileName)) - return true; - - // No need to check linked libraries, as this function is only invoked - // for symbols that cannot be found (neither by dlsym nor in the JIT). - if (m_DynamicLibraryManager.isLibraryLoaded(FileName)) - return true; - - - auto ObjF = llvm::object::ObjectFile::createObjectFile(FileName); - if (!ObjF) { - // Note: It is important to always call handleAllErrors, otherwise the - // destructor of llvm::Error will abort the program "due to an unhandled - // Error" - std::string Message; - handleAllErrors(ObjF.takeError(), [&](llvm::ErrorInfoBase &EIB) { - Message += EIB.message() + "; "; - }); - if (DEBUG > 1) - cling::errs() << "[DyLD] Failed to read object file " - << FileName << ". Message: '" << Message << "\n"; - return true; - } - - llvm::object::ObjectFile *file = ObjF.get().getBinary(); - - if (DEBUG > 1) - cling::errs() << "Current executable format: " << m_ExecutableFormat - << ". Executable format of " << FileName << " : " - << file->getFileFormatName() << "\n"; - - // Ignore libraries with different format than the executing one. - if (m_ExecutableFormat != file->getFileFormatName()) - return true; - - if (llvm::isa(*file)) { - for (auto S : file->sections()) { - llvm::StringRef name = llvm::cantFail(S.getName()); - if (name == ".text") { - // Check if the library has only debug symbols, usually when - // stripped with objcopy --only-keep-debug. This check is done by - // reading the manual of objcopy and inspection of stripped with - // objcopy libraries. - auto SecRef = static_cast(S); - if (SecRef.getType() == llvm::ELF::SHT_NOBITS) - return true; - - return (SecRef.getFlags() & llvm::ELF::SHF_ALLOC) == 0; - } - } - return true; - } - - //FIXME: Handle osx using isStripped after upgrading to llvm9. - - return m_ShouldPermanentlyIgnoreCallback(FileName); - } - - void Dyld::dumpDebugInfo() const { - cling::errs() << "Dyld: m_BasePaths:\n"; - cling::errs() << "---\n"; - size_t x = 0; - for (auto const &item : m_BasePaths.m_Paths) { - cling::errs() << "Dyld: - m_BasePaths[" << x++ << "]:" - << &item << ": " << item << "\n"; - } - cling::errs() << "---\n"; - x = 0; - for (auto const &item : m_Libraries.GetLibraries()) { - cling::errs() << "Dyld: - m_Libraries[" << x++ << "]:" - << &item << ": " << item->m_Path << ", " - << item->m_LibName << "\n"; - } - x = 0; - for (auto const &item : m_SysLibraries.GetLibraries()) { - cling::errs() << "Dyld: - m_SysLibraries[" << x++ << "]:" - << &item << ": " << item->m_Path << ", " - << item->m_LibName << "\n"; - } - } - - std::string Dyld::searchLibrariesForSymbol(StringRef mangledName, - bool searchSystem/* = true*/) { - assert(!llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(mangledName.str()) && - "Library already loaded, please use dlsym!"); - assert(!mangledName.empty()); - - using namespace llvm::sys::path; - using namespace llvm::sys::fs; - - if (m_FirstRun) { - if (DEBUG > 7) { - cling::errs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str() << - ", searchSystem=" << (searchSystem ? "true" : "false") << ", FirstRun(user)... scanning\n"; - } - - if (DEBUG > 7) { - cling::errs() << "Dyld::searchLibrariesForSymbol: Before first ScanForLibraries\n"; - dumpDebugInfo(); - } - - ScanForLibraries(/* SearchSystemLibraries= */ false); - m_FirstRun = false; - - if (DEBUG > 7) { - cling::errs() << "Dyld::searchLibrariesForSymbol: After first ScanForLibraries\n"; - dumpDebugInfo(); - } - } - - if (m_QueriedLibraries.size() > 0) { - // Last call we were asked if a library contains a symbol. Usually, the - // caller wants to load this library. Check if was loaded and remove it - // from our lists of not-yet-loaded libs. - - if (DEBUG > 7) { - cling::errs() << "Dyld::ResolveSymbol: m_QueriedLibraries:\n"; - size_t x = 0; - for (auto item : m_QueriedLibraries.GetLibraries()) { - cling::errs() << "Dyld::ResolveSymbol - [" << x++ << "]:" - << &item << ": " << item->GetFullName() << "\n"; - } - } - - for (const LibraryPath* P : m_QueriedLibraries.GetLibraries()) { - const std::string LibName = P->GetFullName(); - if (!m_DynamicLibraryManager.isLibraryLoaded(LibName)) - continue; - - m_Libraries.UnregisterLib(*P); - m_SysLibraries.UnregisterLib(*P); - } - // TODO: m_QueriedLibraries.clear ? - } - - // Iterate over files under this path. We want to get each ".so" files - for (const LibraryPath* P : m_Libraries.GetLibraries()) { - if (ContainsSymbol(P, mangledName, /*ignore*/ - llvm::object::SymbolRef::SF_Undefined)) { - if (!m_QueriedLibraries.HasRegisteredLib(*P)) - m_QueriedLibraries.RegisterLib(*P); - - if (DEBUG > 7) - cling::errs() << "Dyld::ResolveSymbol: Search found match in [user lib]: " - << P->GetFullName() << "!\n"; - - return P->GetFullName(); - } - } - - if (!searchSystem) - return ""; - - if (DEBUG > 7) - cling::errs() << "Dyld::searchLibrariesForSymbol: SearchSystem!!!\n"; - - // Lookup in non-system libraries failed. Expand the search to the system. - if (m_FirstRunSysLib) { - if (DEBUG > 7) { - cling::errs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str() << - ", searchSystem=" << (searchSystem ? "true" : "false") << ", FirstRun(system)... scanning\n"; - } - - if (DEBUG > 7) { - cling::errs() << "Dyld::searchLibrariesForSymbol: Before first system ScanForLibraries\n"; - dumpDebugInfo(); - } - - ScanForLibraries(/* SearchSystemLibraries= */ true); - m_FirstRunSysLib = false; - - if (DEBUG > 7) { - cling::errs() << "Dyld::searchLibrariesForSymbol: After first system ScanForLibraries\n"; - dumpDebugInfo(); - } - } - - for (const LibraryPath* P : m_SysLibraries.GetLibraries()) { - if (ContainsSymbol(P, mangledName, /*ignore*/ - llvm::object::SymbolRef::SF_Undefined | - llvm::object::SymbolRef::SF_Weak)) { - if (!m_QueriedLibraries.HasRegisteredLib(*P)) - m_QueriedLibraries.RegisterLib(*P); - - if (DEBUG > 7) - cling::errs() << "Dyld::ResolveSymbol: Search found match in [system lib]: " - << P->GetFullName() << "!\n"; - - return P->GetFullName(); - } - } - - if (DEBUG > 7) - cling::errs() << "Dyld::ResolveSymbol: Search found no match!\n"; - - return ""; // Search found no match. - } DynamicLibraryManager::~DynamicLibraryManager() { // static_assert(sizeof(Dyld) > 0, "Incomplete type"); @@ -1342,8 +220,6 @@ namespace cling { void DynamicLibraryManager::initializeDyld( std::function shouldPermanentlyIgnore) { // assert(!m_Dyld && "Already initialized!"); - // if (m_Dyld) - // delete m_Dyld; if (m_DyldController) m_DyldController.reset(); @@ -1368,22 +244,13 @@ namespace cling { for (const auto& lib : m_LoadedLibraries) { m_DyldController->markLibraryLoaded(lib.first()); } - - // std::string exeP = GetExecutablePath(); - // auto ObjF = - // cantFail(llvm::object::ObjectFile::createObjectFile(exeP)); - - // m_Dyld = new Dyld(*this, shouldPermanentlyIgnore, - // ObjF.getBinary()->getFileFormatName()); } std::string - DynamicLibraryManager::searchLibrariesForSymbol(StringRef mangledName, + DynamicLibraryManager::searchLibrariesForSymbol(llvm::StringRef mangledName, bool searchSystem/* = true*/) const { assert(m_DyldController && "Must call initialize dyld before!"); std::string res = ""; - std::vector sym; - sym.push_back(mangledName.str()); llvm::orc::SearchConfig config; config.Policy = { {{llvm::orc::LibState::Queried, llvm::orc::PathType::User}, @@ -1393,17 +260,36 @@ namespace cling { config.Options.FilterFlags = llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; m_DyldController->resolveSymbols( - sym, + {mangledName}, [&](llvm::orc::LibraryResolver::SymbolQuery& Q) { if (auto s = Q.getResolvedLib(mangledName)) res = *s; }, config); return res; - // return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem); + } + + void DynamicLibraryManager::searchLibrariesForSymbol( + llvm::ArrayRef Symbols, + llvm::orc::LibraryResolver::OnSearchComplete OnCompletion, + bool searchSystem) const { + llvm::orc::SearchConfig config; + config.Policy = { + {{llvm::orc::LibState::Queried, llvm::orc::PathType::User}, + {llvm::orc::LibState::Unloaded, llvm::orc::PathType::User}, + {llvm::orc::LibState::Queried, llvm::orc::PathType::System}, + {llvm::orc::LibState::Unloaded, llvm::orc::PathType::System}}}; + config.Options.FilterFlags = + llvm::orc::SymbolEnumeratorOptions::IgnoreUndefined; + m_DyldController->resolveSymbols(Symbols, std::move(OnCompletion), config); + return; } std::string DynamicLibraryManager::getSymbolLocation(void *func) { + // auto cached_realpath = [&] (StringRef Lib) -> std::string { + // auto ResOrOpt = m_DyldController->getPathResolver().resolve(Lib); + // return ResOrOpt ? *ResOrOpt : ""; + // } #if defined(__CYGWIN__) && defined(__GNUC__) return {}; #elif defined(_WIN32) From d01f42b2a8b23f55cf602ea8678a01d3af7873b1 Mon Sep 17 00:00:00 2001 From: SahilPatidar Date: Wed, 24 Dec 2025 16:43:54 +0530 Subject: [PATCH 10/10] Adjust tryToGenerate call to pass symbols at once --- core/metacling/src/TClingCallbacks.cxx | 53 +++++++++++++++----------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/core/metacling/src/TClingCallbacks.cxx b/core/metacling/src/TClingCallbacks.cxx index 771f19fe9feb3..5f284ee255908 100644 --- a/core/metacling/src/TClingCallbacks.cxx +++ b/core/metacling/src/TClingCallbacks.cxx @@ -104,38 +104,45 @@ class AutoloadLibraryGenerator : public llvm::orc::DefinitionGenerator { // so no need to check that again. Instead search for the library that // provides the symbol and create one MaterializationUnit per library to // actually load it if needed. - std::unordered_map found; + llvm::StringMap found; // TODO: Do we need to take gInterpreterMutex? // R__LOCKGUARD(gInterpreterMutex); - for (auto &&KV : Symbols) { - llvm::orc::SymbolStringPtr name = KV.first; - - const cling::DynamicLibraryManager &DLM = *fInterpreter->getDynamicLibraryManager(); - - std::string libName = DLM.searchLibrariesForSymbol((*name).str(), - /*searchSystem=*/true); - - // libNew overrides memory management functions; must never autoload that. - assert(libName.find("/libNew.") == std::string::npos && "We must not autoload libNew!"); - - // libCling symbols are intentionally hidden from the process, and libCling must not be - // dlopened. Instead, symbols must be resolved by specifically querying the dynlib handle of - // libCling, which by definition is loaded - else we could not call this code. The handle - // is made available as argument to `CreateInterpreter`. - assert(libName.find("/libCling.") == std::string::npos && "Must not autoload libCling!"); - - if (!libName.empty()) - found[libName].push_back(name); - } + SmallVector Syms; + for (auto &KV : Symbols) + Syms.push_back(*KV.first); + + const cling::DynamicLibraryManager &DLM = *fInterpreter->getDynamicLibraryManager(); + DLM.searchLibrariesForSymbol( + Syms, + [&](llvm::orc::SymbolQuery &Q) { + for (auto &&KV : Symbols) { + auto ResolvedLibOrOpt = Q.getResolvedLib(*KV.first); + if (!ResolvedLibOrOpt || ResolvedLibOrOpt->empty()) + continue; + auto ResolvedLib = *ResolvedLibOrOpt; + // libNew overrides memory management functions; must never autoload that. + assert(ResolvedLib.find("/libNew.") == std::string::npos && "We must not autoload libNew!"); + + // libCling symbols are intentionally hidden from the process, and libCling must not be + // dlopened. Instead, symbols must be resolved by specifically querying the dynlib handle of + // libCling, which by definition is loaded - else we could not call this code. The handle + // is made available as argument to `CreateInterpreter`. + assert(ResolvedLib.find("/libCling.") == std::string::npos && "Must not autoload libCling!"); + + if (!ResolvedLib.empty()) + found[ResolvedLib].push_back(KV.first); + } + }, + /*searchSystem=*/true); llvm::orc::SymbolMap loadedSymbols; for (const auto &KV : found) { // Try to load the library which should provide the symbol definition. // TODO: Should this interface with the DynamicLibraryManager directly? - if (TCling__LoadLibrary(KV.first.c_str()) < 0) { - ROOT::TMetaUtils::Error("AutoloadLibraryMU", "Failed to load library %s", KV.first.c_str()); + if (TCling__LoadLibrary(KV.first().data()) < 0) { + ROOT::TMetaUtils::Error("AutoloadLibraryMU", "Failed to load library %s", KV.first().data()); } for (const auto &symbol : KV.second) {