[llvm] [ORC] Add Auto-Loading DyLib Feature with Symbol Resolution (PR #109913)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 14 01:19:23 PST 2024
https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/109913
>From 08a5f139bda8a784d1953a798c2268dc46789f7a Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 19 Sep 2024 17:16:45 +0530
Subject: [PATCH 1/4] [ORC] Add Auto-Loading DyLib Feature with Symbol
Resolution
---
.../Orc/EPCDynamicLibrarySearchGenerator.h | 42 +
.../Orc/EPCGenericDylibManager.h | 12 +
.../Orc/ExecutorProcessControl.h | 6 +-
.../Orc/Shared/AutoLoadDylibUtils.h | 212 +++
.../ExecutionEngine/Orc/Shared/OrcRTBridge.h | 7 +
.../Orc/TargetProcess/AutoLoadDylibLookup.h | 155 ++
.../SimpleExecutorDylibManager.h | 8 +
.../Orc/EPCDynamicLibrarySearchGenerator.cpp | 101 +-
.../Orc/EPCGenericDylibManager.cpp | 35 +-
.../Orc/ExecutorProcessControl.cpp | 5 +
.../Orc/Shared/OrcRTBridge.cpp | 2 +
.../ExecutionEngine/Orc/SimpleRemoteEPC.cpp | 37 +-
.../Orc/TargetProcess/AutoLoadDyLoader.cpp | 1306 +++++++++++++++++
.../Orc/TargetProcess/AutoLoadDylibLookUp.cpp | 575 ++++++++
.../Orc/TargetProcess/CMakeLists.txt | 3 +
.../SimpleExecutorDylibManager.cpp | 86 ++
16 files changed, 2585 insertions(+), 7 deletions(-)
create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h
create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
index e56afe4fe656b3..901e5d05bbeb18 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
@@ -15,6 +15,7 @@
#define LLVM_EXECUTIONENGINE_ORC_EPCDYNAMICLIBRARYSEARCHGENERATOR_H
#include "llvm/ADT/FunctionExtras.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
namespace llvm {
@@ -71,6 +72,47 @@ class EPCDynamicLibrarySearchGenerator : public DefinitionGenerator {
AddAbsoluteSymbolsFn AddAbsoluteSymbols;
};
+class AutoLoadDynamicLibrarySearchGenerator : public DefinitionGenerator {
+public:
+ using AddAbsoluteSymbolsFn = unique_function<Error(JITDylib &, SymbolMap)>;
+
+ /// Creates an AutoLoadDynamicLibrarySearchGenerator that searches for symbols
+ /// across all currently loaded libraries. If a symbol is not found, it scans
+ /// all potential dynamic libraries (dylibs), and if the symbol is located,
+ /// the corresponding library is loaded, and the symbol's definition is
+ /// returned.
+ ///
+ /// If \p AddAbsoluteSymbols is provided, it is used to add the symbols to the
+ /// \c JITDylib; otherwise it uses JD.define(absoluteSymbols(...)).
+ AutoLoadDynamicLibrarySearchGenerator(
+ ExecutionSession &ES, AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr)
+ : EPC(ES.getExecutorProcessControl()),
+ AddAbsoluteSymbols(std::move(AddAbsoluteSymbols)) {}
+
+ /// Creates a AutoLoadDynamicLibrarySearchGenerator that searches for symbols
+ /// in the target process.
+ static Expected<std::unique_ptr<AutoLoadDynamicLibrarySearchGenerator>>
+ GetForTargetProcess(ExecutionSession &ES,
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols = nullptr) {
+ return std::make_unique<AutoLoadDynamicLibrarySearchGenerator>(
+ ES, std::move(AddAbsoluteSymbols));
+ }
+
+ Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD,
+ JITDylibLookupFlags JDLookupFlags,
+ const SymbolLookupSet &Symbols) override;
+
+ Error
+ tryToResolve(SymbolNameSet CandidateSyms,
+ ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn);
+
+private:
+ ExecutorProcessControl &EPC;
+ BloomFilter GlobalFilter;
+ StringSet<> ExcludedSymbols;
+ AddAbsoluteSymbolsFn AddAbsoluteSymbols;
+};
+
} // end namespace orc
} // end namespace llvm
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
index 887147a77026e0..6bb1b40b1db933 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
@@ -34,6 +34,7 @@ class EPCGenericDylibManager {
ExecutorAddr Instance;
ExecutorAddr Open;
ExecutorAddr Lookup;
+ ExecutorAddr Resolve;
};
/// Create an EPCGenericMemoryAccess instance from a given set of
@@ -70,6 +71,9 @@ class EPCGenericDylibManager {
using SymbolLookupCompleteFn =
unique_function<void(Expected<std::vector<ExecutorSymbolDef>>)>;
+ using ResolveSymbolsCompleteFn =
+ unique_function<void(Expected<ResolveResult>)>;
+
/// Looks up symbols within the given dylib.
void lookupAsync(tpctypes::DylibHandle H, const SymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete);
@@ -78,6 +82,14 @@ class EPCGenericDylibManager {
void lookupAsync(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete);
+ /// Looks up symbols within the given dylib.
+ void resolveAsync(const SymbolLookupSet &Lookup,
+ ResolveSymbolsCompleteFn Complete);
+
+ /// Looks up symbols within the given dylib.
+ void resolveAsync(const RemoteSymbolLookupSet &Lookup,
+ ResolveSymbolsCompleteFn Complete);
+
private:
ExecutorProcessControl &EPC;
SymbolAddrs SAs;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
index 5d5326c4a469ee..b5fd1c7039af3f 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
@@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/DylibManager.h"
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
@@ -505,7 +506,10 @@ class SelfExecutorProcessControl : public ExecutorProcessControl,
void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) override;
-
+
+ void resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+ ResolveSymbolsCompleteFn F) override;
+
std::unique_ptr<jitlink::JITLinkMemoryManager> OwnedMemMgr;
char GlobalManglingPrefix = 0;
};
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
new file mode 100644
index 00000000000000..73e8b53edf8598
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
@@ -0,0 +1,212 @@
+//===------ AutoLoadDylibUtils.h - Auto-Loading Dynamic Library -------*- C++
+//-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_AUTOLOADDYLIBUTILS_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_AUTOLOADDYLIBUTILS_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
+
+#include <math.h>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+namespace orc {
+
+namespace shared {
+using SPSBloomFilter =
+ SPSTuple<bool, uint32_t, uint32_t, uint32_t, SPSSequence<uint64_t>>;
+}
+
+constexpr uint32_t log2u(std::uint32_t n) {
+ return (n > 1) ? 1 + log2u(n >> 1) : 0;
+}
+
+class BloomFilter {
+private:
+ static constexpr int Bits = 8 * sizeof(uint64_t);
+ static constexpr float P = 0.02f;
+
+ bool Initialized = false;
+ uint32_t SymbolsCount = 0;
+ uint32_t BloomSize = 0;
+ uint32_t BloomShift = 0;
+ std::vector<uint64_t> BloomTable;
+
+ // This is a GNU implementation of hash used in bloom filter!
+ static uint32_t GNUHash(StringRef S) {
+ uint32_t H = 5381;
+ for (uint8_t C : S)
+ H = (H << 5) + H + C;
+ return H;
+ }
+ // Helper method for hash testing
+ bool TestHash(uint32_t hash) const {
+ assert(IsInitialized && "Bloom filter is not initialized!");
+ uint32_t hash2 = hash >> BloomShift;
+ uint32_t n = (hash >> log2u(Bits)) % BloomSize;
+ uint64_t mask = ((1ULL << (hash % Bits)) | (1ULL << (hash2 % Bits)));
+ return (mask & BloomTable[n]) == mask;
+ }
+
+ // Helper method to add a hash
+ void AddHash(uint32_t hash) {
+ assert(IsInitialized && "Bloom filter is not initialized!");
+ uint32_t hash2 = hash >> BloomShift;
+ uint32_t n = (hash >> log2u(Bits)) % BloomSize;
+ uint64_t mask = ((1ULL << (hash % Bits)) | (1ULL << (hash2 % Bits)));
+ BloomTable[n] |= mask;
+ }
+
+ // Resizes the Bloom filter table based on symbol count
+ void ResizeTable(uint32_t newSymbolsCount) {
+ assert(SymbolsCount == 0 && "Resize not supported after initialization!");
+ SymbolsCount = newSymbolsCount;
+ BloomSize =
+ static_cast<uint32_t>(ceil((-1.44f * SymbolsCount * log2f(P)) / Bits));
+ BloomShift = std::min(6u, log2u(SymbolsCount));
+ BloomTable.resize(BloomSize, 0);
+ }
+
+ friend class shared::SPSSerializationTraits<shared::SPSBloomFilter,
+ BloomFilter>;
+
+public:
+ BloomFilter() = default;
+ BloomFilter(const BloomFilter &other) noexcept
+ : Initialized(other.Initialized), SymbolsCount(other.SymbolsCount),
+ BloomSize(other.BloomSize), BloomShift(other.BloomShift),
+ BloomTable(other.BloomTable) {
+ }
+ BloomFilter &operator=(const BloomFilter &other) = delete;
+
+ BloomFilter(BloomFilter &&other) noexcept
+ : Initialized(other.Initialized), SymbolsCount(other.SymbolsCount),
+ BloomSize(other.BloomSize), BloomShift(other.BloomShift),
+ BloomTable(std::move(other.BloomTable)) {
+ other.Initialized = false;
+ other.SymbolsCount = 0;
+ other.BloomSize = 0;
+ other.BloomShift = 0;
+ }
+
+ BloomFilter &operator=(BloomFilter &&other) noexcept {
+ if (this != &other) {
+ Initialized = other.Initialized;
+ SymbolsCount = other.SymbolsCount;
+ BloomSize = other.BloomSize;
+ BloomShift = other.BloomShift;
+ BloomTable = std::move(other.BloomTable);
+
+ other.Initialized = false;
+ other.SymbolsCount = 0;
+ other.BloomSize = 0;
+ other.BloomShift = 0;
+ }
+ return *this;
+ }
+
+ void swap(BloomFilter &other) noexcept {
+ std::swap(Initialized, other.Initialized);
+ std::swap(SymbolsCount, other.SymbolsCount);
+ std::swap(BloomSize, other.BloomSize);
+ std::swap(BloomShift, other.BloomShift);
+ std::swap(BloomTable, other.BloomTable);
+ }
+
+ void Initialize(uint32_t newSymbolsCount) {
+ assert(!Initialized && "Cannot reinitialize the Bloom filter!");
+ Initialized = true;
+ ResizeTable(newSymbolsCount);
+ }
+
+ bool IsEmpty() const { return SymbolsCount == 0; }
+
+ uint32_t getSymCount() const { return SymbolsCount; }
+
+ bool IsInitialized() const { return Initialized; }
+
+ bool MayContain(uint32_t hash) const {
+ if (IsEmpty())
+ return false;
+ return TestHash(hash);
+ }
+
+ bool MayContain(StringRef symbol) const {
+ return MayContain(GNUHash(symbol));
+ }
+
+ void AddSymbol(StringRef symbol) { AddHash(GNUHash(symbol)); }
+};
+
+struct ResolveResult {
+ std::optional<BloomFilter> Filter;
+ std::vector<ExecutorSymbolDef> SymbolDef;
+};
+
+namespace shared {
+
+template <> class SPSSerializationTraits<SPSBloomFilter, BloomFilter> {
+public:
+ static size_t size(const BloomFilter &Filter) {
+ return SPSBloomFilter::AsArgList::size(
+ Filter.Initialized, Filter.SymbolsCount, Filter.BloomSize,
+ Filter.BloomShift, Filter.BloomTable);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const BloomFilter &Filter) {
+ return SPSBloomFilter::AsArgList::serialize(
+ OB, Filter.Initialized, Filter.SymbolsCount, Filter.BloomSize,
+ Filter.BloomShift, Filter.BloomTable);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, BloomFilter &Filter) {
+ bool IsInitialized;
+ uint32_t SymbolsCount = 0, BloomSize = 0, BloomShift = 0;
+ std::vector<uint64_t> BloomTable;
+
+ if (!SPSBloomFilter::AsArgList::deserialize(
+ IB, IsInitialized, SymbolsCount, BloomSize, BloomShift, BloomTable))
+ return false;
+
+ Filter.Initialized = IsInitialized;
+ Filter.SymbolsCount = SymbolsCount;
+ Filter.BloomSize = BloomSize;
+ Filter.BloomShift = BloomShift;
+ Filter.BloomTable = std::move(BloomTable);
+
+ return true;
+ }
+};
+
+using SPSResolveResult =
+ SPSTuple<SPSOptional<SPSBloomFilter>, SPSSequence<SPSExecutorSymbolDef>>;
+template <> class SPSSerializationTraits<SPSResolveResult, ResolveResult> {
+public:
+ static size_t size(const ResolveResult &Result) {
+ return SPSResolveResult::AsArgList::size(Result.Filter, Result.SymbolDef);
+ }
+
+ static bool serialize(SPSOutputBuffer &OB, const ResolveResult &Result) {
+ return SPSResolveResult::AsArgList::serialize(OB, Result.Filter,
+ Result.SymbolDef);
+ }
+
+ static bool deserialize(SPSInputBuffer &IB, ResolveResult &Result) {
+ return SPSResolveResult::AsArgList::deserialize(IB, Result.Filter,
+ Result.SymbolDef);
+ }
+};
+
+} // end namespace shared
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_AUTOLOADDYLIBUTILS_H
\ No newline at end of file
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
index 0c549bcbf0130c..b834ec415820c2 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h
@@ -13,6 +13,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_ORCRTBRIDGE_H
#define LLVM_EXECUTIONENGINE_ORC_SHARED_ORCRTBRIDGE_H
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
@@ -25,6 +26,7 @@ namespace rt {
extern const char *SimpleExecutorDylibManagerInstanceName;
extern const char *SimpleExecutorDylibManagerOpenWrapperName;
extern const char *SimpleExecutorDylibManagerLookupWrapperName;
+extern const char *SimpleExecutorDylibManagerResolveWrapperName;
extern const char *SimpleExecutorMemoryManagerInstanceName;
extern const char *SimpleExecutorMemoryManagerReserveWrapperName;
@@ -59,6 +61,11 @@ using SPSSimpleExecutorDylibManagerLookupSignature =
shared::SPSExecutorAddr, shared::SPSExecutorAddr,
shared::SPSRemoteSymbolLookupSet);
+using SPSSimpleExecutorDylibManagerResolveSignature = shared::SPSExpected<
+ shared::SPSTuple<shared::SPSOptional<shared::SPSBloomFilter>,
+ shared::SPSSequence<shared::SPSExecutorSymbolDef>>>(
+ shared::SPSExecutorAddr, shared::SPSRemoteSymbolLookupSet);
+
using SPSSimpleExecutorMemoryManagerReserveSignature =
shared::SPSExpected<shared::SPSExecutorAddr>(shared::SPSExecutorAddr,
uint64_t);
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h
new file mode 100644
index 00000000000000..83ad22a183f36f
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h
@@ -0,0 +1,155 @@
+//===------------ AutoLoadDylibLookup.h ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_AUTOLOADDYNAMICLIBRARY_H
+#define LLVM_EXECUTIONENGINE_ORC_AUTOLOADDYNAMICLIBRARY_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace llvm {
+namespace orc {
+class DynamicLoader;
+
+#if defined(LLVM_ON_UNIX)
+const char *const kEnvDelim = ":";
+#elif defined(_WIN32)
+const char *const kEnvDelim = ";";
+#else
+#error "Unknown platform (environmental delimiter)"
+#endif
+
+class AutoLoadDynamicLibraryLookup {
+public:
+ /// Describes the library search paths.
+ struct SearchPathInfo {
+ /// The search path.
+ std::string Path;
+
+ /// True if the Path is on the LD_LIBRARY_PATH.
+ bool IsUser;
+
+ bool operator==(const SearchPathInfo &Other) const {
+ return IsUser == Other.IsUser && Path == Other.Path;
+ }
+ };
+ using SearchPathInfos = SmallVector<SearchPathInfo, 32>;
+
+private:
+ StringSet<> LoadedLibraries;
+
+ /// System's include path, get initialized at construction time.
+ SearchPathInfos SearchPaths;
+
+ DynamicLoader *Dyld = nullptr;
+
+ /// Concatenates current and system include paths to look up the filename.
+ /// Considers RPATH and RUNPATH (see: https://en.wikipedia.org/wiki/Rpath).
+ /// Returns the canonical file path or an empty string if not found.
+ std::string lookupLibInPaths(StringRef libStem,
+ SmallVector<StringRef, 2> RPath = {},
+ SmallVector<StringRef, 2> RunPath = {},
+ StringRef libLoader = "") const;
+
+ /// Concatenates current and system include paths, then looks up the filename.
+ /// If not found, adds platform-specific extensions (e.g., .so, .dll, .dylib)
+ /// and retries. Considers RPATH and RUNPATH (see:
+ /// https://en.wikipedia.org/wiki/Rpath). Returns the canonical file path or
+ /// an empty string if not found.
+ std::string lookupLibMaybeAddExt(StringRef filename,
+ SmallVector<StringRef, 2> RPath = {},
+ SmallVector<StringRef, 2> RunPath = {},
+ StringRef libLoader = "") const;
+
+ /// On a success returns to full path to a shared object that holds the
+ /// symbol pointed by func.
+ static std::string getSymbolLocation(void *func);
+
+public:
+ AutoLoadDynamicLibraryLookup();
+ ~AutoLoadDynamicLibraryLookup();
+ AutoLoadDynamicLibraryLookup(const AutoLoadDynamicLibraryLookup &) = delete;
+ AutoLoadDynamicLibraryLookup &
+ operator=(const AutoLoadDynamicLibraryLookup &) = delete;
+
+ const SearchPathInfos &getSearchPaths() const { return SearchPaths; }
+
+ void addSearchPath(StringRef dir, bool isUser = true, bool prepend = false) {
+ if (!dir.empty()) {
+ for (auto &item : SearchPaths)
+ if (dir.equals_insensitive(item.Path))
+ return;
+ auto pos = prepend ? SearchPaths.begin() : SearchPaths.end();
+ SearchPaths.insert(pos, SearchPathInfo{dir.str(), isUser});
+ }
+ }
+
+ /// Searches for a library in current and system include paths.
+ /// Considers RPATH and RUNPATH (see: https://en.wikipedia.org/wiki/Rpath).
+ /// Returns the canonical file path or an empty string if not found.
+ std::string lookupLibrary(StringRef libStem,
+ SmallVector<StringRef, 2> RPath = {},
+ SmallVector<StringRef, 2> RunPath = {},
+ StringRef libLoader = "",
+ bool variateLibStem = true) const;
+
+ /// Add loaded library.
+ void addLoadedLib(StringRef lib);
+
+ /// Returns true if the file was a dynamic library and it was already
+ /// loaded.
+ bool isLibraryLoaded(StringRef fullPath) const;
+
+ /// Initializes the dynamic loader (dyld).
+ /// Accepts a callback to decide if certain libraries, such as those
+ /// overriding malloc, should be ignored.
+ void initializeDynamicLoader(
+ std::function<bool(StringRef)> shouldPermanentlyIgnore);
+
+ /// Finds the first unloaded shared object containing the specified symbol.
+ /// Returns the library name if found, or an empty string otherwise.
+ std::string searchLibrariesForSymbol(StringRef mangledName,
+ bool searchSystem = true) const;
+
+ void dump(raw_ostream *S = nullptr) const;
+
+ /// On a success returns to full path to a shared object that holds the
+ /// symbol pointed by func.
+ template <class T> static std::string getSymbolLocation(T func) {
+ static_assert(std::is_pointer<T>::value, "Must be a function pointer!");
+ return getSymbolLocation(reinterpret_cast<void *>(func));
+ }
+
+ static std::string normalizePath(StringRef path);
+
+ /// Returns true if the file is a shared library.
+ /// Also sets whether the file exists to help identify incompatible formats.
+ static bool isSharedLibrary(StringRef libFullPath, bool *exists = nullptr);
+
+ void BuildGlobalBloomFilter(BloomFilter &Filter) const;
+};
+
+enum class SplitMode {
+ PruneNonExistant, ///< Don't add non-existant paths into output
+ FailNonExistant, ///< Fail on any non-existant paths
+ AllowNonExistant ///< Add all paths whether they exist or not
+};
+
+bool SplitPaths(StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
+ SplitMode Mode, StringRef Delim, bool Verbose = false);
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_AUTOLOADDYNAMICLIBRARY_H
\ No newline at end of file
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h
index 00fd84e3ec1426..132c3c2904732e 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.h
@@ -17,11 +17,13 @@
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_SIMPLEEXECUTORDYLIBMANAGER_H
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Error.h"
@@ -41,6 +43,8 @@ class SimpleExecutorDylibManager : public ExecutorBootstrapService {
Expected<std::vector<ExecutorSymbolDef>>
lookup(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &L);
+ Expected<ResolveResult> resolve(const RemoteSymbolLookupSet &L);
+
Error shutdown() override;
void addBootstrapSymbols(StringMap<ExecutorAddr> &M) override;
@@ -53,8 +57,12 @@ class SimpleExecutorDylibManager : public ExecutorBootstrapService {
static llvm::orc::shared::CWrapperFunctionResult
lookupWrapper(const char *ArgData, size_t ArgSize);
+ static llvm::orc::shared::CWrapperFunctionResult
+ resolveWrapper(const char *ArgData, size_t ArgSize);
+
std::mutex M;
DylibSet Dylibs;
+ std::optional<AutoLoadDynamicLibraryLookup> DylibLookup;
};
} // end namespace rt_bootstrap
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
index 2a93fcbf6c8c83..e58f1d1ad51c94 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
@@ -38,9 +38,9 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
return Error::success();
LLVM_DEBUG({
- dbgs() << "EPCDynamicLibrarySearchGenerator trying to generate "
- << Symbols << "\n";
- });
+ dbgs() << "EPCDynamicLibrarySearchGenerator trying to generate " << Symbols
+ << "\n";
+ });
SymbolLookupSet LookupSymbols;
@@ -95,5 +95,100 @@ Error EPCDynamicLibrarySearchGenerator::tryToGenerate(
return Error::success();
}
+Error AutoLoadDynamicLibrarySearchGenerator::tryToGenerate(
+ LookupState &LS, LookupKind K, JITDylib &JD,
+ JITDylibLookupFlags JDLookupFlags, const SymbolLookupSet &Symbols) {
+
+ if (Symbols.empty())
+ return Error::success();
+
+ LLVM_DEBUG({
+ dbgs() << "AutoLoadDynamicLibrarySearchGenerator trying to generate "
+ << Symbols << "\n";
+ });
+
+ SymbolNameSet CandidateSyms;
+ for (auto &KV : Symbols) {
+ if (GlobalFilter.IsInitialized() && !GlobalFilter.MayContain(*KV.first) &&
+ !ExcludedSymbols.count(*KV.first))
+ continue;
+
+ CandidateSyms.insert(KV.first);
+ }
+
+ if (CandidateSyms.empty())
+ return Error::success();
+
+ auto Err = tryToResolve(CandidateSyms, [this, &JD, LS = std::move(LS),
+ CandidateSyms](auto Result) mutable {
+ auto &ResolveRes = Result->front();
+ bool IsFilter = GlobalFilter.IsInitialized();
+ if (!IsFilter && ResolveRes.Filter.has_value()) {
+ GlobalFilter = std::move(ResolveRes.Filter.value());
+ }
+
+ if (!Result) {
+ LLVM_DEBUG({
+ dbgs() << "AutoLoadDynamicLibrarySearchGenerator resolve failed due to "
+ "error";
+ });
+ return LS.continueLookup(Result.takeError());
+ }
+
+ auto &Symbols = ResolveRes.SymbolDef;
+ assert(Result->size() == 1 && "Results for more than one library returned");
+ assert(Symbols.size() == CandidateSyms.size() &&
+ "Result has incorrect number of elements");
+
+ SymbolMap NewSymbols;
+ auto ResultI = Symbols.begin();
+ for (auto &S : CandidateSyms) {
+ if (ResultI->getAddress())
+ NewSymbols[S] = *ResultI;
+ else if (IsFilter)
+ ExcludedSymbols.insert(*S);
+ ++ResultI;
+ }
+
+ LLVM_DEBUG({
+ dbgs() << "AutoLoadDynamicLibrarySearchGenerator resolve returned "
+ << NewSymbols << "\n";
+ });
+
+ // If there were no resolved symbols bail out.
+ if (NewSymbols.empty())
+ return LS.continueLookup(Error::success());
+
+ // Define resolved symbols.
+ Error Err = AddAbsoluteSymbols
+ ? AddAbsoluteSymbols(JD, std::move(NewSymbols))
+ : JD.define(absoluteSymbols(std::move(NewSymbols)));
+
+ LS.continueLookup(std::move(Err));
+ });
+
+ return Err;
+}
+
+Error AutoLoadDynamicLibrarySearchGenerator::tryToResolve(
+ SymbolNameSet CandidateSyms,
+ ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn) {
+
+ LLVM_DEBUG({
+ dbgs() << "AutoLoadDynamicLibrarySearchGenerator trying to resolve "
+ << CandidateSyms << "\n";
+ });
+
+ SymbolLookupSet LookupSymbols;
+
+ for (auto &S : CandidateSyms) {
+ LookupSymbols.add(S, SymbolLookupFlags::WeaklyReferencedSymbol);
+ }
+
+ EPC.resolveSymbolsAsync(LookupSymbols, std::move(OnCompleteFn));
+
+ return Error::success();
+}
+
} // end namespace orc
} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
index f98b18ccd0dc74..5382c0d7e5cdd5 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCGenericDylibManager.cpp
@@ -66,7 +66,8 @@ EPCGenericDylibManager::CreateWithDefaultBootstrapSymbols(
if (auto Err = EPC.getBootstrapSymbols(
{{SAs.Instance, rt::SimpleExecutorDylibManagerInstanceName},
{SAs.Open, rt::SimpleExecutorDylibManagerOpenWrapperName},
- {SAs.Lookup, rt::SimpleExecutorDylibManagerLookupWrapperName}}))
+ {SAs.Lookup, rt::SimpleExecutorDylibManagerLookupWrapperName},
+ {SAs.Resolve, rt::SimpleExecutorDylibManagerResolveWrapperName}}))
return std::move(Err);
return EPCGenericDylibManager(EPC, std::move(SAs));
}
@@ -117,5 +118,37 @@ void EPCGenericDylibManager::lookupAsync(tpctypes::DylibHandle H,
SAs.Instance, H, Lookup);
}
+void EPCGenericDylibManager::resolveAsync(const SymbolLookupSet &Lookup,
+ ResolveSymbolsCompleteFn Complete) {
+ EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorDylibManagerResolveSignature>(
+ SAs.Resolve,
+ [Complete = std::move(Complete)](Error SerializationErr,
+ Expected<ResolveResult> Result) mutable {
+ if (SerializationErr) {
+ cantFail(Result.takeError());
+ Complete(std::move(SerializationErr));
+ return;
+ }
+ Complete(std::move(Result));
+ },
+ SAs.Instance, Lookup);
+}
+
+void EPCGenericDylibManager::resolveAsync(const RemoteSymbolLookupSet &Lookup,
+ ResolveSymbolsCompleteFn Complete) {
+ EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorDylibManagerResolveSignature>(
+ SAs.Resolve,
+ [Complete = std::move(Complete)](Error SerializationErr,
+ Expected<ResolveResult> Result) mutable {
+ if (SerializationErr) {
+ cantFail(Result.takeError());
+ Complete(std::move(SerializationErr));
+ return;
+ }
+ Complete(std::move(Result));
+ },
+ SAs.Instance, Lookup);
+}
+
} // end namespace orc
} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
index 2a3ede90ade0da..0df3afbf532cb8 100644
--- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
@@ -116,6 +116,11 @@ void SelfExecutorProcessControl::lookupSymbolsAsync(
Complete(std::move(R));
}
+void SelfExecutorProcessControl::resolveSymbolsAsync(
+ ArrayRef<SymbolLookupSet> Request, ResolveSymbolsCompleteFn F) {
+ llvm_unreachable("Unsupported");
+}
+
Expected<int32_t>
SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr,
ArrayRef<std::string> Args) {
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
index ae39b1d1bfaa9d..bb2e31346d25b6 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp
@@ -18,6 +18,8 @@ const char *SimpleExecutorDylibManagerOpenWrapperName =
"__llvm_orc_SimpleExecutorDylibManager_open_wrapper";
const char *SimpleExecutorDylibManagerLookupWrapperName =
"__llvm_orc_SimpleExecutorDylibManager_lookup_wrapper";
+const char *SimpleExecutorDylibManagerResolveWrapperName =
+ "__llvm_orc_SimpleExecutorDylibManager_resolve_wrapper";
const char *SimpleExecutorMemoryManagerInstanceName =
"__llvm_orc_SimpleExecutorMemoryManager_Instance";
diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
index 0f9612bae074c5..a6de6ca7fc33f5 100644
--- a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
@@ -57,11 +57,45 @@ lookupSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
});
}
+static void
+resolveSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
+ ArrayRef<SymbolLookupSet> Request,
+ std::vector<ResolveResult> Result,
+ SimpleRemoteEPC::ResolveSymbolsCompleteFn Complete) {
+ if (Request.empty())
+ return Complete(std::move(Result));
+
+ auto &Symbols = Request.front();
+ DylibMgr.resolveAsync(Symbols, [&DylibMgr, Request,
+ Complete = std::move(Complete),
+ Result = std::move(Result)](auto R) mutable {
+ if (!R)
+ return Complete(R.takeError());
+ Result.push_back({});
+ if (R->Filter.has_value())
+ Result.back().Filter.swap(R->Filter);
+
+ auto &S = R->SymbolDef;
+ auto &SymDef = Result.back().SymbolDef;
+ SymDef.reserve(S.size());
+ for (auto Addr : S)
+ SymDef.push_back(Addr);
+
+ resolveSymbolsAsyncHelper(DylibMgr, Request.drop_front(), std::move(Result),
+ std::move(Complete));
+ });
+}
+
void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn Complete) {
lookupSymbolsAsyncHelper(*EPCDylibMgr, Request, {}, std::move(Complete));
}
+void SimpleRemoteEPC::resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+ ResolveSymbolsCompleteFn Complete) {
+ resolveSymbolsAsyncHelper(*DylibMgr, Request, {}, std::move(Complete));
+}
+
Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
ArrayRef<std::string> Args) {
int64_t Result = 0;
@@ -299,8 +333,7 @@ Error SimpleRemoteEPC::setup(Setup S) {
// Prepare a handler for the setup packet.
PendingCallWrapperResults[0] =
- RunInPlace()(
- [&](shared::WrapperFunctionResult SetupMsgBytes) {
+ RunInPlace()([&](shared::WrapperFunctionResult SetupMsgBytes) {
if (const char *ErrMsg = SetupMsgBytes.getOutOfBandError()) {
EIP.set_value(
make_error<StringError>(ErrMsg, inconvertibleErrorCode()));
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
new file mode 100644
index 00000000000000..334507b6d371a9
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
@@ -0,0 +1,1306 @@
+//===---------------- DynamicLibraryManagerSymbol.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.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/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/WithColor.h"
+
+#include <algorithm>
+#include <list>
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#ifdef LLVM_ON_UNIX
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif // LLVM_ON_UNIX
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#include <sys/stat.h>
+#undef LC_LOAD_DYLIB
+#undef LC_RPATH
+#endif // __APPLE__
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <libloaderapi.h> // For GetModuleFileNameA
+#include <memoryapi.h> // For VirtualQuery
+#include <windows.h>
+#endif
+
+namespace {
+#define PATH_MAX 1024
+using BasePath = std::string;
+using namespace llvm;
+
+// // This is a GNU implementation of hash used in bloom filter!
+static uint32_t GNUHash(StringRef S) {
+ uint32_t H = 5381;
+ for (uint8_t C : S)
+ H = (H << 5) + H + C;
+ return H;
+}
+
+/// 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`, 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 &Path;
+ std::string LibName;
+ orc::BloomFilter Filter;
+ StringSet<> Symbols;
+ // std::vector<const LibraryPath*> LibDeps;
+
+ LibraryPath(const BasePath &Path, const std::string &LibName)
+ : Path(Path), LibName(LibName) {}
+
+ bool operator==(const LibraryPath &other) const {
+ return (&Path == &other.Path || Path == other.Path) &&
+ LibName == other.LibName;
+ }
+
+ const std::string GetFullName() const {
+ SmallString<512> Vec(Path);
+ sys::path::append(Vec, StringRef(LibName));
+ return Vec.str().str();
+ }
+
+ void AddBloom(StringRef symbol) { Filter.AddSymbol(symbol); }
+
+ StringRef AddSymbol(const std::string &symbol) {
+ auto it = Symbols.insert(symbol);
+ return it.first->getKey();
+ }
+
+ bool hasBloomFilter() const { return Filter.IsInitialized(); }
+
+ bool isBloomFilterEmpty() const {
+ assert(Filter.IsInitialized() && "Bloom filter not initialized!");
+ return Filter.IsEmpty();
+ }
+
+ void InitializeBloomFilter(uint32_t newSymbolsCount) {
+ assert(!Filter.IsInitialized() && "Cannot re-initialize non-empty filter!");
+ Filter.Initialize(newSymbolsCount);
+ }
+
+ bool MayExistSymbol(StringRef symbol) const {
+ // The library had no symbols and the bloom filter is empty.
+ if (isBloomFilterEmpty())
+ return false;
+
+ return Filter.MayContain(symbol);
+ }
+
+ bool ExistSymbol(StringRef symbol) const {
+ return Symbols.find(symbol) != 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 (LibName) are relatively short
+/// strings and the base paths (Path) are repetitive long strings.
+class LibraryPaths {
+ struct LibraryPathHashFn {
+ size_t operator()(const LibraryPath &item) const {
+ return std::hash<size_t>()(item.Path.length()) ^
+ std::hash<std::string>()(item.LibName);
+ }
+ };
+
+ std::vector<const LibraryPath *> Libs;
+ std::unordered_set<LibraryPath, LibraryPathHashFn> LibsH;
+
+public:
+ bool HasRegisteredLib(const LibraryPath &Lib) const {
+ return LibsH.count(Lib);
+ }
+
+ const LibraryPath *GetRegisteredLib(const LibraryPath &Lib) const {
+ auto search = LibsH.find(Lib);
+ if (search != LibsH.end())
+ return &(*search);
+ return nullptr;
+ }
+
+ const LibraryPath *RegisterLib(const LibraryPath &Lib) {
+ auto it = LibsH.insert(Lib);
+ assert(it.second && "Already registered!");
+ Libs.push_back(&*it.first);
+ return &*it.first;
+ }
+
+ void UnregisterLib(const LibraryPath &Lib) {
+ auto found = LibsH.find(Lib);
+ if (found == LibsH.end())
+ return;
+
+ Libs.erase(std::find(Libs.begin(), Libs.end(), &*found));
+ LibsH.erase(found);
+ }
+
+ size_t size() const {
+ assert(Libs.size() == LibsH.size());
+ return Libs.size();
+ }
+
+ const std::vector<const LibraryPath *> &GetLibraries() const { return Libs; }
+};
+
+#ifndef _WIN32
+// Cached version of system function lstat
+static inline mode_t cached_lstat(const char *path) {
+ static StringMap<mode_t> lstat_cache;
+
+ // If already cached - retun cached result
+ auto it = lstat_cache.find(path);
+ if (it != lstat_cache.end())
+ return it->second;
+
+ // If result not in cache - call system function and cache result
+ struct stat buf;
+ mode_t st_mode = (lstat(path, &buf) == -1) ? 0 : buf.st_mode;
+ lstat_cache.insert(std::pair<StringRef, mode_t>(path, st_mode));
+ return st_mode;
+}
+
+// Cached version of system function readlink
+static inline StringRef cached_readlink(const char *pathname) {
+ static StringMap<std::string> readlink_cache;
+
+ // If already cached - retun cached result
+ auto it = readlink_cache.find(pathname);
+ if (it != readlink_cache.end())
+ return StringRef(it->second);
+
+ // If result not in cache - call system function and cache result
+ char buf[PATH_MAX];
+ ssize_t len;
+ if ((len = readlink(pathname, buf, sizeof(buf))) != -1) {
+ buf[len] = '\0';
+ std::string s(buf);
+ readlink_cache.insert(std::pair<StringRef, std::string>(pathname, s));
+ return readlink_cache[pathname];
+ }
+ return "";
+}
+#endif
+
+// Cached version of system function realpath
+std::string cached_realpath(StringRef path, StringRef base_path = "",
+ bool is_base_path_real = false,
+ long symlooplevel = 40) {
+ if (path.empty()) {
+ errno = ENOENT;
+ return "";
+ }
+
+ if (!symlooplevel) {
+ errno = ELOOP;
+ return "";
+ }
+
+ // If already cached - retun cached result
+ static StringMap<std::pair<std::string, int>> cache;
+ bool relative_path = sys::path::is_relative(path);
+ if (!relative_path) {
+ auto it = cache.find(path);
+ if (it != cache.end()) {
+ errno = it->second.second;
+ return it->second.first;
+ }
+ }
+
+ // If result not in cache - call system function and cache result
+
+ StringRef sep(sys::path::get_separator());
+ SmallString<256> result(sep);
+#ifndef _WIN32
+ SmallVector<StringRef, 16> p;
+
+ // Relative or absolute path
+ if (relative_path) {
+ if (is_base_path_real) {
+ result.assign(base_path);
+ } else {
+ if (path[0] == '~' &&
+ (path.size() == 1 || sys::path::is_separator(path[1]))) {
+ static SmallString<128> home;
+ if (home.str().empty())
+ sys::path::home_directory(home);
+ StringRef(home).split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ } else if (base_path.empty()) {
+ static SmallString<256> current_path;
+ if (current_path.str().empty())
+ sys::fs::current_path(current_path);
+ StringRef(current_path)
+ .split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ } else {
+ base_path.split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ }
+ }
+ }
+ path.split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+
+ // Handle path list items
+ for (auto item : p) {
+ if (item == ".")
+ continue; // skip "." element in "abc/./def"
+ if (item == "..") {
+ // collapse "a/b/../c" to "a/c"
+ size_t s = result.rfind(sep);
+ if (s != StringRef::npos)
+ result.resize(s);
+ if (result.empty())
+ result = sep;
+ continue;
+ }
+
+ size_t old_size = result.size();
+ sys::path::append(result, item);
+ mode_t st_mode = cached_lstat(result.c_str());
+ if (S_ISLNK(st_mode)) {
+ StringRef symlink = cached_readlink(result.c_str());
+ if (sys::path::is_relative(symlink)) {
+ result.resize(old_size);
+ result = cached_realpath(symlink, result, true, symlooplevel - 1);
+ } else {
+ result = cached_realpath(symlink, "", true, symlooplevel - 1);
+ }
+ } else if (st_mode == 0) {
+ cache.insert(std::pair<StringRef, std::pair<std::string, int>>(
+ path, std::pair<std::string, int>("", ENOENT)));
+ errno = ENOENT;
+ return "";
+ }
+ }
+#else
+ sys::fs::real_path(path, result);
+#endif
+ cache.insert(std::pair<StringRef, std::pair<std::string, int>>(
+ path, std::pair<std::string, int>(result.str().str(), errno)));
+ return result.str().str();
+}
+
+using namespace llvm;
+using namespace object;
+
+template <class ELFT>
+static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *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<const char *>(*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 StringRef GetGnuHashSection(object::ObjectFile *file) {
+ for (auto S : file->sections()) {
+ StringRef name = cantFail(S.getName());
+ if (name == ".gnu.hash") {
+ return 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(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();
+
+ 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<const uint32_t *>(hashContent + 8);
+ uint32_t shift2 = *reinterpret_cast<const uint32_t *>(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<const uint64_t *>(hash_pos);
+ uint64_t bitmask = ((1ULL << (hash % bits)) | (1ULL << (hash2 % bits)));
+ return (bitmask & word) == bitmask;
+}
+
+} // 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 llvm::orc::AutoLoadDynamicLibraryLookup::getSymbolLocation(
+ &GetExecutablePath);
+}
+
+namespace llvm {
+namespace orc {
+class DynamicLoader {
+ struct BasePathHashFunction {
+ size_t operator()(const BasePath &item) const {
+ return std::hash<std::string>()(item);
+ }
+ };
+
+ struct BasePathEqFunction {
+ size_t operator()(const BasePath &l, const BasePath &r) const {
+ return &l == &r || l == r;
+ }
+ };
+ /// A memory efficient 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<BasePath, BasePathHashFunction, BasePathEqFunction>
+ Paths;
+
+ public:
+ const BasePath &RegisterBasePath(const std::string &Path,
+ bool *WasInserted = nullptr) {
+ auto it = Paths.insert(Path);
+ if (WasInserted)
+ *WasInserted = it.second;
+
+ return *it.first;
+ }
+
+ bool Contains(StringRef Path) { return Paths.count(Path.str()); }
+ };
+
+ bool FirstRun = true;
+ bool FirstRunSysLib = true;
+ bool UseBloomFilter = true;
+ bool UseHashTable = true;
+
+ const AutoLoadDynamicLibraryLookup &AutoLoadDylibMgr;
+
+ /// The basename of `/home/.../lib/libA.so`,
+ /// BasePaths will contain `/home/.../lib/`
+ BasePaths BasePaths;
+
+ LibraryPaths Libraries;
+ LibraryPaths 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 QueriedLibraries;
+
+ using PermanentlyIgnoreCallbackProto = std::function<bool(StringRef)>;
+ const PermanentlyIgnoreCallbackProto ShouldPermanentlyIgnoreCallback;
+ const StringRef 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, 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:
+ DynamicLoader(const AutoLoadDynamicLibraryLookup &DLM,
+ PermanentlyIgnoreCallbackProto shouldIgnore,
+ StringRef execFormat)
+ : AutoLoadDylibMgr(DLM), ShouldPermanentlyIgnoreCallback(shouldIgnore),
+ ExecutableFormat(execFormat) {}
+
+ ~DynamicLoader(){};
+
+ std::string searchLibrariesForSymbol(StringRef mangledName,
+ bool searchSystem);
+
+ void BuildGlobalBloomFilter(BloomFilter &Filter) const;
+};
+
+std::string RPathToStr(SmallVector<StringRef, 2> V) {
+ std::string result;
+ for (auto item : V)
+ result += item.str() + ",";
+ if (!result.empty())
+ result.pop_back();
+ return result;
+}
+
+template <class ELFT>
+void HandleDynTab(const ELFFile<ELFT> *Elf, StringRef FileName,
+ SmallVector<StringRef, 2> &RPath,
+ SmallVector<StringRef, 2> &RunPath,
+ std::vector<StringRef> &Deps, bool &isPIEExecutable) {
+#define DEBUG_TYPE "Dyld:"
+ const char *Data = "";
+ if (Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf))
+ Data = StrTabOrErr.get().data();
+
+ isPIEExecutable = false;
+
+ auto DynamicEntriesOrError = Elf->dynamicEntries();
+ if (!DynamicEntriesOrError) {
+ LLVM_DEBUG(dbgs() << "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, SplitMode::AllowNonExistant,
+ kEnvDelim, false);
+ break;
+ case ELF::DT_RUNPATH:
+ SplitPaths(Data + Dyn.d_un.d_val, RunPath, SplitMode::AllowNonExistant,
+ kEnvDelim, false);
+ break;
+ case ELF::DT_FLAGS_1:
+ // Check if this is not a pie executable.
+ if (Dyn.d_un.d_val & 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)
+ }
+ }
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::ScanForLibraries(bool searchSystemLibraries /* = false*/) {
+#define DEBUG_TYPE "Dyld:ScanForLibraries:"
+ const auto &searchPaths = AutoLoadDylibMgr.getSearchPaths();
+
+ LLVM_DEBUG({
+ dbgs() << "Dyld::ScanForLibraries: system="
+ << (searchSystemLibraries ? "true" : "false") << "\n";
+ for (const AutoLoadDynamicLibraryLookup::SearchPathInfo &Info : searchPaths)
+ dbgs() << ">>>" << Info.Path << ", "
+ << (Info.IsUser ? "user\n" : "system\n");
+ });
+
+ SmallSet<const BasePath *, 32> ScannedPaths;
+ // FileName must be always full/absolute/resolved file name.
+ std::function<void(StringRef, unsigned)> ProcessLibraryFile =
+ [&](StringRef FileName, unsigned level) {
+ LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries HandleLib:"
+ << FileName.str() << ", level=" << level << " -> ");
+
+ StringRef FileRealPath = sys::path::parent_path(FileName);
+ StringRef FileRealName = sys::path::filename(FileName);
+ const BasePath &BaseP = BasePaths.RegisterBasePath(FileRealPath.str());
+ LibraryPath LibPath(BaseP, FileRealName.str());
+
+ if (SysLibraries.GetRegisteredLib(LibPath) ||
+ Libraries.GetRegisteredLib(LibPath)) {
+ LLVM_DEBUG(dbgs() << "Already handled!!!\n");
+ return;
+ }
+
+ if (ShouldPermanentlyIgnore(FileName)) {
+ LLVM_DEBUG(dbgs() << "PermanentlyIgnored!!!\n");
+ return;
+ }
+
+ if (searchSystemLibraries)
+ SysLibraries.RegisterLib(LibPath);
+ else
+ Libraries.RegisterLib(LibPath);
+
+ SmallVector<StringRef, 2> RPath, RunPath;
+ std::vector<StringRef> Deps;
+
+ auto ObjFileOrErr = object::ObjectFile::createObjectFile(FileName);
+ if (Error Err = ObjFileOrErr.takeError()) {
+ LLVM_DEBUG({
+ std::string Message;
+ handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+ Message += EIB.message() + "; ";
+ });
+ dbgs() << "Dyld::ScanForLibraries: Failed to read object file "
+ << FileName.str() << " Errors: " << Message << "\n";
+ });
+ return;
+ }
+
+ object::ObjectFile *BinObjF = ObjFileOrErr.get().getBinary();
+ if (BinObjF->isELF()) {
+ bool isPIEExecutable = false;
+
+ if (const auto *ELF = dyn_cast<ELF32LEObjectFile>(BinObjF))
+ HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+ isPIEExecutable);
+ else if (const auto *ELF = dyn_cast<ELF32BEObjectFile>(BinObjF))
+ HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+ isPIEExecutable);
+ else if (const auto *ELF = dyn_cast<ELF64LEObjectFile>(BinObjF))
+ HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+ isPIEExecutable);
+ else if (const auto *ELF = dyn_cast<ELF64BEObjectFile>(BinObjF))
+ HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
+ isPIEExecutable);
+
+ if (level == 0 && isPIEExecutable) {
+ if (searchSystemLibraries)
+ SysLibraries.UnregisterLib(LibPath);
+ else
+ Libraries.UnregisterLib(LibPath);
+ return;
+ }
+ } else if (BinObjF->isMachO()) {
+ MachOObjectFile *Obj = dyn_cast<MachOObjectFile>(BinObjF);
+ for (const auto &Command : Obj->load_commands()) {
+ if (Command.C.cmd == MachO::LC_LOAD_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,
+ SplitMode::AllowNonExistant, kEnvDelim, false);
+ }
+ }
+ } else if (BinObjF->isCOFF()) {
+ // TODO: Implement COFF support
+ }
+
+ LLVM_DEBUG({
+ dbgs() << "Dyld::ScanForLibraries: Deps Info:\n";
+ dbgs() << " RPATH=" << RPathToStr(RPath) << "\n";
+ dbgs() << " RUNPATH=" << RPathToStr(RunPath) << "\n";
+ for (size_t i = 0; i < Deps.size(); ++i)
+ dbgs() << " Deps[" << i << "]=" << Deps[i].str() << "\n";
+ });
+
+ // Heuristics for workaround performance problems:
+ // (H1) If RPATH and RUNPATH == "" -> skip handling Deps
+ if (RPath.empty() && RunPath.empty()) {
+ LLVM_DEBUG(dbgs()
+ << "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(),
+ [&](const AutoLoadDynamicLibraryLookup::SearchPathInfo
+ &info) { return item == info.Path; });
+ }) &&
+ std::all_of(RunPath.begin(), RunPath.end(), [&](StringRef item) {
+ return std::any_of(
+ searchPaths.begin(), searchPaths.end(),
+ [&](const AutoLoadDynamicLibraryLookup::SearchPathInfo
+ &info) { return item == info.Path; });
+ })) {
+ LLVM_DEBUG(dbgs()
+ << "Dyld::ScanForLibraries: Skip all deps by Heuristic2: "
+ << FileName.str() << "\n");
+ return;
+ }
+
+ // Recursively handle dependencies
+ for (StringRef dep : Deps) {
+ std::string dep_full = AutoLoadDylibMgr.lookupLibrary(
+ dep, RPath, RunPath, FileName, false);
+ ProcessLibraryFile(dep_full, level + 1);
+ }
+ };
+
+ for (const AutoLoadDynamicLibraryLookup::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
+
+ // BasePaths = ["/lib/1", "/lib/3", "/system/lib"]
+ // *Libraries = [<0,"1.so">, <1,"1.so">, <2,"s.so">, <1,"3.so">]
+
+ LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries Iter:" << Info.Path
+ << " -> ");
+ std::string RealPath = cached_realpath(Info.Path);
+
+ StringRef DirPath(RealPath);
+ LLVM_DEBUG(dbgs() << RealPath << "\n");
+
+ if (!sys::fs::is_directory(DirPath) || DirPath.empty())
+ continue;
+
+ // Already searched?
+ const BasePath &ScannedBPath = BasePaths.RegisterBasePath(RealPath);
+ if (ScannedPaths.count(&ScannedBPath)) {
+ LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries Already scanned: "
+ << RealPath << "\n");
+ continue;
+ }
+
+ LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Iterator: " << DirPath
+ << "\n");
+ std::error_code EC;
+ for (sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd;
+ DirIt != DirEnd && !EC; DirIt.increment(EC)) {
+
+ LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Iterator >>> "
+ << DirIt->path()
+ << ", type=" << (short)(DirIt->type()) << "\n");
+
+ const sys::fs::file_type ft = DirIt->type();
+ if (ft == sys::fs::file_type::regular_file) {
+ ProcessLibraryFile(DirIt->path(), 0);
+ } else if (ft == sys::fs::file_type::symlink_file) {
+ std::string DepFileName_str = cached_realpath(DirIt->path());
+ StringRef DepFileName = DepFileName_str;
+ assert(!sys::fs::is_symlink_file(DepFileName));
+ if (!sys::fs::is_directory(DepFileName))
+ ProcessLibraryFile(DepFileName, 0);
+ }
+ }
+ for (sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd;
+ DirIt != DirEnd && !EC; DirIt.increment(EC)) {
+ LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: File " << DirIt->path()
+ << ", type=" << (short)DirIt->type() << "\n");
+
+ const sys::fs::file_type ft = DirIt->type();
+ if (ft == sys::fs::file_type::regular_file ||
+ (ft == sys::fs::file_type::symlink_file &&
+ !sys::fs::is_symlink_file(DirIt->path()))) {
+ ProcessLibraryFile(DirIt->path(), 0);
+ }
+ }
+
+ // Register the DirPath as fully scanned.
+ ScannedPaths.insert(&ScannedBPath);
+ }
+ }
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::BuildBloomFilter(LibraryPath *Lib,
+ object::ObjectFile *BinObjFile,
+ unsigned IgnoreSymbolFlags /*= 0*/) const {
+#define DEBUG_TYPE "Dyld::BuildBloomFilter:"
+ assert(UseBloomFilter && "Bloom filter is disabled");
+ assert(!Lib->hasBloomFilter() && "Bloom filter already built!");
+
+ using namespace llvm;
+ // using namespace object;
+
+ LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Building Bloom filter for: "
+ << Lib->GetFullName() << "\n");
+
+ std::vector<StringRef> symbols;
+ uint32_t SymbolsCount = 0;
+ // Helper to process each symbol from a range
+ auto ProcessSymbols = [&](auto range) {
+ for (const object::SymbolRef &S : range) {
+ uint32_t Flags = cantFail(S.getFlags());
+
+ // Skip symbols based on the flags (e.g., undefined or ignored)
+ if (Flags & IgnoreSymbolFlags || Flags & object::SymbolRef::SF_Undefined)
+ continue;
+
+ Expected<StringRef> SymName = S.getName();
+ if (!SymName || SymName->empty()) {
+ LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Skipped empty or failed "
+ "to read symbol\n");
+ continue;
+ }
+
+ symbols.push_back(*SymName);
+ ++SymbolsCount;
+ }
+ };
+
+ ProcessSymbols(BinObjFile->symbols());
+
+ if (BinObjFile->isELF()) {
+ // ELF file format has .dynstr section for the dynamic symbol table.
+ const auto *ElfObj = cast<object::ELFObjectFileBase>(BinObjFile);
+ ProcessSymbols(ElfObj->getDynamicSymbolIterators());
+ } else if (BinObjFile->isCOFF()) { // On Windows, the symbols are present in
+ // COFF format.
+ object::COFFObjectFile *CoffObj = cast<object::COFFObjectFile>(BinObjFile);
+ // In COFF, the symbols are not present in the SymbolTable section
+ // of the Object file. They are present in the ExportDirectory section.
+ for (const object::ExportDirectoryEntryRef &D :
+ CoffObj->export_directories()) {
+ // All the symbols are already flagged as exported.
+ // We cannot really ignore symbols based on flags as we do on unix.
+ StringRef Name;
+ auto Err = D.getSymbolName(Name);
+
+ if (Err) {
+ std::string Message;
+ handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+ Message += EIB.message() + "; ";
+ });
+ LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Failed to read symbol "
+ << Message << "\n");
+ continue;
+ }
+ if (Name.empty())
+ continue;
+
+ ++SymbolsCount;
+ symbols.push_back(Name);
+ }
+ }
+
+ // Initialize the Bloom filter with the count of symbols
+ Lib->InitializeBloomFilter(SymbolsCount);
+
+ if (!SymbolsCount) {
+ LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: No symbols found.\n");
+ return;
+ }
+
+ LLVM_DEBUG({
+ dbgs() << "Dyld::BuildBloomFilter: Adding symbols to Bloom filter:\n";
+ for (const auto &Sym : symbols)
+ dbgs() << "- " << Sym << "\n";
+ });
+
+ // Add symbols to the Bloom filter
+ for (const auto &S : symbols) {
+ Lib->AddBloom(UseHashTable ? Lib->AddSymbol(S.str()) : S);
+ }
+#undef DEBUG_TYPE
+}
+
+bool DynamicLoader::ContainsSymbol(const LibraryPath *Lib,
+ StringRef mangledName,
+ unsigned IgnoreSymbolFlags /*= 0*/) const {
+#define DEBUG_TYPE "Dyld::ContainsSymbol:"
+ // Helper lambda to handle symbol search and logging
+ auto logAndReturn = [](bool result, const std::string &msg) {
+ LLVM_DEBUG(dbgs() << msg);
+ return result;
+ };
+
+ const std::string library_filename = Lib->GetFullName();
+
+ LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Find symbol: lib="
+ << library_filename << ", mangled=" << mangledName.str()
+ << "\n");
+
+ auto ObjF = object::ObjectFile::createObjectFile(library_filename);
+ if (Error Err = ObjF.takeError()) {
+ std::string Message;
+ handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+ Message += EIB.message() + "; ";
+ });
+ return logAndReturn(false,
+ "Dyld::ContainsSymbol: Failed to read object file " +
+ library_filename + " Errors: " + Message + "\n");
+ }
+
+ object::ObjectFile *BinObjFile = ObjF.get().getBinary();
+ uint32_t hashedMangle = GNUHash(mangledName);
+
+ // Check for the gnu.hash section if ELF and exit early if symbol doesn't
+ // exist
+ if (BinObjFile->isELF() &&
+ !MayExistInElfObjectFile(BinObjFile, hashedMangle)) {
+ return logAndReturn(false,
+ "Dyld::ContainsSymbol: ELF BloomFilter: Skip symbol <" +
+ mangledName.str() + ">.\n");
+ }
+
+ // Use Bloom filter if enabled
+ if (UseBloomFilter) {
+ // Use our bloom filters and create them if necessary.
+ if (!Lib->hasBloomFilter()) {
+ BuildBloomFilter(const_cast<LibraryPath *>(Lib), BinObjFile,
+ IgnoreSymbolFlags);
+ }
+
+ // If the symbol does not exist, exit early. In case it may exist, iterate.
+ if (!Lib->MayExistSymbol(mangledName)) {
+ return logAndReturn(false,
+ "Dyld::ContainsSymbol: BloomFilter: Skip symbol <" +
+ mangledName.str() + ">.\n");
+ }
+ LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: BloomFilter: Symbol <"
+ << mangledName.str() << "> May exist. Search for it.\n");
+ }
+
+ // Use hash table if enabled
+ if (UseHashTable) {
+ bool result = Lib->ExistSymbol(mangledName);
+ return logAndReturn(
+ result, result ? "Dyld::ContainsSymbol: HashTable: Symbol Exist\n"
+ : "Dyld::ContainsSymbol: HashTable: Symbol Not exis\n");
+ }
+
+ // Symbol not found in hash table; iterate through all symbols
+ LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Iterate all for <"
+ << mangledName.str() << ">");
+
+ auto ForeachSymbol =
+ [&library_filename](iterator_range<object::symbol_iterator> range,
+ unsigned IgnoreSymbolFlags,
+ StringRef mangledName) -> bool {
+ for (const object::SymbolRef &S : range) {
+
+ uint32_t Flags = cantFail(S.getFlags());
+ 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.
+
+ Expected<StringRef> SymNameErr = S.getName();
+ if (!SymNameErr || SymNameErr.get().empty())
+ continue;
+
+ if (SymNameErr.get() == mangledName) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ // If no hash symbol then iterate to detect symbol
+ // We Iterate only if BloomFilter and/or SymbolHashTable are not supported.
+
+ // Symbol may exist. Iterate.
+ if (ForeachSymbol(BinObjFile->symbols(), IgnoreSymbolFlags, mangledName)) {
+ return logAndReturn(true, "Dyld::ContainsSymbol: Symbol " +
+ mangledName.str() + " found in " +
+ library_filename + "\n");
+ }
+
+ // Check dynamic symbols for ELF files
+ if (BinObjFile->isELF()) {
+ // ELF file format has .dynstr section for the dynamic symbol table.
+ const auto *ElfObj = cast<object::ELFObjectFileBase>(BinObjFile);
+ bool result = ForeachSymbol(ElfObj->getDynamicSymbolIterators(),
+ IgnoreSymbolFlags, mangledName);
+ return logAndReturn(
+ result,
+ result ? "Dyld::ContainsSymbol: Symbol found in ELF dynamic symbols.\n"
+ : "Dyld::ContainsSymbol: Symbol not found in ELF dynamic "
+ "symbols.\n");
+ }
+
+ return logAndReturn(false, "Dyld::ContainsSymbol: Symbol not found.\n");
+#undef DEBUG_TYPE
+}
+
+bool DynamicLoader::ShouldPermanentlyIgnore(StringRef FileName) const {
+#define DEBUG_TYPE "Dyld:"
+ assert(!ExecutableFormat.empty() && "Failed to find the object format!");
+
+ if (!AutoLoadDynamicLibraryLookup::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 (AutoLoadDylibMgr.isLibraryLoaded(FileName))
+ return true;
+
+ auto ObjF = object::ObjectFile::createObjectFile(FileName);
+ if (!ObjF) {
+ LLVM_DEBUG(dbgs() << "[DyLD] Failed to read object file " << FileName
+ << "\n");
+ return true;
+ }
+
+ object::ObjectFile *file = ObjF.get().getBinary();
+
+ LLVM_DEBUG(dbgs() << "Current executable format: " << ExecutableFormat
+ << ". Executable format of " << FileName << " : "
+ << file->getFileFormatName() << "\n");
+
+ // Ignore libraries with different format than the executing one.
+ if (ExecutableFormat != file->getFileFormatName())
+ return true;
+
+ if (isa<object::ELFObjectFileBase>(*file)) {
+ for (auto S : file->sections()) {
+ StringRef name = 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<object::ELFSectionRef &>(S);
+ if (SecRef.getType() == ELF::SHT_NOBITS)
+ return true;
+
+ return (SecRef.getFlags() & ELF::SHF_ALLOC) == 0;
+ }
+ }
+ return true;
+ }
+
+ // FIXME: Handle osx using isStripped after upgrading to llvm9.
+
+ return ShouldPermanentlyIgnoreCallback(FileName);
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::dumpDebugInfo() const {
+#define DEBUG_TYPE "Dyld:"
+ LLVM_DEBUG({
+ dbgs() << "---\n";
+ size_t x = 0;
+ for (auto const &item : BasePaths.Paths) {
+ dbgs() << "Dyld: - BasePaths[" << x++ << "]:" << &item << ": " << item
+ << "\n";
+ }
+ dbgs() << "---\n";
+ x = 0;
+ for (auto const &item : Libraries.GetLibraries()) {
+ dbgs() << "Dyld: - Libraries[" << x++ << "]:" << &item << ": "
+ << item->Path << ", " << item->LibName << "\n";
+ }
+ x = 0;
+ for (auto const &item : SysLibraries.GetLibraries()) {
+ dbgs() << "Dyld: - SysLibraries[" << x++ << "]:" << &item << ": "
+ << item->Path << ", " << item->LibName << "\n";
+ }
+ });
+#undef DEBUG_TYPE
+}
+
+std::string
+DynamicLoader::searchLibrariesForSymbol(StringRef mangledName,
+ bool searchSystem /* = true*/) {
+#define DEBUG_TYPE "Dyld:searchLibrariesForSymbol:"
+ assert(!sys::DynamicLibrary::SearchForAddressOfSymbol(mangledName.str()) &&
+ "Library already loaded, please use dlsym!");
+ assert(!mangledName.empty());
+
+ using namespace sys::path;
+ using namespace sys::fs;
+
+ if (FirstRun) {
+ LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str()
+ << ", searchSystem=" << (searchSystem ? "true" : "false")
+ << ", FirstRun(user)... scanning\n");
+
+ LLVM_DEBUG(
+ dbgs()
+ << "Dyld::searchLibrariesForSymbol: Before first ScanForLibraries\n");
+ dumpDebugInfo();
+
+ ScanForLibraries(/* SearchSystemLibraries= */ false);
+ FirstRun = false;
+
+ LLVM_DEBUG(
+ dbgs()
+ << "Dyld::searchLibrariesForSymbol: After first ScanForLibraries\n");
+ dumpDebugInfo();
+ }
+
+ if (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.
+
+ LLVM_DEBUG({
+ dbgs() << "Dyld::ResolveSymbol: QueriedLibraries:\n";
+ size_t x = 0;
+ for (auto item : QueriedLibraries.GetLibraries()) {
+ dbgs() << "Dyld::ResolveSymbol - [" << x++ << "]:" << &item << ": "
+ << item->GetFullName() << "\n";
+ }
+ });
+
+ for (const LibraryPath *P : QueriedLibraries.GetLibraries()) {
+ const std::string LibName = P->GetFullName();
+ if (!AutoLoadDylibMgr.isLibraryLoaded(LibName))
+ continue;
+
+ Libraries.UnregisterLib(*P);
+ SysLibraries.UnregisterLib(*P);
+ }
+ // TODO: QueriedLibraries.clear ?
+ }
+
+ // Iterate over files under this path. We want to get each ".so" files
+ for (const LibraryPath *P : Libraries.GetLibraries()) {
+ if (ContainsSymbol(P, mangledName, /*ignore*/
+ object::SymbolRef::SF_Undefined)) {
+ if (!QueriedLibraries.HasRegisteredLib(*P))
+ QueriedLibraries.RegisterLib(*P);
+
+ LLVM_DEBUG(
+ dbgs() << "Dyld::ResolveSymbol: Search found match in [user lib]: "
+ << P->GetFullName() << "!\n");
+
+ return P->GetFullName();
+ }
+ }
+
+ if (!searchSystem)
+ return "";
+
+ LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: SearchSystem!!!\n");
+
+ // Lookup in non-system libraries failed. Expand the search to the system.
+ if (FirstRunSysLib) {
+ LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str()
+ << ", searchSystem=" << (searchSystem ? "true" : "false")
+ << ", FirstRun(system)... scanning\n");
+
+ LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: Before first system "
+ "ScanForLibraries\n");
+ dumpDebugInfo();
+
+ ScanForLibraries(/* SearchSystemLibraries= */ true);
+ FirstRunSysLib = false;
+
+ LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: After first system "
+ "ScanForLibraries\n");
+ dumpDebugInfo();
+ }
+
+ for (const LibraryPath *P : SysLibraries.GetLibraries()) {
+ if (ContainsSymbol(P, mangledName, /*ignore*/
+ object::SymbolRef::SF_Undefined |
+ object::SymbolRef::SF_Weak)) {
+ if (!QueriedLibraries.HasRegisteredLib(*P))
+ QueriedLibraries.RegisterLib(*P);
+
+ LLVM_DEBUG(
+ dbgs() << "Dyld::ResolveSymbol: Search found match in [system lib]: "
+ << P->GetFullName() << "!\n");
+
+ return P->GetFullName();
+ }
+ }
+
+ LLVM_DEBUG(dbgs() << "Dyld::ResolveSymbol: Search found no match!\n");
+
+ return ""; // Search found no match.
+#undef DEBUG_TYPE
+}
+
+void DynamicLoader::BuildGlobalBloomFilter(BloomFilter &Filter) const {
+ assert(!Filter.IsInitialized());
+ uint32_t GloabalBloomSize = 0;
+
+ for (auto *L : Libraries.GetLibraries()) {
+ GloabalBloomSize += L->Filter.getSymCount();
+ }
+
+ for (auto *L : SysLibraries.GetLibraries()) {
+ GloabalBloomSize += L->Filter.getSymCount();
+ }
+
+ Filter.Initialize(GloabalBloomSize);
+ for (auto *L : Libraries.GetLibraries()) {
+ for (auto &S : L->Symbols) {
+ Filter.AddSymbol(S.getKey());
+ }
+ }
+
+ for (auto *L : SysLibraries.GetLibraries()) {
+ for (auto &S : L->Symbols) {
+ Filter.AddSymbol(S.getKey());
+ }
+ }
+}
+
+AutoLoadDynamicLibraryLookup::~AutoLoadDynamicLibraryLookup() {
+ static_assert(sizeof(Dyld) > 0, "Incomplete type");
+ delete Dyld;
+}
+
+void AutoLoadDynamicLibraryLookup::initializeDynamicLoader(
+ std::function<bool(StringRef)> shouldPermanentlyIgnore) {
+ assert(!Dyld && "Already initialized!");
+ if (Dyld)
+ return;
+ std::string exeP = GetExecutablePath();
+ auto ObjF = cantFail(object::ObjectFile::createObjectFile(exeP));
+
+ Dyld = new DynamicLoader(*this, shouldPermanentlyIgnore,
+ ObjF.getBinary()->getFileFormatName());
+}
+
+void AutoLoadDynamicLibraryLookup::BuildGlobalBloomFilter(
+ BloomFilter &Filter) const {
+ Dyld->BuildGlobalBloomFilter(Filter);
+}
+
+std::string AutoLoadDynamicLibraryLookup::searchLibrariesForSymbol(
+ StringRef mangledName, bool searchSystem /* = true*/) const {
+ assert(Dyld && "Must call initialize dyld before!");
+ return Dyld->searchLibrariesForSymbol(mangledName, searchSystem);
+}
+
+std::string AutoLoadDynamicLibraryLookup::getSymbolLocation(void *func) {
+#if defined(__CYGWIN__) && defined(__GNUC__)
+ return {};
+#elif defined(_WIN32)
+ MEMORY_BASIC_INFORMATION mbi;
+ if (!VirtualQuery(func, &mbi, sizeof(mbi)))
+ return {};
+
+ HMODULE hMod = (HMODULE)mbi.AllocationBase;
+ char moduleName[MAX_PATH];
+
+ if (!GetModuleFileNameA(hMod, moduleName, sizeof(moduleName)))
+ return {};
+
+ return cached_realpath(moduleName);
+
+#else
+ // assume we have defined HAVE_DLFCN_H and HAVE_DLADDR
+ Dl_info info;
+ if (dladdr((void *)func, &info) == 0) {
+ // Not in a known shared library, let's give up
+ return {};
+ } else {
+ std::string result = cached_realpath(info.dli_fname);
+ if (!result.empty())
+ return result;
+
+ // Else absolute path. For all we know that's a binary.
+ // Some people have dictionaries in binaries, this is how we find their
+ // path: (see also https://stackoverflow.com/a/1024937/6182509)
+#if defined(__APPLE__)
+ char buf[PATH_MAX] = {0};
+ uint32_t bufsize = sizeof(buf);
+ if (_NSGetExecutablePath(buf, &bufsize) >= 0)
+ return cached_realpath(buf);
+ return cached_realpath(info.dli_fname);
+#elif defined(LLVM_ON_UNIX)
+ char buf[PATH_MAX] = {0};
+ // Cross our fingers that /proc/self/exe exists.
+ if (readlink("/proc/self/exe", buf, sizeof(buf)) > 0)
+ return cached_realpath(buf);
+ std::string pipeCmd = std::string("which \"") + info.dli_fname + "\"";
+ FILE *pipe = popen(pipeCmd.c_str(), "r");
+ if (!pipe)
+ return cached_realpath(info.dli_fname);
+ while (fgets(buf, sizeof(buf), pipe))
+ result += buf;
+
+ pclose(pipe);
+ return cached_realpath(result);
+#else
+#error "Unsupported platform."
+#endif
+ return {};
+ }
+#endif
+}
+
+} // namespace orc
+} // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
new file mode 100644
index 00000000000000..b474870cd28cca
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
@@ -0,0 +1,575 @@
+//===---------------- AutoLoadDylibLookup.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookup.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+#if defined(_WIN32)
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Support/Endian.h"
+#endif
+
+#include <fstream>
+#include <sys/stat.h>
+#include <system_error>
+
+static bool GetSystemLibraryPaths(llvm::SmallVectorImpl<std::string> &Paths) {
+#if defined(__APPLE__) || defined(__CYGWIN__)
+ Paths.push_back("/usr/local/lib/");
+ Paths.push_back("/usr/X11R6/lib/");
+ Paths.push_back("/usr/lib/");
+ Paths.push_back("/lib/");
+
+#ifndef __APPLE__
+ Paths.push_back("/lib/x86_64-linux-gnu/");
+ Paths.push_back("/usr/local/lib64/");
+ Paths.push_back("/usr/lib64/");
+ Paths.push_back("/lib64/");
+#endif
+#elif defined(LLVM_ON_UNIX)
+ llvm::SmallString<1024> Buf;
+ Popen("LD_DEBUG=libs LD_PRELOAD=DOESNOTEXIST ls", Buf, true);
+ const llvm::StringRef Result = Buf.str();
+
+ const std::size_t NPos = std::string::npos;
+ const std::size_t LD = Result.find("(LD_LIBRARY_PATH)");
+ std::size_t From = Result.find("search path=", LD == NPos ? 0 : LD);
+ if (From != NPos) {
+ std::size_t To = Result.find("(system search path)", From);
+ if (To != NPos) {
+ From += 12;
+ while (To > From && isspace(Result[To - 1]))
+ --To;
+ std::string SysPath = Result.substr(From, To - From).str();
+ SysPath.erase(std::remove_if(SysPath.begin(), SysPath.end(), ::isspace),
+ SysPath.end());
+
+ llvm::SmallVector<llvm::StringRef, 10> CurPaths;
+ SplitPaths(SysPath, CurPaths);
+ for (const auto &Path : CurPaths)
+ Paths.push_back(Path.str());
+ }
+ }
+#endif
+ return true;
+}
+
+static std::string NormalizePath(const std::string &Path) {
+
+ llvm::SmallString<256> Buffer;
+ std::error_code EC = llvm::sys::fs::real_path(Path, Buffer, true);
+ if (EC)
+ return std::string();
+ return std::string(Buffer.str());
+}
+
+namespace llvm {
+namespace orc {
+
+void LogNonExistantDirectory(StringRef Path) {
+#define DEBUG_TYPE "LogNonExistantDirectory"
+ LLVM_DEBUG(dbgs() << " ignoring nonexistent directory \"" << Path << "\"\n");
+#undef DEBUG_TYPE
+}
+
+bool SplitPaths(StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
+ SplitMode Mode, StringRef Delim, bool Verbose) {
+#define DEBUG_TYPE "SplitPths"
+
+ assert(Delim.size() && "Splitting without a delimiter");
+
+#if defined(_WIN32)
+ // Support using a ':' delimiter on Windows.
+ const bool WindowsColon = Delim.equals(":");
+#endif
+
+ bool AllExisted = true;
+ for (std::pair<StringRef, StringRef> Split = PathStr.split(Delim);
+ !Split.second.empty(); Split = PathStr.split(Delim)) {
+
+ if (!Split.first.empty()) {
+ bool Exists = sys::fs::is_directory(Split.first);
+
+#if defined(_WIN32)
+ // Because drive letters will have a colon we have to make sure the split
+ // occurs at a colon not followed by a path separator.
+ if (!Exists && WindowsColon && Split.first.size() == 1) {
+ // Both clang and cl.exe support '\' and '/' path separators.
+ if (Split.second.front() == '\\' || Split.second.front() == '/') {
+ const std::pair<StringRef, StringRef> Tmp = Split.second.split(Delim);
+ // Split.first = 'C', but we want 'C:', so Tmp.first.size()+2
+ Split.first = StringRef(Split.first.data(), Tmp.first.size() + 2);
+ Split.second = Tmp.second;
+ Exists = sys::fs::is_directory(Split.first);
+ }
+ }
+#endif
+
+ AllExisted = AllExisted && Exists;
+
+ if (!Exists) {
+ if (Mode == SplitMode::FailNonExistant) {
+ if (Verbose) {
+ // Exiting early, but still log all non-existant paths that we have
+ LogNonExistantDirectory(Split.first);
+ while (!Split.second.empty()) {
+ Split = PathStr.split(Delim);
+ if (sys::fs::is_directory(Split.first)) {
+ LLVM_DEBUG(dbgs() << " ignoring directory that exists \""
+ << Split.first << "\"\n");
+ } else
+ LogNonExistantDirectory(Split.first);
+ Split = Split.second.split(Delim);
+ }
+ if (!sys::fs::is_directory(Split.first))
+ LogNonExistantDirectory(Split.first);
+ }
+ return false;
+ } else if (Mode == SplitMode::AllowNonExistant)
+ Paths.push_back(Split.first);
+ else if (Verbose)
+ LogNonExistantDirectory(Split.first);
+ } else
+ Paths.push_back(Split.first);
+ }
+
+ PathStr = Split.second;
+ }
+
+ // Trim trailing sep in case of A:B:C:D:
+ if (!PathStr.empty() && PathStr.ends_with(Delim))
+ PathStr = PathStr.substr(0, PathStr.size() - Delim.size());
+
+ if (!PathStr.empty()) {
+ if (!sys::fs::is_directory(PathStr)) {
+ AllExisted = false;
+ if (Mode == SplitMode::AllowNonExistant)
+ Paths.push_back(PathStr);
+ else if (Verbose)
+ LogNonExistantDirectory(PathStr);
+ } else
+ Paths.push_back(PathStr);
+ }
+
+ return AllExisted;
+
+#undef DEBUG_TYPE
+}
+
+AutoLoadDynamicLibraryLookup ::AutoLoadDynamicLibraryLookup() {
+ const SmallVector<const char *, 10> kSysLibraryEnv = {
+ "LD_LIBRARY_PATH",
+#if __APPLE__
+ "DYLD_LIBRARY_PATH",
+ "DYLD_FALLBACK_LIBRARY_PATH",
+ /*
+ "DYLD_VERSIONED_LIBRARY_PATH",
+ "DYLD_FRAMEWORK_PATH",
+ "DYLD_FALLBACK_FRAMEWORK_PATH",
+ "DYLD_VERSIONED_FRAMEWORK_PATH",
+ */
+#elif defined(_WIN32)
+ "PATH",
+#endif
+ };
+
+ // 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) {
+ if (const char *Env = ::getenv(Var)) {
+ SmallVector<StringRef, 10> CurPaths;
+ SplitPaths(Env, CurPaths, SplitMode::PruneNonExistant, kEnvDelim);
+ for (const auto &Path : CurPaths)
+ addSearchPath(Path);
+ }
+ }
+
+ // $CWD is the last user path searched.
+ addSearchPath(".");
+
+ SmallVector<std::string, 64> SysPaths;
+ GetSystemLibraryPaths(SysPaths);
+
+ for (const std::string &P : SysPaths)
+ addSearchPath(P, /*IsUser*/ false);
+}
+///\returns substitution of pattern in the front of original with replacement
+/// Example: substFront("@rpath/abc", "@rpath/", "/tmp") -> "/tmp/abc"
+static std::string substFront(StringRef original, StringRef pattern,
+ StringRef replacement) {
+ if (!original.starts_with_insensitive(pattern))
+ return original.str();
+ SmallString<512> result(replacement);
+ result.append(original.drop_front(pattern.size()));
+ return result.str().str();
+}
+
+///\returns substitution of all known linker variables in \c original
+static std::string substAll(StringRef original, StringRef libLoader) {
+
+ // Handle substitutions (MacOS):
+ // @rpath - This function does not substitute @rpath, becouse
+ // this variable is already handled by lookupLibrary where
+ // @rpath is replaced with all paths from RPATH one by one.
+ // @executable_path - Main program path.
+ // @loader_path - Loader library (or main program) path.
+ //
+ // Handle substitutions (Linux):
+ // https://man7.org/linux/man-pages/man8/ld.so.8.html
+ // $origin - Loader library (or main program) path.
+ // $lib - lib lib64
+ // $platform - x86_64 AT_PLATFORM
+
+ std::string result;
+#ifdef __APPLE__
+ SmallString<512> mainExecutablePath(
+ llvm::sys::fs::getMainExecutable(nullptr, nullptr));
+ llvm::sys::path::remove_filename(mainExecutablePath);
+ SmallString<512> loaderPath;
+ if (libLoader.empty()) {
+ loaderPath = mainExecutablePath;
+ } else {
+ loaderPath = libLoader.str();
+ llvm::sys::path::remove_filename(loaderPath);
+ }
+
+ result = substFront(original, "@executable_path", mainExecutablePath);
+ result = substFront(result, "@loader_path", loaderPath);
+ return result;
+#else
+ SmallString<512> loaderPath;
+ if (libLoader.empty()) {
+ loaderPath = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+ } else {
+ loaderPath = libLoader.str();
+ }
+ llvm::sys::path::remove_filename(loaderPath);
+
+ result = substFront(original, "$origin", loaderPath);
+ // result = substFront(result, "$lib", true?"lib":"lib64");
+ // result = substFront(result, "$platform", "x86_64");
+ return result;
+#endif
+}
+
+std::string AutoLoadDynamicLibraryLookup::lookupLibInPaths(
+ StringRef libStem, SmallVector<llvm::StringRef, 2> RPath /*={}*/,
+ SmallVector<llvm::StringRef, 2> RunPath /*={}*/,
+ StringRef libLoader /*=""*/) const {
+#define DEBUG_TYPE "Dyld::lookupLibInPaths"
+
+ LLVM_DEBUG(dbgs() << "Dyld::lookupLibInPaths" << libStem.str()
+ << ", ..., libLoader=" << libLoader << "\n");
+
+ // Lookup priority is: RPATH, LD_LIBRARY_PATH/SearchPaths, RUNPATH
+ // See: https://en.wikipedia.org/wiki/Rpath
+ // See: https://amir.rachum.com/blog/2016/09/17/shared-libraries/
+
+ LLVM_DEBUG({
+ dbgs() << "Dyld::lookupLibInPaths: \n";
+ dbgs() << ":: RPATH\n";
+ for (auto Info : RPath) {
+ dbgs() << ":::: " << Info.str() << "\n";
+ }
+ dbgs() << ":: SearchPaths (LD_LIBRARY_PATH, etc...)\n";
+ for (auto Info : getSearchPaths()) {
+ dbgs() << ":::: " << Info.Path
+ << ", user=" << (Info.IsUser ? "true" : "false") << "\n";
+ }
+ dbgs() << ":: RUNPATH\n";
+ for (auto Info : RunPath) {
+ dbgs() << ":::: " << Info.str() << "\n";
+ }
+ });
+
+ SmallString<512> ThisPath;
+ // RPATH
+ for (auto Info : RPath) {
+ ThisPath = substAll(Info, libLoader);
+ llvm::sys::path::append(ThisPath, libStem);
+ // to absolute path?
+ LLVM_DEBUG(dbgs() << "## Try: " << ThisPath);
+ if (isSharedLibrary(ThisPath.str())) {
+ LLVM_DEBUG(dbgs() << " ... Found (in RPATH)!\n");
+ return ThisPath.str().str();
+ }
+ }
+ // SearchPaths
+ for (const SearchPathInfo &Info : SearchPaths) {
+ ThisPath = Info.Path;
+ llvm::sys::path::append(ThisPath, libStem);
+ // to absolute path?
+ LLVM_DEBUG(dbgs() << "## Try: " << ThisPath);
+ if (isSharedLibrary(ThisPath.str())) {
+ LLVM_DEBUG(dbgs() << " ... Found (in SearchPaths)!\n");
+ return ThisPath.str().str();
+ }
+ }
+ // RUNPATH
+ for (auto Info : RunPath) {
+ ThisPath = substAll(Info, libLoader);
+ llvm::sys::path::append(ThisPath, libStem);
+ // to absolute path?
+ LLVM_DEBUG(dbgs() << "## Try: " << ThisPath);
+ if (isSharedLibrary(ThisPath.str())) {
+ LLVM_DEBUG(dbgs() << " ... Found (in RUNPATH)!\n");
+ return ThisPath.str().str();
+ }
+ }
+
+ LLVM_DEBUG(dbgs() << "## NotFound!!!\n");
+
+ return "";
+
+#undef DEBUG_TYPE
+}
+
+std::string AutoLoadDynamicLibraryLookup::lookupLibMaybeAddExt(
+ StringRef libStem, SmallVector<llvm::StringRef, 2> RPath /*={}*/,
+ SmallVector<llvm::StringRef, 2> RunPath /*={}*/,
+ StringRef libLoader /*=""*/) const {
+#define DEBUG_TYPE "Dyld::lookupLibMaybeAddExt:"
+
+ using namespace llvm::sys;
+
+ LLVM_DEBUG(dbgs() << "Dyld::lookupLibMaybeAddExt: " << libStem.str()
+ << ", ..., libLoader=" << libLoader << "\n");
+
+ std::string foundDyLib = lookupLibInPaths(libStem, RPath, RunPath, libLoader);
+
+ if (foundDyLib.empty()) {
+ // Add DyLib extension:
+ SmallString<512> filenameWithExt(libStem);
+#if defined(LLVM_ON_UNIX)
+#ifdef __APPLE__
+ SmallString<512>::iterator IStemEnd = filenameWithExt.end() - 1;
+#endif
+ static const char *DyLibExt = ".so";
+#elif defined(_WIN32)
+ static const char *DyLibExt = ".dll";
+#else
+#error "Unsupported platform."
+#endif
+ filenameWithExt += DyLibExt;
+ foundDyLib = lookupLibInPaths(filenameWithExt, RPath, RunPath, libLoader);
+#ifdef __APPLE__
+ if (foundDyLib.empty()) {
+ filenameWithExt.erase(IStemEnd + 1, filenameWithExt.end());
+ filenameWithExt += ".dylib";
+ foundDyLib = lookupLibInPaths(filenameWithExt, RPath, RunPath, libLoader);
+ }
+#endif
+ }
+
+ if (foundDyLib.empty())
+ return std::string();
+
+ // get canonical path name and check if already loaded
+ const std::string Path = NormalizePath(foundDyLib);
+ if (Path.empty()) {
+ LLVM_DEBUG(
+ dbgs() << "AutoLoadDynamicLibraryLookup::lookupLibMaybeAddExt(): "
+ << "error getting real (canonical) path of library "
+ << foundDyLib << '\n');
+ return foundDyLib;
+ }
+ return Path;
+
+#undef DEBUG_TYPE
+}
+
+std::string AutoLoadDynamicLibraryLookup::normalizePath(StringRef path) {
+#define DEBUG_TYPE "Dyld::normalizePath:"
+ // Make the path canonical if the file exists.
+ const std::string Path = path.str();
+ struct stat buffer;
+ if (::stat(Path.c_str(), &buffer) != 0)
+ return std::string();
+
+ const std::string NPath = NormalizePath(Path);
+ if (NPath.empty())
+ LLVM_DEBUG(dbgs() << "Could not normalize: '" << Path << "'");
+ return NPath;
+#undef DEBUG_TYPE
+}
+
+std::string RPathToStr2(SmallVector<StringRef, 2> V) {
+ std::string result;
+ for (auto item : V)
+ result += item.str() + ",";
+ if (!result.empty())
+ result.pop_back();
+ return result;
+}
+
+std::string AutoLoadDynamicLibraryLookup::lookupLibrary(
+ StringRef libStem, SmallVector<llvm::StringRef, 2> RPath /*={}*/,
+ SmallVector<llvm::StringRef, 2> RunPath /*={}*/,
+ StringRef libLoader /*=""*/, bool variateLibStem /*=true*/) const {
+#define DEBUG_TYPE "Dyld::lookupLibrary:"
+ LLVM_DEBUG(dbgs() << "Dyld::lookupLibrary: " << libStem.str() << ", "
+ << RPathToStr2(RPath) << ", " << RPathToStr2(RunPath)
+ << ", " << libLoader.str() << "\n");
+ if (libStem.empty())
+ return std::string();
+
+ // If it is an absolute path, don't try iterate over the paths.
+ if (llvm::sys::path::is_absolute(libStem)) {
+ if (isSharedLibrary(libStem))
+ return normalizePath(libStem);
+
+ LLVM_DEBUG(dbgs() << "Dyld::lookupLibrary: '" << libStem.str() << "'"
+ << "is not a shared library\n");
+ return std::string();
+ }
+
+ // Subst all known linker variables ($origin, @rpath, etc.)
+#ifdef __APPLE__
+ // On MacOS @rpath is preplaced by all paths in RPATH one by one.
+ if (libStem.starts_with_insensitive("@rpath")) {
+ for (auto &P : RPath) {
+ std::string result = substFront(libStem, "@rpath", P);
+ if (isSharedLibrary(result))
+ return normalizePath(result);
+ }
+ } else {
+#endif
+ std::string result = substAll(libStem, libLoader);
+ if (isSharedLibrary(result))
+ return normalizePath(result);
+#ifdef __APPLE__
+ }
+#endif
+
+ // Expand libStem with paths, extensions, etc.
+ std::string foundName;
+ if (variateLibStem) {
+ foundName = lookupLibMaybeAddExt(libStem, RPath, RunPath, libLoader);
+ if (foundName.empty()) {
+ StringRef libStemName = llvm::sys::path::filename(libStem);
+ if (!libStemName.starts_with("lib")) {
+ // try with "lib" prefix:
+ foundName = lookupLibMaybeAddExt(
+ libStem.str().insert(libStem.size() - libStemName.size(), "lib"),
+ RPath, RunPath, libLoader);
+ }
+ }
+ } else {
+ foundName = lookupLibInPaths(libStem, RPath, RunPath, libLoader);
+ }
+
+ if (!foundName.empty())
+ return NormalizePath(foundName);
+
+ return std::string();
+#undef DEBUG_TYPE
+}
+
+void AutoLoadDynamicLibraryLookup::addLoadedLib(StringRef lib) {
+ LoadedLibraries.insert(lib);
+}
+
+bool AutoLoadDynamicLibraryLookup::isLibraryLoaded(StringRef fullPath) const {
+ std::string canonPath = normalizePath(fullPath);
+ if (LoadedLibraries.find(canonPath) != LoadedLibraries.end())
+ return true;
+ return false;
+}
+
+void AutoLoadDynamicLibraryLookup::dump(
+ llvm::raw_ostream *S /*= nullptr*/) const {
+ llvm::raw_ostream &OS = S ? *S : llvm::outs();
+
+ // FIXME: print in a stable order the contents of SearchPaths
+ for (const auto &Info : getSearchPaths()) {
+ if (!Info.IsUser)
+ OS << "[system] ";
+ OS << Info.Path.c_str() << "\n";
+ }
+}
+
+#if defined(_WIN32)
+static bool IsDLL(llvm::StringRef headers) {
+ using namespace llvm::support::endian;
+
+ uint32_t headeroffset = read32le(headers.data() + 0x3c);
+ auto peheader = headers.substr(headeroffset, 24);
+ if (peheader.size() != 24) {
+ return false;
+ }
+ // Read Characteristics from the coff header
+ uint32_t characteristics = read16le(peheader.data() + 22);
+ return (characteristics & llvm::COFF::IMAGE_FILE_DLL) != 0;
+}
+#endif
+
+bool AutoLoadDynamicLibraryLookup::isSharedLibrary(StringRef libFullPath,
+ bool *exists /*=0*/) {
+ using namespace llvm;
+
+ auto filetype = sys::fs::get_file_type(libFullPath, /*Follow*/ true);
+ if (filetype != sys::fs::file_type::regular_file) {
+ if (exists) {
+ // get_file_type returns status_error also in case of file_not_found.
+ *exists = filetype != sys::fs::file_type::status_error;
+ }
+ return false;
+ }
+
+ // Do not use the identify_magic overload taking a path: It will open the
+ // file and then mmap its contents, possibly causing bus errors when another
+ // process truncates the file while we are trying to read it. Instead just
+ // read the first 1024 bytes, which should be enough for identify_magic to
+ // do its work.
+ // TODO: Fix the code upstream and consider going back to calling the
+ // convenience function after a future LLVM upgrade.
+ std::string path = libFullPath.str();
+ std::ifstream in(path, std::ios::binary);
+ char header[1024] = {0};
+ in.read(header, sizeof(header));
+ if (in.fail()) {
+ if (exists)
+ *exists = false;
+ return false;
+ }
+
+ StringRef headerStr(header, in.gcount());
+ file_magic Magic = identify_magic(headerStr);
+
+ bool result =
+#ifdef __APPLE__
+ (Magic == file_magic::macho_fixed_virtual_memory_shared_lib ||
+ Magic == file_magic::macho_dynamically_linked_shared_lib ||
+ Magic == file_magic::macho_dynamically_linked_shared_lib_stub ||
+ Magic == file_magic::macho_universal_binary)
+#elif defined(LLVM_ON_UNIX)
+#ifdef __CYGWIN__
+ (Magic == file_magic::pecoff_executable)
+#else
+ (Magic == file_magic::elf_shared_object)
+#endif
+#elif defined(_WIN32)
+ // We should only include dll libraries without including executables,
+ // object code and others...
+ (Magic == file_magic::pecoff_executable && IsDLL(headerStr))
+#else
+#error "Unsupported platform."
+#endif
+ ;
+
+ return result;
+}
+
+} // end namespace orc
+} // end namespace llvm
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
index 3d1dfe758c79dd..00f142c23356d6 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -10,6 +10,8 @@ if( LLVM_USE_INTEL_JITEVENTS )
endif()
add_llvm_component_library(LLVMOrcTargetProcess
+ AutoLoadDylibLookup.cpp
+ AutoLoadDyLoader.cpp
ExecutorSharedMemoryMapperService.cpp
JITLoaderGDB.cpp
JITLoaderPerf.cpp
@@ -30,6 +32,7 @@ add_llvm_component_library(LLVMOrcTargetProcess
LINK_COMPONENTS
${intel_jit_profiling}
+ Object
OrcShared
Support
TargetParser
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
index b7e256a826ca43..20f1f45df50d28 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
@@ -11,6 +11,10 @@
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
#include "llvm/Support/FormatVariadic.h"
+#include <dlfcn.h>
+#include <string>
+#include <unordered_map>
+
#define DEBUG_TYPE "orc"
namespace llvm {
@@ -65,6 +69,7 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H,
#endif
void *Addr = DL.getAddressOfSymbol(DemangledSymName);
+
if (!Addr && E.Required)
return make_error<StringError>(Twine("Missing definition for ") +
DemangledSymName,
@@ -78,6 +83,74 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H,
return Result;
}
+Expected<ResolveResult>
+SimpleExecutorDylibManager::resolve(const RemoteSymbolLookupSet &L) {
+ if (!DylibLookup.has_value()) {
+ DylibLookup.emplace();
+ DylibLookup->initializeDynamicLoader([](llvm::StringRef) { /*ignore*/
+ return false;
+ });
+ }
+
+ BloomFilter Filter;
+ std::vector<ExecutorSymbolDef> Result;
+ for (auto &E : L) {
+
+ if (E.Name.empty()) {
+ if (E.Required)
+ return make_error<StringError>("Required address for empty symbol \"\"",
+ inconvertibleErrorCode());
+ else
+ Result.push_back(ExecutorSymbolDef());
+ } else {
+ const char *DemangledSymName = E.Name.c_str();
+#ifdef __APPLE__
+ if (E.Name.front() != '_')
+ return make_error<StringError>(Twine("MachO symbol \"") + E.Name +
+ "\" missing leading '_'",
+ inconvertibleErrorCode());
+ ++DemangledSymName;
+#endif
+
+ void *Addr =
+ sys::DynamicLibrary::SearchForAddressOfSymbol(DemangledSymName);
+
+ if (Addr) {
+ Result.push_back(
+ {ExecutorAddr::fromPtr(Addr), JITSymbolFlags::Exported});
+ continue;
+ }
+
+ auto lib = DylibLookup->searchLibrariesForSymbol(E.Name);
+ auto canonicalLoadedLib = DylibLookup->lookupLibrary(lib);
+ if (canonicalLoadedLib.empty()) {
+ if (!Filter.IsInitialized())
+ DylibLookup->BuildGlobalBloomFilter(Filter);
+ Result.push_back(ExecutorSymbolDef());
+ } else {
+ auto H = open(canonicalLoadedLib, 0);
+ if (!H)
+ return H.takeError();
+
+ DylibLookup->addLoadedLib(canonicalLoadedLib);
+ void *Addr = dlsym(H.get().toPtr<void *>(), DemangledSymName);
+ if (!Addr)
+ return make_error<StringError>(Twine("Missing definition for ") +
+ DemangledSymName,
+ inconvertibleErrorCode());
+ Result.push_back(
+ {ExecutorAddr::fromPtr(Addr), JITSymbolFlags::Exported});
+ }
+ }
+ }
+
+ ResolveResult Res;
+ if (Filter.IsInitialized())
+ Res.Filter.emplace(std::move(Filter));
+ Res.SymbolDef = std::move(Result);
+ return Res;
+}
+
Error SimpleExecutorDylibManager::shutdown() {
DylibSet DS;
@@ -97,6 +170,8 @@ void SimpleExecutorDylibManager::addBootstrapSymbols(
ExecutorAddr::fromPtr(&openWrapper);
M[rt::SimpleExecutorDylibManagerLookupWrapperName] =
ExecutorAddr::fromPtr(&lookupWrapper);
+ M[rt::SimpleExecutorDylibManagerResolveWrapperName] =
+ ExecutorAddr::fromPtr(&resolveWrapper);
}
llvm::orc::shared::CWrapperFunctionResult
@@ -119,6 +194,17 @@ SimpleExecutorDylibManager::lookupWrapper(const char *ArgData, size_t ArgSize) {
.release();
}
+llvm::orc::shared::CWrapperFunctionResult
+SimpleExecutorDylibManager::resolveWrapper(const char *ArgData,
+ size_t ArgSize) {
+ return shared::WrapperFunction<
+ rt::SPSSimpleExecutorDylibManagerResolveSignature>::
+ handle(ArgData, ArgSize,
+ shared::makeMethodWrapperHandler(
+ &SimpleExecutorDylibManager::resolve))
+ .release();
+}
+
} // namespace rt_bootstrap
} // end namespace orc
} // end namespace llvm
>From 74e6356acadc3de50c6d7e18b6023c3eee9e3a23 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 20 Sep 2024 14:20:01 +0530
Subject: [PATCH 2/4] Minor Fix
---
.../llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h | 8 ++++----
.../Orc/TargetProcess/SimpleExecutorDylibManager.cpp | 1 -
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
index 6bb1b40b1db933..0147aa538fbf7a 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCGenericDylibManager.h
@@ -82,13 +82,13 @@ class EPCGenericDylibManager {
void lookupAsync(tpctypes::DylibHandle H, const RemoteSymbolLookupSet &Lookup,
SymbolLookupCompleteFn Complete);
- /// Looks up symbols within the given dylib.
+ /// Look up and resolve symbols across all available dynamic libraries.
void resolveAsync(const SymbolLookupSet &Lookup,
- ResolveSymbolsCompleteFn Complete);
+ ResolveSymbolsCompleteFn Complete);
- /// Looks up symbols within the given dylib.
+ /// Look up and resolve symbols across all available dynamic libraries.
void resolveAsync(const RemoteSymbolLookupSet &Lookup,
- ResolveSymbolsCompleteFn Complete);
+ ResolveSymbolsCompleteFn Complete);
private:
ExecutorProcessControl &EPC;
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
index 20f1f45df50d28..92a5a2abd59899 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
@@ -69,7 +69,6 @@ SimpleExecutorDylibManager::lookup(tpctypes::DylibHandle H,
#endif
void *Addr = DL.getAddressOfSymbol(DemangledSymName);
-
if (!Addr && E.Required)
return make_error<StringError>(Twine("Missing definition for ") +
DemangledSymName,
>From 6dc3c95ee4021c144e044f094eaca7b694719691 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 30 Sep 2024 15:49:49 +0530
Subject: [PATCH 3/4] Refactor code
---
.../llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h | 3 +--
.../Orc/TargetProcess/AutoLoadDyLoader.cpp | 2 +-
.../Orc/TargetProcess/AutoLoadDylibLookUp.cpp | 8 ++++----
.../Orc/TargetProcess/SimpleExecutorDylibManager.cpp | 2 --
4 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
index 73e8b53edf8598..d1ea9e45d09215 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h
@@ -83,8 +83,7 @@ class BloomFilter {
BloomFilter(const BloomFilter &other) noexcept
: Initialized(other.Initialized), SymbolsCount(other.SymbolsCount),
BloomSize(other.BloomSize), BloomShift(other.BloomShift),
- BloomTable(other.BloomTable) {
- }
+ BloomTable(other.BloomTable) {}
BloomFilter &operator=(const BloomFilter &other) = delete;
BloomFilter(BloomFilter &&other) noexcept
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
index 334507b6d371a9..d79a41022b5b55 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDyLoader.cpp
@@ -491,7 +491,7 @@ class DynamicLoader {
: AutoLoadDylibMgr(DLM), ShouldPermanentlyIgnoreCallback(shouldIgnore),
ExecutableFormat(execFormat) {}
- ~DynamicLoader(){};
+ ~DynamicLoader() {};
std::string searchLibrariesForSymbol(StringRef mangledName,
bool searchSystem);
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
index b474870cd28cca..da147002962242 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/AutoLoadDylibLookUp.cpp
@@ -169,10 +169,10 @@ bool SplitPaths(StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
AutoLoadDynamicLibraryLookup ::AutoLoadDynamicLibraryLookup() {
const SmallVector<const char *, 10> kSysLibraryEnv = {
- "LD_LIBRARY_PATH",
+ "LD_LIBRARY_PATH",
#if __APPLE__
- "DYLD_LIBRARY_PATH",
- "DYLD_FALLBACK_LIBRARY_PATH",
+ "DYLD_LIBRARY_PATH",
+ "DYLD_FALLBACK_LIBRARY_PATH",
/*
"DYLD_VERSIONED_LIBRARY_PATH",
"DYLD_FRAMEWORK_PATH",
@@ -180,7 +180,7 @@ AutoLoadDynamicLibraryLookup ::AutoLoadDynamicLibraryLookup() {
"DYLD_VERSIONED_FRAMEWORK_PATH",
*/
#elif defined(_WIN32)
- "PATH",
+ "PATH",
#endif
};
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
index 92a5a2abd59899..4066146f1f04a4 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/SimpleExecutorDylibManager.cpp
@@ -12,8 +12,6 @@
#include "llvm/Support/FormatVariadic.h"
#include <dlfcn.h>
-#include <string>
-#include <unordered_map>
#define DEBUG_TYPE "orc"
>From f7300ec8d1ca708fa045745dfeb2db5300adfae4 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 14 Nov 2024 14:47:37 +0530
Subject: [PATCH 4/4] Merge with main branch
---
llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h | 7 +++++++
.../ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h | 2 +-
.../llvm/ExecutionEngine/Orc/ExecutorProcessControl.h | 1 -
llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h | 3 +++
.../Orc/EPCDynamicLibrarySearchGenerator.cpp | 4 ++--
llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp | 4 ++--
6 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h b/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h
index bbcc2e639a1865..38699dfcac202d 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/DylibManager.h
@@ -13,6 +13,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_DYLIBMANAGER_H
#define LLVM_EXECUTIONENGINE_ORC_DYLIBMANAGER_H
+#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MSVCErrorWorkarounds.h"
@@ -60,6 +61,9 @@ class DylibManager {
using SymbolLookupCompleteFn =
unique_function<void(Expected<std::vector<tpctypes::LookupResult>>)>;
+ using ResolveSymbolsCompleteFn =
+ unique_function<void(Expected<std::vector<ResolveResult>>)>;
+
/// Search for symbols in the target process.
///
/// The result of the lookup is a 2-dimensional array of target addresses
@@ -68,6 +72,9 @@ class DylibManager {
/// symbol is not found then it be assigned a '0' value.
virtual void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) = 0;
+
+ virtual void resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+ ResolveSymbolsCompleteFn F) = 0;
};
} // end namespace llvm::orc
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
index 901e5d05bbeb18..cfb9353e7b12d1 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h
@@ -104,7 +104,7 @@ class AutoLoadDynamicLibrarySearchGenerator : public DefinitionGenerator {
Error
tryToResolve(SymbolNameSet CandidateSyms,
- ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn);
+ DylibManager::ResolveSymbolsCompleteFn OnCompleteFn);
private:
ExecutorProcessControl &EPC;
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
index b5fd1c7039af3f..6333efa0f00fc2 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h
@@ -16,7 +16,6 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/DylibManager.h"
-#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
index 195cf80a1f0fd2..54d84201ff408f 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h
@@ -122,6 +122,9 @@ class SimpleRemoteEPC : public ExecutorProcessControl,
void lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
SymbolLookupCompleteFn F) override;
+ void resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
+ ResolveSymbolsCompleteFn F) override;
+
using PendingCallWrapperResultsMap =
DenseMap<uint64_t, IncomingWFRHandler>;
diff --git a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
index e58f1d1ad51c94..8e0c7f30c1a413 100644
--- a/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.cpp
@@ -172,7 +172,7 @@ Error AutoLoadDynamicLibrarySearchGenerator::tryToGenerate(
Error AutoLoadDynamicLibrarySearchGenerator::tryToResolve(
SymbolNameSet CandidateSyms,
- ExecutorProcessControl::ResolveSymbolsCompleteFn OnCompleteFn) {
+ DylibManager::ResolveSymbolsCompleteFn OnCompleteFn) {
LLVM_DEBUG({
dbgs() << "AutoLoadDynamicLibrarySearchGenerator trying to resolve "
@@ -185,7 +185,7 @@ Error AutoLoadDynamicLibrarySearchGenerator::tryToResolve(
LookupSymbols.add(S, SymbolLookupFlags::WeaklyReferencedSymbol);
}
- EPC.resolveSymbolsAsync(LookupSymbols, std::move(OnCompleteFn));
+ EPC.getDylibMgr().resolveSymbolsAsync(LookupSymbols, std::move(OnCompleteFn));
return Error::success();
}
diff --git a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
index a6de6ca7fc33f5..f9809115c5fd2b 100644
--- a/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/SimpleRemoteEPC.cpp
@@ -61,7 +61,7 @@ static void
resolveSymbolsAsyncHelper(EPCGenericDylibManager &DylibMgr,
ArrayRef<SymbolLookupSet> Request,
std::vector<ResolveResult> Result,
- SimpleRemoteEPC::ResolveSymbolsCompleteFn Complete) {
+ DylibManager::ResolveSymbolsCompleteFn Complete) {
if (Request.empty())
return Complete(std::move(Result));
@@ -93,7 +93,7 @@ void SimpleRemoteEPC::lookupSymbolsAsync(ArrayRef<LookupRequest> Request,
void SimpleRemoteEPC::resolveSymbolsAsync(ArrayRef<SymbolLookupSet> Request,
ResolveSymbolsCompleteFn Complete) {
- resolveSymbolsAsyncHelper(*DylibMgr, Request, {}, std::move(Complete));
+ resolveSymbolsAsyncHelper(*EPCDylibMgr, Request, {}, std::move(Complete));
}
Expected<int32_t> SimpleRemoteEPC::runAsMain(ExecutorAddr MainFnAddr,
More information about the llvm-commits
mailing list