LLVM 23.0.0git
LibraryScanner.h
Go to the documentation of this file.
1//===- LibraryScanner.h - Scanner for Shared Libraries ---------*- 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 functionality for scanning dynamic (shared) libraries.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
14#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
15
18#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/StringSet.h"
22#include "llvm/Support/Error.h"
24
25#include <atomic>
26#include <mutex>
27#include <queue>
28#include <shared_mutex>
29#include <string>
30
31namespace llvm {
32namespace orc {
33
34class LibraryManager;
35
37 friend class PathResolver;
38
39public:
40 LibraryPathCache() = default;
41
42 void clear(bool isRealPathCache = false) {
43 std::unique_lock<std::shared_mutex> lock(Mtx);
44 Seen.clear();
45 if (isRealPathCache) {
46 RealPathCache.clear();
47#ifndef _WIN32
48 ReadlinkCache.clear();
49 LstatCache.clear();
50#endif
51 }
52 }
53
54 void markSeen(const std::string &CanonPath) {
55 std::unique_lock<std::shared_mutex> lock(Mtx);
56 Seen.insert(CanonPath);
57 }
58
59 bool hasSeen(StringRef CanonPath) const {
60 std::shared_lock<std::shared_mutex> lock(Mtx);
61 return Seen.contains(CanonPath);
62 }
63
64 bool hasSeenOrMark(StringRef CanonPath) {
65 std::string s = CanonPath.str();
66 {
67 std::shared_lock<std::shared_mutex> lock(Mtx);
68 if (Seen.contains(s))
69 return true;
70 }
71 {
72 std::unique_lock<std::shared_mutex> lock(Mtx);
73 Seen.insert(s);
74 }
75 return false;
76 }
77
78private:
79 mutable std::shared_mutex Mtx;
80
81 struct PathInfo {
82 std::string canonicalPath;
83 std::error_code ErrnoCode;
84 };
85
86 void insert_realpath(StringRef Path, const PathInfo &Info) {
87 std::unique_lock<std::shared_mutex> lock(Mtx);
88 RealPathCache.insert({Path, Info});
89 }
90
91 std::optional<PathInfo> read_realpath(StringRef Path) const {
92 std::shared_lock<std::shared_mutex> lock(Mtx);
93 auto It = RealPathCache.find(Path);
94 if (It != RealPathCache.end())
95 return It->second;
96
97 return std::nullopt;
98 }
99
100 StringSet<> Seen;
101 StringMap<PathInfo> RealPathCache;
102
103#ifndef _WIN32
104 StringMap<std::string> ReadlinkCache;
105 StringMap<mode_t> LstatCache;
106
107 void insert_link(StringRef Path, const std::string &s) {
108 std::unique_lock<std::shared_mutex> lock(Mtx);
109 ReadlinkCache.insert({Path, s});
110 }
111
112 std::optional<std::string> read_link(StringRef Path) const {
113 std::shared_lock<std::shared_mutex> lock(Mtx);
114 auto It = ReadlinkCache.find(Path);
115 if (It != ReadlinkCache.end())
116 return It->second;
117
118 return std::nullopt;
119 }
120
121 void insert_lstat(StringRef Path, mode_t m) {
122 std::unique_lock<std::shared_mutex> lock(Mtx);
123 LstatCache.insert({Path, m});
124 }
125
126 std::optional<mode_t> read_lstat(StringRef Path) const {
127 std::shared_lock<std::shared_mutex> lock(Mtx);
128 auto It = LstatCache.find(Path);
129 if (It != LstatCache.end())
130 return It->second;
131
132 return std::nullopt;
133 }
134
135#endif
136};
137
138/// Resolves file system paths with optional caching of results.
139///
140/// Supports lstat, readlink, and realpath operations. Can resolve paths
141/// relative to a base and handle symbolic links. Caches results to reduce
142/// repeated system calls when enabled.
144private:
145 std::shared_ptr<LibraryPathCache> LibPathCache;
146
147public:
148 PathResolver(std::shared_ptr<LibraryPathCache> cache)
149 : LibPathCache(std::move(cache)) {}
150
151 std::optional<std::string> resolve(StringRef Path, std::error_code &ec) {
152 return realpathCached(Path, ec);
153 }
154#ifndef _WIN32
155 mode_t lstatCached(StringRef Path);
156 std::optional<std::string> readlinkCached(StringRef Path);
157#endif
158 LLVM_ABI std::optional<std::string>
159 realpathCached(StringRef Path, std::error_code &ec, StringRef base = "",
160 bool baseIsResolved = false, long symloopLevel = 40);
161};
162
163/// Performs placeholder substitution in dynamic library paths.
164///
165/// Configures known placeholders (like @loader_path) and replaces them
166/// in input paths with their resolved values.
168public:
169 LLVM_ABI void configure(StringRef loaderPath);
170
171 std::string substitute(StringRef input) const {
172 for (const auto &[ph, value] : Placeholders) {
173 if (input.starts_with_insensitive(ph))
174 return (Twine(value) + input.drop_front(ph.size())).str();
175 }
176 return input.str();
177 }
178
179private:
181};
182
183/// Loads an object file and provides access to it.
184///
185/// Owns the underlying `ObjectFile` and ensures it is valid.
186/// Any errors encountered during construction are stored and
187/// returned when attempting to access the file.
189public:
190 /// Construct an object file loader from the given path.
192 auto ObjOrErr = loadObjectFileWithOwnership(Path);
193 if (ObjOrErr)
194 Obj = std::move(*ObjOrErr);
195 else {
196 consumeError(std::move(Err));
197 Err = ObjOrErr.takeError();
198 }
199 }
200
203
206
207 /// Get the loaded object file, or return an error if loading failed.
209 if (Err) {
210 // allow the error to be taken only once
211 if (ErrorTaken)
213 "error already taken");
214
215 ErrorTaken = true;
216 return std::move(Err);
217 }
218 return *Obj.getBinary();
219 }
220
222
223private:
225 Error Err = Error::success();
226 bool ErrorTaken = false;
227
229 loadObjectFileWithOwnership(StringRef FilePath);
230};
231
233public:
234 void insert(StringRef Path, ObjectFileLoader &&Loader) {
235 Cache.insert({Path, std::move(Loader)});
236 }
237
238 // Take ownership
239 std::optional<ObjectFileLoader> take(StringRef Path) {
240 std::unique_lock<std::shared_mutex> Lock(Mtx);
241 auto It = Cache.find(Path);
242 if (It == Cache.end())
243 return std::nullopt;
244
245 ObjectFileLoader L = std::move(It->second);
246 Cache.erase(It);
247 return std::move(L);
248 }
249
250 bool contains(StringRef Path) const { return Cache.count(Path) != 0; }
251
252private:
253 mutable std::shared_mutex Mtx;
255};
256
257/// Validates and normalizes dynamic library paths.
258///
259/// Uses a `PathResolver` to resolve paths to their canonical form and
260/// checks whether they point to valid shared libraries.
262public:
264 ObjFileCache *ObjCache = nullptr)
265 : LibPathResolver(PR), LibPathCache(LC), ObjCache(ObjCache) {}
266
267 LLVM_ABI bool isSharedLibrary(StringRef Path) const;
269 if (LibPathCache.hasSeen(Path))
270 return true;
271 return isSharedLibrary(Path);
272 }
273
274 std::optional<std::string> normalize(StringRef Path) const {
275 std::error_code ec;
276 auto real = LibPathResolver.resolve(Path, ec);
277 if (!real || ec)
278 return std::nullopt;
279
280 return real;
281 }
282
283 /// Validate the given path as a shared library.
284 std::optional<std::string> validate(StringRef Path) const {
285 if (LibPathCache.hasSeen(Path))
286 return Path.str();
287 auto realOpt = normalize(Path);
288 if (!realOpt)
289 return std::nullopt;
290
291 if (!isSharedLibraryCached(*realOpt))
292 return std::nullopt;
293
294 return realOpt;
295 }
296
297private:
298 PathResolver &LibPathResolver;
299 LibraryPathCache &LibPathCache;
300 mutable ObjFileCache *ObjCache;
301};
302
308
313
315public:
317 StringRef PlaceholderPrefix = "")
318 : Kind(Cfg.type), PlaceholderPrefix(PlaceholderPrefix) {
319 Paths.reserve(Cfg.Paths.size());
320 for (auto &path : Cfg.Paths)
321 Paths.emplace_back(path.str());
322 }
323
324 LLVM_ABI std::optional<std::string>
325 resolve(StringRef libStem, const DylibSubstitutor &Subst,
326 DylibPathValidator &Validator) const;
327 SearchPathType searchPathType() const { return Kind; }
328
329private:
330 std::vector<std::string> Paths;
331 SearchPathType Kind;
332 std::string PlaceholderPrefix;
333};
334
336public:
338 std::vector<SearchPathResolver> Resolvers)
339 : Substitutor(std::move(Substitutor)), Validator(Validator),
340 Resolvers(std::move(Resolvers)) {}
341
342 LLVM_ABI std::optional<std::string>
343 resolve(StringRef Stem, bool VariateLibStem = false) const;
344
345private:
346 std::optional<std::string> tryWithExtensions(StringRef libstem) const;
347
348 DylibSubstitutor Substitutor;
349 DylibPathValidator &Validator;
350 std::vector<SearchPathResolver> Resolvers;
351};
352
354public:
355 DylibResolver(DylibPathValidator &Validator) : Validator(Validator) {}
356
357 void configure(StringRef loaderPath,
358 ArrayRef<SearchPathConfig> SearchPathCfg) {
359 DylibSubstitutor Substitutor;
360 Substitutor.configure(loaderPath);
361
362 std::vector<SearchPathResolver> Resolvers;
363 for (const auto &cfg : SearchPathCfg) {
364 Resolvers.emplace_back(cfg,
365 cfg.type == SearchPathType::RPath ? "@rpath" : "");
366 }
367
368 impl_ = std::make_unique<DylibResolverImpl>(
369 std::move(Substitutor), Validator, std::move(Resolvers));
370 }
371
372 std::optional<std::string> resolve(StringRef libStem,
373 bool VariateLibStem = false) const {
374 if (!impl_)
375 return std::nullopt;
376 return impl_->resolve(libStem, VariateLibStem);
377 }
378
379 static std::string resolvelinkerFlag(StringRef libStem,
380 StringRef loaderPath) {
381 DylibSubstitutor Substitutor;
382 Substitutor.configure(loaderPath);
383 return Substitutor.substitute(libStem);
384 }
385
386private:
387 DylibPathValidator &Validator;
388 std::unique_ptr<DylibResolverImpl> impl_;
389};
390
391enum class PathType : uint8_t { User, System, Unknown };
392
394
396 std::string BasePath; // Canonical base directory path
397 PathType Kind; // User or System
398 std::atomic<ScanState> State;
399
402};
403
404/// Scans and tracks libraries for symbol resolution.
405///
406/// Maintains a list of library paths to scan, caches scanned units,
407/// and resolves paths canonically for consistent tracking.
409public:
410 explicit LibraryScanHelper(const std::vector<std::string> &SPaths,
411 std::shared_ptr<LibraryPathCache> LibPathCache,
412 std::shared_ptr<PathResolver> LibPathResolver)
413 : LibPathCache(std::move(LibPathCache)),
414 LibPathResolver(std::move(LibPathResolver)) {
416 "orc", dbgs() << "LibraryScanHelper::LibraryScanHelper: base paths : "
417 << SPaths.size() << "\n";);
418 for (const auto &p : SPaths)
419 addBasePath(p);
420 }
421
422 LLVM_ABI void
423 addBasePath(const std::string &P,
424 PathType Kind =
425 PathType::Unknown); // Add a canonical directory for scanning
426
427 LLVM_ABI void getNextBatch(PathType Kind, size_t batchSize,
429
430 LLVM_ABI bool leftToScan(PathType K) const;
431 LLVM_ABI void resetToScan();
432
434 bool hasSearchPath() const { return !LibSearchPaths.empty(); }
435
437 SmallVector<StringRef> SearchPaths;
438 for (const auto &[_, SP] : LibSearchPaths)
439 SearchPaths.push_back(SP->BasePath);
440 return SearchPaths;
441 }
442
443 PathResolver &getPathResolver() const { return *LibPathResolver; }
444
445 LibraryPathCache &getCache() const { return *LibPathCache; }
446
448 return LibPathCache->hasSeenOrMark(P);
449 }
450
451 std::optional<std::string> resolve(StringRef P, std::error_code &ec) const {
452 return LibPathResolver->resolve(P.str(), ec);
453 }
454
455private:
456 std::string resolveCanonical(StringRef P, std::error_code &ec) const;
457 PathType classifyKind(StringRef P) const;
458
459 mutable std::shared_mutex Mtx;
460 std::shared_ptr<LibraryPathCache> LibPathCache;
461 std::shared_ptr<PathResolver> LibPathResolver;
462
464 LibSearchPaths; // key: canonical path
465 std::deque<StringRef> UnscannedUsr;
466 std::deque<StringRef> UnscannedSys;
467};
468
469/// Scans libraries, resolves dependencies, and registers them.
471public:
472 using ShouldScanFn = std::function<bool(StringRef)>;
473
476 ShouldScanFn ShouldScanCall = [](StringRef path) { return true; })
477 : ObjCache(ObjFileCache()), ScanHelper(H), LibMgr(LibMgr),
478 Validator(ScanHelper.getPathResolver(), ScanHelper.getCache(),
479 &ObjCache),
480 ShouldScanCall(std::move(ShouldScanCall)) {}
481
482 LLVM_ABI void scanNext(PathType Kind, size_t batchSize = 1);
483
484 /// Dependency info for a library.
500
501private:
502 ObjFileCache ObjCache;
503 LibraryScanHelper &ScanHelper;
504 LibraryManager &LibMgr;
505 DylibPathValidator Validator;
506 ShouldScanFn ShouldScanCall;
507
508 bool shouldScan(StringRef FilePath, bool IsResolvingDep = false);
509
510 Expected<LibraryDepsInfo> extractDeps(StringRef FilePath);
511
512 void handleLibrary(StringRef FilePath, PathType K, int level = 0);
513
514 void scanBaseDir(LibrarySearchPath *U);
515};
516
518
519} // end namespace orc
520} // end namespace llvm
521
522#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
This file defines the BumpPtrAllocator interface.
#define LLVM_ABI
Definition Compiler.h:213
std::deque< BasicBlock * > PathType
This file provides a collection of function (or more generally, callable) type erasure utilities supp...
#define _
#define H(x, y, z)
Definition MD5.cpp:56
#define P(N)
This file defines the SmallVector class.
StringSet - A set-like wrapper for the StringMap.
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
Definition Debug.h:72
Tile Register Pre configure
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
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
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
Definition StringMap.h:310
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
LLVM_ABI bool starts_with_insensitive(StringRef Prefix) const
Check if this string starts with the given Prefix, ignoring case.
Definition StringRef.cpp:41
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:629
Saves strings in the provided stable storage and returns a StringRef with a stable character pointer.
Definition StringSaver.h:22
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class is the base class for all object file types.
Definition ObjectFile.h:231
Validates and normalizes dynamic library paths.
std::optional< std::string > normalize(StringRef Path) const
DylibPathValidator(PathResolver &PR, LibraryPathCache &LC, ObjFileCache *ObjCache=nullptr)
LLVM_ABI bool isSharedLibrary(StringRef Path) const
bool isSharedLibraryCached(StringRef Path) const
std::optional< std::string > validate(StringRef Path) const
Validate the given path as a shared library.
DylibResolverImpl(DylibSubstitutor Substitutor, DylibPathValidator &Validator, std::vector< SearchPathResolver > Resolvers)
LLVM_ABI std::optional< std::string > resolve(StringRef Stem, bool VariateLibStem=false) const
static std::string resolvelinkerFlag(StringRef libStem, StringRef loaderPath)
std::optional< std::string > resolve(StringRef libStem, bool VariateLibStem=false) const
DylibResolver(DylibPathValidator &Validator)
void configure(StringRef loaderPath, ArrayRef< SearchPathConfig > SearchPathCfg)
Performs placeholder substitution in dynamic library paths.
std::string substitute(StringRef input) const
LLVM_ABI void configure(StringRef loaderPath)
Manages library metadata and state for symbol resolution.
bool hasSeen(StringRef CanonPath) const
bool hasSeenOrMark(StringRef CanonPath)
void clear(bool isRealPathCache=false)
void markSeen(const std::string &CanonPath)
Scans and tracks libraries for symbol resolution.
SmallVector< StringRef > getSearchPaths() const
LibraryPathCache & getCache() const
LLVM_ABI bool isTrackedBasePath(StringRef P) const
std::optional< std::string > resolve(StringRef P, std::error_code &ec) const
bool hasSeenOrMark(StringRef P) const
LLVM_ABI void getNextBatch(PathType Kind, size_t batchSize, SmallVectorImpl< const LibrarySearchPath * > &Out)
LLVM_ABI bool leftToScan(PathType K) const
PathResolver & getPathResolver() const
LLVM_ABI void addBasePath(const std::string &P, PathType Kind=PathType::Unknown)
LibraryScanHelper(const std::vector< std::string > &SPaths, std::shared_ptr< LibraryPathCache > LibPathCache, std::shared_ptr< PathResolver > LibPathResolver)
LLVM_ABI void scanNext(PathType Kind, size_t batchSize=1)
std::function< bool(StringRef)> ShouldScanFn
LibraryScanner(LibraryScanHelper &H, LibraryManager &LibMgr, ShouldScanFn ShouldScanCall=[](StringRef path) { return true;})
std::optional< ObjectFileLoader > take(StringRef Path)
void insert(StringRef Path, ObjectFileLoader &&Loader)
bool contains(StringRef Path) const
Loads an object file and provides access to it.
ObjectFileLoader & operator=(ObjectFileLoader &&)=default
ObjectFileLoader(ObjectFileLoader &&)=default
ObjectFileLoader & operator=(const ObjectFileLoader &)=delete
ObjectFileLoader(StringRef Path)
Construct an object file loader from the given path.
ObjectFileLoader(const ObjectFileLoader &)=delete
static LLVM_ABI bool isArchitectureCompatible(const object::ObjectFile &Obj)
Expected< object::ObjectFile & > getObjectFile()
Get the loaded object file, or return an error if loading failed.
Resolves file system paths with optional caching of results.
std::optional< std::string > readlinkCached(StringRef Path)
PathResolver(std::shared_ptr< LibraryPathCache > cache)
mode_t lstatCached(StringRef Path)
std::optional< std::string > resolve(StringRef Path, std::error_code &ec)
LLVM_ABI std::optional< std::string > realpathCached(StringRef Path, std::error_code &ec, StringRef base="", bool baseIsResolved=false, long symloopLevel=40)
SearchPathType searchPathType() const
LLVM_ABI std::optional< std::string > resolve(StringRef libStem, const DylibSubstitutor &Subst, DylibPathValidator &Validator) const
SearchPathResolver(const SearchPathConfig &Cfg, StringRef PlaceholderPrefix="")
LibraryScanner::LibraryDepsInfo LibraryDepsInfo
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
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
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:383
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:860
LibrarySearchPath(std::string Base, PathType K)
std::atomic< ScanState > State
ArrayRef< StringRef > Paths