LLVM 22.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
389 static bool enumerateSymbols(object::ObjectFile *Obj, OnEachSymbolFn OnEach,
390 const SymbolEnumeratorOptions &Opts);
391 static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
392 const SymbolEnumeratorOptions &Opts);
393 };
394
395 /// Tracks a set of symbols and the libraries where they are resolved.
396 ///
397 /// SymbolQuery is used to keep track of which symbols have been resolved
398 /// to which libraries. It supports concurrent read/write access using a
399 /// shared mutex, allowing multiple readers or a single writer at a time.
401 public:
402 /// Holds the result for a single symbol.
403 struct Entry {
404 std::string Name;
405 std::string ResolvedLibPath;
406 };
407
408 private:
409 mutable std::shared_mutex Mtx;
411 std::atomic<size_t> ResolvedCount = 0;
412
413 public:
415 for (const auto &S : Symbols) {
416 if (!contains(S))
417 Entries.push_back({S.str(), ""});
418 }
419 }
420
421 bool contains(StringRef Name) const {
422 return llvm::any_of(Entries,
423 [&](const Entry &E) { return E.Name == Name; });
424 }
425
428 SymbolFilterFn Allow) const {
429 std::shared_lock<std::shared_mutex> Lock(Mtx);
430 for (const auto &E : Entries) {
431 if (E.ResolvedLibPath.empty() && Allow(E.Name))
432 Unresolved.push_back(E.Name);
433 }
434 }
435
436 void resolve(StringRef Sym, const std::string &LibPath) {
437 std::unique_lock<std::shared_mutex> Lock(Mtx);
438 for (auto &E : Entries) {
439 if (E.Name == Sym && E.ResolvedLibPath.empty()) {
440 E.ResolvedLibPath = LibPath;
441 ResolvedCount.fetch_add(1, std::memory_order_relaxed);
442 return;
443 }
444 }
445 }
446
447 bool allResolved() const {
448 return ResolvedCount.load(std::memory_order_relaxed) == Entries.size();
449 }
450
451 bool hasUnresolved() const {
452 return ResolvedCount.load(std::memory_order_relaxed) < Entries.size();
453 }
454
455 std::optional<StringRef> getResolvedLib(StringRef Sym) const {
456 std::shared_lock<std::shared_mutex> Lock(Mtx);
457 for (const auto &E : Entries)
458 if (E.Name == Sym && !E.ResolvedLibPath.empty())
459 return E.ResolvedLibPath;
460 return std::nullopt;
461 }
462
463 bool isResolved(StringRef Sym) const {
464 std::shared_lock<std::shared_mutex> Lock(Mtx);
465 for (const auto &E : Entries)
466 if (E.Name == Sym && !E.ResolvedLibPath.empty())
467 return true;
468 return false;
469 }
470
471 std::vector<const Entry *> getAllResults() const {
472 std::shared_lock<std::shared_mutex> Lock(Mtx);
473 std::vector<const Entry *> Out;
474 Out.reserve(Entries.size());
475 for (const auto &E : Entries)
476 Out.push_back(&E);
477 return Out;
478 }
479 };
480
481 struct Setup {
482 std::vector<std::string> BasePaths;
483 // std::shared_ptr<LibraryPathCache> Cache;
484 // std::shared_ptr<PathResolver> PResolver;
485
486 size_t ScanBatchSize = 0;
487
491
493
494 static Setup
495 create(std::vector<std::string> BasePaths,
496 // std::shared_ptr<LibraryPathCache> existingCache = nullptr,
497 // std::shared_ptr<PathResolver> existingResolver = nullptr,
498 LibraryScanner::ShouldScanFn customShouldScan = nullptr) {
499 Setup S;
500 S.BasePaths = std::move(BasePaths);
501
502 // S.Cache =
503 // existingCache ? existingCache :
504 // std::make_shared<LibraryPathCache>();
505
506 // S.PResolver = existingResolver ? existingResolver
507 // :
508 // std::make_shared<PathResolver>(S.Cache);
509
510 if (customShouldScan)
511 S.ShouldScanCall = std::move(customShouldScan);
512
513 return S;
514 }
515 };
516
517 LibraryResolver() = delete;
518 explicit LibraryResolver(const Setup &S);
519 ~LibraryResolver() = default;
520
522
523 void dump() {
524 int i = 0;
525 LibMgr.forEachLibrary([&](const LibraryInfo &Lib) -> bool {
526 dbgs() << ++i << ". Library Path : " << Lib.getFullPath() << " -> \n\t\t:"
527 << " ({Type : ("
528 << (Lib.getKind() == PathType::User ? "User" : "System")
529 << ") }, { State : "
530 << (Lib.getState() == LibState::Loaded ? "Loaded" : "Unloaded")
531 << "})\n";
532 return true;
533 });
534 }
535
537 OnSearchComplete OnComplete,
538 const SearchConfig &Config = SearchConfig());
539
540private:
541 bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
542 bool scanForNewLibraries(PathType K, LibraryCursor &Cur);
543 void resolveSymbolsInLibrary(LibraryInfo *Lib, SymbolQuery &Q,
544 const SymbolEnumeratorOptions &Opts);
545
546 LibraryManager LibMgr;
547 std::shared_ptr<LibraryPathCache> LibPathCache;
548 std::shared_ptr<PathResolver> LibPathResolver;
549 LibraryScanHelper ScanHelper;
551 LibraryScanner::ShouldScanFn ShouldScanCall;
552 size_t scanBatchSize;
553};
554
558
559class LibraryResolutionDriver {
560public:
561 static std::unique_ptr<LibraryResolutionDriver>
563
564 void addScanPath(const std::string &Path, PathType Kind);
565 void markLibraryLoaded(StringRef Path);
567 bool isLibraryLoaded(StringRef Path) const {
568 return LR->LibMgr.isLoaded(Path);
569 }
570
571 void resetAll() {
572 LR->LibMgr.clear();
573 LR->ScanHelper.resetToScan();
574 LR->LibPathCache->clear();
575 }
576
577 void scanAll(size_t BatchSize = 0) {
578 LR->scanLibrariesIfNeeded(PathType::User, BatchSize);
579 LR->scanLibrariesIfNeeded(PathType::System, BatchSize);
580 }
581
582 void scan(PathType PK, size_t BatchSize = 0) {
583 LR->scanLibrariesIfNeeded(PK, BatchSize);
584 }
585
588 const SearchConfig &Config = SearchConfig());
589
591
592private:
593 LibraryResolutionDriver(std::unique_ptr<LibraryResolver> L)
594 : LR(std::move(L)) {}
595
596 std::unique_ptr<LibraryResolver> LR;
597};
598
599} // end namespace orc
600} // end namespace llvm
601
602#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")
Analysis containing CSE Info
Definition CSEInfo.cpp:27
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
ArrayRef - 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:133
StringMapIterBase< std::unique_ptr< LibraryInfo >, true > const_iterator
Definition StringMap.h:220
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
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
void resolveSymbols(ArrayRef< StringRef > Symbols, LibraryResolver::OnSearchComplete OnCompletion, const SearchConfig &Config=SearchConfig())
void addScanPath(const std::string &Path, PathType Kind)
void scan(PathType PK, size_t BatchSize=0)
void scanAll(size_t BatchSize=0)
bool isLibraryLoaded(StringRef Path) const
static std::unique_ptr< LibraryResolutionDriver > create(const LibraryResolver::Setup &S)
std::function< EnumerateResult(StringRef Sym)> OnEachSymbolFn
static 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
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:468
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:578
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
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:1744
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
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:1915
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
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()