CppInterOp
C++ Language Interoperability Layer
Loading...
Searching...
No Matches
DynamicLibraryManagerSymbol.cpp
Go to the documentation of this file.
1//------------------------------------------------------------------------------
2// CLING - the C++ LLVM-based InterpreterG :)
3// author: Vassil Vassilev <vvasilev@cern.ch>
4// author: Alexander Penev <alexander_penev@yahoo.com>
5//
6// This file is dual-licensed: you can choose to license it under the University
7// of Illinois Open Source License or the GNU Lesser General Public License. See
8// LICENSE.TXT for details.
9//------------------------------------------------------------------------------
10
12#include "Paths.h"
13
14#include "llvm/ADT/SmallSet.h"
15#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/StringMap.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/StringSet.h"
19#include "llvm/BinaryFormat/MachO.h"
20#include "llvm/Object/COFF.h"
21#include "llvm/Object/ELF.h"
22#include "llvm/Object/ELFObjectFile.h"
23#include "llvm/Object/MachO.h"
24#include "llvm/Object/ObjectFile.h"
25#include "llvm/Support/Debug.h"
26#include "llvm/Support/DynamicLibrary.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/FileSystem.h"
29#include "llvm/Support/Format.h"
30#include "llvm/Support/Path.h"
31#include "llvm/Support/Program.h"
32#include "llvm/Support/WithColor.h"
33
34#include <algorithm>
35#include <list>
36#include <string>
37#include <unordered_set>
38#include <vector>
39
40#ifdef LLVM_ON_UNIX
41#include <dlfcn.h>
42#include <sys/stat.h>
43#include <unistd.h>
44#endif // LLVM_ON_UNIX
45
46#ifdef __APPLE__
47#include <mach-o/dyld.h>
48#include <sys/stat.h>
49#undef LC_LOAD_DYLIB
50#undef LC_RPATH
51#endif // __APPLE__
52
53#ifdef _WIN32
54#define WIN32_LEAN_AND_MEAN
55#define NOMINMAX
56// clang-format off
57#include <windows.h>
58#include <libloaderapi.h> // For GetModuleFileNameA
59#include <memoryapi.h> // For VirtualQuery
60// clang-format on
61#endif
62
63namespace {
64
65using BasePath = std::string;
66using namespace llvm;
67
68// This is a GNU implementation of hash used in bloom filter!
69static uint32_t GNUHash(StringRef S) {
70 uint32_t H = 5381;
71 for (uint8_t C : S)
72 H = (H << 5) + H + C;
73 return H;
74}
75
76constexpr uint32_t log2u(std::uint32_t n) {
77 return (n > 1) ? 1 + log2u(n >> 1) : 0;
78}
79
80struct BloomFilter {
81
82 // https://hur.st/bloomfilter
83 //
84 // n = ceil(m / (-k / log(1 - exp(log(p) / k))))
85 // p = pow(1 - exp(-k / (m / n)), k)
86 // m = ceil((n * log(p)) / log(1 / pow(2, log(2))));
87 // k = round((m / n) * log(2));
88 //
89 // n = symbolsCount
90 // p = 0.02
91 // k = 2 (k1=GNUHash and k2=GNUHash >> bloomShift)
92 // m = ceil((symbolsCount * log(p)) / log(1 / pow(2, log(2))));
93 // bloomShift = min(5 for bits=32 or 6 for bits=64, log2(symbolsCount))
94 // bloomSize = ceil((-1.44 * n * log2f(p)) / bits)
95
96 const int m_Bits = 8 * sizeof(uint64_t);
97 const float m_P = 0.02f;
98
99 bool m_IsInitialized = false;
100 uint32_t m_SymbolsCount = 0;
101 uint32_t m_BloomSize = 0;
102 uint32_t m_BloomShift = 0;
103 std::vector<uint64_t> m_BloomTable;
104
105 bool TestHash(uint32_t hash) const {
106 // This function is superhot. No branches here, breaks inlining and makes
107 // overall performance around 4x slower.
108 assert(m_IsInitialized && "Not yet initialized!");
109 uint32_t hash2 = hash >> m_BloomShift;
110 uint32_t n = (hash >> log2u(m_Bits)) % m_BloomSize;
111 uint64_t mask = ((1ULL << (hash % m_Bits)) | (1ULL << (hash2 % m_Bits)));
112 return (mask & m_BloomTable[n]) == mask;
113 }
114
115 void AddHash(uint32_t hash) {
116 assert(m_IsInitialized && "Not yet initialized!");
117 uint32_t hash2 = hash >> m_BloomShift;
118 uint32_t n = (hash >> log2u(m_Bits)) % m_BloomSize;
119 uint64_t mask = ((1ULL << (hash % m_Bits)) | (1ULL << (hash2 % m_Bits)));
120 m_BloomTable[n] |= mask;
121 }
122
123 void ResizeTable(uint32_t newSymbolsCount) {
124 assert(m_SymbolsCount == 0 && "Not supported yet!");
125 m_SymbolsCount = newSymbolsCount;
126 m_BloomSize = ceil((-1.44f * m_SymbolsCount * log2f(m_P)) / m_Bits);
127 m_BloomShift = std::min(6u, log2u(m_SymbolsCount));
128 m_BloomTable.resize(m_BloomSize);
129 }
130};
131
132/// An efficient representation of a full path to a library which does not
133/// duplicate common path patterns reducing the overall memory footprint.
134///
135/// For example, `/home/.../lib/libA.so`, m_Path will contain a pointer
136/// to `/home/.../lib/`
137/// will be stored and .second `libA.so`.
138/// This approach reduces the duplicate paths as at one location there may be
139/// plenty of libraries.
140struct LibraryPath {
141 const BasePath& m_Path;
142 std::string m_LibName;
143 BloomFilter m_Filter;
144 StringSet<> m_Symbols;
145 // std::vector<const LibraryPath*> m_LibDeps;
146
147 LibraryPath(const BasePath& Path, const std::string& LibName)
148 : m_Path(Path), m_LibName(LibName) {}
149
150 bool operator==(const LibraryPath& other) const {
151 return (&m_Path == &other.m_Path || m_Path == other.m_Path) &&
152 m_LibName == other.m_LibName;
153 }
154
155 const std::string GetFullName() const {
156 SmallString<512> Vec(m_Path);
157 llvm::sys::path::append(Vec, StringRef(m_LibName));
158 return Vec.str().str();
159 }
160
161 void AddBloom(StringRef symbol) { m_Filter.AddHash(GNUHash(symbol)); }
162
163 StringRef AddSymbol(const std::string& symbol) {
164 auto it = m_Symbols.insert(symbol);
165 return it.first->getKey();
166 }
167
168 bool hasBloomFilter() const { return m_Filter.m_IsInitialized; }
169
170 bool isBloomFilterEmpty() const {
171 assert(m_Filter.m_IsInitialized && "Bloom filter not initialized!");
172 return m_Filter.m_SymbolsCount == 0;
173 }
174
175 void InitializeBloomFilter(uint32_t newSymbolsCount) {
176 assert(!m_Filter.m_IsInitialized &&
177 "Cannot re-initialize non-empty filter!");
178 m_Filter.m_IsInitialized = true;
179 m_Filter.ResizeTable(newSymbolsCount);
180 }
181
182 bool MayExistSymbol(uint32_t hash) const {
183 // The library had no symbols and the bloom filter is empty.
184 if (isBloomFilterEmpty())
185 return false;
186
187 return m_Filter.TestHash(hash);
188 }
189
190 bool ExistSymbol(StringRef symbol) const {
191 return m_Symbols.find(symbol) != m_Symbols.end();
192 }
193};
194
195/// A helper class keeping track of loaded libraries. It implements a fast
196/// search O(1) while keeping deterministic iterability in a memory efficient
197/// way. The underlying set uses a custom hasher for better efficiency given the
198/// specific problem where the library names (m_LibName) are relatively short
199/// strings and the base paths (m_Path) are repetitive long strings.
200class LibraryPaths {
201 struct LibraryPathHashFn {
202 size_t operator()(const LibraryPath& item) const {
203 return std::hash<size_t>()(item.m_Path.length()) ^
204 std::hash<std::string>()(item.m_LibName);
205 }
206 };
207
208 std::vector<const LibraryPath*> m_Libs;
209 std::unordered_set<LibraryPath, LibraryPathHashFn> m_LibsH;
210
211public:
212 bool HasRegisteredLib(const LibraryPath& Lib) const {
213 return m_LibsH.count(Lib);
214 }
215
216 const LibraryPath* GetRegisteredLib(const LibraryPath& Lib) const {
217 auto search = m_LibsH.find(Lib);
218 if (search != m_LibsH.end())
219 return &(*search);
220 return nullptr;
221 }
222
223 const LibraryPath* RegisterLib(const LibraryPath& Lib) {
224 auto it = m_LibsH.insert(Lib);
225 assert(it.second && "Already registered!");
226 m_Libs.push_back(&*it.first);
227 return &*it.first;
228 }
229
230 void UnregisterLib(const LibraryPath& Lib) {
231 auto found = m_LibsH.find(Lib);
232 if (found == m_LibsH.end())
233 return;
234
235 m_Libs.erase(std::find(m_Libs.begin(), m_Libs.end(), &*found));
236 m_LibsH.erase(found);
237 }
238
239 size_t size() const {
240 assert(m_Libs.size() == m_LibsH.size());
241 return m_Libs.size();
242 }
243
244 const std::vector<const LibraryPath*>& GetLibraries() const { return m_Libs; }
245};
246
247#ifndef _WIN32
248// Cached version of system function lstat
249static inline mode_t cached_lstat(const char* path) {
250 static StringMap<mode_t> lstat_cache;
251
252 // If already cached - return cached result
253 auto it = lstat_cache.find(path);
254 if (it != lstat_cache.end())
255 return it->second;
256
257 // If result not in cache - call system function and cache result
258 struct stat buf;
259 mode_t st_mode = (lstat(path, &buf) == -1) ? 0 : buf.st_mode;
260 lstat_cache.insert(std::pair<StringRef, mode_t>(path, st_mode));
261 return st_mode;
262}
263
264// Cached version of system function readlink
265static inline StringRef cached_readlink(const char* pathname) {
266 static StringMap<std::string> readlink_cache;
267
268 // If already cached - return cached result
269 auto it = readlink_cache.find(pathname);
270 if (it != readlink_cache.end())
271 return StringRef(it->second);
272
273 // If result not in cache - call system function and cache result
274 char buf[PATH_MAX];
275 ssize_t len;
276 if ((len = readlink(pathname, buf, sizeof(buf))) != -1) {
277 buf[len] = '\0';
278 std::string s(buf);
279 readlink_cache.insert(std::pair<StringRef, std::string>(pathname, s));
280 return readlink_cache[pathname];
281 }
282 return "";
283}
284#endif
285
286// Cached version of system function realpath
287std::string cached_realpath(StringRef path, StringRef base_path = "",
288 bool is_base_path_real = false,
289 long symlooplevel = 40) {
290 if (path.empty()) {
291 errno = ENOENT;
292 return "";
293 }
294
295 if (!symlooplevel) {
296 errno = ELOOP;
297 return "";
298 }
299
300 // If already cached - return cached result
301 static StringMap<std::pair<std::string, int>> cache;
302 bool relative_path = llvm::sys::path::is_relative(path);
303 if (!relative_path) {
304 auto it = cache.find(path);
305 if (it != cache.end()) {
306 errno = it->second.second;
307 return it->second.first;
308 }
309 }
310
311 // If result not in cache - call system function and cache result
312
313 StringRef sep(llvm::sys::path::get_separator());
314 SmallString<256> result(sep);
315#ifndef _WIN32
316 SmallVector<StringRef, 16> p;
317
318 // Relative or absolute path
319 if (relative_path) {
320 if (is_base_path_real) {
321 result.assign(base_path);
322 } else {
323 if (path[0] == '~' &&
324 (path.size() == 1 || llvm::sys::path::is_separator(path[1]))) {
325 static SmallString<128> home;
326 if (home.str().empty())
327 llvm::sys::path::home_directory(home);
328 StringRef(home).split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
329 } else if (base_path.empty()) {
330 static SmallString<256> current_path;
331 if (current_path.str().empty())
332 llvm::sys::fs::current_path(current_path);
333 StringRef(current_path)
334 .split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
335 } else {
336 base_path.split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
337 }
338 }
339 }
340 path.split(p, sep, /*MaxSplit*/ -1, /*KeepEmpty*/ false);
341
342 // Handle path list items
343 for (auto item : p) {
344 if (item == ".")
345 continue; // skip "." element in "abc/./def"
346 if (item == "..") {
347 // collapse "a/b/../c" to "a/c"
348 size_t s = result.rfind(sep);
349 if (s != llvm::StringRef::npos)
350 result.resize(s);
351 if (result.empty())
352 result = sep;
353 continue;
354 }
355
356 size_t old_size = result.size();
357 llvm::sys::path::append(result, item);
358 mode_t st_mode = cached_lstat(result.c_str());
359 if (S_ISLNK(st_mode)) {
360 StringRef symlink = cached_readlink(result.c_str());
361 if (llvm::sys::path::is_relative(symlink)) {
362 result.resize(old_size);
363 result = cached_realpath(symlink, result, true, symlooplevel - 1);
364 } else {
365 result = cached_realpath(symlink, "", true, symlooplevel - 1);
366 }
367 } else if (st_mode == 0) {
368 cache.insert(std::pair<StringRef, std::pair<std::string, int>>(
369 path, std::pair<std::string, int>("", ENOENT)));
370 errno = ENOENT;
371 return "";
372 }
373 }
374#else
375 llvm::sys::fs::real_path(path, result);
376#endif
377 cache.insert(std::pair<StringRef, std::pair<std::string, int>>(
378 path, std::pair<std::string, int>(result.str().str(), errno)));
379 return result.str().str();
380}
381
382using namespace llvm;
383using namespace llvm::object;
384
385template <class ELFT>
386static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT>* Elf) {
387 auto DynamicEntriesOrError = Elf->dynamicEntries();
388 if (!DynamicEntriesOrError)
389 return DynamicEntriesOrError.takeError();
390
391 for (const typename ELFT::Dyn& Dyn : *DynamicEntriesOrError) {
392 if (Dyn.d_tag == ELF::DT_STRTAB) {
393 auto MappedAddrOrError = Elf->toMappedAddr(Dyn.getPtr());
394 if (!MappedAddrOrError)
395 return MappedAddrOrError.takeError();
396 return StringRef(reinterpret_cast<const char*>(*MappedAddrOrError));
397 }
398 }
399
400 // If the dynamic segment is not present, we fall back on the sections.
401 auto SectionsOrError = Elf->sections();
402 if (!SectionsOrError)
403 return SectionsOrError.takeError();
404
405 for (const typename ELFT::Shdr& Sec : *SectionsOrError) {
406 if (Sec.sh_type == ELF::SHT_DYNSYM)
407 return Elf->getStringTableForSymtab(Sec);
408 }
409
410 return createError("dynamic string table not found");
411}
412
413static StringRef GetGnuHashSection(llvm::object::ObjectFile* file) {
414 for (auto S : file->sections()) {
415 StringRef name = llvm::cantFail(S.getName());
416 if (name == ".gnu.hash") {
417 return llvm::cantFail(S.getContents());
418 }
419 }
420 return "";
421}
422
423/// Bloom filter is a stochastic data structure which can tell us if a symbol
424/// name does not exist in a library with 100% certainty. If it tells us it
425/// exists this may not be true:
426/// https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2
427///
428/// ELF has this optimization in the new linkers by default, It is stored in the
429/// gnu.hash section of the object file.
430///
431///\returns true if the symbol may be in the library.
432static bool MayExistInElfObjectFile(llvm::object::ObjectFile* soFile,
433 uint32_t hash) {
434 assert(soFile->isELF() && "Not ELF");
435
436 // Compute the platform bitness -- either 64 or 32.
437 const unsigned bits = 8 * soFile->getBytesInAddress();
438
439 StringRef contents = GetGnuHashSection(soFile);
440 if (contents.size() < 16)
441 // We need to search if the library doesn't have .gnu.hash section!
442 return true;
443 const char* hashContent = contents.data();
444
445 // See https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/ for .gnu.hash
446 // table layout.
447 uint32_t maskWords = *reinterpret_cast<const uint32_t*>(hashContent + 8);
448 uint32_t shift2 = *reinterpret_cast<const uint32_t*>(hashContent + 12);
449 uint32_t hash2 = hash >> shift2;
450 uint32_t n = (hash / bits) % maskWords;
451
452 const char* bloomfilter = hashContent + 16;
453 const char* hash_pos = bloomfilter + n * (bits / 8); // * (Bits / 8)
454 uint64_t word = *reinterpret_cast<const uint64_t*>(hash_pos);
455 uint64_t bitmask = ((1ULL << (hash % bits)) | (1ULL << (hash2 % bits)));
456 return (bitmask & word) == bitmask;
457}
458
459} // namespace
460
461namespace CppInternal {
462
463// This function isn't referenced outside its translation unit, but it
464// can't use the "static" keyword because its address is used for
465// GetMainExecutable (since some platforms don't support taking the
466// address of main, and some platforms can't implement GetMainExecutable
467// without being given the address of a function in the main executable).
468std::string GetExecutablePath() {
469 // This just needs to be some symbol in the binary; C++ doesn't
470 // allow taking the address of ::main however.
471 return DynamicLibraryManager::getSymbolLocation(&GetExecutablePath);
472}
473
474class Dyld {
475 struct BasePathHashFunction {
476 size_t operator()(const BasePath& item) const {
477 return std::hash<std::string>()(item);
478 }
479 };
480
481 struct BasePathEqFunction {
482 size_t operator()(const BasePath& l, const BasePath& r) const {
483 return &l == &r || l == r;
484 }
485 };
486 /// A memory efficient llvm::VectorSet. The class provides O(1) search
487 /// complexity. It is tuned to compare BasePaths first by checking the
488 /// address and then the representation which models the base path reuse.
489 class BasePaths {
490 public:
491 std::unordered_set<BasePath, BasePathHashFunction, BasePathEqFunction>
492 m_Paths;
493
494 public:
495 const BasePath& RegisterBasePath(const std::string& Path,
496 bool* WasInserted = nullptr) {
497 auto it = m_Paths.insert(Path);
498 if (WasInserted)
499 *WasInserted = it.second;
500
501 return *it.first;
502 }
503
504 bool Contains(StringRef Path) { return m_Paths.count(Path.str()); }
505 };
506
507 bool m_FirstRun = true;
508 bool m_FirstRunSysLib = true;
509 bool m_UseBloomFilter = true;
510 bool m_UseHashTable = true;
511
512 const DynamicLibraryManager& m_DynamicLibraryManager;
513
514 /// The basename of `/home/.../lib/libA.so`,
515 /// m_BasePaths will contain `/home/.../lib/`
516 BasePaths m_BasePaths;
517
518 LibraryPaths m_Libraries;
519 LibraryPaths m_SysLibraries;
520 /// Contains a set of libraries which we gave to the user via ResolveSymbol
521 /// call and next time we should check if the user loaded them to avoid
522 /// useless iterations.
523 LibraryPaths m_QueriedLibraries;
524
525 using PermanentlyIgnoreCallbackProto = std::function<bool(StringRef)>;
526 const PermanentlyIgnoreCallbackProto m_ShouldPermanentlyIgnoreCallback;
527 const StringRef m_ExecutableFormat;
528
529 /// Scan for shared objects which are not yet loaded. They are a our symbol
530 /// resolution candidate sources.
531 /// NOTE: We only scan not loaded shared objects.
532 /// \param[in] searchSystemLibraries - whether to decent to standard system
533 /// locations for shared objects.
534 void ScanForLibraries(bool searchSystemLibraries = false);
535
536 /// Builds a bloom filter lookup optimization.
537 void BuildBloomFilter(LibraryPath* Lib, llvm::object::ObjectFile* BinObjFile,
538 unsigned IgnoreSymbolFlags = 0) const;
539
540 /// Looks up symbols from a an object file, representing the library.
541 ///\param[in] Lib - full path to the library.
542 ///\param[in] mangledName - the mangled name to look for.
543 ///\param[in] IgnoreSymbolFlags - The symbols to ignore upon a match.
544 ///\returns true on success.
545 bool ContainsSymbol(const LibraryPath* Lib, StringRef mangledName,
546 unsigned IgnoreSymbolFlags = 0) const;
547
548 bool ShouldPermanentlyIgnore(StringRef FileName) const;
549 void dumpDebugInfo() const;
550
551public:
553 PermanentlyIgnoreCallbackProto shouldIgnore, StringRef execFormat)
554 : m_DynamicLibraryManager(DLM),
555 m_ShouldPermanentlyIgnoreCallback(shouldIgnore),
556 m_ExecutableFormat(execFormat) {}
557
558 ~Dyld() {};
559
560 std::string searchLibrariesForSymbol(StringRef mangledName,
561 bool searchSystem);
562};
563
564std::string RPathToStr(SmallVector<StringRef, 2> V) {
565 std::string result;
566 for (auto item : V)
567 result += item.str() + ",";
568 if (!result.empty())
569 result.pop_back();
570 return result;
571}
572
573template <class ELFT>
574void HandleDynTab(const ELFFile<ELFT>* Elf, StringRef FileName,
575 SmallVector<StringRef, 2>& RPath,
576 SmallVector<StringRef, 2>& RunPath,
577 std::vector<StringRef>& Deps, bool& isPIEExecutable) {
578#define DEBUG_TYPE "Dyld:"
579 const char* Data = "";
580 if (Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf))
581 Data = StrTabOrErr.get().data();
582
583 isPIEExecutable = false;
584
585 auto DynamicEntriesOrError = Elf->dynamicEntries();
586 if (!DynamicEntriesOrError) {
587 LLVM_DEBUG(dbgs() << "Dyld: failed to read dynamic entries in"
588 << "'" << FileName.str() << "'\n");
589 return;
590 }
591
592 for (const typename ELFT::Dyn& Dyn : *DynamicEntriesOrError) {
593 switch (Dyn.d_tag) {
594 case ELF::DT_NEEDED:
595 Deps.push_back(Data + Dyn.d_un.d_val);
596 break;
597 case ELF::DT_RPATH:
598 SplitPaths(Data + Dyn.d_un.d_val, RPath,
601 break;
602 case ELF::DT_RUNPATH:
603 SplitPaths(Data + Dyn.d_un.d_val, RunPath,
606 break;
607 case ELF::DT_FLAGS_1:
608 // Check if this is not a pie executable.
609 if (Dyn.d_un.d_val & llvm::ELF::DF_1_PIE)
610 isPIEExecutable = true;
611 break;
612 // (Dyn.d_tag == ELF::DT_NULL) continue;
613 // (Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER)
614 }
615 }
616#undef DEBUG_TYPE
617}
618
619void Dyld::ScanForLibraries(bool searchSystemLibraries /* = false*/) {
620#define DEBUG_TYPE "Dyld:ScanForLibraries:"
621
622 const auto& searchPaths = m_DynamicLibraryManager.getSearchPaths();
623
624 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: system="
625 << (searchSystemLibraries ? "true" : "false") << "\n");
626#ifndef NDEBUG
627 for (const DynamicLibraryManager::SearchPathInfo& Info : searchPaths)
628 LLVM_DEBUG(dbgs() << ">>>" << Info.Path << ", "
629 << (Info.IsUser ? "user\n" : "system\n"));
630#endif
631 llvm::SmallSet<const BasePath*, 32> ScannedPaths;
632
633 for (const DynamicLibraryManager::SearchPathInfo& Info : searchPaths) {
634 if (Info.IsUser != searchSystemLibraries) {
635 // Examples which we should handle.
636 // File Real
637 // /lib/1/1.so /lib/1/1.so // file
638 // /lib/1/2.so->/lib/1/1.so /lib/1/1.so // file local link
639 // /lib/1/3.so->/lib/3/1.so /lib/3/1.so // file external link
640 // /lib/2->/lib/1 // path link
641 // /lib/2/1.so /lib/1/1.so // path link, file
642 // /lib/2/2.so->/lib/1/1.so /lib/1/1.so // path link, file local link
643 // /lib/2/3.so->/lib/3/1.so /lib/3/1.so // path link, file external link
644 //
645 // /lib/3/1.so
646 // /lib/3/2.so->/system/lib/s.so
647 // /lib/3/3.so
648 // /system/lib/1.so
649 //
650 // libL.so NEEDED/RPATH libR.so /lib/some-rpath/libR.so //
651 // needed/dependedt library in libL.so RPATH/RUNPATH or other (in)direct
652 // dep
653 //
654 // Paths = /lib/1 : /lib/2 : /lib/3
655
656 // m_BasePaths = ["/lib/1", "/lib/3", "/system/lib"]
657 // m_*Libraries = [<0,"1.so">, <1,"1.so">, <2,"s.so">, <1,"3.so">]
658
659 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries Iter:" << Info.Path
660 << " -> ");
661 std::string RealPath = cached_realpath(Info.Path);
662
663 llvm::StringRef DirPath(RealPath);
664 LLVM_DEBUG(dbgs() << RealPath << "\n");
665
666 if (!llvm::sys::fs::is_directory(DirPath) || DirPath.empty())
667 continue;
668
669 // Already searched?
670 const BasePath& ScannedBPath = m_BasePaths.RegisterBasePath(RealPath);
671 if (ScannedPaths.count(&ScannedBPath)) {
672 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries Already scanned: "
673 << RealPath << "\n");
674 continue;
675 }
676
677 // FileName must be always full/absolute/resolved file name.
678 std::function<void(llvm::StringRef, unsigned)> HandleLib =
679 [&](llvm::StringRef FileName, unsigned level) {
680 LLVM_DEBUG(dbgs()
681 << "Dyld::ScanForLibraries HandleLib:" << FileName.str()
682 << ", level=" << level << " -> ");
683
684 llvm::StringRef FileRealPath =
685 llvm::sys::path::parent_path(FileName);
686 llvm::StringRef FileRealName = llvm::sys::path::filename(FileName);
687 const BasePath& BaseP =
688 m_BasePaths.RegisterBasePath(FileRealPath.str());
689 LibraryPath LibPath(BaseP, FileRealName.str()); // bp, str
690
691 if (m_SysLibraries.GetRegisteredLib(LibPath) ||
692 m_Libraries.GetRegisteredLib(LibPath)) {
693 LLVM_DEBUG(dbgs() << "Already handled!!!\n");
694 return;
695 }
696
697 if (ShouldPermanentlyIgnore(FileName)) {
698 LLVM_DEBUG(dbgs() << "PermanentlyIgnored!!!\n");
699 return;
700 }
701
702 if (searchSystemLibraries)
703 m_SysLibraries.RegisterLib(LibPath);
704 else
705 m_Libraries.RegisterLib(LibPath);
706
707 // Handle lib dependencies
708 llvm::SmallVector<llvm::StringRef, 2> RPath;
709 llvm::SmallVector<llvm::StringRef, 2> RunPath;
710 std::vector<StringRef> Deps;
711 auto ObjFileOrErr =
712 llvm::object::ObjectFile::createObjectFile(FileName);
713 if (llvm::Error Err = ObjFileOrErr.takeError()) {
714 std::string Message;
715 handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) {
716 Message += EIB.message() + "; ";
717 });
718 LLVM_DEBUG(
719 dbgs()
720 << "Dyld::ScanForLibraries: Failed to read object file "
721 << FileName.str() << " Errors: " << Message << "\n");
722 return;
723 }
724 llvm::object::ObjectFile* BinObjF = ObjFileOrErr.get().getBinary();
725 if (BinObjF->isELF()) {
726 bool isPIEExecutable = false;
727
728 if (const auto* ELF = dyn_cast<ELF32LEObjectFile>(BinObjF))
729 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
730 isPIEExecutable);
731 else if (const auto* ELF = dyn_cast<ELF32BEObjectFile>(BinObjF))
732 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
733 isPIEExecutable);
734 else if (const auto* ELF = dyn_cast<ELF64LEObjectFile>(BinObjF))
735 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
736 isPIEExecutable);
737 else if (const auto* ELF = dyn_cast<ELF64BEObjectFile>(BinObjF))
738 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
739 isPIEExecutable);
740
741 if ((level == 0) && isPIEExecutable) {
742 if (searchSystemLibraries)
743 m_SysLibraries.UnregisterLib(LibPath);
744 else
745 m_Libraries.UnregisterLib(LibPath);
746 return;
747 }
748 } else if (BinObjF->isMachO()) {
749 MachOObjectFile* Obj = (MachOObjectFile*)BinObjF;
750 for (const auto& Command : Obj->load_commands()) {
751 if (Command.C.cmd == MachO::LC_LOAD_DYLIB) {
752 // Command.C.cmd == MachO::LC_ID_DYLIB ||
753 // Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
754 // Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
755 // Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
756 // Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB ||
757 MachO::dylib_command dylibCmd =
758 Obj->getDylibIDLoadCommand(Command);
759 Deps.push_back(StringRef(Command.Ptr + dylibCmd.dylib.name));
760 } else if (Command.C.cmd == MachO::LC_RPATH) {
761 MachO::rpath_command rpathCmd = Obj->getRpathCommand(Command);
762 SplitPaths(Command.Ptr + rpathCmd.path, RPath,
765 }
766 }
767 } else if (BinObjF->isCOFF()) {
768 // TODO: COFF support
769 }
770
771 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Deps Info:\n");
772 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: RPATH="
773 << RPathToStr(RPath) << "\n");
774 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: RUNPATH="
775 << RPathToStr(RunPath) << "\n");
776#ifndef NDEBUG
777 int x = 0;
778 for (StringRef dep : Deps)
779 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Deps[" << x++
780 << "]=" << dep.str() << "\n");
781#endif
782 // Heuristics for workaround performance problems:
783 // (H1) If RPATH and RUNPATH == "" -> skip handling Deps
784 if (RPath.empty() && RunPath.empty()) {
785 LLVM_DEBUG(
786 dbgs()
787 << "Dyld::ScanForLibraries: Skip all deps by Heuristic1: "
788 << FileName.str() << "\n");
789 return;
790 };
791 // (H2) If RPATH subset of LD_LIBRARY_PATH &&
792 // RUNPATH subset of LD_LIBRARY_PATH -> skip handling Deps
793 if (std::all_of(
794 RPath.begin(), RPath.end(),
795 [&](StringRef item) {
796 return std::any_of(
797 searchPaths.begin(), searchPaths.end(),
798 [&](DynamicLibraryManager::SearchPathInfo item1) {
799 return item == item1.Path;
800 });
801 }) &&
802 std::all_of(
803 RunPath.begin(), RunPath.end(), [&](StringRef item) {
804 return std::any_of(
805 searchPaths.begin(), searchPaths.end(),
806 [&](DynamicLibraryManager::SearchPathInfo item1) {
807 return item == item1.Path;
808 });
809 })) {
810 LLVM_DEBUG(
811 dbgs()
812 << "Dyld::ScanForLibraries: Skip all deps by Heuristic2: "
813 << FileName.str() << "\n");
814 return;
815 }
816
817 // Handle dependencies
818 for (StringRef dep : Deps) {
819 std::string dep_full = m_DynamicLibraryManager.lookupLibrary(
820 dep, RPath, RunPath, FileName, false);
821 HandleLib(dep_full, level + 1);
822 }
823 };
824
825 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Iterator: " << DirPath
826 << "\n");
827 std::error_code EC;
828 for (llvm::sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd;
829 DirIt != DirEnd && !EC; DirIt.increment(EC)) {
830
831 LLVM_DEBUG(dbgs() << "Dyld::ScanForLibraries: Iterator >>> "
832 << DirIt->path()
833 << ", type=" << (short)(DirIt->type()) << "\n");
834
835 const llvm::sys::fs::file_type ft = DirIt->type();
836 if (ft == llvm::sys::fs::file_type::regular_file) {
837 HandleLib(DirIt->path(), 0);
838 } else if (ft == llvm::sys::fs::file_type::symlink_file) {
839 std::string DepFileName_str = cached_realpath(DirIt->path());
840 llvm::StringRef DepFileName = DepFileName_str;
841 assert(!llvm::sys::fs::is_symlink_file(DepFileName));
842 if (!llvm::sys::fs::is_directory(DepFileName))
843 HandleLib(DepFileName, 0);
844 }
845 }
846
847 // Register the DirPath as fully scanned.
848 ScannedPaths.insert(&ScannedBPath);
849 }
850 }
851#undef DEBUG_TYPE
852}
853
854void Dyld::BuildBloomFilter(LibraryPath* Lib,
855 llvm::object::ObjectFile* BinObjFile,
856 unsigned IgnoreSymbolFlags /*= 0*/) const {
857#define DEBUG_TYPE "Dyld::BuildBloomFilter:"
858 assert(m_UseBloomFilter && "Bloom filter is disabled");
859 assert(!Lib->hasBloomFilter() && "Already built!");
860
861 using namespace llvm;
862 using namespace llvm::object;
863
864 LLVM_DEBUG(
865 dbgs() << "Dyld::BuildBloomFilter: Start building Bloom filter for: "
866 << Lib->GetFullName() << "\n");
867
868 // If BloomFilter is empty then build it.
869 // Count Symbols and generate BloomFilter
870 uint32_t SymbolsCount = 0;
871 std::list<llvm::StringRef> symbols;
872 for (const llvm::object::SymbolRef& S : BinObjFile->symbols()) {
873 uint32_t Flags = llvm::cantFail(S.getFlags());
874 // Do not insert in the table symbols flagged to ignore.
875 if (Flags & IgnoreSymbolFlags)
876 continue;
877
878 // Note, we are at last resort and loading library based on a weak
879 // symbol is allowed. Otherwise, the JIT will issue an unresolved
880 // symbol error.
881 //
882 // There are other weak symbol kinds (marked as 'V') to denote
883 // typeinfo and vtables. It is unclear whether we should load such
884 // libraries or from which library we should resolve the symbol.
885 // We seem to not have a way to differentiate it from the symbol API.
886
887 llvm::Expected<llvm::StringRef> SymNameErr = S.getName();
888 if (!SymNameErr) {
889 LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Failed to read symbol "
890 << SymNameErr.get() << "\n");
891 continue;
892 }
893
894 if (SymNameErr.get().empty())
895 continue;
896
897 ++SymbolsCount;
898 symbols.push_back(SymNameErr.get());
899 }
900
901 if (BinObjFile->isELF()) {
902 // ELF file format has .dynstr section for the dynamic symbol table.
903 const auto* ElfObj = cast<llvm::object::ELFObjectFileBase>(BinObjFile);
904
905 for (const object::SymbolRef& S : ElfObj->getDynamicSymbolIterators()) {
906 uint32_t Flags = llvm::cantFail(S.getFlags());
907 // DO NOT insert to table if symbol was undefined
908 if (Flags & llvm::object::SymbolRef::SF_Undefined)
909 continue;
910
911 // Note, we are at last resort and loading library based on a weak
912 // symbol is allowed. Otherwise, the JIT will issue an unresolved
913 // symbol error.
914 //
915 // There are other weak symbol kinds (marked as 'V') to denote
916 // typeinfo and vtables. It is unclear whether we should load such
917 // libraries or from which library we should resolve the symbol.
918 // We seem to not have a way to differentiate it from the symbol API.
919
920 llvm::Expected<StringRef> SymNameErr = S.getName();
921 if (!SymNameErr) {
922 LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Failed to read symbol "
923 << SymNameErr.get() << "\n");
924 continue;
925 }
926
927 if (SymNameErr.get().empty())
928 continue;
929
930 ++SymbolsCount;
931 symbols.push_back(SymNameErr.get());
932 }
933 } else if (BinObjFile->isCOFF()) { // On Windows, the symbols are present in
934 // COFF format.
935 llvm::object::COFFObjectFile* CoffObj =
936 cast<llvm::object::COFFObjectFile>(BinObjFile);
937
938 // In COFF, the symbols are not present in the SymbolTable section
939 // of the Object file. They are present in the ExportDirectory section.
940 for (auto I = CoffObj->export_directory_begin(),
941 E = CoffObj->export_directory_end();
942 I != E; I = ++I) {
943 // All the symbols are already flagged as exported.
944 // We cannot really ignore symbols based on flags as we do on unix.
945 StringRef Name;
946 auto Err = I->getSymbolName(Name);
947
948 if (Err) {
949 std::string Message;
950 handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) {
951 Message += EIB.message() + "; ";
952 });
953 LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Failed to read symbol "
954 << Message << "\n");
955 continue;
956 }
957 if (Name.empty())
958 continue;
959
960 ++SymbolsCount;
961 symbols.push_back(Name);
962 }
963 }
964
965 Lib->InitializeBloomFilter(SymbolsCount);
966
967 if (!SymbolsCount) {
968 LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: No symbols!\n");
969 return;
970 }
971
972 LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter: Symbols:\n");
973#ifndef NDEBUG
974 for (auto it : symbols)
975 LLVM_DEBUG(dbgs() << "Dyld::BuildBloomFilter"
976 << "- " << it << "\n");
977#endif
978 // Generate BloomFilter
979 for (const auto& S : symbols) {
980 if (m_UseHashTable)
981 Lib->AddBloom(Lib->AddSymbol(S.str()));
982 else
983 Lib->AddBloom(S);
984 }
985#undef DEBUG_TYPE
986}
987
988bool Dyld::ContainsSymbol(const LibraryPath* Lib, StringRef mangledName,
989 unsigned IgnoreSymbolFlags /*= 0*/) const {
990#define DEBUG_TYPE "Dyld::ContainsSymbol:"
991 const std::string library_filename = Lib->GetFullName();
992
993 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Find symbol: lib="
994 << library_filename << ", mangled=" << mangledName.str()
995 << "\n");
996
997 auto ObjF = llvm::object::ObjectFile::createObjectFile(library_filename);
998 if (llvm::Error Err = ObjF.takeError()) {
999 std::string Message;
1000 handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) {
1001 Message += EIB.message() + "; ";
1002 });
1003 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Failed to read object file "
1004 << library_filename << " Errors: " << Message << "\n");
1005 return false;
1006 }
1007
1008 llvm::object::ObjectFile* BinObjFile = ObjF.get().getBinary();
1009
1010 uint32_t hashedMangle = GNUHash(mangledName);
1011 // Check for the gnu.hash section if ELF.
1012 // If the symbol doesn't exist, exit early.
1013 if (BinObjFile->isELF() &&
1014 !MayExistInElfObjectFile(BinObjFile, hashedMangle)) {
1015 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: ELF BloomFilter: Skip symbol <"
1016 << mangledName.str() << ">.\n");
1017 return false;
1018 }
1019
1020 if (m_UseBloomFilter) {
1021 // Use our bloom filters and create them if necessary.
1022 if (!Lib->hasBloomFilter())
1023 BuildBloomFilter(const_cast<LibraryPath*>(Lib), BinObjFile,
1024 IgnoreSymbolFlags);
1025
1026 // If the symbol does not exist, exit early. In case it may exist, iterate.
1027 if (!Lib->MayExistSymbol(hashedMangle)) {
1028 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: BloomFilter: Skip symbol <"
1029 << mangledName.str() << ">.\n");
1030 return false;
1031 }
1032 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: BloomFilter: Symbol <"
1033 << mangledName.str() << "> May exist."
1034 << " Search for it. ");
1035 }
1036
1037 if (m_UseHashTable) {
1038 bool result = Lib->ExistSymbol(mangledName);
1039 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: HashTable: Symbol "
1040 << (result ? "Exist" : "Not exist") << "\n");
1041 return result;
1042 }
1043
1044 auto ForeachSymbol =
1045#ifndef NDEBUG
1046 [&library_filename](
1047#else
1048 [](
1049#endif
1050 llvm::iterator_range<llvm::object::symbol_iterator> range,
1051 unsigned IgnoreSymbolFlags, llvm::StringRef mangledName) -> bool {
1052 for (const llvm::object::SymbolRef& S : range) {
1053 uint32_t Flags = llvm::cantFail(S.getFlags());
1054 // Do not insert in the table symbols flagged to ignore.
1055 if (Flags & IgnoreSymbolFlags)
1056 continue;
1057
1058 // Note, we are at last resort and loading library based on a weak
1059 // symbol is allowed. Otherwise, the JIT will issue an unresolved
1060 // symbol error.
1061 //
1062 // There are other weak symbol kinds (marked as 'V') to denote
1063 // typeinfo and vtables. It is unclear whether we should load such
1064 // libraries or from which library we should resolve the symbol.
1065 // We seem to not have a way to differentiate it from the symbol API.
1066
1067 llvm::Expected<llvm::StringRef> SymNameErr = S.getName();
1068 if (!SymNameErr) {
1069 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Failed to read symbol "
1070 << mangledName.str() << "\n");
1071 continue;
1072 }
1073
1074 if (SymNameErr.get().empty())
1075 continue;
1076
1077 if (SymNameErr.get() == mangledName) {
1078 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Symbol "
1079 << mangledName.str() << " found in "
1080 << library_filename << "\n");
1081 return true;
1082 }
1083 }
1084 return false;
1085 };
1086
1087 // If no hash symbol then iterate to detect symbol
1088 // We Iterate only if BloomFilter and/or SymbolHashTable are not supported.
1089
1090 LLVM_DEBUG(dbgs() << "Dyld::ContainsSymbol: Iterate all for <"
1091 << mangledName.str() << ">");
1092
1093 // Symbol may exist. Iterate.
1094 if (ForeachSymbol(BinObjFile->symbols(), IgnoreSymbolFlags, mangledName)) {
1095 LLVM_DEBUG(dbgs() << " -> found.\n");
1096 return true;
1097 }
1098
1099 if (!BinObjFile->isELF()) {
1100 LLVM_DEBUG(dbgs() << " -> not found.\n");
1101 return false;
1102 }
1103
1104 // ELF file format has .dynstr section for the dynamic symbol table.
1105 const auto* ElfObj = llvm::cast<llvm::object::ELFObjectFileBase>(BinObjFile);
1106
1107 bool result = ForeachSymbol(ElfObj->getDynamicSymbolIterators(),
1108 IgnoreSymbolFlags, mangledName);
1109 LLVM_DEBUG(dbgs() << (result ? " -> found.\n" : " -> not found.\n"));
1110 return result;
1111#undef DEBUG_TYPE
1112}
1113
1114bool Dyld::ShouldPermanentlyIgnore(StringRef FileName) const {
1115#define DEBUG_TYPE "Dyld:"
1116 assert(!m_ExecutableFormat.empty() && "Failed to find the object format!");
1117
1118 if (!DynamicLibraryManager::isSharedLibrary(FileName))
1119 return true;
1120
1121 // No need to check linked libraries, as this function is only invoked
1122 // for symbols that cannot be found (neither by dlsym nor in the JIT).
1123 if (m_DynamicLibraryManager.isLibraryLoaded(FileName))
1124 return true;
1125
1126 auto ObjF = llvm::object::ObjectFile::createObjectFile(FileName);
1127 if (!ObjF) {
1128 llvm::consumeError(ObjF.takeError());
1129 LLVM_DEBUG(dbgs() << "[DyLD] Failed to read object file " << FileName
1130 << "\n");
1131 return true;
1132 }
1133
1134 llvm::object::ObjectFile* file = ObjF.get().getBinary();
1135
1136 LLVM_DEBUG(dbgs() << "Current executable format: " << m_ExecutableFormat
1137 << ". Executable format of " << FileName << " : "
1138 << file->getFileFormatName() << "\n");
1139
1140 // Ignore libraries with different format than the executing one.
1141 if (m_ExecutableFormat != file->getFileFormatName())
1142 return true;
1143
1144 if (llvm::isa<llvm::object::ELFObjectFileBase>(*file)) {
1145 for (auto S : file->sections()) {
1146 llvm::StringRef name = llvm::cantFail(S.getName());
1147 if (name == ".text") {
1148 // Check if the library has only debug symbols, usually when
1149 // stripped with objcopy --only-keep-debug. This check is done by
1150 // reading the manual of objcopy and inspection of stripped with
1151 // objcopy libraries.
1152 auto SecRef = static_cast<llvm::object::ELFSectionRef&>(S);
1153 if (SecRef.getType() == llvm::ELF::SHT_NOBITS)
1154 return true;
1155
1156 return (SecRef.getFlags() & llvm::ELF::SHF_ALLOC) == 0;
1157 }
1158 }
1159 return true;
1160 }
1161
1162 // FIXME: Handle osx using isStripped after upgrading to llvm9.
1163
1164 return m_ShouldPermanentlyIgnoreCallback(FileName);
1165#undef DEBUG_TYPE
1166}
1167
1168void Dyld::dumpDebugInfo() const {
1169#define DEBUG_TYPE "Dyld:"
1170 LLVM_DEBUG(dbgs() << "---\n");
1171#ifndef NDEBUG
1172 size_t x = 0;
1173 for (auto const& item : m_BasePaths.m_Paths) {
1174 LLVM_DEBUG(dbgs() << "Dyld: - m_BasePaths[" << x++ << "]:" << &item << ": "
1175 << item << "\n");
1176 }
1177 LLVM_DEBUG(dbgs() << "---\n");
1178 x = 0;
1179 for (auto const& item : m_Libraries.GetLibraries()) {
1180 LLVM_DEBUG(dbgs() << "Dyld: - m_Libraries[" << x++ << "]:" << &item << ": "
1181 << item->m_Path << ", " << item->m_LibName << "\n");
1182 }
1183 x = 0;
1184 for (auto const& item : m_SysLibraries.GetLibraries()) {
1185 LLVM_DEBUG(dbgs() << "Dyld: - m_SysLibraries[" << x++ << "]:" << &item
1186 << ": " << item->m_Path << ", " << item->m_LibName
1187 << "\n");
1188 }
1189#endif
1190#undef DEBUG_TYPE
1191}
1192
1193std::string Dyld::searchLibrariesForSymbol(StringRef mangledName,
1194 bool searchSystem /* = true*/) {
1195#define DEBUG_TYPE "Dyld:searchLibrariesForSymbol:"
1196 assert(
1197 !llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(mangledName.str()) &&
1198 "Library already loaded, please use dlsym!");
1199 assert(!mangledName.empty());
1200
1201 using namespace llvm::sys::path;
1202 using namespace llvm::sys::fs;
1203
1204 if (m_FirstRun) {
1205 LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str()
1206 << ", searchSystem=" << (searchSystem ? "true" : "false")
1207 << ", FirstRun(user)... scanning\n");
1208
1209 LLVM_DEBUG(
1210 dbgs()
1211 << "Dyld::searchLibrariesForSymbol: Before first ScanForLibraries\n");
1212 dumpDebugInfo();
1213
1214 ScanForLibraries(/* SearchSystemLibraries= */ false);
1215 m_FirstRun = false;
1216
1217 LLVM_DEBUG(
1218 dbgs()
1219 << "Dyld::searchLibrariesForSymbol: After first ScanForLibraries\n");
1220 dumpDebugInfo();
1221 }
1222
1223 if (m_QueriedLibraries.size() > 0) {
1224 // Last call we were asked if a library contains a symbol. Usually, the
1225 // caller wants to load this library. Check if was loaded and remove it
1226 // from our lists of not-yet-loaded libs.
1227
1228 LLVM_DEBUG(dbgs() << "Dyld::ResolveSymbol: m_QueriedLibraries:\n");
1229#ifndef NDEBUG
1230 size_t x = 0;
1231 for (auto item : m_QueriedLibraries.GetLibraries()) {
1232 LLVM_DEBUG(dbgs() << "Dyld::ResolveSymbol - [" << x++ << "]:" << &item
1233 << ": " << item->GetFullName() << "\n");
1234 }
1235#endif
1236 for (const LibraryPath* P : m_QueriedLibraries.GetLibraries()) {
1237 const std::string LibName = P->GetFullName();
1238 if (!m_DynamicLibraryManager.isLibraryLoaded(LibName))
1239 continue;
1240
1241 m_Libraries.UnregisterLib(*P);
1242 m_SysLibraries.UnregisterLib(*P);
1243 }
1244 // TODO: m_QueriedLibraries.clear ?
1245 }
1246
1247 // Iterate over files under this path. We want to get each ".so" files
1248 for (const LibraryPath* P : m_Libraries.GetLibraries()) {
1249 if (ContainsSymbol(P, mangledName, /*ignore*/
1250 llvm::object::SymbolRef::SF_Undefined)) {
1251 if (!m_QueriedLibraries.HasRegisteredLib(*P))
1252 m_QueriedLibraries.RegisterLib(*P);
1253
1254 LLVM_DEBUG(
1255 dbgs() << "Dyld::ResolveSymbol: Search found match in [user lib]: "
1256 << P->GetFullName() << "!\n");
1257
1258 return P->GetFullName();
1259 }
1260 }
1261
1262 if (!searchSystem)
1263 return "";
1264
1265 LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: SearchSystem!!!\n");
1266
1267 // Lookup in non-system libraries failed. Expand the search to the system.
1268 if (m_FirstRunSysLib) {
1269 LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol:" << mangledName.str()
1270 << ", searchSystem=" << (searchSystem ? "true" : "false")
1271 << ", FirstRun(system)... scanning\n");
1272
1273 LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: Before first system "
1274 "ScanForLibraries\n");
1275 dumpDebugInfo();
1276
1277 ScanForLibraries(/* SearchSystemLibraries= */ true);
1278 m_FirstRunSysLib = false;
1279
1280 LLVM_DEBUG(dbgs() << "Dyld::searchLibrariesForSymbol: After first system "
1281 "ScanForLibraries\n");
1282 dumpDebugInfo();
1283 }
1284
1285 for (const LibraryPath* P : m_SysLibraries.GetLibraries()) {
1286 if (ContainsSymbol(P, mangledName, /*ignore*/
1287 llvm::object::SymbolRef::SF_Undefined |
1288 llvm::object::SymbolRef::SF_Weak)) {
1289 if (!m_QueriedLibraries.HasRegisteredLib(*P))
1290 m_QueriedLibraries.RegisterLib(*P);
1291
1292 LLVM_DEBUG(
1293 dbgs() << "Dyld::ResolveSymbol: Search found match in [system lib]: "
1294 << P->GetFullName() << "!\n");
1295
1296 return P->GetFullName();
1297 }
1298 }
1299
1300 LLVM_DEBUG(dbgs() << "Dyld::ResolveSymbol: Search found no match!\n");
1301
1302 return ""; // Search found no match.
1303#undef DEBUG_TYPE
1304}
1305
1306DynamicLibraryManager::~DynamicLibraryManager() {
1307 static_assert(sizeof(Dyld) > 0, "Incomplete type");
1308 delete m_Dyld;
1309}
1310
1311void DynamicLibraryManager::initializeDyld(
1312 std::function<bool(llvm::StringRef)> shouldPermanentlyIgnore) {
1313 // assert(!m_Dyld && "Already initialized!");
1314 if (m_Dyld)
1315 delete m_Dyld;
1316
1317 std::string exeP = GetExecutablePath();
1318 auto ObjF = cantFail(llvm::object::ObjectFile::createObjectFile(exeP));
1319
1320 m_Dyld = new Dyld(*this, shouldPermanentlyIgnore,
1321 ObjF.getBinary()->getFileFormatName());
1322}
1323
1324std::string DynamicLibraryManager::searchLibrariesForSymbol(
1325 StringRef mangledName, bool searchSystem /* = true*/) const {
1326 assert(m_Dyld && "Must call initialize dyld before!");
1327 return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem);
1328}
1329
1330std::string DynamicLibraryManager::getSymbolLocation(void* func) {
1331#if defined(__CYGWIN__) && defined(__GNUC__)
1332 return {};
1333#elif defined(_WIN32)
1334 MEMORY_BASIC_INFORMATION mbi;
1335 if (!VirtualQuery(func, &mbi, sizeof(mbi)))
1336 return {};
1337
1338 HMODULE hMod = (HMODULE)mbi.AllocationBase;
1339 char moduleName[MAX_PATH];
1340
1341 if (!GetModuleFileNameA(hMod, moduleName, sizeof(moduleName)))
1342 return {};
1343
1344 return cached_realpath(moduleName);
1345
1346#else
1347 // assume we have defined HAVE_DLFCN_H and HAVE_DLADDR
1348 Dl_info info;
1349 if (dladdr((void*)func, &info) == 0) {
1350 // Not in a known shared library, let's give up
1351 return {};
1352 } else {
1353 std::string result = cached_realpath(info.dli_fname);
1354 if (!result.empty())
1355 return result;
1356
1357 // Else absolute path. For all we know that's a binary.
1358 // Some people have dictionaries in binaries, this is how we find their
1359 // path: (see also https://stackoverflow.com/a/1024937/6182509)
1360#if defined(__APPLE__)
1361 char buf[PATH_MAX] = {0};
1362 uint32_t bufsize = sizeof(buf);
1363 if (_NSGetExecutablePath(buf, &bufsize) >= 0)
1364 return cached_realpath(buf);
1365 return cached_realpath(info.dli_fname);
1366#elif defined(LLVM_ON_UNIX)
1367 char buf[PATH_MAX] = {0};
1368 // Cross our fingers that /proc/self/exe exists.
1369 if (readlink("/proc/self/exe", buf, sizeof(buf)) > 0)
1370 return cached_realpath(buf);
1371 std::string pipeCmd = std::string("which \"") + info.dli_fname + "\"";
1372 FILE* pipe = popen(pipeCmd.c_str(), "r");
1373 if (!pipe)
1374 return cached_realpath(info.dli_fname);
1375 while (fgets(buf, sizeof(buf), pipe))
1376 result += buf;
1377
1378 pclose(pipe);
1379 return cached_realpath(result);
1380#else
1381#error "Unsupported platform."
1382#endif
1383 return {};
1384 }
1385#endif
1386}
1387
1388} // namespace CppInternal
Dyld(const DynamicLibraryManager &DLM, PermanentlyIgnoreCallbackProto shouldIgnore, StringRef execFormat)
std::string searchLibrariesForSymbol(StringRef mangledName, bool searchSystem)
A helper class managing dynamic shared objects.
const SearchPathInfos & getSearchPaths() const
Returns the system include paths.
std::string lookupLibrary(llvm::StringRef libStem, llvm::SmallVector< llvm::StringRef, 2 > RPath={}, llvm::SmallVector< llvm::StringRef, 2 > RunPath={}, llvm::StringRef libLoader="", bool variateLibStem=true) const
Looks up a library taking into account the current include paths and the system include paths.
const char *const kEnvDelim
Platform specific delimiter for splitting environment variables.
@ kAllowNonExistent
Add all paths whether they exist or not.
Definition Paths.h:65
bool SplitPaths(llvm::StringRef PathStr, llvm::SmallVectorImpl< llvm::StringRef > &Paths, SplitMode Mode, llvm::StringRef Delim, bool Verbose)
Collect the constituent paths from a PATH string.
Definition Paths.cpp:250
std::string RPathToStr(SmallVector< StringRef, 2 > V)
void HandleDynTab(const ELFFile< ELFT > *Elf, StringRef FileName, SmallVector< StringRef, 2 > &RPath, SmallVector< StringRef, 2 > &RunPath, std::vector< StringRef > &Deps, bool &isPIEExecutable)
Definition Paths.h:18