[llvm] [ORC] Add auto-loading of shared libraries for unresolved symbols. (PR #148410)

via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 13 03:47:36 PDT 2025


https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/148410

>From 90341d6796276e9cc9d1a0c16a7cd13058cb14aa Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Wed, 2 Jul 2025 14:47:27 +0530
Subject: [PATCH 1/6] [ORC] Add auto-loading of shared libraries for unresolved
 symbols

---
 .../ExecutionEngine/Orc/Shared/SymbolFilter.h | 173 ++++
 .../Orc/TargetProcess/DynamicLoader.h         | 490 +++++++++++
 .../Orc/TargetProcess/LibraryScanner.h        | 253 ++++++
 .../Orc/TargetProcess/CMakeLists.txt          |   2 +
 .../Orc/TargetProcess/DynamicLoader.cpp       | 274 ++++++
 .../Orc/TargetProcess/LibraryScanner.cpp      | 789 ++++++++++++++++++
 6 files changed, 1981 insertions(+)
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
 create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
 create mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h
new file mode 100644
index 0000000000000..8848564d1faef
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h
@@ -0,0 +1,173 @@
+//===--- SymbolFilter.h - Utils for Symbol Filter ---*- 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_SYMBOLFILTER_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLFILTER_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>>;
+}
+
+class BloomFilter {
+public:
+  using HashFunc = std::function<uint32_t(StringRef)>;
+
+  BloomFilter() = default;
+  BloomFilter(BloomFilter &&) noexcept = default;
+  BloomFilter &operator=(BloomFilter &&) noexcept = default;
+  BloomFilter(const BloomFilter &) = delete;
+  BloomFilter &operator=(const BloomFilter &) = delete;
+
+  BloomFilter(uint32_t symbolCount, float falsePositiveRate, HashFunc hashFn)
+      : hashFunc(std::move(hashFn)) {
+    initialize(symbolCount, falsePositiveRate);
+  }
+  bool IsInitialized() const { return initialized; }
+
+  void add(StringRef symbol) {
+    assert(initialized);
+    addHash(hashFunc(symbol));
+  }
+
+  bool mayContain(StringRef symbol) const {
+    return !isEmpty() && testHash(hashFunc(symbol));
+  }
+
+  bool isEmpty() const { return symbolCount_ == 0; }
+
+private:
+  friend class shared::SPSSerializationTraits<shared::SPSBloomFilter,
+                                              BloomFilter>;
+  static constexpr uint32_t bitsPerEntry = 64;
+
+  bool initialized = false;
+  uint32_t symbolCount_ = 0;
+  uint32_t bloomSize = 0;
+  uint32_t bloomShift = 0;
+  std::vector<uint64_t> bloomTable;
+  HashFunc hashFunc;
+
+  void initialize(uint32_t symbolCount, float falsePositiveRate) {
+    assert(symbolCount > 0);
+    symbolCount_ = symbolCount;
+    initialized = true;
+
+    float ln2 = std::log(2.0f);
+    float m = -1.0f * symbolCount * std::log(falsePositiveRate) / (ln2 * ln2);
+    bloomSize = static_cast<uint32_t>(std::ceil(m / bitsPerEntry));
+    bloomShift = std::min(6u, log2ceil(symbolCount));
+    bloomTable.resize(bloomSize, 0);
+  }
+
+  void addHash(uint32_t hash) {
+    uint32_t hash2 = hash >> bloomShift;
+    uint32_t n = (hash / bitsPerEntry) % bloomSize;
+    uint64_t mask =
+        (1ULL << (hash % bitsPerEntry)) | (1ULL << (hash2 % bitsPerEntry));
+    bloomTable[n] |= mask;
+  }
+
+  bool testHash(uint32_t hash) const {
+    uint32_t hash2 = hash >> bloomShift;
+    uint32_t n = (hash / bitsPerEntry) % bloomSize;
+    uint64_t mask =
+        (1ULL << (hash % bitsPerEntry)) | (1ULL << (hash2 % bitsPerEntry));
+    return (bloomTable[n] & mask) == mask;
+  }
+
+  static constexpr uint32_t log2ceil(uint32_t v) {
+    return v <= 1 ? 0 : 32 - countl_zero(v - 1);
+  }
+};
+
+class BloomFilterBuilder {
+public:
+  using HashFunc = BloomFilter::HashFunc;
+
+  BloomFilterBuilder() = default;
+
+  BloomFilterBuilder &setFalsePositiveRate(float rate) {
+    assert(rate > 0.0f && rate < 1.0f);
+    falsePositiveRate = rate;
+    return *this;
+  }
+
+  BloomFilterBuilder &setHashFunction(HashFunc func) {
+    hashFunc = std::move(func);
+    return *this;
+  }
+
+  BloomFilter build(const std::vector<std::string> &symbols) const {
+    assert(!symbols.empty() && "Cannot build filter from empty symbol list.");
+    BloomFilter filter(static_cast<uint32_t>(symbols.size()), falsePositiveRate,
+                       hashFunc);
+    for (const auto &sym : symbols) {
+      filter.add(sym);
+    }
+    return filter;
+  }
+
+private:
+  float falsePositiveRate = 0.02f;
+  HashFunc hashFunc = [](StringRef s) -> uint32_t {
+    uint32_t h = 5381;
+    for (char c : s)
+      h = ((h << 5) + h) + static_cast<uint8_t>(c); // h * 33 + c
+    return h;
+  };
+};
+
+namespace shared {
+
+template <> class SPSSerializationTraits<SPSBloomFilter, BloomFilter> {
+public:
+  static size_t size(const BloomFilter &Filter) {
+    return SPSBloomFilter::AsArgList::size(
+        Filter.initialized, Filter.symbolCount_, Filter.bloomSize,
+        Filter.bloomShift, Filter.bloomTable);
+  }
+
+  static bool serialize(SPSOutputBuffer &OB, const BloomFilter &Filter) {
+    return SPSBloomFilter::AsArgList::serialize(
+        OB, Filter.initialized, Filter.symbolCount_, Filter.bloomSize,
+        Filter.bloomShift, Filter.bloomTable);
+  }
+
+  static bool deserialize(SPSInputBuffer &IB, BloomFilter &Filter) {
+    bool IsInitialized;
+    uint32_t symbolCount_ = 0, bloomSize = 0, bloomShift = 0;
+    std::vector<uint64_t> bloomTable;
+
+    if (!SPSBloomFilter::AsArgList::deserialize(
+            IB, IsInitialized, symbolCount_, bloomSize, bloomShift, bloomTable))
+      return false;
+
+    Filter.initialized = IsInitialized;
+    Filter.symbolCount_ = symbolCount_;
+    Filter.bloomSize = bloomSize;
+    Filter.bloomShift = bloomShift;
+    Filter.bloomTable = std::move(bloomTable);
+
+    return true;
+  }
+};
+
+} // end namespace shared
+} // end namespace orc
+} // end namespace llvm
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLFILTER_H
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
new file mode 100644
index 0000000000000..0b98be4cd9bf1
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
@@ -0,0 +1,490 @@
+//===- DynamicLoader.h - Automatic Dynamic Library Symbol Resolution -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides support for automatically searching symbols across
+// dynamic libraries that have not yet been loaded.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_DYNAMICLOADER_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_DYNAMICLOADER_H
+
+#include "llvm/ADT/FunctionExtras.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SymbolFilter.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h"
+#include "llvm/Support/Path.h"
+
+#include <shared_mutex>
+#include <unordered_map>
+
+namespace llvm {
+namespace orc {
+
+// Represents a collection of libraries, each optionally associated with a
+// symbol filter and hash map.
+// class LibraryCollection {
+// public:
+//   class LibraryInfo {
+//   public:
+//     LibraryInfo(const LibraryInfo &) = delete;
+//     LibraryInfo &operator=(const LibraryInfo &) = delete;
+
+//     LibraryInfo(std::string basePath,
+//                 std::optional<BloomFilter> filter = std::nullopt
+//         : basePath(std::move(basePath)), filter(std::move(filter)) {}
+
+//     StringRef getBasePath() const { return basePath; }
+//     StringRef getFileName() const { return fileName; }
+
+//     std::string getFullPath() const {
+//       llvm::SmallString<512> fullPath(basePath);
+//       llvm::sys::path::append(fullPath, llvm::StringRef(fileName));
+//       return std::string(fullPath.str());
+//     }
+
+//     bool setFilter(const BloomFilter &f);
+//     bool buildFilter(const std::vector<std::string> &symbols);
+//     bool ensureFilterBuilt(const std::vector<std::string> &symbols);
+//     bool buildHashMap(const std::vector<std::string> &symbols);
+
+//     bool mayContain(StringRef symbol) const;
+//     bool hasFilter() const { return filter.has_value(); }
+//     bool hasHashMap() const { return hashMap.has_value(); }
+
+//   private:
+//     std::string basePath;
+//     std::string fileName;
+//     std::optional<BloomFilter> filter;
+//     std::mutex mutex;
+//   };
+
+//   using LibraryVisitor = unique_function<bool(const LibraryInfo &)>;
+
+//   // Visit each library. Stops early if visitor returns false.
+//   bool forEachLibrary(LibraryVisitor &&visitor) const;
+
+//   // Visit each library. Removes those for which the visitor returns true.
+//   bool removeIf(LibraryVisitor &&shouldRemove);
+
+//   // Adds a new library with optional filter and hash map.
+//   bool addLibrary(std::string basePath,
+//                   std::optional<BloomFilter> filter = std::nullopt);
+
+//   // Removes a library by base path.
+//   bool removeLibrary(const std::string &basePath);
+
+// private:
+//   struct LibraryInfoHash {
+//     size_t operator()(const LibraryInfo &lib) const {
+//       return std::hash<size_t>()(lib.getBasePath().length()) ^
+//              std::hash<std::string>()(std::string(lib.getFileName()));
+//     }
+//   };
+
+//   std::unordered_set<LibraryInfo, LibraryInfoHash> libraries;
+//   std::vector<const LibraryInfo *> Libs;
+//   mutable std::mutex mutex;
+// };
+
+/// Manages library metadata and state for symbol resolution.
+///
+/// Tracks libraries by load state and kind (user/system), and stores associated
+/// Bloom filters and hash maps to speed up symbol lookups. Thread-safe for
+/// concurrent access.
+class LibraryManager {
+public:
+  enum class State : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
+  enum class Kind : uint8_t { User = 0, System = 1 };
+
+  class LibraryInfo {
+  public:
+    LibraryInfo(const LibraryInfo &) = delete;
+    LibraryInfo &operator=(const LibraryInfo &) = delete;
+
+    LibraryInfo(std::string filePath, State s, Kind k,
+                std::optional<BloomFilter> filter = std::nullopt)
+        : filePath(std::move(filePath)), state(s), kind(k),
+          filter(std::move(filter)) {}
+
+    StringRef getBasePath() const { return sys::path::parent_path(filePath); }
+    StringRef getFileName() const { return sys::path::filename(filePath); }
+
+    std::string getFullPath() const { return filePath; }
+
+    bool setFilter(BloomFilter F) {
+      std::lock_guard lock(mutex);
+      if (filter)
+        return false;
+      filter.emplace(std::move(F));
+      return true;
+    }
+
+    bool ensureFilterBuilt(const BloomFilterBuilder &FB,
+                           const std::vector<std::string> &symbols) {
+      std::lock_guard lock(mutex);
+      if (filter)
+        return false;
+      filter.emplace(FB.build(symbols));
+      return true;
+    }
+
+    bool mayContain(StringRef symbol) const {
+      assert(hasFilter());
+      std::shared_lock lock(mutex);
+      return filter->mayContain(symbol);
+    }
+
+    bool hasFilter() const {
+      std::shared_lock lock(mutex);
+      return filter.has_value();
+    }
+
+    State getState() const { return state.load(); }
+    Kind getKind() const { return kind; }
+
+    void setState(State s) { state.store(s); }
+
+    bool operator==(const LibraryInfo &other) const {
+      return filePath == other.filePath;
+    }
+
+  private:
+    std::string filePath;
+    std::atomic<State> state;
+    Kind kind;
+    std::optional<BloomFilter> filter;
+    mutable std::shared_mutex mutex;
+  };
+
+  class FilteredView {
+  public:
+    using Map = std::unordered_map<std::string, std::shared_ptr<LibraryInfo>>;
+    using Iterator = typename Map::const_iterator;
+    class FilterIterator {
+    public:
+      FilterIterator(Iterator _it, Iterator _end, State s, Kind k)
+          : it(_it), end(_end), state(s), kind(k) {
+        advance();
+      }
+
+      bool operator!=(const FilterIterator &other) const {
+        return it != other.it;
+      }
+      const std::shared_ptr<LibraryInfo> &operator*() const {
+        return it->second;
+      }
+
+      FilterIterator &operator++() {
+        ++it;
+        advance();
+        return *this;
+      }
+
+    private:
+      void advance() {
+        while (it != end) {
+          const auto &lib = it->second;
+          if (lib->getState() == state && lib->getKind() == kind)
+            break;
+          ++it;
+        }
+      }
+      Iterator it, end;
+      State state;
+      Kind kind;
+    };
+    FilteredView(Iterator begin, Iterator end, State s, Kind k)
+        : begin_(begin), end_(end), state_(s), kind_(k) {}
+
+    FilterIterator begin() const {
+      return FilterIterator(begin_, end_, state_, kind_);
+    }
+
+    FilterIterator end() const {
+      return FilterIterator(end_, end_, state_, kind_);
+    }
+
+  private:
+    Iterator begin_, end_;
+    State state_;
+    Kind kind_;
+  };
+
+private:
+  std::unordered_map<std::string, std::shared_ptr<LibraryInfo>> libraries;
+  mutable std::shared_mutex mutex;
+
+public:
+  using LibraryVisitor = std::function<bool(const LibraryInfo &)>;
+
+  LibraryManager() = default;
+  ~LibraryManager() = default;
+
+  bool addLibrary(std::string path, Kind kind,
+                  std::optional<BloomFilter> filter = std::nullopt) {
+    std::unique_lock<std::shared_mutex> lock(mutex);
+    // SmallString<256> nativePath(path);
+    // sys::path::native(nativePath);
+
+    // auto P = nativePath.str();
+
+    if (libraries.count(path) > 0)
+      return false;
+    libraries.emplace(std::move(path),
+                      std::make_shared<LibraryInfo>(path, State::Unloaded, kind,
+                                                    std::move(filter)));
+    return true;
+  }
+
+  bool hasLibrary(StringRef path) {
+    std::shared_lock<std::shared_mutex> lock(mutex);
+    if (libraries.count(path.str()) > 0)
+      return true;
+    return false;
+  }
+
+  bool removeLibrary(const std::string &path) {
+    std::unique_lock<std::shared_mutex> lock(mutex);
+    // auto P = sys::path::native(path);
+    auto I = libraries.find(path);
+    if (I == libraries.end())
+      return false;
+    libraries.erase(I);
+    return true;
+  }
+
+  void markLoaded(const std::string &path) {
+    std::unique_lock<std::shared_mutex> lock(mutex);
+    if (auto it = libraries.find(path); it != libraries.end()) {
+      it->second->setState(State::Loaded);
+    }
+  }
+
+  void markQueried(const std::string &path) {
+    std::unique_lock<std::shared_mutex> lock(mutex);
+    if (auto it = libraries.find(path); it != libraries.end()) {
+      it->second->setState(State::Queried);
+    }
+  }
+
+  std::shared_ptr<LibraryInfo> getLibrary(const std::string &path) {
+    std::shared_lock<std::shared_mutex> lock(mutex);
+    if (auto it = libraries.find(path); it != libraries.end())
+      return it->second;
+    return nullptr;
+  }
+
+  FilteredView getView(State s, Kind k) const {
+    std::shared_lock lock(mutex);
+    return FilteredView(libraries.begin(), libraries.end(), s, k);
+  }
+
+  void forEachLibrary(const LibraryVisitor &visitor) const {
+    std::unique_lock lock(mutex);
+    for (const auto &[_, entry] : libraries) {
+      if (!visitor(*entry))
+        break;
+    }
+  }
+
+  bool isLoaded(StringRef path) const {
+    std::unique_lock lock(mutex);
+    if (auto it = libraries.find(path.str()); it != libraries.end())
+      return it->second->getState() == State::Loaded;
+    return false;
+  }
+
+  bool isQueried(StringRef path) const {
+    std::unique_lock lock(mutex);
+    if (auto it = libraries.find(path.str()); it != libraries.end())
+      return it->second->getState() == State::Queried;
+    return false;
+  }
+
+  void clear() {
+    std::unique_lock lock(mutex);
+    libraries.clear();
+  }
+};
+
+using LibraryInfo = LibraryManager::LibraryInfo;
+
+/// Scans libraries and resolves symbols across user and system paths.
+///
+/// Supports symbol enumeration and filtering via SymbolEnumerator, and tracks
+/// symbol resolution results through SymbolQuery. Thread-safe and uses
+/// LibraryScanHelper for efficient path resolution and caching.
+class DynamicLoader {
+public:
+  class SymbolEnumerator {
+  public:
+    enum class Result { Continue, Stop, Error };
+
+    using OnEachSymbolFn = std::function<Result(const std::string &)>;
+
+    enum class Filter : uint32_t {
+      None = 0,
+      IgnoreUndefined = 1 << 0,
+      IgnoreWeak = 1 << 1,
+      IgnoreIndirect = 1 << 2,
+
+      Default = IgnoreUndefined
+    };
+
+    struct Options {
+      uint32_t FilterFlags = static_cast<uint32_t>(Filter::Default);
+    };
+
+    static bool enumerateSymbols(llvm::StringRef Path, OnEachSymbolFn OnEach,
+                                 const Options &Opts);
+  };
+
+  class SymbolQuery {
+  public:
+    struct Result {
+      std::string Name;
+      std::string ResolvedLibPath;
+    };
+
+  private:
+    mutable std::shared_mutex mtx;
+    std::unordered_map<std::string, Result> results;
+    std::atomic<size_t> resolvedCount = 0;
+
+  public:
+    explicit SymbolQuery(const std::vector<std::string> &symbols) {
+      for (const auto &s : symbols)
+        results.emplace(s, Result{s, ""});
+    }
+
+    std::vector<std::string> getUnresolvedSymbols() const {
+      std::vector<std::string> unresolved;
+      std::shared_lock lock(mtx);
+      for (const auto &[name, res] : results) {
+        if (res.ResolvedLibPath.empty())
+          unresolved.push_back(name);
+      }
+      return unresolved;
+    }
+
+    void resolve(const std::string &symbol, const std::string &libPath) {
+      std::unique_lock lock(mtx);
+      auto it = results.find(symbol);
+      if (it != results.end() && it->second.ResolvedLibPath.empty()) {
+        it->second.ResolvedLibPath = libPath;
+        ++resolvedCount;
+      }
+    }
+
+    bool allResolved() const {
+      return resolvedCount.load(std::memory_order_relaxed) == results.size();
+    }
+
+    bool hasUnresolved() const {
+      return resolvedCount.load(std::memory_order_relaxed) < results.size();
+    }
+
+    std::optional<std::string> getResolvedLib(const std::string &symbol) const {
+      std::shared_lock lock(mtx);
+      auto it = results.find(symbol);
+      if (it != results.end() && !it->second.ResolvedLibPath.empty())
+        return it->second.ResolvedLibPath;
+      return std::nullopt;
+    }
+
+    bool isResolved(const std::string &symbol) const {
+      std::shared_lock lock(mtx);
+      auto it = results.find(symbol);
+      return it != results.end() && !it->second.ResolvedLibPath.empty();
+    }
+
+    std::vector<Result> getAllResults() const {
+      std::shared_lock lock(mtx);
+      std::vector<Result> out;
+      out.reserve(results.size());
+      for (const auto &[_, res] : results)
+        out.push_back(res);
+      return out;
+    }
+  };
+
+  struct Setup {
+    std::vector<std::string> basePaths;
+    std::shared_ptr<LibraryPathCache> cache;
+    std::shared_ptr<PathResolver> resolver;
+    // std::shared_ptr<DylibPathResolver> dylibResolver;
+
+    bool includeSys = false;
+
+    LibraryScanner::shouldScanFn shouldScan = [](StringRef) { return true; };
+
+    BloomFilterBuilder filterBuilder = BloomFilterBuilder();
+
+    static Setup create(
+        std::vector<std::string> basePaths,
+        std::shared_ptr<LibraryPathCache> existingCache = nullptr,
+        std::shared_ptr<PathResolver> existingResolver = nullptr,
+        //  std::shared_ptr<DylibPathResolver> existingDylibResolver = nullptr,
+        LibraryScanner::shouldScanFn customShouldScan = nullptr) {
+      Setup setup;
+      setup.basePaths = std::move(basePaths);
+
+      setup.cache =
+          existingCache ? existingCache : std::make_shared<LibraryPathCache>();
+
+      setup.resolver = existingResolver
+                           ? existingResolver
+                           : std::make_shared<PathResolver>(setup.cache);
+
+      // setup.dylibResolver = std::move(existingDylibResolver);
+
+      if (customShouldScan)
+        setup.shouldScan = std::move(customShouldScan);
+
+      return setup;
+    }
+  };
+
+  DynamicLoader() = delete;
+  explicit DynamicLoader(const Setup &setup);
+  ~DynamicLoader() = default;
+
+  using OnSearchComplete = unique_function<void(SymbolQuery &)>;
+
+  void searchSymbolsInLibraries(std::vector<std::string> &symbolNames,
+                                OnSearchComplete callback);
+
+private:
+  void scanLibrariesIfNeeded(LibraryManager::Kind K);
+  void resolveSymbolsInLibrary(LibraryInfo &library, SymbolQuery &query);
+  bool
+  symbolExistsInLibrary(const LibraryInfo &library, llvm::StringRef symbol,
+                        std::vector<std::string> *matchedSymbols = nullptr);
+
+  bool symbolExistsInLibrary(const LibraryInfo &lib, llvm::StringRef symbolName,
+                             std::vector<std::string> *allSymbols,
+                             const SymbolEnumerator::Options &opts);
+
+  std::shared_ptr<LibraryPathCache> m_cache;
+  std::shared_ptr<PathResolver> m_PathResolver;
+  LibraryScanHelper ScanH;
+  BloomFilterBuilder FB;
+  LibraryManager LibMgr;
+  LibraryScanner::shouldScanFn m_shouldScan;
+  // std::shared_ptr<DylibPathResolver> m_DylibPathResolver;
+  bool includeSys;
+};
+
+using SymbolEnumerator = DynamicLoader::SymbolEnumerator;
+using EnumerateResult = SymbolEnumerator::Result;
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_DYNAMICLOADER_H
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
new file mode 100644
index 0000000000000..d4be0bce2b125
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -0,0 +1,253 @@
+//===- LibraryScanner.h - Scan 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides support for scanning dynamic library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
+
+#include "llvm/ADT/FunctionExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <mutex>
+#include <queue>
+#include <shared_mutex>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace llvm {
+namespace orc {
+
+class LibraryManager;
+
+class LibraryPathCache {
+  friend class PathResolver;
+
+public:
+  LibraryPathCache() = default;
+
+  void clear();
+
+  void markSeen(const std::string &canon_path) { m_seen.insert(canon_path); }
+
+  bool hasSeen(StringRef canon_path, bool cache = true) {
+    std::shared_lock lock(m_mutex);
+    std::string s = canon_path.str();
+    if (m_seen.count(s) > 0)
+      return true;
+    if (cache)
+      markSeen(s);
+    return false;
+  }
+
+private:
+  mutable std::shared_mutex m_mutex;
+
+  struct PathInfo {
+    std::string canonicalPath;
+    std::error_code errnoCode;
+  };
+
+  std::unordered_map<std::string, std::string> m_readlinkCache;
+  std::unordered_map<std::string, PathInfo> m_realpathCache;
+  std::unordered_map<std::string, mode_t> m_lstatCache;
+  std::unordered_set<std::string> m_seen;
+};
+
+/// Resolves file system paths with optional caching of results.
+///
+/// Supports lstat, readlink, and realpath operations. Can resolve paths
+/// relative to a base and handle symbolic links. Caches results to reduce
+/// repeated system calls when enabled.
+class PathResolver {
+public:
+  PathResolver(std::shared_ptr<LibraryPathCache> cache)
+      : m_cache(std::move(cache)) {}
+
+  std::optional<std::string> resolve(const std::string &path,
+                                     std::error_code &ec) {
+    return realpathCached(path, ec);
+  }
+  mode_t lstatCached(const std::string &path);
+  std::optional<std::string> readlinkCached(const std::string &path);
+  std::optional<std::string> realpathCached(StringRef path, std::error_code &ec,
+                                            StringRef base = "",
+                                            bool baseIsResolved = false,
+                                            long symloopLevel = 40);
+
+private:
+  mutable std::shared_mutex m_mutex;
+  std::shared_ptr<LibraryPathCache> m_cache;
+};
+
+class LibraryScanHelper;
+
+class DylibPathResolver {
+public:
+  DylibPathResolver(LibraryScanHelper &m_helper) : m_helper(m_helper) {}
+
+  /// Resolve a dynamic library path considering RPath, RunPath, and
+  /// substitutions.
+  std::optional<std::string> resolve(StringRef libStem,
+                                     SmallVector<StringRef, 2> RPath = {},
+                                     SmallVector<StringRef, 2> RunPath = {},
+                                     StringRef libLoader = "",
+                                     bool variateLibStem = true);
+
+private:
+  LibraryScanHelper &m_helper;
+
+  std::optional<std::string> substOne(StringRef path, StringRef pattern,
+                                      StringRef replacement);
+
+  /// Apply all known loader substitutions to the path
+  std::optional<std::string> substAll(StringRef path, StringRef loaderPath);
+
+  std::optional<std::string> tryWithBasePaths(ArrayRef<StringRef> basePaths,
+                                              StringRef stem,
+                                              StringRef loaderPath);
+
+  /// Try resolving the path using RPATH, searchPaths, and RUNPATH (in that
+  /// order)
+  std::optional<std::string> tryAllPaths(StringRef stem,
+                                         ArrayRef<StringRef> RPath,
+                                         ArrayRef<StringRef> RunPath,
+                                         StringRef loaderPath);
+
+  std::optional<std::string> tryWithExtensions(StringRef baseName,
+                                               ArrayRef<StringRef> RPath,
+                                               ArrayRef<StringRef> RunPath,
+                                               StringRef loaderPath);
+
+  std::optional<std::string> normalizeIfShared(StringRef path);
+};
+
+enum class PathKind { User, System };
+
+enum class ScanState { NotScanned, Scanning, Scanned };
+
+struct LibraryUnit {
+  std::string basePath; // Canonical base directory path
+  PathKind kind;        // User or System
+  std::atomic<ScanState> state;
+
+  LibraryUnit(std::string base, PathKind k)
+      : basePath(std::move(base)), kind(k), state(ScanState::NotScanned) {}
+};
+
+/// Scans and tracks libraries for symbol resolution.
+///
+/// Maintains a list of library paths to scan, caches scanned units,
+/// and resolves paths canonically for consistent tracking.
+class LibraryScanHelper {
+public:
+  explicit LibraryScanHelper(const std::vector<std::string> &paths,
+                             std::shared_ptr<LibraryPathCache> m_cache,
+                             std::shared_ptr<PathResolver> m_resolver)
+      : m_cache(std::move(m_cache)), m_resolver(std::move(m_resolver)) {
+    for (const auto &p : paths)
+      addBasePath(p);
+  }
+
+  void addBasePath(
+      const std::string &path); // Add a canonical directory for scanning
+  std::vector<std::shared_ptr<LibraryUnit>> getNextBatch(PathKind kind,
+                                                         size_t batchSize);
+
+  bool isTrackedBasePath(const std::string &path) const;
+  std::vector<std::shared_ptr<LibraryUnit>> getAllUnits() const;
+
+  PathResolver &getPathResolver() const { return *m_resolver; }
+
+  LibraryPathCache &getCache() const { return *m_cache; }
+
+  bool hasSeen(StringRef path) const { return m_cache->hasSeen(path); }
+
+  std::optional<std::string> resolve(StringRef path,
+                                     std::error_code &ec) const {
+    return m_resolver->resolve(path.str(), ec);
+  }
+
+private:
+  std::string resolveCanonical(const std::string &path,
+                               std::error_code &ec) const;
+  PathKind classifyKind(const std::string &path) const;
+
+  mutable std::shared_mutex m_fileMutex;
+  mutable std::shared_mutex m_mutex;
+  std::shared_ptr<LibraryPathCache> m_cache;
+  std::shared_ptr<PathResolver> m_resolver;
+
+  std::unordered_map<std::string, std::shared_ptr<LibraryUnit>>
+      m_units; // key: canonical path
+  std::deque<std::string> m_unscannedUsr;
+  std::deque<std::string> m_unscannedSys;
+};
+
+class LibraryScanner {
+public:
+  using shouldScanFn = std::function<bool(StringRef)>;
+
+  LibraryScanner(
+      LibraryScanHelper &H, LibraryManager &m_libMgr,
+      shouldScanFn shouldScanCall = [](StringRef path) { return true; })
+      : m_helper(H), m_libMgr(m_libMgr), m_libResolver(DylibPathResolver(H)),
+        shouldScanCall(std::move(shouldScanCall)) {}
+
+  void scanNext(PathKind kind, size_t batchSize = 1);
+
+  struct LibraryDepsInfo {
+    std::vector<std::string> storage;
+
+    SmallVector<StringRef, 2> rpath;
+    SmallVector<StringRef, 2> runPath;
+    SmallVector<StringRef, 4> deps;
+    bool isPIE = false;
+
+    void addRPath(StringRef s) {
+      storage.emplace_back(s);
+      rpath.push_back(storage.back());
+    }
+
+    void addRunPath(StringRef s) {
+      storage.emplace_back(s);
+      runPath.push_back(storage.back());
+    }
+
+    void addDep(StringRef s) {
+      storage.emplace_back(s);
+      deps.push_back(storage.back());
+    }
+  };
+
+private:
+  LibraryScanHelper &m_helper;
+  LibraryManager &m_libMgr;
+  DylibPathResolver m_libResolver;
+  shouldScanFn shouldScanCall;
+
+  std::optional<std::string> shouldScan(StringRef filePath);
+  Expected<LibraryDepsInfo> extractDeps(StringRef filePath);
+
+  void handleLibrary(StringRef path, PathKind K, int level = 1);
+
+  void scanBaseDir(std::shared_ptr<LibraryUnit> unit);
+};
+
+using LibraryDepsInfo = LibraryScanner::LibraryDepsInfo;
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
index 9f3abac156adb..ee140eb6ed033 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -15,9 +15,11 @@ endif()
 add_llvm_component_library(LLVMOrcTargetProcess
   ExecutorSharedMemoryMapperService.cpp
   DefaultHostBootstrapValues.cpp
+  DynamicLoader.cpp
   JITLoaderGDB.cpp
   JITLoaderPerf.cpp
   JITLoaderVTune.cpp
+  LibraryScanner.cpp
   OrcRTBootstrap.cpp
   RegisterEHFrames.cpp
   SimpleExecutorDylibManager.cpp
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
new file mode 100644
index 0000000000000..1c999c8459e04
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
@@ -0,0 +1,274 @@
+//===----- DynamicLoader.cpp - Defaults for host process -----===//
+//
+// 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/DynamicLoader.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h"
+
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm::orc {
+
+DynamicLoader::DynamicLoader(const DynamicLoader::Setup &setup)
+    : m_cache(setup.cache ? setup.cache : std::make_shared<LibraryPathCache>()),
+      m_PathResolver(setup.resolver ? setup.resolver
+                                    : std::make_shared<PathResolver>(m_cache)),
+      // m_DylibPathResolver(setup.dylibResolver),
+      ScanH(setup.basePaths, m_cache, m_PathResolver), FB(setup.filterBuilder),
+      LibMgr(), m_shouldScan(setup.shouldScan ? setup.shouldScan
+                                              : [](StringRef) { return true; }),
+      includeSys(setup.includeSys) {
+
+  if (ScanH.getAllUnits().empty()) {
+    errs() << "Warning: No base paths provided for scanning.\n";
+  }
+}
+
+static bool shouldIgnoreSymbol(const object::SymbolRef &Sym,
+                               uint32_t IgnoreFlags) {
+  Expected<uint32_t> FlagsOrErr = Sym.getFlags();
+  if (!FlagsOrErr) {
+    consumeError(FlagsOrErr.takeError());
+    return true;
+  }
+
+  uint32_t Flags = *FlagsOrErr;
+  using Filter = SymbolEnumerator::Filter;
+  if ((IgnoreFlags & static_cast<uint32_t>(Filter::IgnoreUndefined)) &&
+      (Flags & object::SymbolRef::SF_Undefined))
+    return true;
+  if ((IgnoreFlags & static_cast<uint32_t>(Filter::IgnoreIndirect)) &&
+      (Flags & object::SymbolRef::SF_Indirect))
+    return true;
+  if ((IgnoreFlags & static_cast<uint32_t>(Filter::IgnoreWeak)) &&
+      (Flags & object::SymbolRef::SF_Weak))
+    return true;
+
+  return false;
+}
+
+bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
+                                        const Options &Opts) {
+  if (Path.empty())
+    return false;
+
+  auto ObjOrErr = object::ObjectFile::createObjectFile(Path);
+  if (!ObjOrErr) {
+    handleAllErrors(ObjOrErr.takeError(), [&](const ErrorInfoBase &EIB) {
+      errs() << "Error loading object: " << EIB.message() << "\n";
+    });
+    return false;
+  }
+
+  object::ObjectFile *Obj = ObjOrErr.get().getBinary();
+
+  auto processSymbolRange =
+      [&](object::ObjectFile::symbol_iterator_range Range) -> EnumerateResult {
+    for (const auto &Sym : Range) {
+      if (shouldIgnoreSymbol(Sym, Opts.FilterFlags))
+        continue;
+
+      auto NameOrErr = Sym.getName();
+      if (!NameOrErr) {
+        consumeError(NameOrErr.takeError());
+        continue;
+      }
+
+      StringRef Name = *NameOrErr;
+      if (Name.empty())
+        continue;
+
+      EnumerateResult Res = OnEach(Name.str());
+      if (Res != EnumerateResult::Continue)
+        return Res;
+    }
+    return EnumerateResult::Continue;
+  };
+
+  EnumerateResult Res = processSymbolRange(Obj->symbols());
+  if (Res != EnumerateResult::Continue)
+    return Res == EnumerateResult::Stop;
+
+  if (Obj->isELF()) {
+    const auto *ElfObj = cast<object::ELFObjectFileBase>(Obj);
+    Res = processSymbolRange(ElfObj->getDynamicSymbolIterators());
+    if (Res != EnumerateResult::Continue)
+      return Res == EnumerateResult::Stop;
+  } else if (Obj->isCOFF()) {
+    const auto *CoffObj = cast<object::COFFObjectFile>(Obj);
+    for (auto I = CoffObj->export_directory_begin(),
+              E = CoffObj->export_directory_end();
+         I != E; ++I) {
+      StringRef Name;
+      if (I->getSymbolName(Name))
+        continue;
+      if (Name.empty())
+        continue;
+
+      if (OnEach(Name.str()) != EnumerateResult::Continue)
+        return false;
+    }
+  } else if (Obj->isMachO()) {
+  }
+
+  return true;
+}
+
+void DynamicLoader::resolveSymbolsInLibrary(LibraryInfo &lib,
+                                            SymbolQuery &unresolvedSymbols) {
+  std::unordered_set<std::string> discoveredSymbols;
+  bool hasEnumerated = false;
+
+  auto enumerateSymbolsIfNeeded = [&]() {
+    if (hasEnumerated)
+      return;
+
+    hasEnumerated = true;
+
+    SymbolEnumerator::Options opts;
+    opts.FilterFlags =
+        static_cast<uint32_t>(SymbolEnumerator::Filter::IgnoreUndefined) |
+        static_cast<uint32_t>(SymbolEnumerator::Filter::IgnoreWeak) |
+        static_cast<uint32_t>(SymbolEnumerator::Filter::IgnoreIndirect);
+
+    SymbolEnumerator::enumerateSymbols(
+        lib.getFullPath(),
+        [&](const std::string &sym) {
+          discoveredSymbols.insert(sym);
+          return SymbolEnumerator::Result::Continue;
+        },
+        opts);
+  };
+
+  const auto &unresolved = unresolvedSymbols.getUnresolvedSymbols();
+
+  if (!unresolved.empty())
+    return;
+
+  if (!lib.hasFilter()) {
+    enumerateSymbolsIfNeeded();
+    lib.ensureFilterBuilt(FB,
+                          {discoveredSymbols.begin(), discoveredSymbols.end()});
+  }
+
+  for (const auto &symbol : unresolved) {
+    if (lib.mayContain(symbol)) {
+      if (discoveredSymbols.count(symbol) > 0)
+        unresolvedSymbols.resolve(symbol, lib.getFullPath());
+    }
+  }
+}
+
+void DynamicLoader::searchSymbolsInLibraries(
+    std::vector<std::string> &symbolList, OnSearchComplete onComplete) {
+  SymbolQuery query(symbolList);
+
+  using LibraryState = LibraryManager::State;
+  using LibraryType = LibraryManager::Kind;
+  auto tryResolveFrom = [&](LibraryState S, LibraryType K) {
+    if (query.allResolved())
+      return;
+    scanLibrariesIfNeeded(K);
+    for (auto &lib : LibMgr.getView(S, K)) {
+      // can use Async here?
+      resolveSymbolsInLibrary(*lib, query);
+      if (query.allResolved())
+        break;
+    }
+  };
+
+  static constexpr LibraryState kStates[] = {
+      LibraryState::Loaded, LibraryState::Queried, LibraryState::Unloaded};
+
+  static constexpr LibraryType kTypes[] = {LibraryType::User,
+                                           LibraryType::System};
+
+  for (auto type : kTypes) {
+    for (auto state : kStates) {
+      tryResolveFrom(state, type);
+      if (query.allResolved())
+        goto done;
+    }
+  }
+
+done:
+  // ProcessLib(query.getResolvedPath());
+  onComplete(query);
+}
+
+// void DynamicLoader::searchSymbolsInLibraries(
+//     std::vector<std::string> &symbolList, OnSearchComplete onComplete) {
+//   SymbolQuery query(symbolList);
+
+//   auto tryResolveFrom = [&](const LibraryCollection &libraries,
+//                             bool isUserLib) {
+//     scanLibrariesIfNeeded(libraries, isUserLib);
+//     for (const auto &lib : libraries) {
+//       // can use Async here?
+//       tryToResolveSymbols(lib, query);
+//       if (query.allResolved())
+//         break;
+//     }
+//   };
+
+//   tryResolveFrom(loadedLibs, /*isUserLib=*/false);
+
+//   if (!query.allResolved())
+//     tryResolveFrom(usrLibs, /*isUserLib=*/true);
+
+//   if (!query.allResolved() && includesys)
+//     tryResolveFrom(sysLibs, /*isUserLib=*/false);
+
+//   onComplete(query);
+// }
+
+void DynamicLoader::scanLibrariesIfNeeded(LibraryManager::Kind PK) {
+  LibraryScanner Scanner(ScanH, LibMgr, m_shouldScan);
+  Scanner.scanNext(PK == LibraryManager::Kind::User ? PathKind::User
+                                                    : PathKind::System);
+}
+
+bool DynamicLoader::symbolExistsInLibrary(
+    const LibraryInfo &lib, StringRef symbolName,
+    std::vector<std::string> *allSymbols) {
+
+  SymbolEnumerator::Options opts;
+  return symbolExistsInLibrary(lib, symbolName, allSymbols, opts);
+}
+
+bool DynamicLoader::symbolExistsInLibrary(
+    const LibraryInfo &lib, StringRef symbolName,
+    std::vector<std::string> *allSymbols,
+    const SymbolEnumerator::Options &opts) {
+
+  bool found = false;
+
+  SymbolEnumerator::enumerateSymbols(
+      lib.getFullPath(),
+      [&](const std::string &sym) {
+        if (allSymbols)
+          allSymbols->emplace_back(sym);
+
+        if (sym == symbolName) {
+          found = true;
+          // return SymbolEnumerator::Result::Stop;
+        }
+
+        return SymbolEnumerator::Result::Continue;
+      },
+      opts);
+
+  return found;
+}
+
+} // end namespace llvm::orc
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
new file mode 100644
index 0000000000000..21085b8aba475
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -0,0 +1,789 @@
+//===----- LibraryScanner.cpp - Provide Library Scaning implementation
+//-----===//
+//
+// 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/LibraryScanner.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#ifdef LLVM_ON_UNIX
+#include <sys/stat.h>
+#include <unistd.h>
+#endif // LLVM_ON_UNIX
+
+#ifdef __APPLE__
+#include <sys/stat.h>
+#undef LC_LOAD_DYLIB
+#undef LC_RPATH
+#endif // __APPLE__
+
+#define DEBUG_TYPE "orc"
+
+namespace llvm::orc {
+
+bool isLibraryFile(StringRef filename) {
+  static const std::vector<std::string> suffixes = {".so", ".so.", ".dylib",
+                                                    ".dll"};
+  for (const auto &suf : suffixes) {
+    if (filename.find(suf) != std::string::npos)
+      return true;
+  }
+  return false;
+}
+
+bool isSharedLibrary(StringRef path) {
+  if (isLibraryFile(path))
+    return true;
+
+  auto filetype = sys::fs::get_file_type(path, /*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;
+  }
+  
+  bool result = false;
+  // TODO Implement ...
+
+  return result;
+}
+
+std::optional<std::string> DylibPathResolver::substOne(StringRef path,
+                                                       StringRef pattern,
+                                                       StringRef replacement) {
+  if (path.size() < pattern.size() || !path.starts_with_insensitive(pattern))
+    return std::nullopt;
+
+  llvm::SmallString<256> result(replacement);
+  result.append(path.drop_front(pattern.size()));
+
+  return normalizeIfShared(result);
+}
+
+std::optional<std::string> DylibPathResolver::substAll(StringRef original,
+                                                       StringRef loaderPath) {
+
+#ifdef __APPLE__
+  llvm::SmallString<256> mainExecutablePath(
+      llvm::sys::fs::getMainExecutable(nullptr, nullptr));
+  llvm::sys::path::remove_filename(mainExecutablePath);
+
+  llvm::SmallString<256> loaderDir;
+  if (loaderPath.empty())
+    loaderDir = mainExecutablePath;
+  else {
+    loaderDir = loaderPath;
+    llvm::sys::path::remove_filename(loaderDir);
+  }
+
+  // Try @loader_path
+  if (auto path = substOne(original, "@loader_path", loaderDir))
+    return path;
+
+  // Try @executable_path
+  if (auto path = substOne(original, "@executable_path", mainExecutablePath))
+    return path;
+
+#else
+  llvm::SmallString<256> loaderDir;
+  if (loaderPath.empty())
+    loaderDir = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+  else
+    loaderDir = loaderPath;
+
+  llvm::sys::path::remove_filename(loaderDir);
+
+  // Try $origin
+  if (auto path = substOne(original, "$origin", loaderDir))
+    return path;
+
+    // Optional: handle $lib or $platform later if needed
+#endif
+
+  return std::nullopt;
+}
+
+std::optional<std::string>
+DylibPathResolver::tryWithBasePaths(ArrayRef<StringRef> basePaths,
+                                    StringRef stem, StringRef loaderPath) {
+  for (const auto &base : basePaths) {
+    auto resolvedBaseOpt = substAll(base, loaderPath);
+    if (!resolvedBaseOpt)
+      continue;
+
+    llvm::SmallString<256> fullPath(*resolvedBaseOpt);
+    llvm::sys::path::append(fullPath, stem);
+
+    if (auto norm = normalizeIfShared(fullPath)) {
+      return norm;
+    }
+  }
+  return std::nullopt;
+}
+
+std::optional<std::string>
+DylibPathResolver::tryAllPaths(StringRef stem, ArrayRef<StringRef> RPath,
+                               ArrayRef<StringRef> RunPath,
+                               StringRef loaderPath) {
+  // Try RPATH
+  if (auto found = tryWithBasePaths(RPath, stem, loaderPath))
+    return found;
+
+  // Try search paths (like LD_LIBRARY_PATH or configured)
+  // for (const auto &entry : m_searchPaths) {
+  // TODO.
+  // }
+
+  // Try RUNPATH
+  if (auto found = tryWithBasePaths(RunPath, stem, loaderPath))
+    return found;
+
+  return std::nullopt;
+}
+
+std::optional<std::string> DylibPathResolver::tryWithExtensions(
+    StringRef baseName, ArrayRef<StringRef> RPath, ArrayRef<StringRef> RunPath,
+    StringRef loaderPath) {
+  SmallVector<StringRef, 4> candidates;
+  candidates.push_back(baseName); // original
+
+  // Add extensions by platform
+#if defined(__APPLE__)
+  candidates.push_back(baseName.str() + ".dylib");
+#elif defined(_WIN32)
+  candidates.push_back(baseName.str() + ".dll");
+#else
+  candidates.push_back(baseName.str() + ".so");
+#endif
+
+  // Optionally try "lib" prefix if not already there
+  StringRef filename = llvm::sys::path::filename(baseName);
+  if (!filename.starts_with("lib")) {
+    SmallString<256> withPrefix("lib");
+    withPrefix += filename;
+    // Apply extension too
+#if defined(__APPLE__)
+    withPrefix += ".dylib";
+#elif defined(_WIN32)
+    withPrefix += ".dll";
+#else
+    withPrefix += ".so";
+#endif
+    candidates.push_back(withPrefix);
+  }
+
+  // Try all variants using tryAllPaths
+  for (const auto &name : candidates) {
+    if (auto found = tryAllPaths(name, RPath, RunPath, loaderPath))
+      return found;
+  }
+
+  return std::nullopt;
+}
+
+std::optional<std::string>
+DylibPathResolver::normalizeIfShared(StringRef path) {
+  std::error_code ec;
+  auto real = m_helper.getPathResolver().realpathCached(path, ec);
+  if (!real || ec)
+    return std::nullopt;
+
+  if (!isSharedLibrary(*real))
+    return std::nullopt;
+
+  return real;
+}
+
+std::optional<std::string>
+DylibPathResolver::resolve(StringRef libStem, SmallVector<StringRef, 2> RPath,
+                           SmallVector<StringRef, 2> RunPath,
+                           StringRef libLoader, bool variateLibStem) {
+  // If it is an absolute path, don't try iterate over the paths.
+  if (llvm::sys::path::is_absolute(libStem)) {
+    return normalizeIfShared(libStem);
+  }
+
+  // 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) {
+      if (auto norm = substOne(libStem, "@rpath", P))
+        return norm;
+    }
+  } else {
+#endif
+    if (auto norm = substAll(libStem, libLoader))
+      return norm;
+#ifdef __APPLE__
+  }
+#endif
+
+  // Expand libStem with paths, extensions, etc.
+  // std::string foundName;
+  if (variateLibStem) {
+    if (auto norm = tryWithExtensions(libStem, RPath, RunPath, libLoader))
+      return norm;
+  } else {
+    if (auto norm = tryAllPaths(libStem, RPath, RunPath, libLoader))
+      return norm;
+  }
+
+  return std::nullopt;
+}
+
+#ifdef _WIN32
+mode_t lstatCached(const std::string &path) { return 0; }
+std::optional<std::string> readlinkCached(const std::string &path) {
+  return std::nullopt;
+}
+#else
+
+mode_t PathResolver::lstatCached(const std::string &path) {
+  // If already cached - retun cached result
+  std::unique_lock lock(m_mutex);
+
+  auto &cache = m_cache->m_lstatCache;
+
+  auto it = cache.find(path);
+  if (it != cache.end())
+    return it->second;
+
+  // Not cached: perform lstat and store
+  struct stat buf {};
+  mode_t st_mode = (lstat(path.c_str(), &buf) == -1) ? 0 : buf.st_mode;
+
+  cache.insert({path, st_mode});
+
+  return st_mode;
+}
+
+std::optional<std::string>
+PathResolver::readlinkCached(const std::string &path) {
+  std::unique_lock lock(m_mutex);
+  auto &cache = m_cache->m_readlinkCache;
+  // If already cached - retun cached result
+  auto it = cache.find(path);
+  if (it != cache.end())
+    return it->second;
+
+  // If result not in cache - call system function and cache result
+  char buf[PATH_MAX];
+  ssize_t len;
+  if ((len = readlink(path.c_str(), buf, sizeof(buf))) != -1) {
+    buf[len] = '\0';
+    std::string s(buf);
+    cache.insert({path, s});
+    return cache[path];
+  }
+  return std::nullopt;
+}
+#endif
+
+void createComponent(StringRef Path, StringRef base_path, bool baseIsResolved,
+                     SmallVector<StringRef, 16> &component) {
+  StringRef Separator = sys::path::get_separator();
+  if (!baseIsResolved) {
+    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(component, Separator, /*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(component, Separator, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+    } else {
+      base_path.split(component, Separator, /*MaxSplit*/ -1,
+                      /*KeepEmpty*/ false);
+    }
+  }
+
+  Path.split(component, Separator, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+}
+
+void normalizePathSegments(SmallVector<StringRef, 16> &pathParts) {
+  SmallVector<StringRef, 16> normalizedPath;
+  for (auto &part : pathParts) {
+    if (part == ".") {
+      continue;
+    } else if (part == "..") {
+      if (!normalizedPath.empty() && normalizedPath.back() != "..") {
+        normalizedPath.pop_back();
+      } else {
+        normalizedPath.push_back("..");
+      }
+    } else {
+      normalizedPath.push_back(part);
+    }
+  }
+  pathParts.swap(normalizedPath);
+}
+
+std::optional<std::string> PathResolver::realpathCached(StringRef path,
+                                                        std::error_code &ec,
+                                                        StringRef base,
+                                                        bool baseIsResolved,
+                                                        long symloopLevel) {
+  ec.clear();
+
+  if (path.empty()) {
+    ec = std::make_error_code(std::errc::no_such_file_or_directory);
+    return std::nullopt;
+  }
+
+  if (symloopLevel <= 0) {
+    ec = std::make_error_code(std::errc::too_many_symbolic_link_levels);
+    return std::nullopt;
+  }
+
+  // If already cached - retun cached result
+  bool isRelative = sys::path::is_relative(path);
+  {
+    std::shared_lock lock(m_mutex);
+    auto it = m_cache->m_realpathCache.find(path.str());
+    if (it != m_cache->m_realpathCache.end()) {
+      ec = it->second.errnoCode;
+      return it->second.canonicalPath;
+    }
+  }
+
+  // If result not in cache - call system function and cache result
+
+  StringRef Separator(sys::path::get_separator());
+  SmallString<256> resolved;
+#ifndef _WIN32
+  SmallVector<StringRef, 16> Components;
+
+  if (isRelative) {
+    if (baseIsResolved) {
+      resolved.assign(base);
+    }
+    createComponent(path, base, baseIsResolved, Components);
+  } else {
+    path.split(Components, Separator, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+  }
+
+  normalizePathSegments(Components);
+
+  // Handle path list items
+  for (const auto &component : Components) {
+    size_t oldSize = resolved.size();
+    sys::path::append(resolved, component);
+    const char *resolvedPath = resolved.c_str();
+
+    mode_t st_mode = lstatCached(resolvedPath);
+
+    if (S_ISLNK(st_mode)) {
+      auto symlinkOpt = readlinkCached(resolvedPath);
+      if (!symlinkOpt) {
+        ec = std::make_error_code(std::errc::no_such_file_or_directory);
+        // std::unique_lock lock(m_mutex);
+        // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+        return std::nullopt;
+      }
+
+      StringRef symlink = *symlinkOpt;
+      resolved.resize(oldSize);
+
+      auto realSymlink =
+          realpathCached(symlink.str(), ec, resolved,
+                         /*baseIsResolved=*/true, symloopLevel - 1);
+      if (!realSymlink) {
+        // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+        return std::nullopt;
+      }
+
+      resolved.assign(*realSymlink);
+    } else if (st_mode == 0) {
+      ec = std::make_error_code(std::errc::no_such_file_or_directory);
+      // std::unique_lock lock(m_mutex);
+      // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+      return std::nullopt;
+    }
+  }
+#else
+  sys::fs::real_path(path, resolved); // Windows fallback
+#endif
+
+  std::string canonical = resolved.str().str();
+  {
+    std::unique_lock lock(m_mutex);
+    m_cache->m_realpathCache.emplace(path, LibraryPathCache::PathInfo{
+                                               canonical,
+                                               std::error_code() // success
+                                           });
+  }
+  return canonical;
+}
+
+void LibraryScanHelper::addBasePath(const std::string &path) {
+  std::error_code ec;
+  std::string canon = resolveCanonical(path, ec);
+  if (ec)
+    return;
+  std::unique_lock lock(m_mutex);
+  if (m_units.count(canon))
+    return;
+
+  PathKind kind = classifyKind(canon);
+  auto unit = std::make_shared<LibraryUnit>(canon, kind);
+  m_units[canon] = unit;
+
+  if (kind == PathKind::User)
+    m_unscannedUsr.push_back(canon);
+  else
+    m_unscannedSys.push_back(canon);
+}
+
+std::vector<std::shared_ptr<LibraryUnit>>
+LibraryScanHelper::getNextBatch(PathKind kind, size_t batchSize) {
+  std::vector<std::shared_ptr<LibraryUnit>> result;
+  auto &queue = (kind == PathKind::User) ? m_unscannedUsr : m_unscannedSys;
+
+  std::unique_lock lock(m_mutex);
+
+  while (!queue.empty() && result.size() < batchSize) {
+    const std::string &base = queue.front(); // no copy
+    auto it = m_units.find(base);
+    if (it != m_units.end()) {
+      auto &unit = it->second;
+      ScanState expected = ScanState::NotScanned;
+      if (unit->state.compare_exchange_strong(expected, ScanState::Scanning)) {
+        result.push_back(unit);
+      }
+    }
+    queue.pop_front();
+  }
+
+  return result;
+}
+
+bool LibraryScanHelper::isTrackedBasePath(const std::string &path) const {
+  std::error_code ec;
+  std::string canon = resolveCanonical(path, ec);
+  if (ec) {
+    return false;
+  }
+  std::shared_lock lock(m_mutex);
+  return m_units.count(canon) > 0;
+}
+
+std::vector<std::shared_ptr<LibraryUnit>>
+LibraryScanHelper::getAllUnits() const {
+  std::shared_lock lock(m_mutex);
+  std::vector<std::shared_ptr<LibraryUnit>> result;
+  result.reserve(m_units.size());
+  for (const auto &[_, unit] : m_units) {
+    result.push_back(unit);
+  }
+  return result;
+}
+
+std::string LibraryScanHelper::resolveCanonical(const std::string &path,
+                                                std::error_code &ec) const {
+  auto canon = m_resolver->resolve(path, ec);
+  return ec ? path : *canon;
+}
+
+PathKind LibraryScanHelper::classifyKind(const std::string &path) const {
+  if (path.find("/usr") == 0 || path.find("/home") == 0)
+    return PathKind::User;
+  return PathKind::System;
+}
+
+Expected<LibraryDepsInfo> parseMachODeps(const object::MachOObjectFile &Obj) {
+  LibraryDepsInfo libdeps;
+  for (const auto &Command : Obj.load_commands()) {
+    switch (Command.C.cmd) {
+    case MachO::LC_LOAD_DYLIB: {
+      MachO::dylib_command dylibCmd = Obj.getDylibIDLoadCommand(Command);
+      libdeps.addDep(Command.Ptr + dylibCmd.dylib.name);
+    } break;
+    case MachO::LC_LOAD_WEAK_DYLIB:
+    case MachO::LC_REEXPORT_DYLIB:
+    case MachO::LC_LOAD_UPWARD_DYLIB:
+    case MachO::LC_LAZY_LOAD_DYLIB:
+      break;
+    case MachO::LC_RPATH: {
+      // Extract RPATH
+      MachO::rpath_command rpathCmd = Obj.getRpathCommand(Command);
+      const char *rpath = Command.Ptr + rpathCmd.path;
+
+      SmallVector<StringRef, 4> RawPaths;
+      SplitString(StringRef(rpath), RawPaths,
+                  sys::EnvPathSeparator == ':' ? ":" : ";");
+
+      for (const auto &raw : RawPaths)
+        libdeps.addRPath(raw.str()); // Convert to std::string
+      break;
+    }
+    }
+  }
+  return libdeps;
+}
+
+template <class ELFT>
+static Expected<StringRef> getDynamicStrTab(const object::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 make_error<StringError>("dynamic string table not found",
+                                 inconvertibleErrorCode());
+}
+
+template <typename ELFT>
+Expected<LibraryDepsInfo> parseELF(const object::ELFFile<ELFT> &Elf) {
+  LibraryDepsInfo Deps;
+  Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);
+  if (!StrTabOrErr)
+    return StrTabOrErr.takeError();
+
+  const char *Data = StrTabOrErr->data();
+
+  auto DynamicEntriesOrError = Elf.dynamicEntries();
+  if (!DynamicEntriesOrError) {
+    return DynamicEntriesOrError.takeError();
+  }
+
+  for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
+    switch (Dyn.d_tag) {
+    case ELF::DT_NEEDED:
+      Deps.addDep(Data + Dyn.d_un.d_val);
+      break;
+    case ELF::DT_RPATH: {
+      SmallVector<StringRef, 4> RawPaths;
+      SplitString(Data + Dyn.d_un.d_val, RawPaths,
+                  sys::EnvPathSeparator == ':' ? ":" : ";");
+      for (const auto &raw : RawPaths)
+        Deps.addRPath(raw.str());
+      break;
+    }
+    case ELF::DT_RUNPATH: {
+      SmallVector<StringRef, 4> RawPaths;
+      SplitString(Data + Dyn.d_un.d_val, RawPaths,
+                  sys::EnvPathSeparator == ':' ? ":" : ";");
+      for (const auto &raw : RawPaths)
+        Deps.addRunPath(raw.str());
+      break;
+    }
+    case ELF::DT_FLAGS_1:
+      // Check if this is not a pie executable.
+      if (Dyn.d_un.d_val & ELF::DF_1_PIE)
+        Deps.isPIE = true;
+      break;
+      // (Dyn.d_tag == ELF::DT_NULL) continue;
+      // (Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER)
+    default:
+      break;
+    }
+  }
+  return Deps;
+}
+
+Expected<LibraryDepsInfo> parseELFDeps(const object::ELFObjectFileBase &obj) {
+  using namespace object;
+
+  if (const auto *ELF = dyn_cast<ELF32LEObjectFile>(&obj))
+    return parseELF(ELF->getELFFile());
+  else if (const auto *ELF = dyn_cast<ELF32BEObjectFile>(&obj))
+    return parseELF(ELF->getELFFile());
+  else if (const auto *ELF = dyn_cast<ELF64LEObjectFile>(&obj))
+    return parseELF(ELF->getELFFile());
+  else if (const auto *ELF = dyn_cast<ELF64BEObjectFile>(&obj))
+    return parseELF(ELF->getELFFile());
+
+  return createStringError(std::errc::not_supported, "Unknown ELF format");
+}
+
+Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef filePath) {
+  auto ObjOrErr = object::ObjectFile::createObjectFile(filePath);
+  if (!ObjOrErr)
+    return createStringError(std::errc::file_exists, "Failed to open %s",
+                             filePath.str().c_str());
+
+  object::ObjectFile *Obj = ObjOrErr.get().getBinary();
+
+  if (auto *elfObj = dyn_cast<object::ELFObjectFileBase>(Obj)) {
+    return parseELFDeps(*elfObj);
+  }
+
+  if (auto *macho = dyn_cast<object::MachOObjectFile>(Obj)) {
+    return parseMachODeps(*macho);
+  }
+
+  return createStringError(inconvertibleErrorCode(),
+                           "Unsupported binary format: %s",
+                           filePath.str().c_str());
+}
+
+std::optional<std::string> LibraryScanner::shouldScan(StringRef filePath) {
+  std::error_code EC;
+
+  // [1] Check file existence early
+  if (!sys::fs::exists(filePath))
+    return std::nullopt;
+
+  // [2] Resolve to canonical path
+  auto CanonicalPathOpt = m_helper.resolve(filePath, EC);
+  if (EC || !CanonicalPathOpt)
+    return std::nullopt;
+
+  const std::string &CanonicalPath = *CanonicalPathOpt;
+
+  // [3] Check if it's a directory — skip directories
+  if (sys::fs::is_directory(CanonicalPath))
+    return std::nullopt;
+
+  // [4] Skip if we've already seen this path (via cache)
+  if (m_helper.hasSeen(CanonicalPath))
+    return std::nullopt;
+
+  // [5] Already tracked in LibraryManager?
+  if (m_libMgr.hasLibrary(CanonicalPath))
+    return std::nullopt;
+
+  // [6] Is this a shared library?
+  if (!isSharedLibrary(CanonicalPath))
+    return std::nullopt;
+
+  // [7] Run user-defined hook (default: always true)
+  if (!shouldScanCall(CanonicalPath))
+    return std::nullopt;
+
+  return CanonicalPath;
+}
+
+void LibraryScanner::handleLibrary(StringRef filePath, PathKind K, int level) {
+  auto CanonPathOpt = shouldScan(filePath);
+  if (!CanonPathOpt)
+    return;
+
+  const std::string CanonicalPath = *CanonPathOpt;
+
+  auto DepsOrErr = extractDeps(CanonicalPath);
+  if (!DepsOrErr) {
+    consumeError(DepsOrErr.takeError());
+    return;
+  }
+
+  LibraryDepsInfo &Deps = *DepsOrErr;
+
+  if (Deps.isPIE && level == 0)
+    return;
+
+  bool added = m_libMgr.addLibrary(
+      CanonicalPath, K == PathKind::User ? LibraryManager::Kind::User
+                                         : LibraryManager::Kind::System);
+  if (!added)
+    return;
+
+  // Heuristic 1: No RPATH/RUNPATH, skip deps
+  if (Deps.rpath.empty() && Deps.runPath.empty()) {
+    LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic1): "
+                      << CanonicalPath << "\n");
+    return;
+  }
+
+  // Heuristic 2: All RPATH and RUNPATH already tracked
+  auto allTracked = [&](const auto &Paths) {
+    return std::all_of(Paths.begin(), Paths.end(), [&](StringRef P) {
+      return m_helper.isTrackedBasePath(P.str());
+    });
+  };
+
+  if (allTracked(Deps.rpath) && allTracked(Deps.runPath)) {
+    LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic2): "
+                      << CanonicalPath << "\n");
+    return;
+  }
+
+  for (StringRef dep : Deps.deps) {
+    auto dep_fullopt = m_libResolver.resolve(dep, Deps.rpath, Deps.runPath,
+                                             CanonicalPath, false);
+    if (!dep_fullopt)
+      continue;
+
+    handleLibrary(*dep_fullopt, K, level + 1);
+  }
+}
+
+void LibraryScanner::scanBaseDir(std::shared_ptr<LibraryUnit> unit) {
+  if (!sys::fs::is_directory(unit->basePath) || unit->basePath.empty())
+    return;
+
+  std::error_code ec;
+
+  unit->state.store(ScanState::Scanning);
+
+  for (sys::fs::directory_iterator it(unit->basePath, ec), end;
+       it != end && !ec; it.increment(ec)) {
+    auto entry = *it;
+    if (!entry.status())
+      continue;
+
+    auto status = *entry.status();
+    if (sys::fs::is_regular_file(status) || sys::fs::is_symlink_file(status)) {
+      // if (m_cache->hasSeen(entry.path()))
+      //   continue;
+      // std::string path = m_helper->resolvePath(entry.path(), ec);
+      // if (!sys::fs::is_director(path))
+      handleLibrary(entry.path(), unit->kind);
+    }
+  }
+
+  unit->state.store(ScanState::Scanned);
+}
+
+void LibraryScanner::scanNext(PathKind K, size_t batchSize) {
+  auto Units = m_helper.getNextBatch(K, batchSize);
+  for (auto &unit : Units) {
+    scanBaseDir(unit);
+  }
+}
+
+} // end namespace llvm::orc

