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
28/// Manages library metadata and state for symbol resolution.
29///
30/// Tracks libraries by load state and kind (user/system), and stores
31/// associated Bloom filters and hash maps to speed up symbol lookups.
32/// Thread-safe for concurrent access.
34public:
35 enum class LibState : uint8_t { Unloaded = 0, Loaded = 1, Queried = 2 };
36
38 public:
39 LibraryInfo(const LibraryInfo &) = delete;
40 LibraryInfo &operator=(const LibraryInfo &) = delete;
41
42 LibraryInfo(std::string FilePath, LibState S, PathType K,
43 std::optional<BloomFilter> Filter = std::nullopt)
44 : FilePath(std::move(FilePath)), S(S), K(K), Filter(std::move(Filter)) {
45 }
46
47 StringRef getBasePath() const { return sys::path::parent_path(FilePath); }
48 StringRef getFileName() const { return sys::path::filename(FilePath); }
49
50 std::string getFullPath() const { return FilePath; }
51
53 std::lock_guard<std::shared_mutex> Lock(Mtx);
54 if (Filter)
55 return;
56 Filter.emplace(std::move(F));
57 }
58
60 ArrayRef<StringRef> Symbols) {
61 std::lock_guard<std::shared_mutex> Lock(Mtx);
62 if (Filter)
63 return;
64 Filter.emplace(FB.build(Symbols));
65 }
66
67 bool mayContain(StringRef Symbol) const {
69 std::shared_lock<std::shared_mutex> Lock(Mtx);
70 return Filter->mayContain(Symbol);
71 }
72
73 bool hasFilter() const {
74 std::shared_lock<std::shared_mutex> Lock(Mtx);
75 return Filter.has_value();
76 }
77
78 LibState getState() const { return S.load(); }
79 PathType getKind() const { return K; }
80
81 void setState(LibState s) { S.store(s); }
82
83 bool operator==(const LibraryInfo &other) const {
84 return FilePath == other.FilePath;
85 }
86
87 private:
88 std::string FilePath;
89 std::atomic<LibState> S;
90 PathType K;
91 std::optional<BloomFilter> Filter;
92 mutable std::shared_mutex Mtx;
93 };
94
95 /// A read-only view of libraries filtered by state and kind.
96 ///
97 /// Lets you loop over only the libraries in a map that match a given State
98 /// and PathType.
100 public:
104 public:
106 : it(it_), end(end_), S(S), K(K) {
107 advance();
108 }
109
110 bool operator!=(const FilterIterator &other) const {
111 return it != other.it;
112 }
113
114 const std::shared_ptr<LibraryInfo> &operator*() const {
115 return it->second;
116 }
117
119 ++it;
120 advance();
121 return *this;
122 }
123
124 private:
125 void advance() {
126 for (; it != end; ++it)
127 if (it->second->getState() == S && it->second->getKind() == K)
128 break;
129 }
130 Iterator it;
132 LibState S;
133 PathType K;
134 };
136 : mapBegin(begin), mapEnd(end), state(s), kind(k) {}
137
139 return FilterIterator(mapBegin, mapEnd, state, kind);
140 }
141
143 return FilterIterator(mapEnd, mapEnd, state, kind);
144 }
145
146 private:
147 Iterator mapBegin;
148 Iterator mapEnd;
149 LibState state;
150 PathType kind;
151 };
152
153private:
155 mutable std::shared_mutex Mtx;
156
157public:
158 using LibraryVisitor = std::function<bool(const LibraryInfo &)>;
159
160 LibraryManager() = default;
161 ~LibraryManager() = default;
162
163 bool addLibrary(std::string Path, PathType Kind,
164 std::optional<BloomFilter> Filter = std::nullopt) {
165 std::unique_lock<std::shared_mutex> Lock(Mtx);
166 if (Libraries.count(Path) > 0)
167 return false;
168 Libraries.insert({std::move(Path),
169 std::make_shared<LibraryInfo>(Path, LibState::Unloaded,
170 Kind, std::move(Filter))});
171 return true;
172 }
173
174 bool hasLibrary(StringRef Path) const {
175 std::shared_lock<std::shared_mutex> Lock(Mtx);
176 if (Libraries.count(Path) > 0)
177 return true;
178 return false;
179 }
180
182 std::unique_lock<std::shared_mutex> Lock(Mtx);
183 auto I = Libraries.find(Path);
184 if (I == Libraries.end())
185 return;
186 Libraries.erase(I);
187 }
188
190 std::unique_lock<std::shared_mutex> Lock(Mtx);
191 if (auto It = Libraries.find(Path); It != Libraries.end())
192 It->second->setState(LibState::Loaded);
193 }
194
196 std::unique_lock<std::shared_mutex> Lock(Mtx);
197 if (auto It = Libraries.find(Path); It != Libraries.end())
198 It->second->setState(LibState::Queried);
199 }
200
201 std::shared_ptr<LibraryInfo> getLibrary(StringRef Path) {
202 std::shared_lock<std::shared_mutex> Lock(Mtx);
203 if (auto It = Libraries.find(Path); It != Libraries.end())
204 return It->second;
205 return nullptr;
206 }
207
209 std::shared_lock<std::shared_mutex> Lock(Mtx);
210 return FilteredView(Libraries.begin(), Libraries.end(), S, K);
211 }
212
213 using LibraryFilterFn = std::function<bool(const LibraryInfo &)>;
215 std::vector<std::shared_ptr<LibraryInfo>> &Outs,
216 LibraryFilterFn Filter = nullptr) const {
217 std::shared_lock<std::shared_mutex> Lock(Mtx);
218 for (const auto &[_, Entry] : Libraries) {
219 const auto &Info = *Entry;
220 if (Info.getKind() != K || Info.getState() != S)
221 continue;
222 if (Filter && !Filter(Info))
223 continue;
224 Outs.push_back(Entry);
225 }
226 }
227
228 void forEachLibrary(const LibraryVisitor &visitor) const {
229 std::unique_lock<std::shared_mutex> Lock(Mtx);
230 for (const auto &[_, entry] : Libraries) {
231 if (!visitor(*entry))
232 break;
233 }
234 }
235
236 bool isLoaded(StringRef Path) const {
237 std::shared_lock<std::shared_mutex> Lock(Mtx);
238 if (auto It = Libraries.find(Path.str()); It != Libraries.end())
239 return It->second->getState() == LibState::Loaded;
240 return false;
241 }
242
243 bool isQueried(StringRef Path) const {
244 std::shared_lock<std::shared_mutex> Lock(Mtx);
245 if (auto It = Libraries.find(Path.str()); It != Libraries.end())
246 return It->second->getState() == LibState::Queried;
247 return false;
248 }
249
250 void clear() {
251 std::unique_lock<std::shared_mutex> Lock(Mtx);
252 Libraries.clear();
253 }
254};
255
257
259 LibraryManager::LibState State; // Loaded, Queried, Unloaded
260 PathType Type; // User, System
261};
262
264 std::vector<SearchPlanEntry> Plan;
265
267 return {{{LibraryManager::LibState::Loaded, PathType::User},
268 {LibraryManager::LibState::Queried, PathType::User},
269 {LibraryManager::LibState::Unloaded, PathType::User},
270 {LibraryManager::LibState::Loaded, PathType::System},
271 {LibraryManager::LibState::Queried, PathType::System},
272 {LibraryManager::LibState::Unloaded, PathType::System}}};
273 }
274};
275
292
296
298 : Policy(SearchPolicy::defaultPlan()), // default plan
299 Options(SymbolEnumeratorOptions::defaultOptions()) {}
300};
301
302/// Scans libraries and resolves Symbols across user and system paths.
303///
304/// Supports symbol enumeration and filtering via SymbolEnumerator, and tracks
305/// symbol resolution results through SymbolQuery. Thread-safe and uses
306/// LibraryScanHelper for efficient path resolution and caching.
309
310public:
312 public:
314
315 using OnEachSymbolFn = std::function<EnumerateResult(StringRef Sym)>;
316
317 static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
318 const SymbolEnumeratorOptions &Opts);
319 };
320
321 /// Tracks a set of symbols and the libraries where they are resolved.
322 ///
323 /// SymbolQuery is used to keep track of which symbols have been resolved
324 /// to which libraries. It supports concurrent read/write access using a
325 /// shared mutex, allowing multiple readers or a single writer at a time.
327 public:
328 /// Holds the result for a single symbol.
329 struct Result {
330 std::string Name;
331 std::string ResolvedLibPath;
332 };
333
334 private:
335 mutable std::shared_mutex Mtx;
336 StringMap<Result> Results;
337 std::atomic<size_t> ResolvedCount = 0;
338
339 public:
340 explicit SymbolQuery(const std::vector<std::string> &Symbols) {
341 for (const auto &s : Symbols) {
342 if (!Results.contains(s))
343 Results.insert({s, Result{s, ""}});
344 }
345 }
346
348 SmallVector<StringRef> Unresolved;
349 std::shared_lock<std::shared_mutex> Lock(Mtx);
350 for (const auto &[name, res] : Results) {
351 if (res.ResolvedLibPath.empty())
352 Unresolved.push_back(name);
353 }
354 return Unresolved;
355 }
356
357 void resolve(StringRef Sym, const std::string &LibPath) {
358 std::unique_lock<std::shared_mutex> Lock(Mtx);
359 auto It = Results.find(Sym);
360 if (It != Results.end() && It->second.ResolvedLibPath.empty()) {
361 It->second.ResolvedLibPath = LibPath;
362 ResolvedCount.fetch_add(1, std::memory_order_relaxed);
363 }
364 }
365
366 bool allResolved() const {
367 return ResolvedCount.load(std::memory_order_relaxed) == Results.size();
368 }
369
370 bool hasUnresolved() const {
371 return ResolvedCount.load(std::memory_order_relaxed) < Results.size();
372 }
373
374 std::optional<StringRef> getResolvedLib(StringRef Sym) const {
375 std::shared_lock<std::shared_mutex> Lock(Mtx);
376 auto It = Results.find(Sym);
377 if (It != Results.end() && !It->second.ResolvedLibPath.empty())
378 return StringRef(It->second.ResolvedLibPath);
379 return std::nullopt;
380 }
381
382 bool isResolved(StringRef Sym) const {
383 std::shared_lock<std::shared_mutex> Lock(Mtx);
384 auto It = Results.find(Sym.str());
385 return It != Results.end() && !It->second.ResolvedLibPath.empty();
386 }
387
388 std::vector<const Result *> getAllResults() const {
389 std::shared_lock<std::shared_mutex> Lock(Mtx);
390 std::vector<const Result *> Out;
391 Out.reserve(Results.size());
392 for (const auto &[_, res] : Results)
393 Out.push_back(&res);
394 return Out;
395 }
396 };
397
398 struct Setup {
399 std::vector<std::string> BasePaths;
400 std::shared_ptr<LibraryPathCache> Cache;
401 std::shared_ptr<PathResolver> PResolver;
402
403 size_t ScanBatchSize = 0;
404
408
410
411 static Setup
412 create(std::vector<std::string> BasePaths,
413 std::shared_ptr<LibraryPathCache> existingCache = nullptr,
414 std::shared_ptr<PathResolver> existingResolver = nullptr,
415 LibraryScanner::ShouldScanFn customShouldScan = nullptr) {
416 Setup S;
417 S.BasePaths = std::move(BasePaths);
418
419 S.Cache =
420 existingCache ? existingCache : std::make_shared<LibraryPathCache>();
421
422 S.PResolver = existingResolver ? existingResolver
423 : std::make_shared<PathResolver>(S.Cache);
424
425 if (customShouldScan)
426 S.ShouldScanCall = std::move(customShouldScan);
427
428 return S;
429 }
430 };
431
432 LibraryResolver() = delete;
433 explicit LibraryResolver(const Setup &S);
434 ~LibraryResolver() = default;
435
437
438 void dump() {
439 int i = 0;
440 LibMgr.forEachLibrary([&](const LibraryInfo &Lib) -> bool {
441 dbgs() << ++i << ". Library Path : " << Lib.getFullPath() << " -> \n\t\t:"
442 << " ({Type : ("
443 << (Lib.getKind() == PathType::User ? "User" : "System")
444 << ") }, { State : "
445 << (Lib.getState() == LibraryManager::LibState::Loaded
446 ? "Loaded"
447 : "Unloaded")
448 << "})\n";
449 return true;
450 });
451 }
452
453 void searchSymbolsInLibraries(std::vector<std::string> &SymList,
454 OnSearchComplete OnComplete,
455 const SearchConfig &Config = SearchConfig());
456
457private:
458 bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
459 void resolveSymbolsInLibrary(LibraryInfo &Lib, SymbolQuery &Q,
460 const SymbolEnumeratorOptions &Opts);
461 bool
462 symbolExistsInLibrary(const LibraryInfo &Lib, StringRef Sym,
463 std::vector<std::string> *MatchedSymbols = nullptr);
464
465 bool symbolExistsInLibrary(const LibraryInfo &Lib, StringRef SymName,
466 std::vector<std::string> *AllSymbols,
467 const SymbolEnumeratorOptions &Opts);
468
469 std::shared_ptr<LibraryPathCache> LibPathCache;
470 std::shared_ptr<PathResolver> LibPathResolver;
471 LibraryScanHelper ScanHelper;
473 LibraryManager LibMgr;
474 LibraryScanner::ShouldScanFn ShouldScanCall;
475 size_t scanBatchSize;
476};
477
481
482class LibraryResolutionDriver {
483public:
484 static std::unique_ptr<LibraryResolutionDriver>
486
487 void addScanPath(const std::string &Path, PathType Kind);
488 bool markLibraryLoaded(StringRef Path);
490 bool isLibraryLoaded(StringRef Path) const {
491 return LR->LibMgr.isLoaded(Path);
492 }
493
494 void resetAll() {
495 LR->LibMgr.clear();
496 LR->ScanHelper.resetToScan();
497 LR->LibPathCache->clear();
498 }
499
500 void scanAll(size_t BatchSize = 0) {
501 LR->scanLibrariesIfNeeded(PathType::User, BatchSize);
502 LR->scanLibrariesIfNeeded(PathType::System, BatchSize);
503 }
504
505 void scan(PathType PK, size_t BatchSize = 0) {
506 LR->scanLibrariesIfNeeded(PK, BatchSize);
507 }
508
509 void resolveSymbols(std::vector<std::string> Symbols,
511 const SearchConfig &Config = SearchConfig());
512
514
515private:
516 LibraryResolutionDriver(std::unique_ptr<LibraryResolver> L)
517 : LR(std::move(L)) {}
518
519 std::unique_ptr<LibraryResolver> LR;
520};
521
522} // end namespace orc
523} // end namespace llvm
524
525#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
static const char * name
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
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::shared_ptr< LibraryInfo >, true > const_iterator
Definition StringMap.h:220
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::string str() const
str - Get the contents as an std::string.
Definition StringRef.h:225
BloomFilter build(ArrayRef< StringRef > Symbols) const
bool operator!=(const FilterIterator &other) const
const std::shared_ptr< LibraryInfo > & operator*() const
FilterIterator(Iterator it_, Iterator end_, LibState S, PathType K)
A read-only view of libraries filtered by state and kind.
StringMap< std::shared_ptr< LibraryInfo > > Map
FilteredView(Iterator begin, Iterator end, LibState s, PathType k)
bool mayContain(StringRef Symbol) const
LibraryInfo(const LibraryInfo &)=delete
void ensureFilterBuilt(const BloomFilterBuilder &FB, ArrayRef< StringRef > Symbols)
LibraryInfo & operator=(const LibraryInfo &)=delete
bool operator==(const LibraryInfo &other) const
LibraryInfo(std::string FilePath, LibState S, PathType K, std::optional< BloomFilter > Filter=std::nullopt)
Manages library metadata and state for symbol resolution.
void getLibraries(LibState S, PathType K, std::vector< std::shared_ptr< LibraryInfo > > &Outs, LibraryFilterFn Filter=nullptr) const
std::shared_ptr< LibraryInfo > getLibrary(StringRef Path)
bool hasLibrary(StringRef Path) const
bool isLoaded(StringRef Path) const
void markLoaded(StringRef Path)
FilteredView getView(LibState S, PathType K) const
void removeLibrary(StringRef Path)
void forEachLibrary(const LibraryVisitor &visitor) const
std::function< bool(const LibraryInfo &)> LibraryFilterFn
std::function< bool(const LibraryInfo &)> LibraryVisitor
bool addLibrary(std::string Path, PathType Kind, std::optional< BloomFilter > Filter=std::nullopt)
bool isQueried(StringRef Path) const
void markQueried(StringRef Path)
void resolveSymbols(std::vector< std::string > 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(StringRef Path, OnEachSymbolFn OnEach, const SymbolEnumeratorOptions &Opts)
Tracks a set of symbols and the libraries where they are resolved.
SymbolQuery(const std::vector< std::string > &Symbols)
std::optional< StringRef > getResolvedLib(StringRef Sym) const
SmallVector< StringRef > getUnresolvedSymbols() const
std::vector< const Result * > getAllResults() const
void resolve(StringRef Sym, const std::string &LibPath)
unique_function< void(SymbolQuery &)> OnSearchComplete
void searchSymbolsInLibraries(std::vector< std::string > &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.
LibraryManager::LibraryInfo LibraryInfo
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:467
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:577
This is an optimization pass for GlobalISel generic memory operations.
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:1867
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867
static Setup create(std::vector< std::string > BasePaths, std::shared_ptr< LibraryPathCache > existingCache=nullptr, std::shared_ptr< PathResolver > existingResolver=nullptr, LibraryScanner::ShouldScanFn customShouldScan=nullptr)
LibraryScanner::ShouldScanFn ShouldScanCall
std::vector< std::string > BasePaths
std::shared_ptr< PathResolver > PResolver
std::shared_ptr< LibraryPathCache > Cache
Holds the result for a single symbol.
SymbolEnumeratorOptions Options
LibraryManager::LibState State
static SearchPolicy defaultPlan()
std::vector< SearchPlanEntry > Plan
static SymbolEnumeratorOptions defaultOptions()