LLVM 23.0.0git
LibraryResolver.h
Go to the documentation of this file.
1//===- LibraryResolver.h - Automatic Library Symbol Resolution -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides support for automatically searching symbols across
10// dynamic libraries that have not yet been loaded.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H
15#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H
16
20#include "llvm/Support/Path.h"
21
22#include <atomic>
23#include <shared_mutex>
24
25namespace llvm {
26namespace orc {
27
28class LibraryManager;
29
30enum class LibState : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
31
33public:
34 LibraryInfo(const LibraryInfo &) = delete;
35 LibraryInfo &operator=(const LibraryInfo &) = delete;
36
37 LibraryInfo(std::string FilePath, LibState S, PathType K,
38 std::optional<BloomFilter> Filter = std::nullopt)
39 : FilePath(std::move(FilePath)), S(S), K(K), Filter(std::move(Filter)) {}
40
41 StringRef getBasePath() const { return sys::path::parent_path(FilePath); }
42 StringRef getFileName() const { return sys::path::filename(FilePath); }
43
44 std::string getFullPath() const { return FilePath; }
45
47 std::lock_guard<std::shared_mutex> Lock(Mtx);
48 if (Filter)
49 return;
50 Filter.emplace(std::move(F));
51 }
52
54 ArrayRef<StringRef> Symbols) {
55 std::lock_guard<std::shared_mutex> Lock(Mtx);
56 if (Filter)
57 return;
58 Filter.emplace(FB.build(Symbols));
59 }
60
61 bool mayContain(StringRef Symbol) const {
63 std::shared_lock<std::shared_mutex> Lock(Mtx);
64 return Filter->mayContain(Symbol);
65 }
66
67 bool hasFilter() const {
68 std::shared_lock<std::shared_mutex> Lock(Mtx);
69 return Filter.has_value();
70 }
71
72 LibState getState() const { return S.load(); }
73 PathType getKind() const { return K; }
74
75 void setState(LibState s) { S.store(s); }
76
77 bool operator==(const LibraryInfo &other) const {
78 return FilePath == other.FilePath;
79 }
80
81private:
82 std::string FilePath;
83 std::atomic<LibState> S;
84 PathType K;
85 std::optional<BloomFilter> Filter;
86 mutable std::shared_mutex Mtx;
87};
88
89// The LibraryCursor iterates through a list of LibraryInfo pointers,
90// returning only those libraries that match a specified LibState. LibraryIndex
91// provides these lists based on PathType, and the cursor filters them as it
92// iterates.
94public:
95 LibraryCursor(const std::vector<const LibraryInfo *> &L, LibState S)
96 : Lists(L), S(S) {}
97
99 while (Pos < Lists.size()) {
100 const LibraryInfo *Lib = Lists[Pos++];
101 if (Lib->getState() == S)
102 return Lib;
103 }
104
105 return nullptr;
106 }
107
108 bool hasMoreValidLib() const { return Pos < Lists.size(); }
109
110private:
111 const std::vector<const LibraryInfo *> &Lists;
112 LibState S;
113 size_t Pos = 0; // cursor position
114};
115
116// LibraryIndex keeps libraries grouped by PathType and lets you
117// get a cursor to walk through libraries of a specific type/state.
119 friend LibraryManager;
120
121public:
123 static std::vector<const LibraryInfo *> Empty;
124 auto It = Lists.find(K);
125 if (It == Lists.end())
126 return LibraryCursor(Empty, S);
127
128 return LibraryCursor(It->second, S);
129 }
130
131 bool hasLibLeftFor(PathType K, uint32_t Idx) const {
132 auto It = Lists.find(K);
133 if (It == Lists.end())
134 return false;
135
136 const auto &L = It->second;
137 return L.size() > Idx;
138 }
139
140private:
141 void addLibrary(const LibraryInfo *Lib) {
142 Lists[Lib->getKind()].push_back(Lib);
143 }
144
145 void clear() { Lists.clear(); }
146
147 DenseMap<PathType, std::vector<const LibraryInfo *>> Lists;
148};
149
150/// Manages library metadata and state for symbol resolution.
151///
152/// Tracks libraries by load state and kind (user/system), and stores
153/// associated Bloom filters and hash maps to speed up symbol lookups.
154/// Thread-safe for concurrent access.
156public:
157 /// A read-only view of libraries filtered by state and kind.
158 ///
159 /// Lets you loop over only the libraries in a map that match a given State
160 /// and PathType.
162 public:
166 public:
168 : it(it_), end(end_), S(S), K(K) {
169 advance();
170 }
171
172 bool operator!=(const FilterIterator &other) const {
173 return it != other.it;
174 }
175
176 const LibraryInfo &operator*() const { return *it->second; }
177
179 ++it;
180 advance();
181 return *this;
182 }
183
184 private:
185 void advance() {
186 for (; it != end; ++it)
187 if (it->second->getState() == S && it->second->getKind() == K)
188 break;
189 }
190 Iterator it;
192 LibState S;
193 PathType K;
194 };
196 : mapBegin(begin), mapEnd(end), state(s), kind(k) {}
197
199 return FilterIterator(mapBegin, mapEnd, state, kind);
200 }
201
203 return FilterIterator(mapEnd, mapEnd, state, kind);
204 }
205
206 private:
207 Iterator mapBegin;
208 Iterator mapEnd;
209 LibState state;
210 PathType kind;
211 };
212
213private:
214 LibraryIndex Index;
216 mutable std::shared_mutex Mtx;
217
218public:
219 using LibraryVisitor = std::function<bool(const LibraryInfo &)>;
220
221 LibraryManager() = default;
222 ~LibraryManager() = default;
223
224 bool addLibrary(std::string Path, PathType Kind,
225 std::optional<BloomFilter> Filter = std::nullopt) {
226 std::unique_lock<std::shared_mutex> Lock(Mtx);
227 if (Libraries.count(Path) > 0)
228 return false;
229 std::unique_ptr<LibraryInfo> Lib = std::make_unique<LibraryInfo>(
230 Path, LibState::Unloaded, Kind, std::move(Filter));
231 const LibraryInfo *Ptr = Lib.get();
232 Libraries.insert({Path, std::move(Lib)});
233 Index.addLibrary(Ptr);
234 return true;
235 }
236
237 bool hasLibrary(StringRef Path) const {
238 std::shared_lock<std::shared_mutex> Lock(Mtx);
239 if (Libraries.count(Path) > 0)
240 return true;
241 return false;
242 }
243
245 std::unique_lock<std::shared_mutex> Lock(Mtx);
246 auto I = Libraries.find(Path);
247 if (I == Libraries.end())
248 return;
249 Libraries.erase(I);
250 }
251
253 std::unique_lock<std::shared_mutex> Lock(Mtx);
254 if (auto It = Libraries.find(Path); It != Libraries.end())
255 It->second->setState(LibState::Loaded);
256 }
257
259 std::unique_lock<std::shared_mutex> Lock(Mtx);
260 if (auto It = Libraries.find(Path); It != Libraries.end())
261 It->second->setState(LibState::Unloaded);
262 }
263
265 std::unique_lock<std::shared_mutex> Lock(Mtx);
266 if (auto It = Libraries.find(Path); It != Libraries.end())
267 It->second->setState(LibState::Queried);
268 }
269
270 const LibraryInfo *getLibrary(StringRef Path) const {
271 std::shared_lock<std::shared_mutex> Lock(Mtx);
272 if (auto It = Libraries.find(Path); It != Libraries.end())
273 return It->second.get();
274 return nullptr;
275 }
276
278 std::shared_lock<std::shared_mutex> Lock(Mtx);
279 return FilteredView(Libraries.begin(), Libraries.end(), S, K);
280 }
281
282 using LibraryFilterFn = std::function<bool(const LibraryInfo &)>;
284 std::vector<const LibraryInfo *> &Outs,
285 LibraryFilterFn Filter = nullptr) const {
286 std::shared_lock<std::shared_mutex> Lock(Mtx);
287 for (const auto &[_, Entry] : Libraries) {
288 const auto &Info = *Entry;
289 if (Info.getKind() != K || Info.getState() != S)
290 continue;
291 if (Filter && !Filter(Info))
292 continue;
293 Outs.push_back(&Info);
294 }
295 }
296
298 return Index.getCursor(K, S);
299 }
300
301 void forEachLibrary(const LibraryVisitor &visitor) const {
302 std::shared_lock<std::shared_mutex> Lock(Mtx);
303 for (const auto &[_, entry] : Libraries) {
304 if (!visitor(*entry))
305 break;
306 }
307 }
308
309 bool isLoaded(StringRef Path) const {
310 std::shared_lock<std::shared_mutex> Lock(Mtx);
311 if (auto It = Libraries.find(Path.str()); It != Libraries.end())
312 return It->second->getState() == LibState::Loaded;
313 return false;
314 }
315
316 bool isQueried(StringRef Path) const {
317 std::shared_lock<std::shared_mutex> Lock(Mtx);
318 if (auto It = Libraries.find(Path.str()); It != Libraries.end())
319 return It->second->getState() == LibState::Queried;
320 return false;
321 }
322
323 void clear() {
324 std::unique_lock<std::shared_mutex> Lock(Mtx);
325 Libraries.clear();
326 }
327};
328
330 LibState State; // Loaded, Queried, Unloaded
331 PathType Type; // User, System
332};
333
335 std::vector<SearchPlanEntry> Plan;
336
338 return {{{LibState::Loaded, PathType::User},
339 {LibState::Queried, PathType::User},
340 {LibState::Unloaded, PathType::User},
341 {LibState::Loaded, PathType::System},
342 {LibState::Queried, PathType::System},
343 {LibState::Unloaded, PathType::System}}};
344 }
345};
346
364
368
370 : Policy(SearchPolicy::defaultPlan()), // default plan
371 Options(SymbolEnumeratorOptions::defaultOptions()) {}
372};
373
374/// Scans libraries and resolves Symbols across user and system paths.
375///
376/// Supports symbol enumeration and filtering via SymbolEnumerator, and tracks
377/// symbol resolution results through SymbolQuery. Thread-safe and uses
378/// LibraryScanHelper for efficient path resolution and caching.
381
382public:
384 public:
386
387 using OnEachSymbolFn = std::function<EnumerateResult(StringRef Sym)>;
388
390 OnEachSymbolFn OnEach,
391 const SymbolEnumeratorOptions &Opts);
392 LLVM_ABI static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
393 const SymbolEnumeratorOptions &Opts);
394 };
395
396 /// Tracks a set of symbols and the libraries where they are resolved.
397 ///
398 /// SymbolQuery is used to keep track of which symbols have been resolved
399 /// to which libraries. It supports concurrent read/write access using a
400 /// shared mutex, allowing multiple readers or a single writer at a time.
402 public:
403 /// Holds the result for a single symbol.
404 struct Entry {
405 std::string Name;
406 std::string ResolvedLibPath;
407 };
408
409 private:
410 mutable std::shared_mutex Mtx;
412 std::atomic<size_t> ResolvedCount = 0;
413
414 public:
416 for (const auto &S : Symbols) {
417 if (!contains(S))
418 Entries.push_back({S.str(), ""});
419 }
420 }
421
422 bool contains(StringRef Name) const {
423 return llvm::any_of(Entries,
424 [&](const Entry &E) { return E.Name == Name; });
425 }
426
429 SymbolFilterFn Allow) const {
430 std::shared_lock<std::shared_mutex> Lock(Mtx);
431 for (const auto &E : Entries) {
432 if (E.ResolvedLibPath.empty() && Allow(E.Name))
433 Unresolved.push_back(E.Name);
434 }
435 }
436
437 void resolve(StringRef Sym, const std::string &LibPath) {
438 std::unique_lock<std::shared_mutex> Lock(Mtx);
439 for (auto &E : Entries) {
440 if (E.Name == Sym && E.ResolvedLibPath.empty()) {
441 E.ResolvedLibPath = LibPath;
442 ResolvedCount.fetch_add(1, std::memory_order_relaxed);
443 return;
444 }
445 }
446 }
447
448 bool allResolved() const {
449 return ResolvedCount.load(std::memory_order_relaxed) == Entries.size();
450 }
451
452 bool hasUnresolved() const {
453 return ResolvedCount.load(std::memory_order_relaxed) < Entries.size();
454 }
455
456 std::optional<StringRef> getResolvedLib(StringRef Sym) const {
457 std::shared_lock<std::shared_mutex> Lock(Mtx);
458 for (const auto &E : Entries)
459 if (E.Name == Sym && !E.ResolvedLibPath.empty())
460 return E.ResolvedLibPath;
461 return std::nullopt;
462 }
463
464 bool isResolved(StringRef Sym) const {
465 std::shared_lock<std::shared_mutex> Lock(Mtx);
466 for (const auto &E : Entries)
467 if (E.Name == Sym && !E.ResolvedLibPath.empty())
468 return true;
469 return false;
470 }
471
472 std::vector<const Entry *> getAllResults() const {
473 std::shared_lock<std::shared_mutex> Lock(Mtx);
474 std::vector<const Entry *> Out;
475 Out.reserve(Entries.size());
476 for (const auto &E : Entries)
477 Out.push_back(&E);
478 return Out;
479 }
480 };
481
482 struct Setup {
483 std::vector<std::string> BasePaths;
484 // std::shared_ptr<LibraryPathCache> Cache;
485 // std::shared_ptr<PathResolver> PResolver;
486
487 size_t ScanBatchSize = 0;
488
492
494
495 static Setup
496 create(std::vector<std::string> BasePaths,
497 // std::shared_ptr<LibraryPathCache> existingCache = nullptr,
498 // std::shared_ptr<PathResolver> existingResolver = nullptr,
499 LibraryScanner::ShouldScanFn customShouldScan = nullptr) {
500 Setup S;
501 S.BasePaths = std::move(BasePaths);
502
503 // S.Cache =
504 // existingCache ? existingCache :
505 // std::make_shared<LibraryPathCache>();
506
507 // S.PResolver = existingResolver ? existingResolver
508 // :
509 // std::make_shared<PathResolver>(S.Cache);
510
511 if (customShouldScan)
512 S.ShouldScanCall = std::move(customShouldScan);
513
514 return S;
515 }
516 };
517
518 LibraryResolver() = delete;
519 LLVM_ABI explicit LibraryResolver(const Setup &S);
520 ~LibraryResolver() = default;
521
523
524 void dump() {
525 int i = 0;
526 LibMgr.forEachLibrary([&](const LibraryInfo &Lib) -> bool {
527 dbgs() << ++i << ". Library Path : " << Lib.getFullPath() << " -> \n\t\t:"
528 << " ({Type : ("
529 << (Lib.getKind() == PathType::User ? "User" : "System")
530 << ") }, { State : "
531 << (Lib.getState() == LibState::Loaded ? "Loaded" : "Unloaded")
532 << "})\n";
533 return true;
534 });
535 }
536
537 LLVM_ABI void
539 OnSearchComplete OnComplete,
540 const SearchConfig &Config = SearchConfig());
541
542private:
543 LLVM_ABI bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
544 bool scanForNewLibraries(PathType K, LibraryCursor &Cur);
545 void resolveSymbolsInLibrary(LibraryInfo *Lib, SymbolQuery &Q,
546 const SymbolEnumeratorOptions &Opts);
547
548 LibraryManager LibMgr;
549 std::shared_ptr<LibraryPathCache> LibPathCache;
550 std::shared_ptr<PathResolver> LibPathResolver;
551 LibraryScanHelper ScanHelper;
553 LibraryScanner::ShouldScanFn ShouldScanCall;
554 size_t scanBatchSize;
555};
556
560
561class LibraryResolutionDriver {
562public:
563 LLVM_ABI static std::unique_ptr<LibraryResolutionDriver>
565
566 LLVM_ABI void addScanPath(const std::string &Path, PathType Kind);
569 bool isLibraryLoaded(StringRef Path) const {
570 return LR->LibMgr.isLoaded(Path);
571 }
572
573 void resetAll() {
574 LR->LibMgr.clear();
575 LR->ScanHelper.resetToScan();
576 LR->LibPathCache->clear();
577 }
578
579 void scanAll(size_t BatchSize = 0) {
580 LR->scanLibrariesIfNeeded(PathType::User, BatchSize);
581 LR->scanLibrariesIfNeeded(PathType::System, BatchSize);
582 }
583
584 void scan(PathType PK, size_t BatchSize = 0) {
585 LR->scanLibrariesIfNeeded(PK, BatchSize);
586 }
587
590 const SearchConfig &Config = SearchConfig());
591
593
594private:
595 LibraryResolutionDriver(std::unique_ptr<LibraryResolver> L)
596 : LR(std::move(L)) {}
597
598 std::unique_ptr<LibraryResolver> LR;
599};
600
601} // end namespace orc
602} // end namespace llvm
603
604#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_ABI
Definition Compiler.h:213
This file provides a collection of function (or more generally, callable) type erasure utilities supp...
#define _
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:128
StringMapIterBase< std::unique_ptr< LibraryInfo >, true > const_iterator
Definition StringMap.h:207
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
This class is the base class for all object file types.
Definition ObjectFile.h:231
BloomFilter build(ArrayRef< StringRef > Symbols) const
LibraryCursor(const std::vector< const LibraryInfo * > &L, LibState S)
const LibraryInfo * nextValidLib()
LibraryCursor getCursor(PathType K, LibState S) const
bool hasLibLeftFor(PathType K, uint32_t Idx) const
LibraryInfo & operator=(const LibraryInfo &)=delete
void setState(LibState s)
bool operator==(const LibraryInfo &other) const
bool mayContain(StringRef Symbol) const
std::string getFullPath() const
StringRef getBasePath() const
void setFilter(BloomFilter F)
StringRef getFileName() const
PathType getKind() const
void ensureFilterBuilt(const BloomFilterBuilder &FB, ArrayRef< StringRef > Symbols)
LibraryInfo(const LibraryInfo &)=delete
LibState getState() const
LibraryInfo(std::string FilePath, LibState S, PathType K, std::optional< BloomFilter > Filter=std::nullopt)
bool operator!=(const FilterIterator &other) const
FilterIterator(Iterator it_, Iterator end_, LibState S, PathType K)
A read-only view of libraries filtered by state and kind.
StringMap< std::unique_ptr< LibraryInfo > > Map
FilteredView(Iterator begin, Iterator end, LibState s, PathType k)
Manages library metadata and state for symbol resolution.
bool hasLibrary(StringRef Path) const
bool isLoaded(StringRef Path) const
void markLoaded(StringRef Path)
FilteredView getView(LibState S, PathType K) const
void markUnloaded(StringRef Path)
void removeLibrary(StringRef Path)
void forEachLibrary(const LibraryVisitor &visitor) const
const LibraryInfo * getLibrary(StringRef Path) const
std::function< bool(const LibraryInfo &)> LibraryFilterFn
std::function< bool(const LibraryInfo &)> LibraryVisitor
void getLibraries(LibState S, PathType K, std::vector< const LibraryInfo * > &Outs, LibraryFilterFn Filter=nullptr) const
bool addLibrary(std::string Path, PathType Kind, std::optional< BloomFilter > Filter=std::nullopt)
bool isQueried(StringRef Path) const
void markQueried(StringRef Path)
LibraryCursor getCursor(PathType K, LibState S) const
LLVM_ABI void resolveSymbols(ArrayRef< StringRef > Symbols, LibraryResolver::OnSearchComplete OnCompletion, const SearchConfig &Config=SearchConfig())
LLVM_ABI void addScanPath(const std::string &Path, PathType Kind)
LLVM_ABI void markLibraryUnLoaded(StringRef Path)
LLVM_ABI void markLibraryLoaded(StringRef Path)
void scan(PathType PK, size_t BatchSize=0)
void scanAll(size_t BatchSize=0)
bool isLibraryLoaded(StringRef Path) const
static LLVM_ABI std::unique_ptr< LibraryResolutionDriver > create(const LibraryResolver::Setup &S)
std::function< EnumerateResult(StringRef Sym)> OnEachSymbolFn
static LLVM_ABI bool enumerateSymbols(object::ObjectFile *Obj, OnEachSymbolFn OnEach, const SymbolEnumeratorOptions &Opts)
Tracks a set of symbols and the libraries where they are resolved.
std::optional< StringRef > getResolvedLib(StringRef Sym) const
SymbolQuery(ArrayRef< StringRef > Symbols)
unique_function< bool(StringRef)> SymbolFilterFn
void getUnresolvedSymbols(SmallVectorImpl< StringRef > &Unresolved, SymbolFilterFn Allow) const
std::vector< const Entry * > getAllResults() const
void resolve(StringRef Sym, const std::string &LibPath)
unique_function< void(SymbolQuery &)> OnSearchComplete
LLVM_ABI void searchSymbolsInLibraries(ArrayRef< StringRef > SymList, OnSearchComplete OnComplete, const SearchConfig &Config=SearchConfig())
Scans and tracks libraries for symbol resolution.
std::function< bool(StringRef)> ShouldScanFn
unique_function is a type-erasing functor similar to std::function.
SymbolEnumerator::EnumerateResult EnumerateResult
LibraryResolver::SymbolEnumerator SymbolEnumerator
LibraryResolver::SymbolQuery SymbolQuery
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
Definition Path.cpp:478
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:594
This is an optimization pass for GlobalISel generic memory operations.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1745
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1916
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:860
LibraryScanner::ShouldScanFn ShouldScanCall
static Setup create(std::vector< std::string > BasePaths, LibraryScanner::ShouldScanFn customShouldScan=nullptr)
std::vector< std::string > BasePaths
Holds the result for a single symbol.
SymbolEnumeratorOptions Options
static SearchPolicy defaultPlan()
std::vector< SearchPlanEntry > Plan
static SymbolEnumeratorOptions defaultOptions()