LLVM: lib/ExecutionEngine/Orc/TargetProcess/LibraryScanner.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
11
27
28#ifdef LLVM_ON_UNIX
29#include <sys/stat.h>
30#include <unistd.h>
31#endif
32
33#ifdef __APPLE__
34#include <sys/stat.h>
35#undef LC_LOAD_DYLIB
36#undef LC_RPATH
37#endif
38
39#define DEBUG_TYPE "orc-scanner"
40
42
45 dbgs() << "LLVM Error";
46 if (!context.empty())
47 dbgs() << " [" << context << "]";
49 }));
50}
51
54 Triple ObjTriple = Obj.makeTriple();
55
57 dbgs() << "Host triple: " << HostTriple.str()
58 << ", Object triple: " << ObjTriple.str() << "\n";
59 });
60
63 return false;
64
66 HostTriple.getOS() != ObjTriple.getOS())
67 return false;
68
72 return false;
73
74 return true;
75}
76
78ObjectFileLoader::loadObjectFileWithOwnership(StringRef FilePath) {
79 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Attempting to open file " << FilePath
80 << "\n";);
82 if (!BinOrErr) {
83 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Failed to open file " << FilePath
84 << "\n";);
85 return BinOrErr.takeError();
86 }
87
88 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Successfully opened file " << FilePath
89 << "\n";);
90
91 auto OwningBin = BinOrErr->takeBinary();
93
94 if (Bin->isArchive()) {
95 LLVM_DEBUG(dbgs() << "ObjectFileLoader: File is an archive, not supported: "
96 << FilePath << "\n";);
98 "Archive files are not supported: %s",
99 FilePath.str().c_str());
100 }
101
102#if defined(__APPLE__)
104 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Detected Mach-O universal binary: "
105 << FilePath << "\n";);
106 for (auto ObjForArch : UB->objects()) {
107 auto ObjOrErr = ObjForArch.getAsObjectFile();
108 if (!ObjOrErr) {
111 << "ObjectFileLoader: Skipping invalid architecture slice\n";);
112
114 continue;
115 }
116
117 std::unique_ptrobject::ObjectFile Obj = std::move(ObjOrErr.get());
120 dbgs() << "ObjectFileLoader: Found compatible object slice\n";);
121
122 return object::OwningBinaryobject::ObjectFile(
123 std::move(Obj), std::move(OwningBin.second));
124
125 } else {
126 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Incompatible architecture "
127 "slice skipped\n";);
128 }
129 }
130 LLVM_DEBUG(dbgs() << "ObjectFileLoader: No compatible slices found in "
131 "universal binary\n";);
133 "No compatible object found in fat binary: %s",
134 FilePath.str().c_str());
135 }
136#endif
137
138 auto ObjOrErr =
140 if (!ObjOrErr) {
141 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Failed to create object file\n";);
142 return ObjOrErr.takeError();
143 }
144 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Detected object file\n";);
145
146 std::unique_ptrobject::ObjectFile Obj = std::move(*ObjOrErr);
148 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Incompatible architecture: "
149 << FilePath << "\n";);
151 "Incompatible object file: %s",
152 FilePath.str().c_str());
153 }
154
155 LLVM_DEBUG(dbgs() << "ObjectFileLoader: Object file is compatible\n";);
156
157 return object::OwningBinaryobject::ObjectFile(std::move(Obj),
158 std::move(OwningBin.second));
159}
160
161template
164 return false;
165
167 if (!PHOrErr) {
169 return true;
170 }
171
172 for (auto Phdr : *PHOrErr) {
174 return false;
175 }
176
177 return true;
178}
179
181 if (Obj.isELF()) {
190 } else if (Obj.isMachO()) {
194 LLVM_DEBUG(dbgs() << "Failed to cast to MachOObjectFile.\n";);
195 return false;
196 }
200 dbgs() << "Mach-O filetype: " << MachO->getHeader().filetype
202 << "), shared: " << Result << "\n";
203 });
204
206 } else if (Obj.isCOFF()) {
208 if (!coff)
209 return false;
211 } else {
212 LLVM_DEBUG(dbgs() << "Binary is not an ObjectFile.\n";);
213 }
214
215 return false;
216}
217
219 LLVM_DEBUG(dbgs() << "Checking if path is a shared library: " << Path
220 << "\n";);
221
224 LLVM_DEBUG(dbgs() << "File type is not a regular file for path: " << Path
225 << "\n";);
226 return false;
227 }
228
231
232
234 return false;
235
236
237#if defined(__APPLE__)
241 if (!ObjOrErr) {
243 return false;
244 }
246 }
247#endif
248
249
250 bool NeedsObjectInspection =
251#if defined(_WIN32)
253#elif defined(__APPLE__)
257#elif defined(LLVM_ON_UNIX)
258#ifdef __CYGWIN__
260#else
262#endif
263#else
264#error "Unsupported platform."
265#endif
266
267 if (NeedsObjectInspection) {
270 if (!ObjOrErr) {
272 return false;
273 }
275 }
276
277 LLVM_DEBUG(dbgs() << "Path is not identified as a shared library: " << Path
278 << "\n";);
279 return false;
280}
281
285
287 if (LoaderPath.empty()) {
288 LoaderDir = ExecPath;
289 } else {
290 LoaderDir = LoaderPath.str();
293 }
294
295#ifdef __APPLE__
296 Placeholders["@loader_path"] = std::string(LoaderDir);
297 Placeholders["@executable_path"] = std::string(ExecPath);
298#else
299 Placeholders["$origin"] = std::string(LoaderDir);
300#endif
301}
302
303std::optionalstd::string
306 for (const auto &SP : Paths) {
308
310 if (!PlaceholderPrefix.empty() &&
313 else
315
316 LLVM_DEBUG(dbgs() << "SearchPathResolver::resolve FullPath = " << FullPath
317 << "\n";);
318
319 if (auto Valid = Validator.validate(FullPath.str()))
320 return Valid;
321 }
322
323 return std::nullopt;
324}
325
326std::optionalstd::string
327DylibResolverImpl::tryWithExtensions(StringRef LibStem) const {
328 LLVM_DEBUG(dbgs() << "tryWithExtensions: baseName = " << LibStem << "\n";);
330
331
332#if defined(__APPLE__)
334 Candidates.back() += ".dylib";
335#elif defined(_WIN32)
336 Candidates.emplace_back(LibStem);
337 Candidates.back() += ".dll";
338#else
339 Candidates.emplace_back(LibStem);
340 Candidates.back() += ".so";
341#endif
342
343
348 if (!WithPrefix.empty())
350 WithPrefix += "lib";
351 WithPrefix += FileName;
352
353#if defined(__APPLE__)
354 WithPrefix += ".dylib";
355#elif defined(_WIN32)
356 WithPrefix += ".dll";
357#else
358 WithPrefix += ".so";
359#endif
360
361 Candidates.push_back(std::move(WithPrefix));
362 }
363
365 dbgs() << " Candidates to try:\n";
366 for (const auto &C : Candidates)
367 dbgs() << " " << C << "\n";
368 });
369
370
371 for (const auto &Name : Candidates) {
372
373 LLVM_DEBUG(dbgs() << " Trying candidate: " << Name << "\n";);
374
375 for (const auto &R : Resolvers) {
376 if (auto Res = R.resolve(Name, Substitutor, Validator))
377 return Res;
378 }
379 }
380
381 LLVM_DEBUG(dbgs() << " -> No candidate Resolved.\n";);
382
383 return std::nullopt;
384}
385
386std::optionalstd::string
388 LLVM_DEBUG(dbgs() << "Resolving library stem: " << LibStem << "\n";);
389
390
392 LLVM_DEBUG(dbgs() << " -> Absolute path detected.\n";);
393 return Validator.validate(LibStem);
394 }
395
397 if (auto norm = Validator.validate(Substitutor.substitute(LibStem))) {
398 LLVM_DEBUG(dbgs() << " -> Resolved after substitution: " << *norm
399 << "\n";);
400
401 return norm;
402 }
403 }
404
405 for (const auto &R : Resolvers) {
406 LLVM_DEBUG(dbgs() << " -> Resolving via search path ... \n";);
407 if (auto Result = R.resolve(LibStem, Substitutor, Validator)) {
409 << "\n";);
410
412 }
413 }
414
415
416
417 if (VariateLibStem) {
418 LLVM_DEBUG(dbgs() << " -> Trying with extensions...\n";);
419
420 if (auto Norm = tryWithExtensions(LibStem)) {
421 LLVM_DEBUG(dbgs() << " -> Resolved via tryWithExtensions: " << *Norm
422 << "\n";);
423
424 return Norm;
425 }
426 }
427
428 LLVM_DEBUG(dbgs() << " -> Could not resolve: " << LibStem << "\n";);
429
430 return std::nullopt;
431}
432
433#ifndef _WIN32
435
436 if (auto Cache = LibPathCache->read_lstat(Path))
437 return *Cache;
438
439
440 struct stat buf{};
441 mode_t st_mode = (lstat(Path.str().c_str(), &buf) == -1) ? 0 : buf.st_mode;
442
443 LibPathCache->insert_lstat(Path, st_mode);
444
445 return st_mode;
446}
447
449
450 if (auto Cache = LibPathCache->read_link(Path))
451 return Cache;
452
453
455 ssize_t len;
456 if ((len = readlink(Path.str().c_str(), buf, sizeof(buf))) != -1) {
457 buf[len] = '\0';
458 std::string s(buf);
459 LibPathCache->insert_link(Path, s);
460 return s;
461 }
462 return std::nullopt;
463}
464
468 if (!BaseIsResolved) {
469 if (Path[0] == '~' &&
474 StringRef(HomeP).split(Component, Separator, -1,
475 false);
476 } else if (BasePath.empty()) {
478 if (CurrentPath.str().empty())
481 .split(Component, Separator, -1, false);
482 } else {
483 BasePath.split(Component, Separator, -1,
484 false);
485 }
486 }
487
488 Path.split(Component, Separator, -1, false);
489}
490
493 for (auto &Part : PathParts) {
494 if (Part == ".") {
495 continue;
496 } else if (Part == "..") {
497 if (!NormalizedPath.empty() && NormalizedPath.back() != "..") {
499 } else {
501 }
502 } else {
504 }
505 }
506 PathParts.swap(NormalizedPath);
507}
508#endif
509
511 std::error_code &EC,
513 bool BaseIsResolved,
514 long SymLoopLevel) {
515 EC.clear();
516
517 if (Path.empty()) {
518 EC = std::make_error_code(std::errc::no_such_file_or_directory);
519 LLVM_DEBUG(dbgs() << "PathResolver::realpathCached: Empty path\n";);
520
521 return std::nullopt;
522 }
523
524 if (SymLoopLevel <= 0) {
525 EC = std::make_error_code(std::errc::too_many_symbolic_link_levels);
527 dbgs() << "PathResolver::realpathCached: Too many Symlink levels: "
528 << Path << "\n";);
529
530 return std::nullopt;
531 }
532
533
535 if (!isRelative) {
536 if (auto Cached = LibPathCache->read_realpath(Path)) {
537 EC = Cached->ErrnoCode;
538 if (EC) {
539 LLVM_DEBUG(dbgs() << "PathResolver::realpathCached: Cached (error) for "
540 << Path << "\n";);
541 } else {
543 dbgs() << "PathResolver::realpathCached: Cached (success) for "
544 << Path << " => " << Cached->canonicalPath << "\n";);
545 }
546 return Cached->canonicalPath.empty()
547 ? std::nullopt
548 : std::make_optional(Cached->canonicalPath);
549 }
550 }
551
552 LLVM_DEBUG(dbgs() << "PathResolver::realpathCached: Resolving path: " << Path
553 << "\n";);
554
555
556
559#ifndef _WIN32
561
562 if (isRelative) {
563 if (BaseIsResolved) {
566 }
568 } else {
569 Path.split(Components, Separator, -1, false);
570 }
571
574 for (auto &C : Components)
575 dbgs() << " " << C << " ";
576
577 dbgs() << "\n";
578 });
579
580
581 for (const auto &Component : Components) {
582 if (Component == ".")
583 continue;
584 if (Component == "..") {
585
586 size_t S = Resolved.rfind(Separator);
591 continue;
592 }
593
594 size_t oldSize = Resolved.size();
596 const char *ResolvedPath = Resolved.c_str();
597 LLVM_DEBUG(dbgs() << " Processing Component: " << Component << " => "
598 << ResolvedPath << "\n";);
599 mode_t st_mode = lstatCached(ResolvedPath);
600
601 if (S_ISLNK(st_mode)) {
602 LLVM_DEBUG(dbgs() << " Found symlink: " << ResolvedPath << "\n";);
603
605 if (!SymlinkOpt) {
606 EC = std::make_error_code(std::errc::no_such_file_or_directory);
607 LibPathCache->insert_realpath(Path, LibraryPathCache::PathInfo{"", EC});
608 LLVM_DEBUG(dbgs() << " Failed to read symlink: " << ResolvedPath
609 << "\n";);
610
611 return std::nullopt;
612 }
613
615 LLVM_DEBUG(dbgs() << " Symlink points to: " << Symlink << "\n";);
616
617 std::string resolvedBase = "";
620 resolvedBase = Resolved.str().str();
621 }
622
623 auto RealSymlink =
625 true, SymLoopLevel - 1);
626 if (!RealSymlink) {
627 LibPathCache->insert_realpath(Path, LibraryPathCache::PathInfo{"", EC});
628 LLVM_DEBUG(dbgs() << " Failed to resolve symlink target: " << Symlink
629 << "\n";);
630
631 return std::nullopt;
632 }
633
634 Resolved.assign(*RealSymlink);
636
637 } else if (st_mode == 0) {
638 EC = std::make_error_code(std::errc::no_such_file_or_directory);
639 LibPathCache->insert_realpath(Path, LibraryPathCache::PathInfo{"", EC});
640 LLVM_DEBUG(dbgs() << " Component does not exist: " << ResolvedPath
641 << "\n";);
642
643 return std::nullopt;
644 }
645 }
646#else
648#endif
649
650 std::string Canonical = Resolved.str().str();
651 {
652 LibPathCache->insert_realpath(Path, LibraryPathCache::PathInfo{
653 Canonical,
654 std::error_code()
655 });
656 }
657 LLVM_DEBUG(dbgs() << "PathResolver::realpathCached: Final Resolved: " << Path
658 << " => " << Canonical << "\n";);
659 return Canonical;
660}
661
663 std::error_code EC;
664 std::string Canon = resolveCanonical(Path, EC);
665 if (EC) {
668 << "LibraryScanHelper::addBasePath: Failed to canonicalize path: "
669 << Path << "\n";);
670 return;
671 }
672 std::unique_lockstd::shared\_mutex Lock(Mtx);
673 if (LibSearchPaths.count(Canon)) {
674 LLVM_DEBUG(dbgs() << "LibraryScanHelper::addBasePath: Already added: "
675 << Canon << "\n";);
676 return;
677 }
678 K = K == PathType::Unknown ? classifyKind(Canon) : K;
679 auto SP = std::make_shared(Canon, K);
680 LibSearchPaths[Canon] = SP;
681
682 if (K == PathType::User) {
683 LLVM_DEBUG(dbgs() << "LibraryScanHelper::addBasePath: Added User path: "
684 << Canon << "\n";);
685 UnscannedUsr.push_back(StringRef(SP->BasePath));
686 } else {
687 LLVM_DEBUG(dbgs() << "LibraryScanHelper::addBasePath: Added System path: "
688 << Canon << "\n";);
689 UnscannedSys.push_back(StringRef(SP->BasePath));
690 }
691}
692
693std::vector<std::shared_ptr>
695 std::vector<std::shared_ptr> Result;
696 auto &Queue = (K == PathType::User) ? UnscannedUsr : UnscannedSys;
697
698 std::unique_lockstd::shared\_mutex Lock(Mtx);
699
700 while (!Queue.empty() && (BatchSize == 0 || Result.size() < BatchSize)) {
702 auto It = LibSearchPaths.find(Base);
703 if (It != LibSearchPaths.end()) {
704 auto &SP = It->second;
707 Result.push_back(SP);
708 }
709 }
710 Queue.pop_front();
711 }
712
714}
715
717 std::error_code EC;
718 std::string Canon = resolveCanonical(Path, EC);
719 if (EC)
720 return false;
721
722 std::shared_lockstd::shared\_mutex Lock(Mtx);
723 return LibSearchPaths.count(Canon) > 0;
724}
725
727 std::shared_lockstd::shared\_mutex Lock(Mtx);
728 for (const auto &KV : LibSearchPaths) {
729 const auto &SP = KV.second;
731 return true;
732 }
733 return false;
734}
735
737 std::shared_lockstd::shared\_mutex Lock(Mtx);
738
739 for (auto &[_, SP] : LibSearchPaths) {
741
743 continue;
744
745 auto &TargetList =
746 (SP->Kind == PathType::User) ? UnscannedUsr : UnscannedSys;
748 }
749}
750
751std::vector<std::shared_ptr>
753 std::shared_lockstd::shared\_mutex Lock(Mtx);
754 std::vector<std::shared_ptr> Result;
755 Result.reserve(LibSearchPaths.size());
756 for (const auto &[_, SP] : LibSearchPaths) {
757 Result.push_back(SP);
758 }
760}
761
762std::string LibraryScanHelper::resolveCanonical(StringRef Path,
763 std::error_code &EC) const {
764 auto Canon = LibPathResolver->resolve(Path, EC);
765 return EC ? Path.str() : *Canon;
766}
767
769
770 const char *Home = getenv("HOME");
771 if (Home && Path.starts_with(Home))
772 return PathType::User;
773
774 static const std::array<std::string, 5> UserPrefixes = {
775 "/usr/local",
776 "/opt/homebrew",
777 "/opt/local",
778 "/home",
779 "/Users",
780 };
781
782 for (const auto &Prefix : UserPrefixes) {
783 if (Path.starts_with(Prefix))
784 return PathType::User;
785 }
786
787 return PathType::System;
788}
789
792 LLVM_DEBUG(dbgs() << "Parsing Mach-O dependencies...\n";);
793 for (const auto &Command : Obj.load_commands()) {
794 switch (Command.C.cmd) {
795 case MachO::LC_LOAD_DYLIB: {
797 const char *name = Command.Ptr + dylibCmd.dylib.name;
800 } break;
801 case MachO::LC_LOAD_WEAK_DYLIB:
802 case MachO::LC_REEXPORT_DYLIB:
803 case MachO::LC_LOAD_UPWARD_DYLIB:
804 case MachO::LC_LAZY_LOAD_DYLIB:
805 break;
806 case MachO::LC_RPATH: {
807
809 const char *rpath = Command.Ptr + rpathCmd.path;
810 LLVM_DEBUG(dbgs() << " Found LC_RPATH: " << rpath << "\n";);
811
815
816 for (const auto &raw : RawPaths) {
817 Libdeps.addRPath(raw.str());
818 LLVM_DEBUG(dbgs() << " Parsed RPATH entry: " << raw << "\n";);
819 }
820 break;
821 }
822 }
823 }
824
826}
827
828template
831 if (!DynamicEntriesOrError)
832 return DynamicEntriesOrError.takeError();
833
834 for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
835 if (Dyn.d_tag == ELF::DT_STRTAB) {
836 auto MappedAddrOrError = Elf.toMappedAddr(Dyn.getPtr());
837 if (!MappedAddrOrError)
838 return MappedAddrOrError.takeError();
839 return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError));
840 }
841 }
842
843
844 auto SectionsOrError = Elf.sections();
845 if (!SectionsOrError)
846 return SectionsOrError.takeError();
847
848 for (const typename ELFT::Shdr &Sec : *SectionsOrError) {
851 }
852
855}
856
857template
861 if (!StrTabOrErr)
863
864 const char *Data = StrTabOrErr->data();
865
867 if (!DynamicEntriesOrError) {
868 return DynamicEntriesOrError.takeError();
869 }
870
871 for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
872 switch (Dyn.d_tag) {
873 case ELF::DT_NEEDED:
875 break;
876 case ELF::DT_RPATH: {
880 for (const auto &raw : RawPaths)
882 break;
883 }
884 case ELF::DT_RUNPATH: {
888 for (const auto &raw : RawPaths)
890 break;
891 }
892 case ELF::DT_FLAGS_1:
893
895 Deps.isPIE = true;
896 break;
897
898
899 default:
900 break;
901 }
902 }
903
905}
906
922
924 LLVM_DEBUG(dbgs() << "extractDeps: Attempting to open file " << FilePath
925 << "\n";);
926
927 ObjectFileLoader ObjLoader(FilePath);
928 auto ObjOrErr = ObjLoader.getObjectFile();
929 if (!ObjOrErr) {
930 LLVM_DEBUG(dbgs() << "extractDeps: Failed to open " << FilePath << "\n";);
931 return ObjOrErr.takeError();
932 }
933
934 object::ObjectFile *Obj = &ObjOrErr.get();
935
937 LLVM_DEBUG(dbgs() << "extractDeps: File " << FilePath
938 << " is an ELF object\n";);
939
941 }
942
944 LLVM_DEBUG(dbgs() << "extractDeps: File " << FilePath
945 << " is a Mach-O object\n";);
947 }
948
949 if (Obj->isCOFF()) {
950
952 }
953
954 LLVM_DEBUG(dbgs() << "extractDeps: Unsupported binary format for file "
955 << FilePath << "\n";);
957 "Unsupported binary format: %s",
958 FilePath.str().c_str());
959}
960
961std::optionalstd::string LibraryScanner::shouldScan(StringRef FilePath) {
962 std::error_code EC;
963
964 LLVM_DEBUG(dbgs() << "[shouldScan] Checking: " << FilePath << "\n";);
965
966
968 LLVM_DEBUG(dbgs() << " -> Skipped: file does not exist.\n";);
969
970 return std::nullopt;
971 }
972
973
974 auto CanonicalPathOpt = ScanHelper.resolve(FilePath, EC);
975 if (EC || !CanonicalPathOpt) {
976 LLVM_DEBUG(dbgs() << " -> Skipped: failed to resolve path (EC="
977 << EC.message() << ").\n";);
978
979 return std::nullopt;
980 }
981
982 const std::string &CanonicalPath = *CanonicalPathOpt;
983 LLVM_DEBUG(dbgs() << " -> Canonical path: " << CanonicalPath << "\n");
984
985
987 LLVM_DEBUG(dbgs() << " -> Skipped: path is a directory.\n";);
988
989 return std::nullopt;
990 }
991
992
994 LLVM_DEBUG(dbgs() << " -> Skipped: not a shared library.\n";);
995 return std::nullopt;
996 }
997
998
999 if (ScanHelper.hasSeenOrMark(CanonicalPath)) {
1000 LLVM_DEBUG(dbgs() << " -> Skipped: already seen.\n";);
1001
1002 return std::nullopt;
1003 }
1004
1005
1006 if (LibMgr.hasLibrary(CanonicalPath)) {
1007 LLVM_DEBUG(dbgs() << " -> Skipped: already tracked by LibraryManager.\n";);
1008
1009 return std::nullopt;
1010 }
1011
1012
1013 if (!ShouldScanCall(CanonicalPath)) {
1014 LLVM_DEBUG(dbgs() << " -> Skipped: user-defined hook rejected.\n";);
1015
1016 return std::nullopt;
1017 }
1018
1019 LLVM_DEBUG(dbgs() << " -> Accepted: ready to scan " << CanonicalPath
1020 << "\n";);
1021 return CanonicalPath;
1022}
1023
1024void LibraryScanner::handleLibrary(StringRef FilePath, PathType K, int level) {
1025 LLVM_DEBUG(dbgs() << "LibraryScanner::handleLibrary: Scanning: " << FilePath
1026 << ", level=" << level << "\n";);
1027 auto CanonPathOpt = shouldScan(FilePath);
1028 if (!CanonPathOpt) {
1029 LLVM_DEBUG(dbgs() << " Skipped (shouldScan returned false): " << FilePath
1030 << "\n";);
1031
1032 return;
1033 }
1034 const std::string CanonicalPath = *CanonPathOpt;
1035
1036 auto DepsOrErr = extractDeps(CanonicalPath);
1037 if (!DepsOrErr) {
1038 LLVM_DEBUG(dbgs() << " Failed to extract deps for: " << CanonicalPath
1039 << "\n";);
1041 return;
1042 }
1043
1045
1047 dbgs() << " Found deps : \n";
1048 for (const auto &dep : Deps.deps)
1049 dbgs() << " : " << dep << "\n";
1050 dbgs() << " Found @rpath : " << Deps.rpath.size() << "\n";
1051 for (const auto &r : Deps.rpath)
1052 dbgs() << " : " << r << "\n";
1053 dbgs() << " Found @runpath : \n";
1054 for (const auto &r : Deps.runPath)
1055 dbgs() << " : " << r << "\n";
1056 });
1057
1058 if (Deps.isPIE && level == 0) {
1059 LLVM_DEBUG(dbgs() << " Skipped PIE executable at top level: "
1060 << CanonicalPath << "\n";);
1061
1062 return;
1063 }
1064
1065 bool Added = LibMgr.addLibrary(CanonicalPath, K);
1066 if (!Added) {
1067 LLVM_DEBUG(dbgs() << " Already added: " << CanonicalPath << "\n";);
1068 return;
1069 }
1070
1071
1072 if (Deps.rpath.empty() && Deps.runPath.empty()) {
1074 dbgs() << "LibraryScanner::handleLibrary: Skipping deps (Heuristic1): "
1075 << CanonicalPath << "\n";);
1076 return;
1077 }
1078
1079
1080 auto allTracked = [&](const auto &Paths) {
1081 LLVM_DEBUG(dbgs() << " Checking : " << Paths.size() << "\n";);
1082 return std::all_of(Paths.begin(), Paths.end(), [&](StringRef P) {
1083 LLVM_DEBUG(dbgs() << " Checking isTrackedBasePath : " << P << "\n";);
1084 return ScanHelper.isTrackedBasePath(
1085 DylibResolver::resolvelinkerFlag(P, CanonicalPath));
1086 });
1087 };
1088
1089 if (allTracked(Deps.rpath) && allTracked(Deps.runPath)) {
1091 dbgs() << "LibraryScanner::handleLibrary: Skipping deps (Heuristic2): "
1092 << CanonicalPath << "\n";);
1093 return;
1094 }
1095
1096 DylibPathValidator Validator(ScanHelper.getPathResolver());
1097 DylibResolver Resolver(Validator);
1098 Resolver.configure(CanonicalPath,
1102 for (StringRef Dep : Deps.deps) {
1103 LLVM_DEBUG(dbgs() << " Resolving dep: " << Dep << "\n";);
1104 auto DepFullOpt = Resolver.resolve(Dep);
1105 if (!DepFullOpt) {
1106 LLVM_DEBUG(dbgs() << " Failed to resolve dep: " << Dep << "\n";);
1107
1108 continue;
1109 }
1110 LLVM_DEBUG(dbgs() << " Resolved dep to: " << *DepFullOpt << "\n";);
1111
1112 handleLibrary(*DepFullOpt, K, level + 1);
1113 }
1114}
1115
1116void LibraryScanner::scanBaseDir(std::shared_ptr SP) {
1119 dbgs() << "LibraryScanner::scanBaseDir: Invalid or empty basePath: "
1120 << SP->BasePath << "\n";);
1121 return;
1122 }
1123
1124 LLVM_DEBUG(dbgs() << "LibraryScanner::scanBaseDir: Scanning directory: "
1125 << SP->BasePath << "\n";);
1126 std::error_code EC;
1127
1129
1130 for (sys::fs::directory_iterator It(SP->BasePath, EC), end; It != end && !EC;
1131 It.increment(EC)) {
1132 auto Entry = *It;
1133 if (.status())
1134 continue;
1135
1136 auto Status = *Entry.status();
1139
1140 handleLibrary(Entry.path(), SP->Kind);
1141 }
1142 }
1143
1145}
1146
1148 LLVM_DEBUG(dbgs() << "LibraryScanner::scanNext: Scanning next batch of size "
1149 << BatchSize << " for kind "
1150 << (K == PathType::User ? "User" : "System") << "\n";);
1151
1152 auto SearchPaths = ScanHelper.getNextBatch(K, BatchSize);
1153 for (auto &SP : SearchPaths) {
1154 LLVM_DEBUG(dbgs() << " Scanning unit with basePath: " << SP->BasePath
1155 << "\n";);
1156
1157 scanBaseDir(SP);
1158 }
1159}
1160
1161}
std::deque< BasicBlock * > PathType
Base class for error info classes.
virtual std::string message() const
Return the error message as a string.
Lightweight error class with error context and mandatory checking.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void append(StringRef RHS)
Append from a StringRef.
StringRef str() const
Explicit conversion to StringRef.
reference emplace_back(ArgTypes &&... Args)
void swap(SmallVectorImpl &RHS)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
static constexpr size_t npos
std::string str() const
str - Get the contents as an std::string.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
LLVM_ABI bool starts_with_insensitive(StringRef Prefix) const
Check if this string starts with the given Prefix, ignoring case.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Triple - Helper class for working with autoconf configuration names.
OSType getOS() const
Get the parsed operating system type of this triple.
ArchType getArch() const
Get the parsed architecture type of this triple.
const std::string & str() const
EnvironmentType getEnvironment() const
Get the parsed environment type of this triple.
uint16_t getCharacteristics() const
const Elf_Ehdr & getHeader() const
Expected< Elf_Phdr_Range > program_headers() const
Iterate over program header table.
Expected< StringRef > getStringTableForSymtab(const Elf_Shdr &Section) const
Expected< Elf_Dyn_Range > dynamicEntries() const
Expected< Elf_Shdr_Range > sections() const
Expected< const uint8_t * > toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler=&defaultWarningHandler) const
This class is the base class for all object file types.
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
Validates and normalizes dynamic library paths.
static bool isSharedLibrary(StringRef Path)
Definition LibraryScanner.cpp:218
std::optional< std::string > validate(StringRef Path) const
Validate the given path as a shared library.
std::optional< std::string > resolve(StringRef Stem, bool VariateLibStem=false) const
Definition LibraryScanner.cpp:387
Performs placeholder substitution in dynamic library paths.
std::string substitute(StringRef input) const
void configure(StringRef loaderPath)
Definition LibraryScanner.cpp:282
std::vector< std::shared_ptr< LibrarySearchPath > > getNextBatch(PathType Kind, size_t batchSize)
Definition LibraryScanner.cpp:694
bool isTrackedBasePath(StringRef P) const
Definition LibraryScanner.cpp:716
bool leftToScan(PathType K) const
Definition LibraryScanner.cpp:726
std::vector< std::shared_ptr< LibrarySearchPath > > getAllUnits() const
Definition LibraryScanner.cpp:752
void resetToScan()
Definition LibraryScanner.cpp:736
void addBasePath(const std::string &P, PathType Kind=PathType::Unknown)
Definition LibraryScanner.cpp:662
void scanNext(PathType Kind, size_t batchSize=1)
Definition LibraryScanner.cpp:1147
Loads an object file and provides access to it.
static bool isArchitectureCompatible(const object::ObjectFile &Obj)
Definition LibraryScanner.cpp:52
Expected< object::ObjectFile & > getObjectFile()
Get the loaded object file, or return an error if loading failed.
std::optional< std::string > readlinkCached(StringRef Path)
Definition LibraryScanner.cpp:448
mode_t lstatCached(StringRef Path)
Definition LibraryScanner.cpp:434
std::optional< std::string > realpathCached(StringRef Path, std::error_code &ec, StringRef base="", bool baseIsResolved=false, long symloopLevel=40)
Definition LibraryScanner.cpp:510
std::optional< std::string > resolve(StringRef libStem, const DylibSubstitutor &Subst, DylibPathValidator &Validator) const
Definition LibraryScanner.cpp:304
@ IMAGE_FILE_DLL
The image file is a DLL.
@ C
The default llvm calling convention, compatible with C.
LLVM_ABI Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
Expected< LibraryDepsInfo > parseELF(const object::ELFFile< ELFT > &Elf)
Definition LibraryScanner.cpp:858
LibraryScanner::LibraryDepsInfo LibraryDepsInfo
Expected< LibraryDepsInfo > parseMachODeps(const object::MachOObjectFile &Obj)
Definition LibraryScanner.cpp:790
void createComponent(StringRef Path, StringRef BasePath, bool BaseIsResolved, SmallVector< StringRef, 16 > &Component)
Definition LibraryScanner.cpp:465
void handleError(Error Err, StringRef context="")
Definition LibraryScanner.cpp:43
void normalizePathSegments(SmallVector< StringRef, 16 > &PathParts)
Definition LibraryScanner.cpp:491
bool isELFSharedLibrary(const object::ELFFile< ELFT > &ELFObj)
Definition LibraryScanner.cpp:162
@ Resolved
Queried, materialization begun.
bool isSharedLibraryObject(object::ObjectFile &Obj)
Definition LibraryScanner.cpp:180
Expected< LibraryDepsInfo > parseELFDeps(const object::ELFObjectFileBase &Obj)
Definition LibraryScanner.cpp:907
static Expected< StringRef > getDynamicStrTab(const object::ELFFile< ELFT > &Elf)
Definition LibraryScanner.cpp:829
LLVM_ABI bool is_regular_file(const basic_file_status &status)
Does status represent a regular file?
LLVM_ABI bool is_symlink_file(const basic_file_status &status)
Does status represent a symlink file?
LLVM_ABI bool exists(const basic_file_status &status)
Does file exist?
LLVM_ABI std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
LLVM_ABI std::string getMainExecutable(const char *argv0, void *MainExecAddr)
Return the path to the main executable, given the value of argv[0] from program startup and the addre...
LLVM_ABI file_type get_file_type(const Twine &Path, bool Follow=true)
Does status represent a directory?
LLVM_ABI std::error_code current_path(SmallVectorImpl< char > &result)
Get the current path.
LLVM_ABI bool is_directory(const basic_file_status &status)
Does status represent a directory?
LLVM_ABI StringRef get_separator(Style style=Style::native)
Return the preferred separator for this platform.
LLVM_ABI void remove_filename(SmallVectorImpl< char > &path, Style style=Style::native)
Remove the last component from path unless it is the root dir.
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
LLVM_ABI bool is_relative(const Twine &path, Style style=Style::native)
Is path relative?
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
LLVM_ABI bool home_directory(SmallVectorImpl< char > &result)
Get the user's home directory.
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
const char EnvPathSeparator
This is the OS-specific separator for PATH like environment variables:
LLVM_ABI std::string getProcessTriple()
getProcessTriple() - Return an appropriate target triple for generating code to be loaded into the cu...
LLVM_ABI file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
LLVM_ABI void SplitString(StringRef Source, SmallVectorImpl< StringRef > &OutFragments, StringRef Delimiters=" \t\n\v\f\r")
SplitString - Split up the specified string according to the specified delimiters,...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
void consumeError(Error Err)
Consume a Error without doing anything.
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
@ archive
ar style archive file
@ elf_shared_object
ELF dynamically linked shared lib.
@ macho_dynamically_linked_shared_lib
Mach-O dynlinked shared lib.
@ macho_dynamically_linked_shared_lib_stub
Mach-O Shared lib stub.
@ pecoff_executable
PECOFF executable file.
@ macho_universal_binary
Mach-O universal binary.
@ macho_fixed_virtual_memory_shared_lib
Mach-O Shared Lib, FVM.
Dependency info for a library.
void addRunPath(StringRef s)
void addRPath(StringRef s)