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"
37#include <unordered_set>
47#include <mach-o/dyld.h>
54#define WIN32_LEAN_AND_MEAN
58#include <libloaderapi.h>
65using BasePath = std::string;
69static uint32_t GNUHash(StringRef S) {
76constexpr uint32_t log2u(std::uint32_t n) {
77 return (n > 1) ? 1 + log2u(n >> 1) : 0;
96 const int m_Bits = 8 *
sizeof(uint64_t);
97 const float m_P = 0.02f;
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;
105 bool TestHash(uint32_t hash)
const {
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;
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;
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);
141 const BasePath& m_Path;
142 std::string m_LibName;
143 BloomFilter m_Filter;
144 StringSet<> m_Symbols;
147 LibraryPath(
const BasePath& Path,
const std::string& LibName)
148 : m_Path(Path), m_LibName(LibName) {}
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;
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();
161 void AddBloom(StringRef symbol) { m_Filter.AddHash(GNUHash(symbol)); }
163 StringRef AddSymbol(
const std::string& symbol) {
164 auto it = m_Symbols.insert(symbol);
165 return it.first->getKey();
168 bool hasBloomFilter()
const {
return m_Filter.m_IsInitialized; }
170 bool isBloomFilterEmpty()
const {
171 assert(m_Filter.m_IsInitialized &&
"Bloom filter not initialized!");
172 return m_Filter.m_SymbolsCount == 0;
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);
182 bool MayExistSymbol(uint32_t hash)
const {
184 if (isBloomFilterEmpty())
187 return m_Filter.TestHash(hash);
190 bool ExistSymbol(StringRef symbol)
const {
191 return m_Symbols.find(symbol) != m_Symbols.end();
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);
208 std::vector<const LibraryPath*> m_Libs;
209 std::unordered_set<LibraryPath, LibraryPathHashFn> m_LibsH;
212 bool HasRegisteredLib(
const LibraryPath& Lib)
const {
213 return m_LibsH.count(Lib);
216 const LibraryPath* GetRegisteredLib(
const LibraryPath& Lib)
const {
217 auto search = m_LibsH.find(Lib);
218 if (search != m_LibsH.end())
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);
230 void UnregisterLib(
const LibraryPath& Lib) {
231 auto found = m_LibsH.find(Lib);
232 if (found == m_LibsH.end())
235 m_Libs.erase(std::find(m_Libs.begin(), m_Libs.end(), &*found));
236 m_LibsH.erase(found);
239 size_t size()
const {
240 assert(m_Libs.size() == m_LibsH.size());
241 return m_Libs.size();
244 const std::vector<const LibraryPath*>& GetLibraries()
const {
return m_Libs; }
249static inline mode_t cached_lstat(
const char* path) {
250 static StringMap<mode_t> lstat_cache;
253 auto it = lstat_cache.find(path);
254 if (it != lstat_cache.end())
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));
265static inline StringRef cached_readlink(
const char* pathname) {
266 static StringMap<std::string> readlink_cache;
269 auto it = readlink_cache.find(pathname);
270 if (it != readlink_cache.end())
271 return StringRef(it->second);
276 if ((len = readlink(pathname, buf,
sizeof(buf))) != -1) {
279 readlink_cache.insert(std::pair<StringRef, std::string>(pathname, s));
280 return readlink_cache[pathname];
287std::string cached_realpath(StringRef path, StringRef base_path =
"",
288 bool is_base_path_real =
false,
289 long symlooplevel = 40) {
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;
313 StringRef sep(llvm::sys::path::get_separator());
314 SmallString<256> result(sep);
316 SmallVector<StringRef, 16> p;
320 if (is_base_path_real) {
321 result.assign(base_path);
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, -1,
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, -1,
false);
336 base_path.split(p, sep, -1,
false);
340 path.split(p, sep, -1,
false);
343 for (
auto item : p) {
348 size_t s = result.rfind(sep);
349 if (s != llvm::StringRef::npos)
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);
365 result = cached_realpath(symlink,
"",
true, symlooplevel - 1);
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)));
375 llvm::sys::fs::real_path(path, result);
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();
383using namespace llvm::object;
386static Expected<StringRef> getDynamicStrTab(
const ELFFile<ELFT>* Elf) {
387 auto DynamicEntriesOrError = Elf->dynamicEntries();
388 if (!DynamicEntriesOrError)
389 return DynamicEntriesOrError.takeError();
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));
401 auto SectionsOrError = Elf->sections();
402 if (!SectionsOrError)
403 return SectionsOrError.takeError();
405 for (
const typename ELFT::Shdr& Sec : *SectionsOrError) {
406 if (Sec.sh_type == ELF::SHT_DYNSYM)
407 return Elf->getStringTableForSymtab(Sec);
410 return createError(
"dynamic string table not found");
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());
432static bool MayExistInElfObjectFile(llvm::object::ObjectFile* soFile,
434 assert(soFile->isELF() &&
"Not ELF");
437 const unsigned bits = 8 * soFile->getBytesInAddress();
439 StringRef contents = GetGnuHashSection(soFile);
440 if (contents.size() < 16)
443 const char* hashContent = contents.data();
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;
452 const char* bloomfilter = hashContent + 16;
453 const char* hash_pos = bloomfilter + n * (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;
475 struct BasePathHashFunction {
476 size_t operator()(
const BasePath& item)
const {
477 return std::hash<std::string>()(item);
481 struct BasePathEqFunction {
482 size_t operator()(
const BasePath& l,
const BasePath& r)
const {
483 return &l == &r || l == r;
491 std::unordered_set<BasePath, BasePathHashFunction, BasePathEqFunction>
495 const BasePath& RegisterBasePath(
const std::string& Path,
496 bool* WasInserted =
nullptr) {
497 auto it = m_Paths.insert(Path);
499 *WasInserted = it.second;
504 bool Contains(StringRef Path) {
return m_Paths.count(Path.str()); }
507 bool m_FirstRun =
true;
508 bool m_FirstRunSysLib =
true;
509 bool m_UseBloomFilter =
true;
510 bool m_UseHashTable =
true;
516 BasePaths m_BasePaths;
518 LibraryPaths m_Libraries;
519 LibraryPaths m_SysLibraries;
523 LibraryPaths m_QueriedLibraries;
525 using PermanentlyIgnoreCallbackProto = std::function<bool(StringRef)>;
526 const PermanentlyIgnoreCallbackProto m_ShouldPermanentlyIgnoreCallback;
527 const StringRef m_ExecutableFormat;
534 void ScanForLibraries(
bool searchSystemLibraries =
false);
537 void BuildBloomFilter(LibraryPath* Lib, llvm::object::ObjectFile* BinObjFile,
538 unsigned IgnoreSymbolFlags = 0)
const;
545 bool ContainsSymbol(
const LibraryPath* Lib, StringRef mangledName,
546 unsigned IgnoreSymbolFlags = 0)
const;
548 bool ShouldPermanentlyIgnore(StringRef FileName)
const;
549 void dumpDebugInfo()
const;
553 PermanentlyIgnoreCallbackProto shouldIgnore, StringRef execFormat)
554 : m_DynamicLibraryManager(DLM),
555 m_ShouldPermanentlyIgnoreCallback(shouldIgnore),
556 m_ExecutableFormat(execFormat) {}
567 result += item.str() +
",";
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();
583 isPIEExecutable =
false;
585 auto DynamicEntriesOrError = Elf->dynamicEntries();
586 if (!DynamicEntriesOrError) {
587 LLVM_DEBUG(dbgs() <<
"Dyld: failed to read dynamic entries in"
588 <<
"'" << FileName.str() <<
"'\n");
592 for (
const typename ELFT::Dyn& Dyn : *DynamicEntriesOrError) {
595 Deps.push_back(Data + Dyn.d_un.d_val);
602 case ELF::DT_RUNPATH:
607 case ELF::DT_FLAGS_1:
609 if (Dyn.d_un.d_val & llvm::ELF::DF_1_PIE)
610 isPIEExecutable =
true;
619void Dyld::ScanForLibraries(
bool searchSystemLibraries ) {
620#define DEBUG_TYPE "Dyld:ScanForLibraries:"
622 const auto& searchPaths = m_DynamicLibraryManager.
getSearchPaths();
624 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: system="
625 << (searchSystemLibraries ?
"true" :
"false") <<
"\n");
627 for (
const DynamicLibraryManager::SearchPathInfo& Info : searchPaths)
628 LLVM_DEBUG(dbgs() <<
">>>" << Info.Path <<
", "
629 << (Info.IsUser ?
"user\n" :
"system\n"));
631 llvm::SmallSet<const BasePath*, 32> ScannedPaths;
633 for (
const DynamicLibraryManager::SearchPathInfo& Info : searchPaths) {
634 if (Info.IsUser != searchSystemLibraries) {
659 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries Iter:" << Info.Path
661 std::string RealPath = cached_realpath(Info.Path);
663 llvm::StringRef DirPath(RealPath);
664 LLVM_DEBUG(dbgs() << RealPath <<
"\n");
666 if (!llvm::sys::fs::is_directory(DirPath) || DirPath.empty())
670 const BasePath& ScannedBPath = m_BasePaths.RegisterBasePath(RealPath);
671 if (ScannedPaths.count(&ScannedBPath)) {
672 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries Already scanned: "
673 << RealPath <<
"\n");
678 std::function<void(llvm::StringRef,
unsigned)> HandleLib =
679 [&](llvm::StringRef FileName,
unsigned level) {
681 <<
"Dyld::ScanForLibraries HandleLib:" << FileName.str()
682 <<
", level=" << level <<
" -> ");
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());
691 if (m_SysLibraries.GetRegisteredLib(LibPath) ||
692 m_Libraries.GetRegisteredLib(LibPath)) {
693 LLVM_DEBUG(dbgs() <<
"Already handled!!!\n");
697 if (ShouldPermanentlyIgnore(FileName)) {
698 LLVM_DEBUG(dbgs() <<
"PermanentlyIgnored!!!\n");
702 if (searchSystemLibraries)
703 m_SysLibraries.RegisterLib(LibPath);
705 m_Libraries.RegisterLib(LibPath);
708 llvm::SmallVector<llvm::StringRef, 2> RPath;
709 llvm::SmallVector<llvm::StringRef, 2> RunPath;
710 std::vector<StringRef> Deps;
712 llvm::object::ObjectFile::createObjectFile(FileName);
713 if (llvm::Error Err = ObjFileOrErr.takeError()) {
715 handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) {
716 Message += EIB.message() +
"; ";
720 <<
"Dyld::ScanForLibraries: Failed to read object file "
721 << FileName.str() <<
" Errors: " << Message <<
"\n");
724 llvm::object::ObjectFile* BinObjF = ObjFileOrErr.get().getBinary();
725 if (BinObjF->isELF()) {
726 bool isPIEExecutable =
false;
728 if (
const auto* ELF = dyn_cast<ELF32LEObjectFile>(BinObjF))
729 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
731 else if (
const auto* ELF = dyn_cast<ELF32BEObjectFile>(BinObjF))
732 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
734 else if (
const auto* ELF = dyn_cast<ELF64LEObjectFile>(BinObjF))
735 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
737 else if (
const auto* ELF = dyn_cast<ELF64BEObjectFile>(BinObjF))
738 HandleDynTab(&ELF->getELFFile(), FileName, RPath, RunPath, Deps,
741 if ((level == 0) && isPIEExecutable) {
742 if (searchSystemLibraries)
743 m_SysLibraries.UnregisterLib(LibPath);
745 m_Libraries.UnregisterLib(LibPath);
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) {
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,
767 }
else if (BinObjF->isCOFF()) {
771 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: Deps Info:\n");
772 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: RPATH="
774 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: RUNPATH="
778 for (StringRef dep : Deps)
779 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: Deps[" << x++
780 <<
"]=" << dep.str() <<
"\n");
784 if (RPath.empty() && RunPath.empty()) {
787 <<
"Dyld::ScanForLibraries: Skip all deps by Heuristic1: "
788 << FileName.str() <<
"\n");
794 RPath.begin(), RPath.end(),
795 [&](StringRef item) {
797 searchPaths.begin(), searchPaths.end(),
798 [&](DynamicLibraryManager::SearchPathInfo item1) {
799 return item == item1.Path;
803 RunPath.begin(), RunPath.end(), [&](StringRef item) {
805 searchPaths.begin(), searchPaths.end(),
806 [&](DynamicLibraryManager::SearchPathInfo item1) {
807 return item == item1.Path;
812 <<
"Dyld::ScanForLibraries: Skip all deps by Heuristic2: "
813 << FileName.str() <<
"\n");
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);
825 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: Iterator: " << DirPath
828 for (llvm::sys::fs::directory_iterator DirIt(DirPath, EC), DirEnd;
829 DirIt != DirEnd && !EC; DirIt.increment(EC)) {
831 LLVM_DEBUG(dbgs() <<
"Dyld::ScanForLibraries: Iterator >>> "
833 <<
", type=" << (
short)(DirIt->type()) <<
"\n");
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);
848 ScannedPaths.insert(&ScannedBPath);
854void Dyld::BuildBloomFilter(LibraryPath* Lib,
855 llvm::object::ObjectFile* BinObjFile,
856 unsigned IgnoreSymbolFlags )
const {
857#define DEBUG_TYPE "Dyld::BuildBloomFilter:"
858 assert(m_UseBloomFilter &&
"Bloom filter is disabled");
859 assert(!Lib->hasBloomFilter() &&
"Already built!");
861 using namespace llvm;
862 using namespace llvm::object;
865 dbgs() <<
"Dyld::BuildBloomFilter: Start building Bloom filter for: "
866 << Lib->GetFullName() <<
"\n");
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());
875 if (Flags & IgnoreSymbolFlags)
887 llvm::Expected<llvm::StringRef> SymNameErr = S.getName();
889 LLVM_DEBUG(dbgs() <<
"Dyld::BuildBloomFilter: Failed to read symbol "
890 << SymNameErr.get() <<
"\n");
894 if (SymNameErr.get().empty())
898 symbols.push_back(SymNameErr.get());
901 if (BinObjFile->isELF()) {
903 const auto* ElfObj = cast<llvm::object::ELFObjectFileBase>(BinObjFile);
905 for (
const object::SymbolRef& S : ElfObj->getDynamicSymbolIterators()) {
906 uint32_t Flags = llvm::cantFail(S.getFlags());
908 if (Flags & llvm::object::SymbolRef::SF_Undefined)
920 llvm::Expected<StringRef> SymNameErr = S.getName();
922 LLVM_DEBUG(dbgs() <<
"Dyld::BuildBloomFilter: Failed to read symbol "
923 << SymNameErr.get() <<
"\n");
927 if (SymNameErr.get().empty())
931 symbols.push_back(SymNameErr.get());
933 }
else if (BinObjFile->isCOFF()) {
935 llvm::object::COFFObjectFile* CoffObj =
936 cast<llvm::object::COFFObjectFile>(BinObjFile);
940 for (
auto I = CoffObj->export_directory_begin(),
941 E = CoffObj->export_directory_end();
946 auto Err = I->getSymbolName(Name);
950 handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) {
951 Message += EIB.message() +
"; ";
953 LLVM_DEBUG(dbgs() <<
"Dyld::BuildBloomFilter: Failed to read symbol "
961 symbols.push_back(Name);
965 Lib->InitializeBloomFilter(SymbolsCount);
968 LLVM_DEBUG(dbgs() <<
"Dyld::BuildBloomFilter: No symbols!\n");
972 LLVM_DEBUG(dbgs() <<
"Dyld::BuildBloomFilter: Symbols:\n");
974 for (
auto it : symbols)
975 LLVM_DEBUG(dbgs() <<
"Dyld::BuildBloomFilter"
976 <<
"- " << it <<
"\n");
979 for (
const auto& S : symbols) {
981 Lib->AddBloom(Lib->AddSymbol(S.str()));
988bool Dyld::ContainsSymbol(
const LibraryPath* Lib, StringRef mangledName,
989 unsigned IgnoreSymbolFlags )
const {
990#define DEBUG_TYPE "Dyld::ContainsSymbol:"
991 const std::string library_filename = Lib->GetFullName();
993 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: Find symbol: lib="
994 << library_filename <<
", mangled=" << mangledName.str()
997 auto ObjF = llvm::object::ObjectFile::createObjectFile(library_filename);
998 if (llvm::Error Err = ObjF.takeError()) {
1000 handleAllErrors(std::move(Err), [&](llvm::ErrorInfoBase& EIB) {
1001 Message += EIB.message() +
"; ";
1003 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: Failed to read object file "
1004 << library_filename <<
" Errors: " << Message <<
"\n");
1008 llvm::object::ObjectFile* BinObjFile = ObjF.get().getBinary();
1010 uint32_t hashedMangle = GNUHash(mangledName);
1013 if (BinObjFile->isELF() &&
1014 !MayExistInElfObjectFile(BinObjFile, hashedMangle)) {
1015 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: ELF BloomFilter: Skip symbol <"
1016 << mangledName.str() <<
">.\n");
1020 if (m_UseBloomFilter) {
1022 if (!Lib->hasBloomFilter())
1023 BuildBloomFilter(
const_cast<LibraryPath*
>(Lib), BinObjFile,
1027 if (!Lib->MayExistSymbol(hashedMangle)) {
1028 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: BloomFilter: Skip symbol <"
1029 << mangledName.str() <<
">.\n");
1032 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: BloomFilter: Symbol <"
1033 << mangledName.str() <<
"> May exist."
1034 <<
" Search for it. ");
1037 if (m_UseHashTable) {
1038 bool result = Lib->ExistSymbol(mangledName);
1039 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: HashTable: Symbol "
1040 << (result ?
"Exist" :
"Not exist") <<
"\n");
1044 auto ForeachSymbol =
1046 [&library_filename](
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());
1055 if (Flags & IgnoreSymbolFlags)
1067 llvm::Expected<llvm::StringRef> SymNameErr = S.getName();
1069 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: Failed to read symbol "
1070 << mangledName.str() <<
"\n");
1074 if (SymNameErr.get().empty())
1077 if (SymNameErr.get() == mangledName) {
1078 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: Symbol "
1079 << mangledName.str() <<
" found in "
1080 << library_filename <<
"\n");
1090 LLVM_DEBUG(dbgs() <<
"Dyld::ContainsSymbol: Iterate all for <"
1091 << mangledName.str() <<
">");
1094 if (ForeachSymbol(BinObjFile->symbols(), IgnoreSymbolFlags, mangledName)) {
1095 LLVM_DEBUG(dbgs() <<
" -> found.\n");
1099 if (!BinObjFile->isELF()) {
1100 LLVM_DEBUG(dbgs() <<
" -> not found.\n");
1105 const auto* ElfObj = llvm::cast<llvm::object::ELFObjectFileBase>(BinObjFile);
1107 bool result = ForeachSymbol(ElfObj->getDynamicSymbolIterators(),
1108 IgnoreSymbolFlags, mangledName);
1109 LLVM_DEBUG(dbgs() << (result ?
" -> found.\n" :
" -> not found.\n"));
1114bool Dyld::ShouldPermanentlyIgnore(StringRef FileName)
const {
1115#define DEBUG_TYPE "Dyld:"
1116 assert(!m_ExecutableFormat.empty() &&
"Failed to find the object format!");
1118 if (!DynamicLibraryManager::isSharedLibrary(FileName))
1123 if (m_DynamicLibraryManager.isLibraryLoaded(FileName))
1126 auto ObjF = llvm::object::ObjectFile::createObjectFile(FileName);
1128 llvm::consumeError(ObjF.takeError());
1129 LLVM_DEBUG(dbgs() <<
"[DyLD] Failed to read object file " << FileName
1134 llvm::object::ObjectFile* file = ObjF.get().getBinary();
1136 LLVM_DEBUG(dbgs() <<
"Current executable format: " << m_ExecutableFormat
1137 <<
". Executable format of " << FileName <<
" : "
1138 << file->getFileFormatName() <<
"\n");
1141 if (m_ExecutableFormat != file->getFileFormatName())
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") {
1152 auto SecRef =
static_cast<llvm::object::ELFSectionRef&
>(S);
1153 if (SecRef.getType() == llvm::ELF::SHT_NOBITS)
1156 return (SecRef.getFlags() & llvm::ELF::SHF_ALLOC) == 0;
1164 return m_ShouldPermanentlyIgnoreCallback(FileName);
1168void Dyld::dumpDebugInfo()
const {
1169#define DEBUG_TYPE "Dyld:"
1170 LLVM_DEBUG(dbgs() <<
"---\n");
1173 for (
auto const& item : m_BasePaths.m_Paths) {
1174 LLVM_DEBUG(dbgs() <<
"Dyld: - m_BasePaths[" << x++ <<
"]:" << &item <<
": "
1177 LLVM_DEBUG(dbgs() <<
"---\n");
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");
1184 for (
auto const& item : m_SysLibraries.GetLibraries()) {
1185 LLVM_DEBUG(dbgs() <<
"Dyld: - m_SysLibraries[" << x++ <<
"]:" << &item
1186 <<
": " << item->m_Path <<
", " << item->m_LibName
1193std::string Dyld::searchLibrariesForSymbol(StringRef mangledName,
1194 bool searchSystem ) {
1195#define DEBUG_TYPE "Dyld:searchLibrariesForSymbol:"
1197 !llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(mangledName.str()) &&
1198 "Library already loaded, please use dlsym!");
1199 assert(!mangledName.empty());
1201 using namespace llvm::sys::path;
1202 using namespace llvm::sys::fs;
1205 LLVM_DEBUG(dbgs() <<
"Dyld::searchLibrariesForSymbol:" << mangledName.str()
1206 <<
", searchSystem=" << (searchSystem ?
"true" :
"false")
1207 <<
", FirstRun(user)... scanning\n");
1211 <<
"Dyld::searchLibrariesForSymbol: Before first ScanForLibraries\n");
1214 ScanForLibraries(
false);
1219 <<
"Dyld::searchLibrariesForSymbol: After first ScanForLibraries\n");
1223 if (m_QueriedLibraries.size() > 0) {
1228 LLVM_DEBUG(dbgs() <<
"Dyld::ResolveSymbol: m_QueriedLibraries:\n");
1231 for (
auto item : m_QueriedLibraries.GetLibraries()) {
1232 LLVM_DEBUG(dbgs() <<
"Dyld::ResolveSymbol - [" << x++ <<
"]:" << &item
1233 <<
": " << item->GetFullName() <<
"\n");
1236 for (
const LibraryPath* P : m_QueriedLibraries.GetLibraries()) {
1237 const std::string LibName = P->GetFullName();
1238 if (!m_DynamicLibraryManager.isLibraryLoaded(LibName))
1241 m_Libraries.UnregisterLib(*P);
1242 m_SysLibraries.UnregisterLib(*P);
1248 for (
const LibraryPath* P : m_Libraries.GetLibraries()) {
1249 if (ContainsSymbol(P, mangledName,
1250 llvm::object::SymbolRef::SF_Undefined)) {
1251 if (!m_QueriedLibraries.HasRegisteredLib(*P))
1252 m_QueriedLibraries.RegisterLib(*P);
1255 dbgs() <<
"Dyld::ResolveSymbol: Search found match in [user lib]: "
1256 << P->GetFullName() <<
"!\n");
1258 return P->GetFullName();
1265 LLVM_DEBUG(dbgs() <<
"Dyld::searchLibrariesForSymbol: SearchSystem!!!\n");
1268 if (m_FirstRunSysLib) {
1269 LLVM_DEBUG(dbgs() <<
"Dyld::searchLibrariesForSymbol:" << mangledName.str()
1270 <<
", searchSystem=" << (searchSystem ?
"true" :
"false")
1271 <<
", FirstRun(system)... scanning\n");
1273 LLVM_DEBUG(dbgs() <<
"Dyld::searchLibrariesForSymbol: Before first system "
1274 "ScanForLibraries\n");
1277 ScanForLibraries(
true);
1278 m_FirstRunSysLib =
false;
1280 LLVM_DEBUG(dbgs() <<
"Dyld::searchLibrariesForSymbol: After first system "
1281 "ScanForLibraries\n");
1285 for (
const LibraryPath* P : m_SysLibraries.GetLibraries()) {
1286 if (ContainsSymbol(P, mangledName,
1287 llvm::object::SymbolRef::SF_Undefined |
1288 llvm::object::SymbolRef::SF_Weak)) {
1289 if (!m_QueriedLibraries.HasRegisteredLib(*P))
1290 m_QueriedLibraries.RegisterLib(*P);
1293 dbgs() <<
"Dyld::ResolveSymbol: Search found match in [system lib]: "
1294 << P->GetFullName() <<
"!\n");
1296 return P->GetFullName();
1300 LLVM_DEBUG(dbgs() <<
"Dyld::ResolveSymbol: Search found no match!\n");
1306DynamicLibraryManager::~DynamicLibraryManager() {
1307 static_assert(
sizeof(
Dyld) > 0,
"Incomplete type");
1311void DynamicLibraryManager::initializeDyld(
1312 std::function<
bool(llvm::StringRef)> shouldPermanentlyIgnore) {
1318 auto ObjF = cantFail(llvm::object::ObjectFile::createObjectFile(exeP));
1320 m_Dyld =
new Dyld(*
this, shouldPermanentlyIgnore,
1321 ObjF.getBinary()->getFileFormatName());
1324std::string DynamicLibraryManager::searchLibrariesForSymbol(
1325 StringRef mangledName,
bool searchSystem )
const {
1326 assert(m_Dyld &&
"Must call initialize dyld before!");
1327 return m_Dyld->searchLibrariesForSymbol(mangledName, searchSystem);
1330std::string DynamicLibraryManager::getSymbolLocation(
void* func) {
1331#if defined(__CYGWIN__) && defined(__GNUC__)
1333#elif defined(_WIN32)
1334 MEMORY_BASIC_INFORMATION mbi;
1335 if (!VirtualQuery(func, &mbi,
sizeof(mbi)))
1338 HMODULE hMod = (HMODULE)mbi.AllocationBase;
1339 char moduleName[MAX_PATH];
1341 if (!GetModuleFileNameA(hMod, moduleName,
sizeof(moduleName)))
1344 return cached_realpath(moduleName);
1349 if (dladdr((
void*)func, &info) == 0) {
1353 std::string result = cached_realpath(info.dli_fname);
1354 if (!result.empty())
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};
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");
1374 return cached_realpath(info.dli_fname);
1375 while (fgets(buf,
sizeof(buf), pipe))
1379 return cached_realpath(result);
1381#error "Unsupported platform."
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.
@ kAllowNonExistent
Add all paths whether they exist or not.
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.
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)
std::string GetExecutablePath()