>From c20d6dbe930e87d9e5037fe9b3174eb08dc659ba Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 4 Jul 2025 10:26:18 +0530
Subject: [PATCH 2/6] Fix minor logic issues and add debug logs

---
 .../Orc/TargetProcess/LibraryScanner.h        |   3 +
 .../Orc/TargetProcess/DynamicLoader.cpp       |  39 +++-
 .../Orc/TargetProcess/LibraryScanner.cpp      | 215 +++++++++++++++---
 3 files changed, 226 insertions(+), 31 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index d4be0bce2b125..ffe41c118c84e 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -156,6 +156,9 @@ class LibraryScanHelper {
                              std::shared_ptr<LibraryPathCache> m_cache,
                              std::shared_ptr<PathResolver> m_resolver)
       : m_cache(std::move(m_cache)), m_resolver(std::move(m_resolver)) {
+    // LLVM_DEBUG(
+    llvm::dbgs() << "LibraryScanHelper::LibraryScanHelper: base paths : "
+                 << paths.size() << "\n"; //);
     for (const auto &p : paths)
       addBasePath(p);
   }
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
index 1c999c8459e04..5388d8d1aa9c0 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
@@ -17,6 +17,8 @@
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Error.h"
 
+#define DEBUG_TYPE "orc"
+
 namespace llvm::orc {
 
 DynamicLoader::DynamicLoader(const DynamicLoader::Setup &setup)
@@ -140,7 +142,9 @@ void DynamicLoader::resolveSymbolsInLibrary(LibraryInfo &lib,
         static_cast<uint32_t>(SymbolEnumerator::Filter::IgnoreUndefined) |
         static_cast<uint32_t>(SymbolEnumerator::Filter::IgnoreWeak) |
         static_cast<uint32_t>(SymbolEnumerator::Filter::IgnoreIndirect);
-
+    // LLVM_DEBUG(
+    dbgs() << "Enumerating symbols in library: " << lib.getFullPath() << "\n";
+    // );
     SymbolEnumerator::enumerateSymbols(
         lib.getFullPath(),
         [&](const std::string &sym) {
@@ -152,19 +156,35 @@ void DynamicLoader::resolveSymbolsInLibrary(LibraryInfo &lib,
 
   const auto &unresolved = unresolvedSymbols.getUnresolvedSymbols();
 
-  if (!unresolved.empty())
+  if (unresolved.empty()) {
+    // LLVM_DEBUG(
+    dbgs() << "Skipping library: " << lib.getFullPath()
+           << " — unresolved symbols exist.\n";
+    // );
     return;
-
+  }
+  enumerateSymbolsIfNeeded();
   if (!lib.hasFilter()) {
-    enumerateSymbolsIfNeeded();
+    // LLVM_DEBUG(
+    dbgs() << "Building filter for library: " << lib.getFullPath() << "\n"; //);
     lib.ensureFilterBuilt(FB,
                           {discoveredSymbols.begin(), discoveredSymbols.end()});
+    dbgs() << "discoveredSymbols : " << discoveredSymbols.size() << "\n";
+    for (const auto &sym : discoveredSymbols)
+      dbgs() << "discoveredSymbols : " << sym << "\n";
   }
 
   for (const auto &symbol : unresolved) {
     if (lib.mayContain(symbol)) {
-      if (discoveredSymbols.count(symbol) > 0)
+      // LLVM_DEBUG(
+      dbgs() << "Checking symbol '" << symbol
+             << "' in library: " << lib.getFullPath() << "\n"; //);
+      if (discoveredSymbols.count(symbol) > 0) {
+        // LLVM_DEBUG(
+        dbgs() << "  Resolved symbol: " << symbol
+               << " in library: " << lib.getFullPath() << "\n"; //);
         unresolvedSymbols.resolve(symbol, lib.getFullPath());
+      }
     }
   }
 }
@@ -178,6 +198,9 @@ void DynamicLoader::searchSymbolsInLibraries(
   auto tryResolveFrom = [&](LibraryState S, LibraryType K) {
     if (query.allResolved())
       return;
+    // LLVM_DEBUG(
+    dbgs() << "Trying resolve from state=" << static_cast<int>(S)
+           << " type=" << static_cast<int>(K) << "\n"; //);
     scanLibrariesIfNeeded(K);
     for (auto &lib : LibMgr.getView(S, K)) {
       // can use Async here?
@@ -202,6 +225,8 @@ void DynamicLoader::searchSymbolsInLibraries(
   }
 
 done:
+  // LLVM_DEBUG(
+  dbgs() << "Search complete.\n"; //);
   // ProcessLib(query.getResolvedPath());
   onComplete(query);
 }
@@ -233,6 +258,10 @@ void DynamicLoader::searchSymbolsInLibraries(
 // }
 
 void DynamicLoader::scanLibrariesIfNeeded(LibraryManager::Kind PK) {
+  // LLVM_DEBUG(
+  llvm::dbgs() << "DynamicLoader::scanLibrariesIfNeeded: Scanning for "
+               << (PK == LibraryManager::Kind::User ? "User" : "System")
+               << " libraries\n"; //);
   LibraryScanner Scanner(ScanH, LibMgr, m_shouldScan);
   Scanner.scanNext(PK == LibraryManager::Kind::User ? PathKind::User
                                                     : PathKind::System);
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 21085b8aba475..436c8fce75a15 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -49,11 +49,16 @@ bool isLibraryFile(StringRef filename) {
   return false;
 }
 
-bool isSharedLibrary(StringRef path) {
-  if (isLibraryFile(path))
+template <class ELFT>
+bool isELFSharedLibrary(const object::ELFFile<ELFT> &ELFObj) {
+  return ELFObj.getHeader().e_type == llvm::ELF::ET_DYN;
+}
+
+bool isSharedLibrary(StringRef Path) {
+  if (isLibraryFile(Path))
     return true;
 
-  auto filetype = sys::fs::get_file_type(path, /*Follow*/ true);
+  auto filetype = sys::fs::get_file_type(Path, /*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.
@@ -61,11 +66,43 @@ bool isSharedLibrary(StringRef path) {
     // }
     return false;
   }
-  
-  bool result = false;
-  // TODO Implement ...
 
-  return result;
+  Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
+      object::createBinary(Path);
+  if (!BinaryOrErr) {
+    // Could not open or parse the binary
+    consumeError(BinaryOrErr.takeError());
+    return false;
+  }
+
+  object::Binary *Bin = BinaryOrErr->getBinary();
+
+  if (auto *Obj = dyn_cast<object::ObjectFile>(Bin)) {
+    if (Obj->isELF()) {
+      if (auto *ELF32LE = dyn_cast<object::ELF32LEObjectFile>(Obj))
+        return isELFSharedLibrary(ELF32LE->getELFFile());
+      if (auto *ELF64LE = dyn_cast<object::ELF64LEObjectFile>(Obj))
+        return isELFSharedLibrary(ELF64LE->getELFFile());
+      if (auto *ELF32BE = dyn_cast<object::ELF32BEObjectFile>(Obj))
+        return isELFSharedLibrary(ELF32BE->getELFFile());
+      if (auto *ELF64BE = dyn_cast<object::ELF64BEObjectFile>(Obj))
+        return isELFSharedLibrary(ELF64BE->getELFFile());
+    } else if (Obj->isMachO()) {
+      const object::MachOObjectFile *MachO =
+          dyn_cast<object::MachOObjectFile>(Obj);
+      if (!MachO)
+        return false;
+      return MachO->getHeader().filetype == MachO::HeaderFileType::MH_DYLIB;
+    } else if (Obj->isCOFF()) {
+      const object::COFFObjectFile *coff =
+          dyn_cast<object::COFFObjectFile>(Obj);
+      if (!coff)
+        return false;
+      return coff->getCharacteristics() & COFF::IMAGE_FILE_DLL;
+    }
+  }
+
+  return false;
 }
 
 std::optional<std::string> DylibPathResolver::substOne(StringRef path,
@@ -353,11 +390,18 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
 
   if (path.empty()) {
     ec = std::make_error_code(std::errc::no_such_file_or_directory);
+    // LLVM_DEBUG(
+    dbgs() << "PathResolver::realpathCached: Empty path\n"; //);
+
     return std::nullopt;
   }
 
   if (symloopLevel <= 0) {
     ec = std::make_error_code(std::errc::too_many_symbolic_link_levels);
+    // LLVM_DEBUG(
+    dbgs() << "PathResolver::realpathCached: Too many symlink levels: " << path
+           << "\n"; //);
+
     return std::nullopt;
   }
 
@@ -368,20 +412,34 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
     auto it = m_cache->m_realpathCache.find(path.str());
     if (it != m_cache->m_realpathCache.end()) {
       ec = it->second.errnoCode;
+      if (ec) {
+        // LLVM_DEBUG(
+        dbgs() << "PathResolver::realpathCached: Cached (error) for " << path
+               << "\n"; //);
+      } else {
+        // LLVM_DEBUG(
+        dbgs() << "PathResolver::realpathCached: Cached (success) for " << path
+               << " => " << it->second.canonicalPath << "\n"; //);
+      }
       return it->second.canonicalPath;
     }
   }
+  // LLVM_DEBUG(
+  dbgs() << "PathResolver::realpathCached: Resolving path: " << path
+         << "\n"; //);
 
   // If result not in cache - call system function and cache result
 
   StringRef Separator(sys::path::get_separator());
-  SmallString<256> resolved;
+  SmallString<256> resolved(Separator);
 #ifndef _WIN32
   SmallVector<StringRef, 16> Components;
 
   if (isRelative) {
     if (baseIsResolved) {
       resolved.assign(base);
+      // LLVM_DEBUG(
+      dbgs() << "  Using resolved base: " << base << "\n"; //);
     }
     createComponent(path, base, baseIsResolved, Components);
   } else {
@@ -389,25 +447,39 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
   }
 
   normalizePathSegments(Components);
+  for (auto &C : Components)
+    // LLVM_DEBUG(
+    dbgs() << " " << C << "\n"; //);
 
   // Handle path list items
   for (const auto &component : Components) {
     size_t oldSize = resolved.size();
     sys::path::append(resolved, component);
     const char *resolvedPath = resolved.c_str();
-
+    // LLVM_DEBUG(
+    dbgs() << "  Processing component: " << component << " => " << resolvedPath
+           << "\n"; //);
     mode_t st_mode = lstatCached(resolvedPath);
 
     if (S_ISLNK(st_mode)) {
+      // LLVM_DEBUG(
+      dbgs() << "    Found symlink: " << resolvedPath << "\n"; //);
+
       auto symlinkOpt = readlinkCached(resolvedPath);
       if (!symlinkOpt) {
         ec = std::make_error_code(std::errc::no_such_file_or_directory);
         // std::unique_lock lock(m_mutex);
         // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+        // LLVM_DEBUG(
+        dbgs() << "    Failed to read symlink: " << resolvedPath << "\n"; //);
+
         return std::nullopt;
       }
 
       StringRef symlink = *symlinkOpt;
+      // LLVM_DEBUG(
+      dbgs() << "    Symlink points to: " << symlink << "\n"; //);
+
       resolved.resize(oldSize);
 
       auto realSymlink =
@@ -415,14 +487,24 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
                          /*baseIsResolved=*/true, symloopLevel - 1);
       if (!realSymlink) {
         // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+        // LLVM_DEBUG(
+        dbgs() << "    Failed to resolve symlink target: " << symlink
+               << "\n"; //);
+
         return std::nullopt;
       }
 
       resolved.assign(*realSymlink);
+      // LLVM_DEBUG(
+      dbgs() << "    Symlink resolved to: " << resolved << "\n"; //);
+
     } else if (st_mode == 0) {
       ec = std::make_error_code(std::errc::no_such_file_or_directory);
       // std::unique_lock lock(m_mutex);
       // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+      // LLVM_DEBUG(
+      dbgs() << "    Component does not exist: " << resolvedPath << "\n"; //);
+
       return std::nullopt;
     }
   }
@@ -438,26 +520,44 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
                                                std::error_code() // success
                                            });
   }
+  // LLVM_DEBUG(
+  dbgs() << "PathResolver::realpathCached: Final resolved: " << path << " => "
+         << canonical << "\n"; //);
   return canonical;
 }
 
 void LibraryScanHelper::addBasePath(const std::string &path) {
   std::error_code ec;
   std::string canon = resolveCanonical(path, ec);
-  if (ec)
+  if (ec) {
+    // LLVM_DEBUG(
+    llvm::dbgs()
+        << "LibraryScanHelper::addBasePath: Failed to canonicalize path: "
+        << path << "\n"; //);
     return;
+  }
   std::unique_lock lock(m_mutex);
-  if (m_units.count(canon))
+  if (m_units.count(canon)) {
+    // LLVM_DEBUG(
+    llvm::dbgs() << "LibraryScanHelper::addBasePath: Already added: " << canon
+                 << "\n"; //);
     return;
-
+  }
   PathKind kind = classifyKind(canon);
   auto unit = std::make_shared<LibraryUnit>(canon, kind);
   m_units[canon] = unit;
 
-  if (kind == PathKind::User)
+  if (kind == PathKind::User) {
+    // LLVM_DEBUG(
+    llvm::dbgs() << "LibraryScanHelper::addBasePath: Added User path: " << canon
+                 << "\n"; //);
     m_unscannedUsr.push_back(canon);
-  else
+  } else {
+    // LLVM_DEBUG(
+    llvm::dbgs() << "LibraryScanHelper::addBasePath: Added System path: "
+                 << canon << "\n"; //);
     m_unscannedSys.push_back(canon);
+  }
 }
 
 std::vector<std::shared_ptr<LibraryUnit>>
@@ -511,8 +611,25 @@ std::string LibraryScanHelper::resolveCanonical(const std::string &path,
 }
 
 PathKind LibraryScanHelper::classifyKind(const std::string &path) const {
-  if (path.find("/usr") == 0 || path.find("/home") == 0)
+  // Detect home directory
+  const char *home = getenv("HOME");
+  if (home && path.find(home) == 0)
     return PathKind::User;
+
+  // Standard user install locations
+  static const std::vector<std::string> userPrefixes = {
+      "/usr/local",    // often used by users for manual installs
+      "/opt/homebrew", // common on macOS M1/M2
+      "/opt/local",    // MacPorts
+      "/home",         // Linux home dirs
+      "/Users",        // macOS user dirs
+  };
+
+  for (const auto &prefix : userPrefixes) {
+    if (path.find(prefix) == 0)
+      return PathKind::User;
+  }
+
   return PathKind::System;
 }
 
@@ -699,33 +816,52 @@ std::optional<std::string> LibraryScanner::shouldScan(StringRef filePath) {
 }
 
 void LibraryScanner::handleLibrary(StringRef filePath, PathKind K, int level) {
+  // LLVM_DEBUG(
+  dbgs() << "LibraryScanner::handleLibrary: Scanning: " << filePath
+         << ", level=" << level << "\n"; //);
   auto CanonPathOpt = shouldScan(filePath);
-  if (!CanonPathOpt)
-    return;
+  if (!CanonPathOpt) {
+    // LLVM_DEBUG(
+    dbgs() << "  Skipped (shouldScan returned false): " << filePath
+           << "\n"; //);
 
+    return;
+  }
   const std::string CanonicalPath = *CanonPathOpt;
 
   auto DepsOrErr = extractDeps(CanonicalPath);
   if (!DepsOrErr) {
+    // LLVM_DEBUG(
+    dbgs() << "  Failed to extract deps for: " << CanonicalPath << "\n"; //);
+
     consumeError(DepsOrErr.takeError());
     return;
   }
 
   LibraryDepsInfo &Deps = *DepsOrErr;
 
-  if (Deps.isPIE && level == 0)
+  if (Deps.isPIE && level == 0) {
+    // LLVM_DEBUG(
+    dbgs() << "  Skipped PIE executable at top level: " << CanonicalPath
+           << "\n"; //);
+
     return;
+  }
 
   bool added = m_libMgr.addLibrary(
       CanonicalPath, K == PathKind::User ? LibraryManager::Kind::User
                                          : LibraryManager::Kind::System);
-  if (!added)
-    return;
+  if (!added) {
+    // LLVM_DEBUG(
+    dbgs() << "  Already added: " << CanonicalPath << "\n"; //);
 
+    return;
+  }
   // Heuristic 1: No RPATH/RUNPATH, skip deps
   if (Deps.rpath.empty() && Deps.runPath.empty()) {
-    LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic1): "
-                      << CanonicalPath << "\n");
+    // LLVM_DEBUG(
+    dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic1): "
+           << CanonicalPath << "\n"; //);
     return;
   }
 
@@ -737,25 +873,41 @@ void LibraryScanner::handleLibrary(StringRef filePath, PathKind K, int level) {
   };
 
   if (allTracked(Deps.rpath) && allTracked(Deps.runPath)) {
-    LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic2): "
-                      << CanonicalPath << "\n");
+    // LLVM_DEBUG(
+    dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic2): "
+           << CanonicalPath << "\n"; //);
     return;
   }
 
   for (StringRef dep : Deps.deps) {
+    // LLVM_DEBUG(
+    dbgs() << "  Resolving dep: " << dep << "\n"; //);
     auto dep_fullopt = m_libResolver.resolve(dep, Deps.rpath, Deps.runPath,
                                              CanonicalPath, false);
-    if (!dep_fullopt)
+    if (!dep_fullopt) {
+      // LLVM_DEBUG(
+      dbgs() << "    Failed to resolve dep: " << dep << "\n"; //);
+
       continue;
+    }
+    // LLVM_DEBUG(
+    dbgs() << "    Resolved dep to: " << *dep_fullopt << "\n"; //);
 
     handleLibrary(*dep_fullopt, K, level + 1);
   }
 }
 
 void LibraryScanner::scanBaseDir(std::shared_ptr<LibraryUnit> unit) {
-  if (!sys::fs::is_directory(unit->basePath) || unit->basePath.empty())
+  if (!sys::fs::is_directory(unit->basePath) || unit->basePath.empty()) {
+    // LLVM_DEBUG(
+    dbgs() << "LibraryScanner::scanBaseDir: Invalid or empty basePath: "
+           << unit->basePath << "\n"; //);
     return;
+  }
 
+  // LLVM_DEBUG(
+  dbgs() << "LibraryScanner::scanBaseDir: Scanning directory: "
+         << unit->basePath << "\n"; //);
   std::error_code ec;
 
   unit->state.store(ScanState::Scanning);
@@ -768,6 +920,9 @@ void LibraryScanner::scanBaseDir(std::shared_ptr<LibraryUnit> unit) {
 
     auto status = *entry.status();
     if (sys::fs::is_regular_file(status) || sys::fs::is_symlink_file(status)) {
+      // LLVM_DEBUG(
+      dbgs() << "  Found file: " << entry.path() << "\n"; //);
+
       // if (m_cache->hasSeen(entry.path()))
       //   continue;
       // std::string path = m_helper->resolvePath(entry.path(), ec);
@@ -780,8 +935,16 @@ void LibraryScanner::scanBaseDir(std::shared_ptr<LibraryUnit> unit) {
 }
 
 void LibraryScanner::scanNext(PathKind K, size_t batchSize) {
+  // LLVM_DEBUG(
+  dbgs() << "LibraryScanner::scanNext: Scanning next batch of size "
+         << batchSize << " for kind "
+         << (K == PathKind::User ? "User" : "System") << "\n"; //);
+
   auto Units = m_helper.getNextBatch(K, batchSize);
   for (auto &unit : Units) {
+    // LLVM_DEBUG(
+    dbgs() << "  Scanning unit with basePath: " << unit->basePath << "\n"; //);
+
     scanBaseDir(unit);
   }
 }

>From 595cad222d66f817e26bca753ed551844da95f63 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Thu, 10 Jul 2025 15:51:11 +0530
Subject: [PATCH 3/6] Fix some issues

---
 .../Orc/TargetProcess/DynamicLoader.h         | 187 +++++++++---------
 .../Orc/TargetProcess/LibraryScanner.h        |   4 +-
 .../Orc/TargetProcess/DynamicLoader.cpp       |  65 +++---
 .../Orc/TargetProcess/LibraryScanner.cpp      | 123 +++++++-----
 4 files changed, 202 insertions(+), 177 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
index 0b98be4cd9bf1..ef42f3897f9cc 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
@@ -26,77 +26,82 @@
 namespace llvm {
 namespace orc {
 
-// Represents a collection of libraries, each optionally associated with a
-// symbol filter and hash map.
-// class LibraryCollection {
+// template <typename Iterator, typename Predicate, typename Projection>
+// class FilterIterator {
 // public:
-//   class LibraryInfo {
-//   public:
-//     LibraryInfo(const LibraryInfo &) = delete;
-//     LibraryInfo &operator=(const LibraryInfo &) = delete;
-
-//     LibraryInfo(std::string basePath,
-//                 std::optional<BloomFilter> filter = std::nullopt
-//         : basePath(std::move(basePath)), filter(std::move(filter)) {}
-
-//     StringRef getBasePath() const { return basePath; }
-//     StringRef getFileName() const { return fileName; }
-
-//     std::string getFullPath() const {
-//       llvm::SmallString<512> fullPath(basePath);
-//       llvm::sys::path::append(fullPath, llvm::StringRef(fileName));
-//       return std::string(fullPath.str());
-//     }
-
-//     bool setFilter(const BloomFilter &f);
-//     bool buildFilter(const std::vector<std::string> &symbols);
-//     bool ensureFilterBuilt(const std::vector<std::string> &symbols);
-//     bool buildHashMap(const std::vector<std::string> &symbols);
-
-//     bool mayContain(StringRef symbol) const;
-//     bool hasFilter() const { return filter.has_value(); }
-//     bool hasHashMap() const { return hashMap.has_value(); }
+//   FilterIterator(Iterator current, Iterator end, Predicate pred,
+//                  Projection proj)
+//       : current_(current), end_(end), pred_(pred), proj_(proj) {
+//     advance_to_valid();
+//   }
 
-//   private:
-//     std::string basePath;
-//     std::string fileName;
-//     std::optional<BloomFilter> filter;
-//     std::mutex mutex;
-//   };
+//   decltype(auto) operator*() { return proj_(*current_); }
 
-//   using LibraryVisitor = unique_function<bool(const LibraryInfo &)>;
+//   FilterIterator &operator++() {
+//     ++current_;
+//     advance_to_valid();
+//     return *this;
+//   }
 
-//   // Visit each library. Stops early if visitor returns false.
-//   bool forEachLibrary(LibraryVisitor &&visitor) const;
+//   bool operator!=(const FilterIterator &other) const {
+//     return current_ != other.current_;
+//   }
 
-//   // Visit each library. Removes those for which the visitor returns true.
-//   bool removeIf(LibraryVisitor &&shouldRemove);
+// private:
+//   void advance_to_valid() {
+//     while (current_ != end_ && !pred_(*current_)) {
+//       ++current_;
+//     }
+//   }
 
-//   // Adds a new library with optional filter and hash map.
-//   bool addLibrary(std::string basePath,
-//                   std::optional<BloomFilter> filter = std::nullopt);
+//   Iterator current_, end_;
+//   Predicate pred_;
+//   Projection proj_;
+// };
 
-//   // Removes a library by base path.
-//   bool removeLibrary(const std::string &basePath);
+// template <typename Iterator, typename Predicate, typename Projection>
+// class FilterView {
+// public:
+//   FilterView(Iterator begin, Iterator end, Predicate pred, Projection proj)
+//       : begin_(begin), end_(end), pred_(pred), proj_(proj) {}
+
+//   auto begin() {
+//     return FilterIterator<Iterator, Predicate, Projection>(begin_, end_,
+//     pred_,
+//                                                            proj_);
+//   }
+
+//   auto end() {
+//     return FilterIterator<Iterator, Predicate, Projection>(end_, end_, pred_,
+//                                                            proj_);
+//   }
+
+//   template <typename Iterator, typename Predicate, typename Projection>
+//   static auto make_filter_view(Iterator begin, Iterator end, Predicate pred,
+//                                Projection proj) {
+//     return FilterView<Iterator, Predicate, Projection>(begin, end, pred,
+//     proj);
+//   }
+
+//   template <typename Iterator, typename Predicate>
+//   static auto make_filter_view(Iterator begin, Iterator end, Predicate pred)
+//   {
+//     return FilterView<Iterator, Predicate,
+//                       decltype([](auto &x) -> decltype(auto) { return x; })>(
+//         begin, end, pred, [](auto &x) -> decltype(auto) { return x; });
+//   }
 
 // private:
-//   struct LibraryInfoHash {
-//     size_t operator()(const LibraryInfo &lib) const {
-//       return std::hash<size_t>()(lib.getBasePath().length()) ^
-//              std::hash<std::string>()(std::string(lib.getFileName()));
-//     }
-//   };
-
-//   std::unordered_set<LibraryInfo, LibraryInfoHash> libraries;
-//   std::vector<const LibraryInfo *> Libs;
-//   mutable std::mutex mutex;
+//   Iterator begin_, end_;
+//   Predicate pred_;
+//   Projection proj_;
 // };
 
 /// Manages library metadata and state for symbol resolution.
 ///
-/// Tracks libraries by load state and kind (user/system), and stores associated
-/// Bloom filters and hash maps to speed up symbol lookups. Thread-safe for
-/// concurrent access.
+/// Tracks libraries by load state and kind (user/system), and stores
+/// associated Bloom filters and hash maps to speed up symbol lookups.
+/// Thread-safe for concurrent access.
 class LibraryManager {
 public:
   enum class State : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
@@ -164,7 +169,7 @@ class LibraryManager {
 
   class FilteredView {
   public:
-    using Map = std::unordered_map<std::string, std::shared_ptr<LibraryInfo>>;
+    using Map = StringMap<std::shared_ptr<LibraryInfo>>;
     using Iterator = typename Map::const_iterator;
     class FilterIterator {
     public:
@@ -217,7 +222,7 @@ class LibraryManager {
   };
 
 private:
-  std::unordered_map<std::string, std::shared_ptr<LibraryInfo>> libraries;
+  StringMap<std::shared_ptr<LibraryInfo>> libraries;
   mutable std::shared_mutex mutex;
 
 public:
@@ -236,20 +241,20 @@ class LibraryManager {
 
     if (libraries.count(path) > 0)
       return false;
-    libraries.emplace(std::move(path),
+    libraries.insert({std::move(path),
                       std::make_shared<LibraryInfo>(path, State::Unloaded, kind,
-                                                    std::move(filter)));
+                                                    std::move(filter))});
     return true;
   }
 
   bool hasLibrary(StringRef path) {
     std::shared_lock<std::shared_mutex> lock(mutex);
-    if (libraries.count(path.str()) > 0)
+    if (libraries.count(path) > 0)
       return true;
     return false;
   }
 
-  bool removeLibrary(const std::string &path) {
+  bool removeLibrary(StringRef path) {
     std::unique_lock<std::shared_mutex> lock(mutex);
     // auto P = sys::path::native(path);
     auto I = libraries.find(path);
@@ -259,21 +264,21 @@ class LibraryManager {
     return true;
   }
 
-  void markLoaded(const std::string &path) {
+  void markLoaded(StringRef path) {
     std::unique_lock<std::shared_mutex> lock(mutex);
     if (auto it = libraries.find(path); it != libraries.end()) {
       it->second->setState(State::Loaded);
     }
   }
 
-  void markQueried(const std::string &path) {
+  void markQueried(StringRef path) {
     std::unique_lock<std::shared_mutex> lock(mutex);
     if (auto it = libraries.find(path); it != libraries.end()) {
       it->second->setState(State::Queried);
     }
   }
 
-  std::shared_ptr<LibraryInfo> getLibrary(const std::string &path) {
+  std::shared_ptr<LibraryInfo> getLibrary(StringRef path) {
     std::shared_lock<std::shared_mutex> lock(mutex);
     if (auto it = libraries.find(path); it != libraries.end())
       return it->second;
@@ -326,7 +331,7 @@ class DynamicLoader {
   public:
     enum class Result { Continue, Stop, Error };
 
-    using OnEachSymbolFn = std::function<Result(const std::string &)>;
+    using OnEachSymbolFn = std::function<Result(StringRef Sym)>;
 
     enum class Filter : uint32_t {
       None = 0,
@@ -341,7 +346,7 @@ class DynamicLoader {
       uint32_t FilterFlags = static_cast<uint32_t>(Filter::Default);
     };
 
-    static bool enumerateSymbols(llvm::StringRef Path, OnEachSymbolFn OnEach,
+    static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
                                  const Options &Opts);
   };
 
@@ -354,17 +359,18 @@ class DynamicLoader {
 
   private:
     mutable std::shared_mutex mtx;
-    std::unordered_map<std::string, Result> results;
+    StringMap<Result> results;
     std::atomic<size_t> resolvedCount = 0;
 
   public:
     explicit SymbolQuery(const std::vector<std::string> &symbols) {
+      // results.reserve(symbols.size());
       for (const auto &s : symbols)
-        results.emplace(s, Result{s, ""});
+        results.insert({s, Result{s, ""}});
     }
 
-    std::vector<std::string> getUnresolvedSymbols() const {
-      std::vector<std::string> unresolved;
+    std::vector<StringRef> getUnresolvedSymbols() const {
+      std::vector<StringRef> unresolved;
       std::shared_lock lock(mtx);
       for (const auto &[name, res] : results) {
         if (res.ResolvedLibPath.empty())
@@ -373,12 +379,12 @@ class DynamicLoader {
       return unresolved;
     }
 
-    void resolve(const std::string &symbol, const std::string &libPath) {
+    void resolve(StringRef symbol, const std::string &libPath) {
       std::unique_lock lock(mtx);
       auto it = results.find(symbol);
       if (it != results.end() && it->second.ResolvedLibPath.empty()) {
         it->second.ResolvedLibPath = libPath;
-        ++resolvedCount;
+        resolvedCount.fetch_add(1, std::memory_order_relaxed);
       }
     }
 
@@ -390,26 +396,26 @@ class DynamicLoader {
       return resolvedCount.load(std::memory_order_relaxed) < results.size();
     }
 
-    std::optional<std::string> getResolvedLib(const std::string &symbol) const {
+    std::optional<StringRef> getResolvedLib(StringRef symbol) const {
       std::shared_lock lock(mtx);
       auto it = results.find(symbol);
       if (it != results.end() && !it->second.ResolvedLibPath.empty())
-        return it->second.ResolvedLibPath;
+        return StringRef(it->second.ResolvedLibPath);
       return std::nullopt;
     }
 
-    bool isResolved(const std::string &symbol) const {
+    bool isResolved(StringRef symbol) const {
       std::shared_lock lock(mtx);
-      auto it = results.find(symbol);
+      auto it = results.find(symbol.str());
       return it != results.end() && !it->second.ResolvedLibPath.empty();
     }
 
-    std::vector<Result> getAllResults() const {
+    std::vector<const Result *> getAllResults() const {
       std::shared_lock lock(mtx);
-      std::vector<Result> out;
+      std::vector<const Result *> out;
       out.reserve(results.size());
       for (const auto &[_, res] : results)
-        out.push_back(res);
+        out.push_back(&res);
       return out;
     }
   };
@@ -426,12 +432,13 @@ class DynamicLoader {
 
     BloomFilterBuilder filterBuilder = BloomFilterBuilder();
 
-    static Setup create(
-        std::vector<std::string> basePaths,
-        std::shared_ptr<LibraryPathCache> existingCache = nullptr,
-        std::shared_ptr<PathResolver> existingResolver = nullptr,
-        //  std::shared_ptr<DylibPathResolver> existingDylibResolver = nullptr,
-        LibraryScanner::shouldScanFn customShouldScan = nullptr) {
+    static Setup
+    create(std::vector<std::string> basePaths,
+           std::shared_ptr<LibraryPathCache> existingCache = nullptr,
+           std::shared_ptr<PathResolver> existingResolver = nullptr,
+           //  std::shared_ptr<DylibPathResolver> existingDylibResolver =
+           //  nullptr,
+           LibraryScanner::shouldScanFn customShouldScan = nullptr) {
       Setup setup;
       setup.basePaths = std::move(basePaths);
 
@@ -464,10 +471,10 @@ class DynamicLoader {
   void scanLibrariesIfNeeded(LibraryManager::Kind K);
   void resolveSymbolsInLibrary(LibraryInfo &library, SymbolQuery &query);
   bool
-  symbolExistsInLibrary(const LibraryInfo &library, llvm::StringRef symbol,
+  symbolExistsInLibrary(const LibraryInfo &library, StringRef symbol,
                         std::vector<std::string> *matchedSymbols = nullptr);
 
-  bool symbolExistsInLibrary(const LibraryInfo &lib, llvm::StringRef symbolName,
+  bool symbolExistsInLibrary(const LibraryInfo &lib, StringRef symbolName,
                              std::vector<std::string> *allSymbols,
                              const SymbolEnumerator::Options &opts);
 
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index ffe41c118c84e..d55f82ed105af 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -157,8 +157,8 @@ class LibraryScanHelper {
                              std::shared_ptr<PathResolver> m_resolver)
       : m_cache(std::move(m_cache)), m_resolver(std::move(m_resolver)) {
     // LLVM_DEBUG(
-    llvm::dbgs() << "LibraryScanHelper::LibraryScanHelper: base paths : "
-                 << paths.size() << "\n"; //);
+    dbgs() << "LibraryScanHelper::LibraryScanHelper: base paths : "
+           << paths.size() << "\n"; //);
     for (const auto &p : paths)
       addBasePath(p);
   }
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
index 5388d8d1aa9c0..0abff22611bb8 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
@@ -9,6 +9,8 @@
 #include "llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h"
 
+#include "llvm/ADT/StringSet.h"
+
 #include "llvm/BinaryFormat/MachO.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Object/ELF.h"
@@ -17,6 +19,9 @@
 #include "llvm/Object/ObjectFile.h"
 #include "llvm/Support/Error.h"
 
+#include <mutex>
+#include <thread>
+
 #define DEBUG_TYPE "orc"
 
 namespace llvm::orc {
@@ -90,7 +95,7 @@ bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
       if (Name.empty())
         continue;
 
-      EnumerateResult Res = OnEach(Name.str());
+      EnumerateResult Res = OnEach(Name);
       if (Res != EnumerateResult::Continue)
         return Res;
     }
@@ -117,7 +122,7 @@ bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
       if (Name.empty())
         continue;
 
-      if (OnEach(Name.str()) != EnumerateResult::Continue)
+      if (OnEach(Name) != EnumerateResult::Continue)
         return false;
     }
   } else if (Obj->isMachO()) {
@@ -147,16 +152,14 @@ void DynamicLoader::resolveSymbolsInLibrary(LibraryInfo &lib,
     // );
     SymbolEnumerator::enumerateSymbols(
         lib.getFullPath(),
-        [&](const std::string &sym) {
-          discoveredSymbols.insert(sym);
+        [&](StringRef sym) {
+          discoveredSymbols.insert(sym.str());
           return SymbolEnumerator::Result::Continue;
         },
         opts);
   };
 
-  const auto &unresolved = unresolvedSymbols.getUnresolvedSymbols();
-
-  if (unresolved.empty()) {
+  if (!unresolvedSymbols.hasUnresolved()) {
     // LLVM_DEBUG(
     dbgs() << "Skipping library: " << lib.getFullPath()
            << " — unresolved symbols exist.\n";
@@ -174,12 +177,13 @@ void DynamicLoader::resolveSymbolsInLibrary(LibraryInfo &lib,
       dbgs() << "discoveredSymbols : " << sym << "\n";
   }
 
+  const auto &unresolved = unresolvedSymbols.getUnresolvedSymbols();
   for (const auto &symbol : unresolved) {
     if (lib.mayContain(symbol)) {
       // LLVM_DEBUG(
       dbgs() << "Checking symbol '" << symbol
              << "' in library: " << lib.getFullPath() << "\n"; //);
-      if (discoveredSymbols.count(symbol) > 0) {
+      if (discoveredSymbols.count(symbol.str()) > 0) {
         // LLVM_DEBUG(
         dbgs() << "  Resolved symbol: " << symbol
                << " in library: " << lib.getFullPath() << "\n"; //);
@@ -225,43 +229,22 @@ void DynamicLoader::searchSymbolsInLibraries(
   }
 
 done:
-  // LLVM_DEBUG(
-  dbgs() << "Search complete.\n"; //);
+  // LLVM_DEBUG({
+  dbgs() << "Search complete.\n";
+  for (const auto &r : query.getAllResults())
+    dbgs() << "Resolved Symbol:" << r->Name << " -> " << r->ResolvedLibPath
+           << "\n";
+  //});
+
   // ProcessLib(query.getResolvedPath());
   onComplete(query);
 }
 
-// void DynamicLoader::searchSymbolsInLibraries(
-//     std::vector<std::string> &symbolList, OnSearchComplete onComplete) {
-//   SymbolQuery query(symbolList);
-
-//   auto tryResolveFrom = [&](const LibraryCollection &libraries,
-//                             bool isUserLib) {
-//     scanLibrariesIfNeeded(libraries, isUserLib);
-//     for (const auto &lib : libraries) {
-//       // can use Async here?
-//       tryToResolveSymbols(lib, query);
-//       if (query.allResolved())
-//         break;
-//     }
-//   };
-
-//   tryResolveFrom(loadedLibs, /*isUserLib=*/false);
-
-//   if (!query.allResolved())
-//     tryResolveFrom(usrLibs, /*isUserLib=*/true);
-
-//   if (!query.allResolved() && includesys)
-//     tryResolveFrom(sysLibs, /*isUserLib=*/false);
-
-//   onComplete(query);
-// }
-
 void DynamicLoader::scanLibrariesIfNeeded(LibraryManager::Kind PK) {
   // LLVM_DEBUG(
-  llvm::dbgs() << "DynamicLoader::scanLibrariesIfNeeded: Scanning for "
-               << (PK == LibraryManager::Kind::User ? "User" : "System")
-               << " libraries\n"; //);
+  dbgs() << "DynamicLoader::scanLibrariesIfNeeded: Scanning for "
+         << (PK == LibraryManager::Kind::User ? "User" : "System")
+         << " libraries\n"; //);
   LibraryScanner Scanner(ScanH, LibMgr, m_shouldScan);
   Scanner.scanNext(PK == LibraryManager::Kind::User ? PathKind::User
                                                     : PathKind::System);
@@ -284,9 +267,9 @@ bool DynamicLoader::symbolExistsInLibrary(
 
   SymbolEnumerator::enumerateSymbols(
       lib.getFullPath(),
-      [&](const std::string &sym) {
+      [&](StringRef sym) {
         if (allSymbols)
-          allSymbols->emplace_back(sym);
+          allSymbols->emplace_back(sym.str());
 
         if (sym == symbolName) {
           found = true;
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 436c8fce75a15..75dcabb9a5d42 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -51,7 +51,7 @@ bool isLibraryFile(StringRef filename) {
 
 template <class ELFT>
 bool isELFSharedLibrary(const object::ELFFile<ELFT> &ELFObj) {
-  return ELFObj.getHeader().e_type == llvm::ELF::ET_DYN;
+  return ELFObj.getHeader().e_type == ELF::ET_DYN;
 }
 
 bool isSharedLibrary(StringRef Path) {
@@ -111,7 +111,7 @@ std::optional<std::string> DylibPathResolver::substOne(StringRef path,
   if (path.size() < pattern.size() || !path.starts_with_insensitive(pattern))
     return std::nullopt;
 
-  llvm::SmallString<256> result(replacement);
+  SmallString<256> result(replacement);
   result.append(path.drop_front(pattern.size()));
 
   return normalizeIfShared(result);
@@ -121,16 +121,16 @@ std::optional<std::string> DylibPathResolver::substAll(StringRef original,
                                                        StringRef loaderPath) {
 
 #ifdef __APPLE__
-  llvm::SmallString<256> mainExecutablePath(
-      llvm::sys::fs::getMainExecutable(nullptr, nullptr));
-  llvm::sys::path::remove_filename(mainExecutablePath);
+  SmallString<256> mainExecutablePath(
+      sys::fs::getMainExecutable(nullptr, nullptr));
+  sys::path::remove_filename(mainExecutablePath);
 
-  llvm::SmallString<256> loaderDir;
+  SmallString<256> loaderDir;
   if (loaderPath.empty())
     loaderDir = mainExecutablePath;
   else {
     loaderDir = loaderPath;
-    llvm::sys::path::remove_filename(loaderDir);
+    sys::path::remove_filename(loaderDir);
   }
 
   // Try @loader_path
@@ -142,13 +142,13 @@ std::optional<std::string> DylibPathResolver::substAll(StringRef original,
     return path;
 
 #else
-  llvm::SmallString<256> loaderDir;
+  SmallString<256> loaderDir;
   if (loaderPath.empty())
-    loaderDir = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+    loaderDir = sys::fs::getMainExecutable(nullptr, nullptr);
   else
     loaderDir = loaderPath;
 
-  llvm::sys::path::remove_filename(loaderDir);
+  sys::path::remove_filename(loaderDir);
 
   // Try $origin
   if (auto path = substOne(original, "$origin", loaderDir))
@@ -168,8 +168,8 @@ DylibPathResolver::tryWithBasePaths(ArrayRef<StringRef> basePaths,
     if (!resolvedBaseOpt)
       continue;
 
-    llvm::SmallString<256> fullPath(*resolvedBaseOpt);
-    llvm::sys::path::append(fullPath, stem);
+    SmallString<256> fullPath(*resolvedBaseOpt);
+    sys::path::append(fullPath, stem);
 
     if (auto norm = normalizeIfShared(fullPath)) {
       return norm;
@@ -214,7 +214,7 @@ std::optional<std::string> DylibPathResolver::tryWithExtensions(
 #endif
 
   // Optionally try "lib" prefix if not already there
-  StringRef filename = llvm::sys::path::filename(baseName);
+  StringRef filename = sys::path::filename(baseName);
   if (!filename.starts_with("lib")) {
     SmallString<256> withPrefix("lib");
     withPrefix += filename;
@@ -256,7 +256,7 @@ DylibPathResolver::resolve(StringRef libStem, SmallVector<StringRef, 2> RPath,
                            SmallVector<StringRef, 2> RunPath,
                            StringRef libLoader, bool variateLibStem) {
   // If it is an absolute path, don't try iterate over the paths.
-  if (llvm::sys::path::is_absolute(libStem)) {
+  if (sys::path::is_absolute(libStem)) {
     return normalizeIfShared(libStem);
   }
 
@@ -447,9 +447,11 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
   }
 
   normalizePathSegments(Components);
+  // LLVM_DEBUG({
   for (auto &C : Components)
-    // LLVM_DEBUG(
-    dbgs() << " " << C << "\n"; //);
+    dbgs() << " " << C << " ";
+
+  dbgs() << "\n"; //});
 
   // Handle path list items
   for (const auto &component : Components) {
@@ -468,8 +470,9 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
       auto symlinkOpt = readlinkCached(resolvedPath);
       if (!symlinkOpt) {
         ec = std::make_error_code(std::errc::no_such_file_or_directory);
-        // std::unique_lock lock(m_mutex);
-        // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+        std::unique_lock lock(m_mutex);
+        m_cache->m_realpathCache.emplace(path,
+                                         LibraryPathCache::PathInfo{"", ec});
         // LLVM_DEBUG(
         dbgs() << "    Failed to read symlink: " << resolvedPath << "\n"; //);
 
@@ -486,7 +489,9 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
           realpathCached(symlink.str(), ec, resolved,
                          /*baseIsResolved=*/true, symloopLevel - 1);
       if (!realSymlink) {
-        // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+        std::unique_lock lock(m_mutex);
+        m_cache->m_realpathCache.emplace(path,
+                                         LibraryPathCache::PathInfo{"", ec});
         // LLVM_DEBUG(
         dbgs() << "    Failed to resolve symlink target: " << symlink
                << "\n"; //);
@@ -500,8 +505,9 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
 
     } else if (st_mode == 0) {
       ec = std::make_error_code(std::errc::no_such_file_or_directory);
-      // std::unique_lock lock(m_mutex);
-      // m_cache->m_realpathCache.emplace(path, PathInfo{"", ec});
+      std::unique_lock lock(m_mutex);
+      m_cache->m_realpathCache.emplace(path,
+                                       LibraryPathCache::PathInfo{"", ec});
       // LLVM_DEBUG(
       dbgs() << "    Component does not exist: " << resolvedPath << "\n"; //);
 
@@ -531,16 +537,15 @@ void LibraryScanHelper::addBasePath(const std::string &path) {
   std::string canon = resolveCanonical(path, ec);
   if (ec) {
     // LLVM_DEBUG(
-    llvm::dbgs()
-        << "LibraryScanHelper::addBasePath: Failed to canonicalize path: "
-        << path << "\n"; //);
+    dbgs() << "LibraryScanHelper::addBasePath: Failed to canonicalize path: "
+           << path << "\n"; //);
     return;
   }
   std::unique_lock lock(m_mutex);
   if (m_units.count(canon)) {
     // LLVM_DEBUG(
-    llvm::dbgs() << "LibraryScanHelper::addBasePath: Already added: " << canon
-                 << "\n"; //);
+    dbgs() << "LibraryScanHelper::addBasePath: Already added: " << canon
+           << "\n"; //);
     return;
   }
   PathKind kind = classifyKind(canon);
@@ -549,13 +554,13 @@ void LibraryScanHelper::addBasePath(const std::string &path) {
 
   if (kind == PathKind::User) {
     // LLVM_DEBUG(
-    llvm::dbgs() << "LibraryScanHelper::addBasePath: Added User path: " << canon
-                 << "\n"; //);
+    dbgs() << "LibraryScanHelper::addBasePath: Added User path: " << canon
+           << "\n"; //);
     m_unscannedUsr.push_back(canon);
   } else {
     // LLVM_DEBUG(
-    llvm::dbgs() << "LibraryScanHelper::addBasePath: Added System path: "
-                 << canon << "\n"; //);
+    dbgs() << "LibraryScanHelper::addBasePath: Added System path: " << canon
+           << "\n"; //);
     m_unscannedSys.push_back(canon);
   }
 }
@@ -744,7 +749,8 @@ Expected<LibraryDepsInfo> parseELF(const object::ELFFile<ELFT> &Elf) {
 
 Expected<LibraryDepsInfo> parseELFDeps(const object::ELFObjectFileBase &obj) {
   using namespace object;
-
+  // LLVM_DEBUG(
+  dbgs() << "parseELFDeps: Detected ELF object\n"; //);
   if (const auto *ELF = dyn_cast<ELF32LEObjectFile>(&obj))
     return parseELF(ELF->getELFFile());
   else if (const auto *ELF = dyn_cast<ELF32BEObjectFile>(&obj))
@@ -754,25 +760,55 @@ Expected<LibraryDepsInfo> parseELFDeps(const object::ELFObjectFileBase &obj) {
   else if (const auto *ELF = dyn_cast<ELF64BEObjectFile>(&obj))
     return parseELF(ELF->getELFFile());
 
+  // LLVM_DEBUG(
+  dbgs() << "parseELFDeps: Unknown ELF format\n"; //);
   return createStringError(std::errc::not_supported, "Unknown ELF format");
 }
 
+void handleError(Error Err) {
+  consumeError(llvm::handleErrors(std::move(Err), [](const ErrorInfoBase &EIB) {
+    dbgs() << "LLVM Error: " << EIB.message() << "\n";
+  }));
+}
+
+template <typename T> T handleErrorAndReturn(Error Err, T ReturnValue) {
+  handleError(std::move(Err));
+  return ReturnValue;
+}
+
 Expected<LibraryDepsInfo> LibraryScanner::extractDeps(StringRef filePath) {
+  // LLVM_DEBUG(
+  dbgs() << "extractDeps: Attempting to open file " << filePath << "\n"; //);
+
   auto ObjOrErr = object::ObjectFile::createObjectFile(filePath);
-  if (!ObjOrErr)
+  if (!ObjOrErr) {
+    // LLVM_DEBUG(
+    dbgs() << "extractDeps: Failed to open " << filePath << "\n"; //);
+    consumeError(ObjOrErr.takeError());
+    return handleErrorAndReturn(ObjOrErr.takeError(),
+                                createStringError(std::errc::file_exists,
+                                                  "Failed to open %s",
+                                                  filePath.str().c_str()));
     return createStringError(std::errc::file_exists, "Failed to open %s",
                              filePath.str().c_str());
-
+  }
   object::ObjectFile *Obj = ObjOrErr.get().getBinary();
 
   if (auto *elfObj = dyn_cast<object::ELFObjectFileBase>(Obj)) {
+    // LLVM_DEBUG(
+    dbgs() << "extractDeps: File " << filePath << " is an ELF object\n"; //);
+
     return parseELFDeps(*elfObj);
   }
 
   if (auto *macho = dyn_cast<object::MachOObjectFile>(Obj)) {
+    // LLVM_DEBUG(
+    dbgs() << "extractDeps: File " << filePath << " is a Mach-O object\n"; //);
     return parseMachODeps(*macho);
   }
-
+  // LLVM_DEBUG(
+  dbgs() << "extractDeps: Unsupported binary format for file " << filePath
+         << "\n"; //);
   return createStringError(inconvertibleErrorCode(),
                            "Unsupported binary format: %s",
                            filePath.str().c_str());
@@ -796,16 +832,16 @@ std::optional<std::string> LibraryScanner::shouldScan(StringRef filePath) {
   if (sys::fs::is_directory(CanonicalPath))
     return std::nullopt;
 
-  // [4] Skip if we've already seen this path (via cache)
-  if (m_helper.hasSeen(CanonicalPath))
+  // [4] Skip if it's not a shared library.
+  if (!isSharedLibrary(CanonicalPath))
     return std::nullopt;
 
-  // [5] Already tracked in LibraryManager?
-  if (m_libMgr.hasLibrary(CanonicalPath))
+  // [5] Skip if we've already seen this path (via cache)
+  if (m_helper.hasSeen(CanonicalPath))
     return std::nullopt;
 
-  // [6] Is this a shared library?
-  if (!isSharedLibrary(CanonicalPath))
+  // [6] Already tracked in LibraryManager?
+  if (m_libMgr.hasLibrary(CanonicalPath))
     return std::nullopt;
 
   // [7] Run user-defined hook (default: always true)
@@ -833,8 +869,7 @@ void LibraryScanner::handleLibrary(StringRef filePath, PathKind K, int level) {
   if (!DepsOrErr) {
     // LLVM_DEBUG(
     dbgs() << "  Failed to extract deps for: " << CanonicalPath << "\n"; //);
-
-    consumeError(DepsOrErr.takeError());
+    handleError(DepsOrErr.takeError());
     return;
   }
 
@@ -860,7 +895,7 @@ void LibraryScanner::handleLibrary(StringRef filePath, PathKind K, int level) {
   // Heuristic 1: No RPATH/RUNPATH, skip deps
   if (Deps.rpath.empty() && Deps.runPath.empty()) {
     // LLVM_DEBUG(
-    dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic1): "
+    dbgs() << "LibraryScanner::handleLibrary: Skipping deps (Heuristic1): "
            << CanonicalPath << "\n"; //);
     return;
   }
@@ -874,7 +909,7 @@ void LibraryScanner::handleLibrary(StringRef filePath, PathKind K, int level) {
 
   if (allTracked(Deps.rpath) && allTracked(Deps.runPath)) {
     // LLVM_DEBUG(
-    dbgs() << "Dyld::ScanForLibraries: Skipping deps (Heuristic2): "
+    dbgs() << "LibraryScanner::handleLibrary: Skipping deps (Heuristic2): "
            << CanonicalPath << "\n"; //);
     return;
   }

>From cef69e40cbf1808fb5cd71343bd278666bc586f5 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sun, 13 Jul 2025 12:03:34 +0530
Subject: [PATCH 4/6] Fix some compilation issues

---
 .../Orc/TargetProcess/DynamicLoader.h         | 107 ++++--------------
 .../Orc/TargetProcess/LibraryScanner.h        |  21 +++-
 .../Orc/TargetProcess/DynamicLoader.cpp       |  13 ++-
 .../Orc/TargetProcess/LibraryScanner.cpp      |  26 ++---
 4 files changed, 55 insertions(+), 112 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
index ef42f3897f9cc..6492823aa0d56 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/DynamicLoader.h
@@ -20,83 +20,13 @@
 #include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h"
 #include "llvm/Support/Path.h"
 
+#include <atomic>
 #include <shared_mutex>
 #include <unordered_map>
 
 namespace llvm {
 namespace orc {
 
-// template <typename Iterator, typename Predicate, typename Projection>
-// class FilterIterator {
-// public:
-//   FilterIterator(Iterator current, Iterator end, Predicate pred,
-//                  Projection proj)
-//       : current_(current), end_(end), pred_(pred), proj_(proj) {
-//     advance_to_valid();
-//   }
-
-//   decltype(auto) operator*() { return proj_(*current_); }
-
-//   FilterIterator &operator++() {
-//     ++current_;
-//     advance_to_valid();
-//     return *this;
-//   }
-
-//   bool operator!=(const FilterIterator &other) const {
-//     return current_ != other.current_;
-//   }
-
-// private:
-//   void advance_to_valid() {
-//     while (current_ != end_ && !pred_(*current_)) {
-//       ++current_;
-//     }
-//   }
-
-//   Iterator current_, end_;
-//   Predicate pred_;
-//   Projection proj_;
-// };
-
-// template <typename Iterator, typename Predicate, typename Projection>
-// class FilterView {
-// public:
-//   FilterView(Iterator begin, Iterator end, Predicate pred, Projection proj)
-//       : begin_(begin), end_(end), pred_(pred), proj_(proj) {}
-
-//   auto begin() {
-//     return FilterIterator<Iterator, Predicate, Projection>(begin_, end_,
-//     pred_,
-//                                                            proj_);
-//   }
-
-//   auto end() {
-//     return FilterIterator<Iterator, Predicate, Projection>(end_, end_, pred_,
-//                                                            proj_);
-//   }
-
-//   template <typename Iterator, typename Predicate, typename Projection>
-//   static auto make_filter_view(Iterator begin, Iterator end, Predicate pred,
-//                                Projection proj) {
-//     return FilterView<Iterator, Predicate, Projection>(begin, end, pred,
-//     proj);
-//   }
-
-//   template <typename Iterator, typename Predicate>
-//   static auto make_filter_view(Iterator begin, Iterator end, Predicate pred)
-//   {
-//     return FilterView<Iterator, Predicate,
-//                       decltype([](auto &x) -> decltype(auto) { return x; })>(
-//         begin, end, pred, [](auto &x) -> decltype(auto) { return x; });
-//   }
-
-// private:
-//   Iterator begin_, end_;
-//   Predicate pred_;
-//   Projection proj_;
-// };
-
 /// Manages library metadata and state for symbol resolution.
 ///
 /// Tracks libraries by load state and kind (user/system), and stores
@@ -123,7 +53,7 @@ class LibraryManager {
     std::string getFullPath() const { return filePath; }
 
     bool setFilter(BloomFilter F) {
-      std::lock_guard lock(mutex);
+      std::lock_guard<std::shared_mutex> lock(mutex);
       if (filter)
         return false;
       filter.emplace(std::move(F));
@@ -132,7 +62,7 @@ class LibraryManager {
 
     bool ensureFilterBuilt(const BloomFilterBuilder &FB,
                            const std::vector<std::string> &symbols) {
-      std::lock_guard lock(mutex);
+      std::lock_guard<std::shared_mutex> lock(mutex);
       if (filter)
         return false;
       filter.emplace(FB.build(symbols));
@@ -141,12 +71,12 @@ class LibraryManager {
 
     bool mayContain(StringRef symbol) const {
       assert(hasFilter());
-      std::shared_lock lock(mutex);
+      std::shared_lock<std::shared_mutex> lock(mutex);
       return filter->mayContain(symbol);
     }
 
     bool hasFilter() const {
-      std::shared_lock lock(mutex);
+      std::shared_lock<std::shared_mutex> lock(mutex);
       return filter.has_value();
     }
 
@@ -286,12 +216,12 @@ class LibraryManager {
   }
 
   FilteredView getView(State s, Kind k) const {
-    std::shared_lock lock(mutex);
+    std::shared_lock<std::shared_mutex> lock(mutex);
     return FilteredView(libraries.begin(), libraries.end(), s, k);
   }
 
   void forEachLibrary(const LibraryVisitor &visitor) const {
-    std::unique_lock lock(mutex);
+    std::unique_lock<std::shared_mutex> lock(mutex);
     for (const auto &[_, entry] : libraries) {
       if (!visitor(*entry))
         break;
@@ -299,21 +229,21 @@ class LibraryManager {
   }
 
   bool isLoaded(StringRef path) const {
-    std::unique_lock lock(mutex);
+    std::unique_lock<std::shared_mutex> lock(mutex);
     if (auto it = libraries.find(path.str()); it != libraries.end())
       return it->second->getState() == State::Loaded;
     return false;
   }
 
   bool isQueried(StringRef path) const {
-    std::unique_lock lock(mutex);
+    std::unique_lock<std::shared_mutex> lock(mutex);
     if (auto it = libraries.find(path.str()); it != libraries.end())
       return it->second->getState() == State::Queried;
     return false;
   }
 
   void clear() {
-    std::unique_lock lock(mutex);
+    std::unique_lock<std::shared_mutex> lock(mutex);
     libraries.clear();
   }
 };
@@ -326,6 +256,8 @@ using LibraryInfo = LibraryManager::LibraryInfo;
 /// symbol resolution results through SymbolQuery. Thread-safe and uses
 /// LibraryScanHelper for efficient path resolution and caching.
 class DynamicLoader {
+  friend class LoaderControllerImpl;
+
 public:
   class SymbolEnumerator {
   public:
@@ -371,7 +303,7 @@ class DynamicLoader {
 
     std::vector<StringRef> getUnresolvedSymbols() const {
       std::vector<StringRef> unresolved;
-      std::shared_lock lock(mtx);
+      std::shared_lock<std::shared_mutex> lock(mtx);
       for (const auto &[name, res] : results) {
         if (res.ResolvedLibPath.empty())
           unresolved.push_back(name);
@@ -380,7 +312,7 @@ class DynamicLoader {
     }
 
     void resolve(StringRef symbol, const std::string &libPath) {
-      std::unique_lock lock(mtx);
+      std::unique_lock<std::shared_mutex> lock(mtx);
       auto it = results.find(symbol);
       if (it != results.end() && it->second.ResolvedLibPath.empty()) {
         it->second.ResolvedLibPath = libPath;
@@ -397,7 +329,7 @@ class DynamicLoader {
     }
 
     std::optional<StringRef> getResolvedLib(StringRef symbol) const {
-      std::shared_lock lock(mtx);
+      std::shared_lock<std::shared_mutex> lock(mtx);
       auto it = results.find(symbol);
       if (it != results.end() && !it->second.ResolvedLibPath.empty())
         return StringRef(it->second.ResolvedLibPath);
@@ -405,13 +337,13 @@ class DynamicLoader {
     }
 
     bool isResolved(StringRef symbol) const {
-      std::shared_lock lock(mtx);
+      std::shared_lock<std::shared_mutex> lock(mtx);
       auto it = results.find(symbol.str());
       return it != results.end() && !it->second.ResolvedLibPath.empty();
     }
 
     std::vector<const Result *> getAllResults() const {
-      std::shared_lock lock(mtx);
+      std::shared_lock<std::shared_mutex> lock(mtx);
       std::vector<const Result *> out;
       out.reserve(results.size());
       for (const auto &[_, res] : results)
@@ -480,15 +412,16 @@ class DynamicLoader {
 
   std::shared_ptr<LibraryPathCache> m_cache;
   std::shared_ptr<PathResolver> m_PathResolver;
-  LibraryScanHelper ScanH;
+  LibraryScanHelper m_scanH;
   BloomFilterBuilder FB;
-  LibraryManager LibMgr;
+  LibraryManager m_libMgr;
   LibraryScanner::shouldScanFn m_shouldScan;
   // std::shared_ptr<DylibPathResolver> m_DylibPathResolver;
   bool includeSys;
 };
 
 using SymbolEnumerator = DynamicLoader::SymbolEnumerator;
+using SymbolQuery = DynamicLoader::SymbolQuery;
 using EnumerateResult = SymbolEnumerator::Result;
 
 } // end namespace orc
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index d55f82ed105af..2420ff5c82b38 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 
+#include <atomic>
 #include <mutex>
 #include <queue>
 #include <shared_mutex>
@@ -37,12 +38,18 @@ class LibraryPathCache {
 public:
   LibraryPathCache() = default;
 
-  void clear();
+  void clear() {
+    std::unique_lock<std::shared_mutex> lock(m_mutex);
+    m_seen.clear();
+    m_readlinkCache.clear();
+    m_realpathCache.clear();
+    m_lstatCache.clear();
+  }
 
   void markSeen(const std::string &canon_path) { m_seen.insert(canon_path); }
 
   bool hasSeen(StringRef canon_path, bool cache = true) {
-    std::shared_lock lock(m_mutex);
+    std::shared_lock<std::shared_mutex> lock(m_mutex);
     std::string s = canon_path.str();
     if (m_seen.count(s) > 0)
       return true;
@@ -133,9 +140,9 @@ class DylibPathResolver {
   std::optional<std::string> normalizeIfShared(StringRef path);
 };
 
-enum class PathKind { User, System };
+enum class PathKind : uint8_t { User, System, Unknown };
 
-enum class ScanState { NotScanned, Scanning, Scanned };
+enum class ScanState : uint8_t { NotScanned, Scanning, Scanned };
 
 struct LibraryUnit {
   std::string basePath; // Canonical base directory path
@@ -163,8 +170,10 @@ class LibraryScanHelper {
       addBasePath(p);
   }
 
-  void addBasePath(
-      const std::string &path); // Add a canonical directory for scanning
+  void
+  addBasePath(const std::string &path,
+              PathKind Kind =
+                  PathKind::Unknown); // Add a canonical directory for scanning
   std::vector<std::shared_ptr<LibraryUnit>> getNextBatch(PathKind kind,
                                                          size_t batchSize);
 
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
index 0abff22611bb8..9168af976d993 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/DynamicLoader.cpp
@@ -31,12 +31,13 @@ DynamicLoader::DynamicLoader(const DynamicLoader::Setup &setup)
       m_PathResolver(setup.resolver ? setup.resolver
                                     : std::make_shared<PathResolver>(m_cache)),
       // m_DylibPathResolver(setup.dylibResolver),
-      ScanH(setup.basePaths, m_cache, m_PathResolver), FB(setup.filterBuilder),
-      LibMgr(), m_shouldScan(setup.shouldScan ? setup.shouldScan
-                                              : [](StringRef) { return true; }),
+      m_scanH(setup.basePaths, m_cache, m_PathResolver),
+      FB(setup.filterBuilder), m_libMgr(),
+      m_shouldScan(setup.shouldScan ? setup.shouldScan
+                                    : [](StringRef) { return true; }),
       includeSys(setup.includeSys) {
 
-  if (ScanH.getAllUnits().empty()) {
+  if (m_scanH.getAllUnits().empty()) {
     errs() << "Warning: No base paths provided for scanning.\n";
   }
 }
@@ -206,7 +207,7 @@ void DynamicLoader::searchSymbolsInLibraries(
     dbgs() << "Trying resolve from state=" << static_cast<int>(S)
            << " type=" << static_cast<int>(K) << "\n"; //);
     scanLibrariesIfNeeded(K);
-    for (auto &lib : LibMgr.getView(S, K)) {
+    for (auto &lib : m_libMgr.getView(S, K)) {
       // can use Async here?
       resolveSymbolsInLibrary(*lib, query);
       if (query.allResolved())
@@ -245,7 +246,7 @@ void DynamicLoader::scanLibrariesIfNeeded(LibraryManager::Kind PK) {
   dbgs() << "DynamicLoader::scanLibrariesIfNeeded: Scanning for "
          << (PK == LibraryManager::Kind::User ? "User" : "System")
          << " libraries\n"; //);
-  LibraryScanner Scanner(ScanH, LibMgr, m_shouldScan);
+  LibraryScanner Scanner(m_scanH, m_libMgr, m_shouldScan);
   Scanner.scanNext(PK == LibraryManager::Kind::User ? PathKind::User
                                                     : PathKind::System);
 }
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 75dcabb9a5d42..9c443b8375f77 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -298,7 +298,7 @@ std::optional<std::string> readlinkCached(const std::string &path) {
 
 mode_t PathResolver::lstatCached(const std::string &path) {
   // If already cached - retun cached result
-  std::unique_lock lock(m_mutex);
+  std::unique_lock<std::shared_mutex> lock(m_mutex);
 
   auto &cache = m_cache->m_lstatCache;
 
@@ -317,7 +317,7 @@ mode_t PathResolver::lstatCached(const std::string &path) {
 
 std::optional<std::string>
 PathResolver::readlinkCached(const std::string &path) {
-  std::unique_lock lock(m_mutex);
+  std::unique_lock<std::shared_mutex> lock(m_mutex);
   auto &cache = m_cache->m_readlinkCache;
   // If already cached - retun cached result
   auto it = cache.find(path);
@@ -408,7 +408,7 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
   // If already cached - retun cached result
   bool isRelative = sys::path::is_relative(path);
   {
-    std::shared_lock lock(m_mutex);
+    std::shared_lock<std::shared_mutex> lock(m_mutex);
     auto it = m_cache->m_realpathCache.find(path.str());
     if (it != m_cache->m_realpathCache.end()) {
       ec = it->second.errnoCode;
@@ -470,7 +470,7 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
       auto symlinkOpt = readlinkCached(resolvedPath);
       if (!symlinkOpt) {
         ec = std::make_error_code(std::errc::no_such_file_or_directory);
-        std::unique_lock lock(m_mutex);
+        std::unique_lock<std::shared_mutex> lock(m_mutex);
         m_cache->m_realpathCache.emplace(path,
                                          LibraryPathCache::PathInfo{"", ec});
         // LLVM_DEBUG(
@@ -489,7 +489,7 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
           realpathCached(symlink.str(), ec, resolved,
                          /*baseIsResolved=*/true, symloopLevel - 1);
       if (!realSymlink) {
-        std::unique_lock lock(m_mutex);
+        std::unique_lock<std::shared_mutex> lock(m_mutex);
         m_cache->m_realpathCache.emplace(path,
                                          LibraryPathCache::PathInfo{"", ec});
         // LLVM_DEBUG(
@@ -505,7 +505,7 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
 
     } else if (st_mode == 0) {
       ec = std::make_error_code(std::errc::no_such_file_or_directory);
-      std::unique_lock lock(m_mutex);
+      std::unique_lock<std::shared_mutex> lock(m_mutex);
       m_cache->m_realpathCache.emplace(path,
                                        LibraryPathCache::PathInfo{"", ec});
       // LLVM_DEBUG(
@@ -520,7 +520,7 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
 
   std::string canonical = resolved.str().str();
   {
-    std::unique_lock lock(m_mutex);
+    std::unique_lock<std::shared_mutex> lock(m_mutex);
     m_cache->m_realpathCache.emplace(path, LibraryPathCache::PathInfo{
                                                canonical,
                                                std::error_code() // success
@@ -532,7 +532,7 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
   return canonical;
 }
 
-void LibraryScanHelper::addBasePath(const std::string &path) {
+void LibraryScanHelper::addBasePath(const std::string &path, PathKind kind) {
   std::error_code ec;
   std::string canon = resolveCanonical(path, ec);
   if (ec) {
@@ -541,14 +541,14 @@ void LibraryScanHelper::addBasePath(const std::string &path) {
            << path << "\n"; //);
     return;
   }
-  std::unique_lock lock(m_mutex);
+  std::unique_lock<std::shared_mutex> lock(m_mutex);
   if (m_units.count(canon)) {
     // LLVM_DEBUG(
     dbgs() << "LibraryScanHelper::addBasePath: Already added: " << canon
            << "\n"; //);
     return;
   }
-  PathKind kind = classifyKind(canon);
+  kind = kind == PathKind::Unknown ? classifyKind(canon) : kind;
   auto unit = std::make_shared<LibraryUnit>(canon, kind);
   m_units[canon] = unit;
 
@@ -570,7 +570,7 @@ LibraryScanHelper::getNextBatch(PathKind kind, size_t batchSize) {
   std::vector<std::shared_ptr<LibraryUnit>> result;
   auto &queue = (kind == PathKind::User) ? m_unscannedUsr : m_unscannedSys;
 
-  std::unique_lock lock(m_mutex);
+  std::unique_lock<std::shared_mutex> lock(m_mutex);
 
   while (!queue.empty() && result.size() < batchSize) {
     const std::string &base = queue.front(); // no copy
@@ -594,13 +594,13 @@ bool LibraryScanHelper::isTrackedBasePath(const std::string &path) const {
   if (ec) {
     return false;
   }
-  std::shared_lock lock(m_mutex);
+  std::shared_lock<std::shared_mutex> lock(m_mutex);
   return m_units.count(canon) > 0;
 }
 
 std::vector<std::shared_ptr<LibraryUnit>>
 LibraryScanHelper::getAllUnits() const {
-  std::shared_lock lock(m_mutex);
+  std::shared_lock<std::shared_mutex> lock(m_mutex);
   std::vector<std::shared_ptr<LibraryUnit>> result;
   result.reserve(m_units.size());
   for (const auto &[_, unit] : m_units) {

>From e32a10a5be8ae8b6bfad5faf51b87e4450e9826a Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sun, 13 Jul 2025 15:08:17 +0530
Subject: [PATCH 5/6] Fix window build issue

---
 .../Orc/TargetProcess/LibraryScanner.h        |  12 +-
 .../Orc/TargetProcess/LibraryScanner.cpp      | 104 +++++++++---------
 2 files changed, 56 insertions(+), 60 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index 2420ff5c82b38..09150c5779759 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -86,8 +86,10 @@ class PathResolver {
                                      std::error_code &ec) {
     return realpathCached(path, ec);
   }
+#ifndef _WIN32
   mode_t lstatCached(const std::string &path);
   std::optional<std::string> readlinkCached(const std::string &path);
+#endif
   std::optional<std::string> realpathCached(StringRef path, std::error_code &ec,
                                             StringRef base = "",
                                             bool baseIsResolved = false,
@@ -115,15 +117,14 @@ class DylibPathResolver {
 private:
   LibraryScanHelper &m_helper;
 
-  std::optional<std::string> substOne(StringRef path, StringRef pattern,
+  std::string substOne(StringRef path, StringRef pattern,
                                       StringRef replacement);
 
   /// Apply all known loader substitutions to the path
-  std::optional<std::string> substAll(StringRef path, StringRef loaderPath);
+  std::string substAll(StringRef path, StringRef loaderPath);
 
-  std::optional<std::string> tryWithBasePaths(ArrayRef<StringRef> basePaths,
-                                              StringRef stem,
-                                              StringRef loaderPath);
+  std::optional<std::string> tryWithBasePath(StringRef basePath, StringRef stem,
+                                             StringRef loaderPath);
 
   /// Try resolving the path using RPATH, searchPaths, and RUNPATH (in that
   /// order)
@@ -138,6 +139,7 @@ class DylibPathResolver {
                                                StringRef loaderPath);
 
   std::optional<std::string> normalizeIfShared(StringRef path);
+  std::optional<std::string> normalize(StringRef path);
 };
 
 enum class PathKind : uint8_t { User, System, Unknown };
diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
index 9c443b8375f77..47251d3345eaa 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp
@@ -105,20 +105,19 @@ bool isSharedLibrary(StringRef Path) {
   return false;
 }
 
-std::optional<std::string> DylibPathResolver::substOne(StringRef path,
-                                                       StringRef pattern,
-                                                       StringRef replacement) {
+std::string DylibPathResolver::substOne(StringRef path, StringRef pattern,
+                                        StringRef replacement) {
   if (path.size() < pattern.size() || !path.starts_with_insensitive(pattern))
-    return std::nullopt;
+    return path.str();
 
   SmallString<256> result(replacement);
   result.append(path.drop_front(pattern.size()));
 
-  return normalizeIfShared(result);
+  return result.str().str();
 }
 
-std::optional<std::string> DylibPathResolver::substAll(StringRef original,
-                                                       StringRef loaderPath) {
+std::string DylibPathResolver::substAll(StringRef original,
+                                        StringRef loaderPath) {
 
 #ifdef __APPLE__
   SmallString<256> mainExecutablePath(
@@ -134,12 +133,9 @@ std::optional<std::string> DylibPathResolver::substAll(StringRef original,
   }
 
   // Try @loader_path
-  if (auto path = substOne(original, "@loader_path", loaderDir))
-    return path;
-
+  std::string result_path = substOne(original, "@loader_path", loaderDir);
   // Try @executable_path
-  if (auto path = substOne(original, "@executable_path", mainExecutablePath))
-    return path;
+  return substOne(result_path, "@executable_path", mainExecutablePath);
 
 #else
   SmallString<256> loaderDir;
@@ -151,31 +147,21 @@ std::optional<std::string> DylibPathResolver::substAll(StringRef original,
   sys::path::remove_filename(loaderDir);
 
   // Try $origin
-  if (auto path = substOne(original, "$origin", loaderDir))
-    return path;
+  return substOne(original, "$origin", loaderDir);
 
-    // Optional: handle $lib or $platform later if needed
+  // Optional: handle $lib or $platform later if needed
 #endif
-
-  return std::nullopt;
 }
 
 std::optional<std::string>
-DylibPathResolver::tryWithBasePaths(ArrayRef<StringRef> basePaths,
-                                    StringRef stem, StringRef loaderPath) {
-  for (const auto &base : basePaths) {
-    auto resolvedBaseOpt = substAll(base, loaderPath);
-    if (!resolvedBaseOpt)
-      continue;
+DylibPathResolver::tryWithBasePath(StringRef basePath, StringRef stem,
+                                   StringRef loaderPath) {
+  std::string resolvedBase = substAll(basePath, loaderPath);
 
-    SmallString<256> fullPath(*resolvedBaseOpt);
-    sys::path::append(fullPath, stem);
+  SmallString<256> fullPath(resolvedBase);
+  sys::path::append(fullPath, stem);
 
-    if (auto norm = normalizeIfShared(fullPath)) {
-      return norm;
-    }
-  }
-  return std::nullopt;
+  return normalizeIfShared(fullPath);
 }
 
 std::optional<std::string>
@@ -183,18 +169,22 @@ DylibPathResolver::tryAllPaths(StringRef stem, ArrayRef<StringRef> RPath,
                                ArrayRef<StringRef> RunPath,
                                StringRef loaderPath) {
   // Try RPATH
-  if (auto found = tryWithBasePaths(RPath, stem, loaderPath))
-    return found;
+  for (const auto &rpath : RPath) {
+    if (auto found = tryWithBasePath(rpath, stem, loaderPath))
+      return found;
+  }
 
   // Try search paths (like LD_LIBRARY_PATH or configured)
-  // for (const auto &entry : m_searchPaths) {
-  // TODO.
-  // }
+  for (const auto &entry : m_helper.getAllUnits()) {
+    if (auto found = tryWithBasePath(entry->basePath, stem, loaderPath))
+      return found;
+  }
 
   // Try RUNPATH
-  if (auto found = tryWithBasePaths(RunPath, stem, loaderPath))
-    return found;
-
+  for (const auto &runpath : RunPath) {
+    if (auto found = tryWithBasePath(runpath, stem, loaderPath))
+      return found;
+  }
   return std::nullopt;
 }
 
@@ -215,8 +205,10 @@ std::optional<std::string> DylibPathResolver::tryWithExtensions(
 
   // Optionally try "lib" prefix if not already there
   StringRef filename = sys::path::filename(baseName);
+  StringRef base = sys::path::parent_path(baseName);
+  SmallString<256> withPrefix(base);
   if (!filename.starts_with("lib")) {
-    SmallString<256> withPrefix("lib");
+    withPrefix += "lib";
     withPrefix += filename;
     // Apply extension too
 #if defined(__APPLE__)
@@ -226,7 +218,7 @@ std::optional<std::string> DylibPathResolver::tryWithExtensions(
 #else
     withPrefix += ".so";
 #endif
-    candidates.push_back(withPrefix);
+    candidates.push_back(withPrefix.str());
   }
 
   // Try all variants using tryAllPaths
@@ -238,17 +230,25 @@ std::optional<std::string> DylibPathResolver::tryWithExtensions(
   return std::nullopt;
 }
 
-std::optional<std::string>
-DylibPathResolver::normalizeIfShared(StringRef path) {
+std::optional<std::string> DylibPathResolver::normalize(StringRef path) {
   std::error_code ec;
   auto real = m_helper.getPathResolver().realpathCached(path, ec);
   if (!real || ec)
     return std::nullopt;
 
-  if (!isSharedLibrary(*real))
+  return real;
+}
+
+std::optional<std::string>
+DylibPathResolver::normalizeIfShared(StringRef path) {
+  auto realOpt = normalize(path);
+  if (!realOpt)
     return std::nullopt;
 
-  return real;
+  if (!isSharedLibrary(*realOpt))
+    return std::nullopt;
+
+  return realOpt;
 }
 
 std::optional<std::string>
@@ -265,12 +265,12 @@ DylibPathResolver::resolve(StringRef libStem, SmallVector<StringRef, 2> RPath,
   // On MacOS @rpath is preplaced by all paths in RPATH one by one.
   if (libStem.starts_with_insensitive("@rpath")) {
     for (auto &P : RPath) {
-      if (auto norm = substOne(libStem, "@rpath", P))
+      if (auto norm = normalizeIfShared(substOne(libStem, "@rpath", P)))
         return norm;
     }
   } else {
 #endif
-    if (auto norm = substAll(libStem, libLoader))
+    if (auto norm = normalizeIfShared(substAll(libStem, libLoader)))
       return norm;
 #ifdef __APPLE__
   }
@@ -289,13 +289,7 @@ DylibPathResolver::resolve(StringRef libStem, SmallVector<StringRef, 2> RPath,
   return std::nullopt;
 }
 
-#ifdef _WIN32
-mode_t lstatCached(const std::string &path) { return 0; }
-std::optional<std::string> readlinkCached(const std::string &path) {
-  return std::nullopt;
-}
-#else
-
+#ifndef _WIN32
 mode_t PathResolver::lstatCached(const std::string &path) {
   // If already cached - retun cached result
   std::unique_lock<std::shared_mutex> lock(m_mutex);
@@ -335,7 +329,6 @@ PathResolver::readlinkCached(const std::string &path) {
   }
   return std::nullopt;
 }
-#endif
 
 void createComponent(StringRef Path, StringRef base_path, bool baseIsResolved,
                      SmallVector<StringRef, 16> &component) {
@@ -380,6 +373,7 @@ void normalizePathSegments(SmallVector<StringRef, 16> &pathParts) {
   }
   pathParts.swap(normalizedPath);
 }
+#endif
 
 std::optional<std::string> PathResolver::realpathCached(StringRef path,
                                                         std::error_code &ec,
@@ -430,9 +424,9 @@ std::optional<std::string> PathResolver::realpathCached(StringRef path,
 
   // If result not in cache - call system function and cache result
 
+#ifndef _WIN32
   StringRef Separator(sys::path::get_separator());
   SmallString<256> resolved(Separator);
-#ifndef _WIN32
   SmallVector<StringRef, 16> Components;
 
   if (isRelative) {

>From c012916b63fb6878063f211b4e5e00c50ce87509 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sun, 13 Jul 2025 16:16:25 +0530
Subject: [PATCH 6/6] Minor fix related to windows

---
 .../llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
index 09150c5779759..ee7efc9cc9f71 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h
@@ -66,10 +66,12 @@ class LibraryPathCache {
     std::error_code errnoCode;
   };
 
-  std::unordered_map<std::string, std::string> m_readlinkCache;
+  std::unordered_set<std::string> m_seen;
   std::unordered_map<std::string, PathInfo> m_realpathCache;
+#ifndef _WIN32
+  std::unordered_map<std::string, std::string> m_readlinkCache;
   std::unordered_map<std::string, mode_t> m_lstatCache;
-  std::unordered_set<std::string> m_seen;
+#endif
 };
 
 /// Resolves file system paths with optional caching of results.



More information about the llvm-commits mailing list