LLVM 22.0.0git
LibraryResolver.cpp
Go to the documentation of this file.
1//===- LibraryResolver.cpp - Library Resolution of Unresolved Symbols ---===//
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// Library resolution impl for unresolved symbols
10//
11//===----------------------------------------------------------------------===//
12
15
16#include "llvm/ADT/StringSet.h"
17
19#include "llvm/Object/COFF.h"
20#include "llvm/Object/ELF.h"
22#include "llvm/Object/MachO.h"
24#include "llvm/Support/Error.h"
25
26#include <mutex>
27#include <thread>
28
29#define DEBUG_TYPE "orc-resolver"
30
31namespace llvm::orc {
32
34 : LibPathCache(S.Cache ? S.Cache : std::make_shared<LibraryPathCache>()),
35 LibPathResolver(S.PResolver
36 ? S.PResolver
37 : std::make_shared<PathResolver>(LibPathCache)),
38 ScanHelper(S.BasePaths, LibPathCache, LibPathResolver),
39 FB(S.FilterBuilder), LibMgr(),
40 ShouldScanCall(S.ShouldScanCall ? S.ShouldScanCall
41 : [](StringRef) -> bool { return true; }),
42 scanBatchSize(S.ScanBatchSize) {
43
44 if (ScanHelper.getAllUnits().empty()) {
45 LLVM_DEBUG(dbgs() << "Warning: No base paths provided for scanning.\n");
46 }
47}
48
49std::unique_ptr<LibraryResolutionDriver>
51 auto LR = std::make_unique<LibraryResolver>(S);
52 return std::unique_ptr<LibraryResolutionDriver>(
53 new LibraryResolutionDriver(std::move(LR)));
54}
55
56void LibraryResolutionDriver::addScanPath(const std::string &Path, PathType K) {
57 LR->ScanHelper.addBasePath(Path, K);
58}
59
61 auto Lib = LR->LibMgr.getLibrary(Path);
62 if (!Lib)
63 return false;
64
66
67 return true;
68}
69
71 auto Lib = LR->LibMgr.getLibrary(Path);
72 if (!Lib)
73 return false;
74
76
77 return true;
78}
79
81 std::vector<std::string> Syms,
83 const SearchConfig &Config) {
84 LR->searchSymbolsInLibraries(Syms, std::move(OnCompletion), Config);
85}
86
88 uint32_t IgnoreFlags) {
89 Expected<uint32_t> FlagsOrErr = Sym.getFlags();
90 if (!FlagsOrErr) {
91 consumeError(FlagsOrErr.takeError());
92 return true;
93 }
94
95 uint32_t Flags = *FlagsOrErr;
96
98 if ((IgnoreFlags & Filter::IgnoreUndefined) &&
100 return true;
101 if ((IgnoreFlags & Filter::IgnoreIndirect) &&
103 return true;
104 if ((IgnoreFlags & Filter::IgnoreWeak) &&
106 return true;
107
108 return false;
109}
110
112 const SymbolEnumeratorOptions &Opts) {
113 if (Path.empty())
114 return false;
115
116 ObjectFileLoader ObjLoader(Path);
117
118 auto ObjOrErr = ObjLoader.getObjectFile();
119 if (!ObjOrErr) {
120 std::string ErrMsg;
121 handleAllErrors(ObjOrErr.takeError(),
122 [&](const ErrorInfoBase &EIB) { ErrMsg = EIB.message(); });
123 LLVM_DEBUG(dbgs() << "Failed loading object file: " << Path
124 << "\nError: " << ErrMsg << "\n");
125 return false;
126 }
127
128 object::ObjectFile *Obj = &ObjOrErr.get();
129
130 auto processSymbolRange =
132 for (const auto &Sym : Range) {
133 if (shouldIgnoreSymbol(Sym, Opts.FilterFlags))
134 continue;
135
136 auto NameOrErr = Sym.getName();
137 if (!NameOrErr) {
138 consumeError(NameOrErr.takeError());
139 continue;
140 }
141
142 StringRef Name = *NameOrErr;
143 if (Name.empty())
144 continue;
145
146 EnumerateResult Res = OnEach(Name);
147 if (Res != EnumerateResult::Continue)
148 return Res;
149 }
150 return EnumerateResult::Continue;
151 };
152
153 EnumerateResult Res = processSymbolRange(Obj->symbols());
154 if (Res != EnumerateResult::Continue)
155 return Res == EnumerateResult::Stop;
156
157 if (Obj->isELF()) {
158 const auto *ElfObj = cast<object::ELFObjectFileBase>(Obj);
159 Res = processSymbolRange(ElfObj->getDynamicSymbolIterators());
160 if (Res != EnumerateResult::Continue)
161 return Res == EnumerateResult::Stop;
162 } else if (Obj->isCOFF()) {
163 const auto *CoffObj = cast<object::COFFObjectFile>(Obj);
164 for (auto I = CoffObj->export_directory_begin(),
165 E = CoffObj->export_directory_end();
166 I != E; ++I) {
167 StringRef Name;
168 if (I->getSymbolName(Name))
169 continue;
170 if (Name.empty())
171 continue;
172
173 EnumerateResult Res = OnEach(Name);
174 if (Res != EnumerateResult::Continue)
175 return Res == EnumerateResult::Stop;
176 }
177 } else if (Obj->isMachO()) {
178 }
179
180 return true;
181}
182
184public:
186
187 bool hasSearched(LibraryInfo *Lib) const { return Searched.count(Lib); }
188
189 void markSearched(LibraryInfo *Lib) { Searched.insert(Lib); }
190
191 inline bool allResolved() const { return Q.allResolved(); }
192
193 SymbolQuery &query() { return Q; }
194
195private:
196 SymbolQuery &Q;
198};
199
200void LibraryResolver::resolveSymbolsInLibrary(
201 LibraryInfo &Lib, SymbolQuery &UnresolvedSymbols,
202 const SymbolEnumeratorOptions &Opts) {
203 LLVM_DEBUG(dbgs() << "Checking unresolved symbols "
204 << " in library : " << Lib.getFileName() << "\n";);
205 StringSet<> DiscoveredSymbols;
206
207 if (!UnresolvedSymbols.hasUnresolved()) {
208 LLVM_DEBUG(dbgs() << "Skipping library: " << Lib.getFullPath()
209 << " — unresolved symbols exist.\n";);
210 return;
211 }
212
213 bool HasEnumerated = false;
214 auto enumerateSymbolsIfNeeded = [&]() {
215 if (HasEnumerated)
216 return;
217
218 HasEnumerated = true;
219
220 LLVM_DEBUG(dbgs() << "Enumerating symbols in library: " << Lib.getFullPath()
221 << "\n";);
222 SymbolEnumerator::enumerateSymbols(
223 Lib.getFullPath(),
224 [&](StringRef sym) {
225 DiscoveredSymbols.insert(sym);
226 return EnumerateResult::Continue;
227 },
228 Opts);
229
230 if (DiscoveredSymbols.empty()) {
231 LLVM_DEBUG(dbgs() << " No symbols and remove library : "
232 << Lib.getFullPath() << "\n";);
233 LibMgr.removeLibrary(Lib.getFullPath());
234 return;
235 }
236 };
237
238 if (!Lib.hasFilter()) {
239 LLVM_DEBUG(dbgs() << "Building filter for library: " << Lib.getFullPath()
240 << "\n";);
241 enumerateSymbolsIfNeeded();
242 SmallVector<StringRef> SymbolVec;
243 SymbolVec.reserve(DiscoveredSymbols.size());
244 for (const auto &KV : DiscoveredSymbols)
245 SymbolVec.push_back(KV.first());
246
247 Lib.ensureFilterBuilt(FB, SymbolVec);
248 LLVM_DEBUG({
249 dbgs() << "DiscoveredSymbols : " << DiscoveredSymbols.size() << "\n";
250 for (const auto &KV : DiscoveredSymbols)
251 dbgs() << "DiscoveredSymbols : " << KV.first() << "\n";
252 });
253 }
254
255 const auto &Unresolved = UnresolvedSymbols.getUnresolvedSymbols();
256 bool HadAnySym = false;
257 LLVM_DEBUG(dbgs() << "Total unresolved symbols : " << Unresolved.size()
258 << "\n";);
259 for (const auto &Sym : Unresolved) {
260 if (Lib.mayContain(Sym)) {
261 LLVM_DEBUG(dbgs() << "Checking symbol '" << Sym
262 << "' in library: " << Lib.getFullPath() << "\n";);
263 enumerateSymbolsIfNeeded();
264 if (DiscoveredSymbols.count(Sym) > 0) {
265 LLVM_DEBUG(dbgs() << " Resolved symbol: " << Sym
266 << " in library: " << Lib.getFullPath() << "\n";);
267 UnresolvedSymbols.resolve(Sym, Lib.getFullPath());
268 HadAnySym = true;
269 }
270 }
271 }
272
273 using LibraryState = LibraryManager::LibState;
274 if (HadAnySym && Lib.getState() != LibraryState::Loaded)
275 Lib.setState(LibraryState::Queried);
276}
277
279 std::vector<std::string> &SymbolList, OnSearchComplete OnComplete,
280 const SearchConfig &Config) {
281 SymbolQuery Q(SymbolList);
282
283 using LibraryState = LibraryManager::LibState;
284 using LibraryType = PathType;
285 auto tryResolveFrom = [&](LibraryState S, LibraryType K) {
286 LLVM_DEBUG(dbgs() << "Trying resolve from state=" << static_cast<int>(S)
287 << " type=" << static_cast<int>(K) << "\n";);
288
289 SymbolSearchContext Ctx(Q);
290 while (!Ctx.allResolved()) {
291
292 for (auto &Lib : LibMgr.getView(S, K)) {
293 if (Ctx.hasSearched(Lib.get()))
294 continue;
295
296 // can use Async here?
297 resolveSymbolsInLibrary(*Lib, Ctx.query(), Config.Options);
298 Ctx.markSearched(Lib.get());
299
300 if (Ctx.allResolved())
301 return;
302 }
303
304 if (Ctx.allResolved())
305 return;
306
307 if (!scanLibrariesIfNeeded(K, scanBatchSize))
308 break; // no more new libs to scan
309 }
310 };
311
312 for (const auto &[St, Ty] : Config.Policy.Plan) {
313 tryResolveFrom(St, Ty);
314 if (Q.allResolved())
315 break;
316 }
317
318 // done:
319 LLVM_DEBUG({
320 dbgs() << "Search complete.\n";
321 for (const auto &r : Q.getAllResults())
322 dbgs() << "Resolved Symbol:" << r->Name << " -> " << r->ResolvedLibPath
323 << "\n";
324 });
325
326 OnComplete(Q);
327}
328
329bool LibraryResolver::scanLibrariesIfNeeded(PathType PK, size_t BatchSize) {
330 LLVM_DEBUG(dbgs() << "LibraryResolver::scanLibrariesIfNeeded: Scanning for "
331 << (PK == PathType::User ? "User" : "System")
332 << " libraries\n";);
333 if (!ScanHelper.leftToScan(PK))
334 return false;
335
336 LibraryScanner Scanner(ScanHelper, LibMgr, ShouldScanCall);
337 Scanner.scanNext(PK, BatchSize);
338 return true;
339}
340
341bool LibraryResolver::symbolExistsInLibrary(const LibraryInfo &Lib,
342 StringRef SymName,
343 std::vector<std::string> *AllSyms) {
344 SymbolEnumeratorOptions Opts;
345 return symbolExistsInLibrary(Lib, SymName, AllSyms, Opts);
346}
347
348bool LibraryResolver::symbolExistsInLibrary(
349 const LibraryInfo &Lib, StringRef SymName,
350 std::vector<std::string> *AllSyms, const SymbolEnumeratorOptions &Opts) {
351 bool Found = false;
352
353 SymbolEnumerator::enumerateSymbols(
354 Lib.getFullPath(),
355 [&](StringRef Sym) {
356 if (AllSyms)
357 AllSyms->emplace_back(Sym.str());
358
359 if (Sym == SymName) {
360 Found = true;
361 }
362
363 return EnumerateResult::Continue;
364 },
365 Opts);
366
367 return Found;
368}
369
370} // end namespace llvm::orc
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define I(x, y, z)
Definition MD5.cpp:58
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
StringSet - A set-like wrapper for the StringMap.
#define LLVM_DEBUG(...)
Definition Debug.h:114
Implements a dense probed hash-table based set.
Definition DenseSet.h:279
Base class for error info classes.
Definition Error.h:44
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
unsigned size() const
Definition StringMap.h:109
bool empty() const
Definition StringMap.h:108
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition StringSet.h:25
Expected< uint32_t > getFlags() const
Get symbol flags (bitwise OR of SymbolRef::Flags)
bool isMachO() const
Definition Binary.h:129
bool isCOFF() const
Definition Binary.h:133
bool isELF() const
Definition Binary.h:125
This class is the base class for all object file types.
Definition ObjectFile.h:231
symbol_iterator_range symbols() const
Definition ObjectFile.h:323
iterator_range< symbol_iterator > symbol_iterator_range
Definition ObjectFile.h:322
This is a value type class that represents a single symbol in the list of symbols in the object file.
Definition ObjectFile.h:170
void resolveSymbols(std::vector< std::string > Symbols, LibraryResolver::OnSearchComplete OnCompletion, const SearchConfig &Config=SearchConfig())
void addScanPath(const std::string &Path, PathType Kind)
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.
std::vector< const Result * > getAllResults() const
unique_function< void(SymbolQuery &)> OnSearchComplete
void searchSymbolsInLibraries(std::vector< std::string > &SymList, OnSearchComplete OnComplete, const SearchConfig &Config=SearchConfig())
Scans libraries, resolves dependencies, and registers them.
Loads an object file and provides access to it.
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.
bool hasSearched(LibraryInfo *Lib) const
void markSearched(LibraryInfo *Lib)
LibraryManager::LibraryInfo LibraryInfo
static bool shouldIgnoreSymbol(const object::SymbolRef &Sym, uint32_t IgnoreFlags)
LibraryResolver::SymbolQuery SymbolQuery
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition Error.h:990
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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
SymbolEnumeratorOptions Options
std::vector< SearchPlanEntry > Plan