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 void forEachLibrary(const LibraryVisitor &visitor) const {
215 std::unique_lock<std::shared_mutex> Lock(Mtx);
216 for (const auto &[_, entry] : Libraries) {
217 if (!visitor(*entry))
218 break;
219 }
220 }
221
222 bool isLoaded(StringRef Path) const {
223 std::unique_lock<std::shared_mutex> Lock(Mtx);
224 if (auto It = Libraries.find(Path.str()); It != Libraries.end())
225 return It->second->getState() == LibState::Loaded;
226 return false;
227 }
228
229 bool isQueried(StringRef Path) const {
230 std::unique_lock<std::shared_mutex> Lock(Mtx);
231 if (auto It = Libraries.find(Path.str()); It != Libraries.end())
232 return It->second->getState() == LibState::Queried;
233 return false;
234 }
235
236 void clear() {
237 std::unique_lock<std::shared_mutex> Lock(Mtx);
238 Libraries.clear();
239 }
240};
241
243
245 LibraryManager::LibState State; // Loaded, Queried, Unloaded
246 PathType Type; // User, System
247};
248
250 std::vector<SearchPlanEntry> Plan;
251
253 return {{{LibraryManager::LibState::Loaded, PathType::User},
254 {LibraryManager::LibState::Queried, PathType::User},
255 {LibraryManager::LibState::Unloaded, PathType::User},
256 {LibraryManager::LibState::Loaded, PathType::System},
257 {LibraryManager::LibState::Queried, PathType::System},
258 {LibraryManager::LibState::Unloaded, PathType::System}}};
259 }
260};
261
278
282
284 : Policy(SearchPolicy::defaultPlan()), // default plan
285 Options(SymbolEnumeratorOptions::defaultOptions()) {}
286};
287
288/// Scans libraries and resolves Symbols across user and system paths.
289///
290/// Supports symbol enumeration and filtering via SymbolEnumerator, and tracks
291/// symbol resolution results through SymbolQuery. Thread-safe and uses
292/// LibraryScanHelper for efficient path resolution and caching.
295
296public:
298 public:
300
301 using OnEachSymbolFn = std::function<EnumerateResult(StringRef Sym)>;
302
303 static bool enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,
304 const SymbolEnumeratorOptions &Opts);
305 };
306
307 /// Tracks a set of symbols and the libraries where they are resolved.
308 ///
309 /// SymbolQuery is used to keep track of which symbols have been resolved
310 /// to which libraries. It supports concurrent read/write access using a
311 /// shared mutex, allowing multiple readers or a single writer at a time.
313 public:
314 /// Holds the result for a single symbol.
315 struct Result {
316 std::string Name;
317 std::string ResolvedLibPath;
318 };
319
320 private:
321 mutable std::shared_mutex Mtx;
322 StringMap<Result> Results;
323 std::atomic<size_t> ResolvedCount = 0;
324
325 public:
326 explicit SymbolQuery(const std::vector<std::string> &Symbols) {
327 for (const auto &s : Symbols) {
328 if (!Results.contains(s))
329 Results.insert({s, Result{s, ""}});
330 }
331 }
332
334 SmallVector<StringRef> Unresolved;
335 std::shared_lock<std::shared_mutex> Lock(Mtx);
336 for (const auto &[name, res] : Results) {
337 if (res.ResolvedLibPath.empty())
338 Unresolved.push_back(name);
339 }
340 return Unresolved;
341 }
342
343 void resolve(StringRef Sym, const std::string &LibPath) {
344 std::unique_lock<std::shared_mutex> Lock(Mtx);
345 auto It = Results.find(Sym);
346 if (It != Results.end() && It->second.ResolvedLibPath.empty()) {
347 It->second.ResolvedLibPath = LibPath;
348 ResolvedCount.fetch_add(1, std::memory_order_relaxed);
349 }
350 }
351
352 bool allResolved() const {
353 return ResolvedCount.load(std::memory_order_relaxed) == Results.size();
354 }
355
356 bool hasUnresolved() const {
357 return ResolvedCount.load(std::memory_order_relaxed) < Results.size();
358 }
359
360 std::optional<StringRef> getResolvedLib(StringRef Sym) const {
361 std::shared_lock<std::shared_mutex> Lock(Mtx);
362 auto It = Results.find(Sym);
363 if (It != Results.end() && !It->second.ResolvedLibPath.empty())
364 return StringRef(It->second.ResolvedLibPath);
365 return std::nullopt;
366 }
367
368 bool isResolved(StringRef Sym) const {
369 std::shared_lock<std::shared_mutex> Lock(Mtx);
370 auto It = Results.find(Sym.str());
371 return It != Results.end() && !It->second.ResolvedLibPath.empty();
372 }
373
374 std::vector<const Result *> getAllResults() const {
375 std::shared_lock<std::shared_mutex> Lock(Mtx);
376 std::vector<const Result *> Out;
377 Out.reserve(Results.size());
378 for (const auto &[_, res] : Results)
379 Out.push_back(&res);
380 return Out;
381 }
382 };
383
384 struct Setup {
385 std::vector<std::string> BasePaths;
386 std::shared_ptr<LibraryPathCache> Cache;
387 std::shared_ptr<PathResolver> PResolver;
388
389 size_t ScanBatchSize = 0;
390
394
396
397 static Setup
398 create(std::vector<std::string> BasePaths,
399 std::shared_ptr<LibraryPathCache> existingCache = nullptr,
400 std::shared_ptr<PathResolver> existingResolver = nullptr,
401 LibraryScanner::ShouldScanFn customShouldScan = nullptr) {
402 Setup S;
403 S.BasePaths = std::move(BasePaths);
404
405 S.Cache =
406 existingCache ? existingCache : std::make_shared<LibraryPathCache>();
407
408 S.PResolver = existingResolver ? existingResolver
409 : std::make_shared<PathResolver>(S.Cache);
410
411 if (customShouldScan)
412 S.ShouldScanCall = std::move(customShouldScan);
413
414 return S;
415 }
416 };
417
418 LibraryResolver() = delete;
419 explicit LibraryResolver(const Setup &S);
420 ~LibraryResolver() = default;
421
423
424 void dump() {
425 int i = 0;
426 LibMgr.forEachLibrary([&](const LibraryInfo &Lib) -> bool {
427 dbgs() << ++i << ". Library Path : " << Lib.getFullPath() << " -> \n\t\t:"
428 << " ({Type : ("
429 << (Lib.getKind() == PathType::User ? "User" : "System")
430 << ") }, { State : "
431 << (Lib.getState() == LibraryManager::LibState::Loaded
432 ? "Loaded"
433 : "Unloaded")
434 << "})\n";
435 return true;
436 });
437 }
438
439 void searchSymbolsInLibraries(std::vector<std::string> &SymList,
440 OnSearchComplete OnComplete,
441 const SearchConfig &Config = SearchConfig());
442
443private:
444 bool scanLibrariesIfNeeded(PathType K, size_t BatchSize = 0);
445 void resolveSymbolsInLibrary(LibraryInfo &Lib, SymbolQuery &Q,
446 const SymbolEnumeratorOptions &Opts);
447 bool
448 symbolExistsInLibrary(const LibraryInfo &Lib, StringRef Sym,
449 std::vector<std::string> *MatchedSymbols = nullptr);
450
451 bool symbolExistsInLibrary(const LibraryInfo &Lib, StringRef SymName,
452 std::vector<std::string> *AllSymbols,
453 const SymbolEnumeratorOptions &Opts);
454
455 std::shared_ptr<LibraryPathCache> LibPathCache;
456 std::shared_ptr<PathResolver> LibPathResolver;
457 LibraryScanHelper ScanHelper;
459 LibraryManager LibMgr;
460 LibraryScanner::ShouldScanFn ShouldScanCall;
461 size_t scanBatchSize;
462};
463
467
468class LibraryResolutionDriver {
469public:
470 static std::unique_ptr<LibraryResolutionDriver>
472
473 void addScanPath(const std::string &Path, PathType Kind);
474 bool markLibraryLoaded(StringRef Path);
476 bool isLibraryLoaded(StringRef Path) const {
477 return LR->LibMgr.isLoaded(Path);
478 }
479
480 void resetAll() {
481 LR->LibMgr.clear();
482 LR->ScanHelper.resetToScan();
483 LR->LibPathCache->clear();
484 }
485
486 void scanAll(size_t BatchSize = 0) {
487 LR->scanLibrariesIfNeeded(PathType::User, BatchSize);
488 LR->scanLibrariesIfNeeded(PathType::System, BatchSize);
489 }
490
491 void scan(PathType PK, size_t BatchSize = 0) {
492 LR->scanLibrariesIfNeeded(PK, BatchSize);
493 }
494
495 void resolveSymbols(std::vector<std::string> Symbols,
497 const SearchConfig &Config = SearchConfig());
498
500
501private:
502 LibraryResolutionDriver(std::unique_ptr<LibraryResolver> L)
503 : LR(std::move(L)) {}
504
505 std::unique_ptr<LibraryResolver> LR;
506};
507
508} // end namespace orc
509} // end namespace llvm
510
511#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYRESOLVER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
typename Map::const_iterator Iterator
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.
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 &)> 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()