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 (Entry.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)