LLVM 22.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#include <unordered_map>
31#include <unordered_set>
32
33namespace llvm {
34namespace orc {
35
36class LibraryManager;
37
39 friend class PathResolver;
40
41public:
42 LibraryPathCache() = default;
43
44 void clear(bool isRealPathCache = false) {
45 std::unique_lock<std::shared_mutex> lock(Mtx);
46 Seen.clear();
47 if (isRealPathCache) {
48 RealPathCache.clear();
49#ifndef _WIN32
50 ReadlinkCache.clear();
51 LstatCache.clear();
52#endif
53 }
54 }
55
56 void markSeen(const std::string &CanonPath) {
57 std::unique_lock<std::shared_mutex> lock(Mtx);
58 Seen.insert(CanonPath);
59 }
60
61 bool hasSeen(StringRef CanonPath) const {
62 std::shared_lock<std::shared_mutex> lock(Mtx);
63 return Seen.contains(CanonPath);
64 }
65
66 bool hasSeenOrMark(StringRef CanonPath) {
67 std::string s = CanonPath.str();
68 {
69 std::shared_lock<std::shared_mutex> lock(Mtx);
70 if (Seen.contains(s))
71 return true;
72 }
73 {
74 std::unique_lock<std::shared_mutex> lock(Mtx);
75 Seen.insert(s);
76 }
77 return false;
78 }
79
80private:
81 mutable std::shared_mutex Mtx;
82
83 struct PathInfo {
84 std::string canonicalPath;
85 std::error_code ErrnoCode;
86 };
87
88 void insert_realpath(StringRef Path, const PathInfo &Info) {
89 std::unique_lock<std::shared_mutex> lock(Mtx);
90 RealPathCache.insert({Path, Info});
91 }
92
93 std::optional<PathInfo> read_realpath(StringRef Path) const {
94 std::shared_lock<std::shared_mutex> lock(Mtx);
95 auto It = RealPathCache.find(Path);
96 if (It != RealPathCache.end())
97 return It->second;
98
99 return std::nullopt;
100 }
101
102 StringSet<> Seen;
103 StringMap<PathInfo> RealPathCache;
104
105#ifndef _WIN32
106 StringMap<std::string> ReadlinkCache;
107 StringMap<mode_t> LstatCache;
108
109 void insert_link(StringRef Path, const std::string &s) {
110 std::unique_lock<std::shared_mutex> lock(Mtx);
111 ReadlinkCache.insert({Path, s});
112 }
113
114 std::optional<std::string> read_link(StringRef Path) const {
115 std::shared_lock<std::shared_mutex> lock(Mtx);
116 auto It = ReadlinkCache.find(Path);
117 if (It != ReadlinkCache.end())
118 return It->second;
119
120 return std::nullopt;
121 }
122
123 void insert_lstat(StringRef Path, mode_t m) {
124 std::unique_lock<std::shared_mutex> lock(Mtx);
125 LstatCache.insert({Path, m});
126 }
127
128 std::optional<mode_t> read_lstat(StringRef Path) const {
129 std::shared_lock<std::shared_mutex> lock(Mtx);
130 auto It = LstatCache.find(Path);
131 if (It != LstatCache.end())
132 return It->second;
133
134 return std::nullopt;
135 }
136
137#endif
138};
139
140/// Resolves file system paths with optional caching of results.
141///
142/// Supports lstat, readlink, and realpath operations. Can resolve paths
143/// relative to a base and handle symbolic links. Caches results to reduce
144/// repeated system calls when enabled.
146private:
147 std::shared_ptr<LibraryPathCache> LibPathCache;
148
149public:
150 PathResolver(std::shared_ptr<LibraryPathCache> cache)
151 : LibPathCache(std::move(cache)) {}
152
153 std::optional<std::string> resolve(StringRef Path, std::error_code &ec) {
154 return realpathCached(Path, ec);
155 }
156#ifndef _WIN32
157 mode_t lstatCached(StringRef Path);
158 std::optional<std::string> readlinkCached(StringRef Path);
159#endif
160 std::optional<std::string> realpathCached(StringRef Path, std::error_code &ec,
161 StringRef base = "",
162 bool baseIsResolved = false,
163 long symloopLevel = 40);
164};
165
166/// Performs placeholder substitution in dynamic library paths.
167///
168/// Configures known placeholders (like @loader_path) and replaces them
169/// in input paths with their resolved values.
171public:
172 void configure(StringRef loaderPath);
173
174 std::string substitute(StringRef input) const {
175 for (const auto &[ph, value] : Placeholders) {
176 if (input.starts_with_insensitive(ph))
177 return (Twine(value) + input.drop_front(ph.size())).str();
178 }
179 return input.str();
180 }
181
182private:
183 StringMap<std::string> Placeholders;
184};
185
186/// Validates and normalizes dynamic library paths.
187///
188/// Uses a `PathResolver` to resolve paths to their canonical form and
189/// checks whether they point to valid shared libraries.
191public:
192 DylibPathValidator(PathResolver &PR) : LibPathResolver(PR) {}
193
194 static bool isSharedLibrary(StringRef Path);
195
196 std::optional<std::string> normalize(StringRef Path) const {
197 std::error_code ec;
198 auto real = LibPathResolver.resolve(Path, ec);
199 if (!real || ec)
200 return std::nullopt;
201
202 return real;
203 }
204
205 /// Validate the given path as a shared library.
206 std::optional<std::string> validate(StringRef Path) const {
207 auto realOpt = normalize(Path);
208 if (!realOpt)
209 return std::nullopt;
210
211 if (!isSharedLibrary(*realOpt))
212 return std::nullopt;
213
214 return realOpt;
215 }
216
217private:
218 PathResolver &LibPathResolver;
219};
220
226
231
233public:
235 StringRef PlaceholderPrefix = "")
236 : Kind(Cfg.type), PlaceholderPrefix(PlaceholderPrefix) {
237 for (auto &path : Cfg.Paths)
238 Paths.emplace_back(path.str());
239 }
240
241 std::optional<std::string> resolve(StringRef libStem,
242 const DylibSubstitutor &Subst,
243 DylibPathValidator &Validator) const;
244 SearchPathType searchPathType() const { return Kind; }
245
246private:
247 std::vector<std::string> Paths;
248 SearchPathType Kind;
249 std::string PlaceholderPrefix;
250};
251
253public:
255 std::vector<SearchPathResolver> Resolvers)
256 : Substitutor(std::move(Substitutor)), Validator(Validator),
257 Resolvers(std::move(Resolvers)) {}
258
259 std::optional<std::string> resolve(StringRef Stem,
260 bool VariateLibStem = false) const;
261
262private:
263 std::optional<std::string> tryWithExtensions(StringRef libstem) const;
264
265 DylibSubstitutor Substitutor;
266 DylibPathValidator &Validator;
267 std::vector<SearchPathResolver> Resolvers;
268};
269
271public:
272 DylibResolver(DylibPathValidator &Validator) : Validator(Validator) {}
273
274 void configure(StringRef loaderPath,
275 ArrayRef<SearchPathConfig> SearchPathCfg) {
276 DylibSubstitutor Substitutor;
277 Substitutor.configure(loaderPath);
278
279 std::vector<SearchPathResolver> Resolvers;
280 for (const auto &cfg : SearchPathCfg) {
281 Resolvers.emplace_back(cfg,
282 cfg.type == SearchPathType::RPath ? "@rpath" : "");
283 }
284
285 impl_ = std::make_unique<DylibResolverImpl>(
286 std::move(Substitutor), Validator, std::move(Resolvers));
287 }
288
289 std::optional<std::string> resolve(StringRef libStem,
290 bool VariateLibStem = false) const {
291 if (!impl_)
292 return std::nullopt;
293 return impl_->resolve(libStem, VariateLibStem);
294 }
295
296 static std::string resolvelinkerFlag(StringRef libStem,
297 StringRef loaderPath) {
298 DylibSubstitutor Substitutor;
299 Substitutor.configure(loaderPath);
300 return Substitutor.substitute(libStem);
301 }
302
303private:
304 DylibPathValidator &Validator;
305 std::unique_ptr<DylibResolverImpl> impl_;
306};
307
308enum class PathType : uint8_t { User, System, Unknown };
309
311
313 std::string BasePath; // Canonical base directory path
314 PathType Kind; // User or System
315 std::atomic<ScanState> State;
316
319};
320
321/// Scans and tracks libraries for symbol resolution.
322///
323/// Maintains a list of library paths to scan, caches scanned units,
324/// and resolves paths canonically for consistent tracking.
326public:
327 explicit LibraryScanHelper(const std::vector<std::string> &SPaths,
328 std::shared_ptr<LibraryPathCache> LibPathCache,
329 std::shared_ptr<PathResolver> LibPathResolver)
330 : LibPathCache(std::move(LibPathCache)),
331 LibPathResolver(std::move(LibPathResolver)) {
333 "orc", dbgs() << "LibraryScanHelper::LibraryScanHelper: base paths : "
334 << SPaths.size() << "\n";);
335 for (const auto &p : SPaths)
336 addBasePath(p);
337 }
338
339 void
340 addBasePath(const std::string &P,
341 PathType Kind =
342 PathType::Unknown); // Add a canonical directory for scanning
343 std::vector<std::shared_ptr<LibrarySearchPath>>
344 getNextBatch(PathType Kind, size_t batchSize);
345
346 bool leftToScan(PathType K) const;
347 void resetToScan();
348
349 bool isTrackedBasePath(StringRef P) const;
350 std::vector<std::shared_ptr<LibrarySearchPath>> getAllUnits() const;
351
353 SmallVector<StringRef> SearchPaths;
354 for (const auto &[_, SP] : LibSearchPaths)
355 SearchPaths.push_back(SP->BasePath);
356 return SearchPaths;
357 }
358
359 PathResolver &getPathResolver() const { return *LibPathResolver; }
360
361 LibraryPathCache &getCache() const { return *LibPathCache; }
362
364 return LibPathCache->hasSeenOrMark(P);
365 }
366
367 std::optional<std::string> resolve(StringRef P, std::error_code &ec) const {
368 return LibPathResolver->resolve(P.str(), ec);
369 }
370
371private:
372 std::string resolveCanonical(StringRef P, std::error_code &ec) const;
373 PathType classifyKind(StringRef P) const;
374
375 mutable std::shared_mutex Mtx;
376 std::shared_ptr<LibraryPathCache> LibPathCache;
377 std::shared_ptr<PathResolver> LibPathResolver;
378
380 LibSearchPaths; // key: canonical path
381 std::deque<StringRef> UnscannedUsr;
382 std::deque<StringRef> UnscannedSys;
383};
384
385/// Loads an object file and provides access to it.
386///
387/// Owns the underlying `ObjectFile` and ensures it is valid.
388/// Any errors encountered during construction are stored and
389/// returned when attempting to access the file.
391public:
392 /// Construct an object file loader from the given path.
394 auto ObjOrErr = loadObjectFileWithOwnership(Path);
395 if (ObjOrErr)
396 Obj = std::move(*ObjOrErr);
397 else {
398 consumeError(std::move(Err));
399 Err = ObjOrErr.takeError();
400 }
401 }
402
405
408
409 /// Get the loaded object file, or return an error if loading failed.
411 if (Err)
412 return std::move(Err);
413 return *Obj.getBinary();
414 }
415
416 static bool isArchitectureCompatible(const object::ObjectFile &Obj);
417
418private:
420 Error Err = Error::success();
421
423 loadObjectFileWithOwnership(StringRef FilePath);
424};
425
426/// Scans libraries, resolves dependencies, and registers them.
428public:
429 using ShouldScanFn = std::function<bool(StringRef)>;
430
433 ShouldScanFn ShouldScanCall = [](StringRef path) { return true; })
434 : ScanHelper(H), LibMgr(LibMgr),
435 ShouldScanCall(std::move(ShouldScanCall)) {}
436
437 void scanNext(PathType Kind, size_t batchSize = 1);
438
439 /// Dependency info for a library.
455
456private:
457 LibraryScanHelper &ScanHelper;
458 LibraryManager &LibMgr;
459 ShouldScanFn ShouldScanCall;
460
461 std::optional<std::string> shouldScan(StringRef FilePath);
462 Expected<LibraryDepsInfo> extractDeps(StringRef FilePath);
463
464 void handleLibrary(StringRef P, PathType K, int level = 1);
465
466 void scanBaseDir(std::shared_ptr<LibrarySearchPath> U);
467};
468
470
471} // end namespace orc
472} // end namespace llvm
473
474#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_LIBRARYSCANNER_H
This file defines the BumpPtrAllocator interface.
Analysis containing CSE Info
Definition CSEInfo.cpp:27
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:57
#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
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
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
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
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
Definition StringMap.h:321
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
LLVM_ABI bool starts_with_insensitive(StringRef Prefix) const
Check if this string starts with the given Prefix, ignoring case.
Definition StringRef.cpp:46
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:611
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
static bool isSharedLibrary(StringRef Path)
DylibPathValidator(PathResolver &PR)
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)
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
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.
std::vector< std::shared_ptr< LibrarySearchPath > > getNextBatch(PathType Kind, size_t batchSize)
SmallVector< StringRef > getSearchPaths() const
LibraryPathCache & getCache() const
bool isTrackedBasePath(StringRef P) const
std::optional< std::string > resolve(StringRef P, std::error_code &ec) const
bool hasSeenOrMark(StringRef P) const
bool leftToScan(PathType K) const
std::vector< std::shared_ptr< LibrarySearchPath > > getAllUnits() const
PathResolver & getPathResolver() const
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)
void scanNext(PathType Kind, size_t batchSize=1)
std::function< bool(StringRef)> ShouldScanFn
LibraryScanner(LibraryScanHelper &H, LibraryManager &LibMgr, ShouldScanFn ShouldScanCall=[](StringRef path) { return true;})
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 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)
std::optional< std::string > realpathCached(StringRef Path, std::error_code &ec, StringRef base="", bool baseIsResolved=false, long symloopLevel=40)
SearchPathType searchPathType() const
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 raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
BumpPtrAllocatorImpl BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:383
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
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867
LibrarySearchPath(std::string Base, PathType K)
std::atomic< ScanState > State
ArrayRef< StringRef > Paths