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