brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.0 KiB · 7e1d528 Raw
368 lines · cpp
1//===- LibraryResolver.cpp - Library Resolution of Unresolved Symbols ---===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Library resolution impl for unresolved symbols10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryResolver.h"14#include "llvm/ExecutionEngine/Orc/TargetProcess/LibraryScanner.h"15 16#include "llvm/ADT/StringSet.h"17 18#include "llvm/BinaryFormat/MachO.h"19#include "llvm/Object/COFF.h"20#include "llvm/Object/ELF.h"21#include "llvm/Object/ELFObjectFile.h"22#include "llvm/Object/MachO.h"23#include "llvm/Object/ObjectFile.h"24#include "llvm/Support/Error.h"25 26#include <mutex>27#include <thread>28 29#define DEBUG_TYPE "orc-resolver"30 31namespace llvm::orc {32 33LibraryResolver::LibraryResolver(const LibraryResolver::Setup &S)34    : LibPathCache(S.Cache ? S.Cache : std::make_shared<LibraryPathCache>()),35      LibPathResolver(S.PResolver36                          ? S.PResolver37                          : std::make_shared<PathResolver>(LibPathCache)),38      ScanHelper(S.BasePaths, LibPathCache, LibPathResolver),39      FB(S.FilterBuilder), LibMgr(),40      ShouldScanCall(S.ShouldScanCall ? S.ShouldScanCall41                                      : [](StringRef) -> bool { return true; }),42      scanBatchSize(S.ScanBatchSize) {43 44  if (ScanHelper.getAllUnits().empty()) {45    LLVM_DEBUG(dbgs() << "Warning: No base paths provided for scanning.\n");46  }47}48 49std::unique_ptr<LibraryResolutionDriver>50LibraryResolutionDriver::create(const LibraryResolver::Setup &S) {51  auto LR = std::make_unique<LibraryResolver>(S);52  return std::unique_ptr<LibraryResolutionDriver>(53      new LibraryResolutionDriver(std::move(LR)));54}55 56void LibraryResolutionDriver::addScanPath(const std::string &Path, PathType K) {57  LR->ScanHelper.addBasePath(Path, K);58}59 60bool LibraryResolutionDriver::markLibraryLoaded(StringRef Path) {61  auto Lib = LR->LibMgr.getLibrary(Path);62  if (!Lib)63    return false;64 65  Lib->setState(LibraryManager::LibState::Loaded);66 67  return true;68}69 70bool LibraryResolutionDriver::markLibraryUnLoaded(StringRef Path) {71  auto Lib = LR->LibMgr.getLibrary(Path);72  if (!Lib)73    return false;74 75  Lib->setState(LibraryManager::LibState::Unloaded);76 77  return true;78}79 80void LibraryResolutionDriver::resolveSymbols(81    std::vector<std::string> Syms,82    LibraryResolver::OnSearchComplete OnCompletion,83    const SearchConfig &Config) {84  LR->searchSymbolsInLibraries(Syms, std::move(OnCompletion), Config);85}86 87static bool shouldIgnoreSymbol(const object::SymbolRef &Sym,88                               uint32_t IgnoreFlags) {89  Expected<uint32_t> FlagsOrErr = Sym.getFlags();90  if (!FlagsOrErr) {91    consumeError(FlagsOrErr.takeError());92    return true;93  }94 95  uint32_t Flags = *FlagsOrErr;96 97  using Filter = SymbolEnumeratorOptions;98  if ((IgnoreFlags & Filter::IgnoreUndefined) &&99      (Flags & object::SymbolRef::SF_Undefined))100    return true;101  if ((IgnoreFlags & Filter::IgnoreIndirect) &&102      (Flags & object::SymbolRef::SF_Indirect))103    return true;104  if ((IgnoreFlags & Filter::IgnoreWeak) &&105      (Flags & object::SymbolRef::SF_Weak))106    return true;107 108  return false;109}110 111bool SymbolEnumerator::enumerateSymbols(StringRef Path, OnEachSymbolFn OnEach,112                                        const SymbolEnumeratorOptions &Opts) {113  if (Path.empty())114    return false;115 116  ObjectFileLoader ObjLoader(Path);117 118  auto ObjOrErr = ObjLoader.getObjectFile();119  if (!ObjOrErr) {120    std::string ErrMsg;121    handleAllErrors(ObjOrErr.takeError(),122                    [&](const ErrorInfoBase &EIB) { ErrMsg = EIB.message(); });123    LLVM_DEBUG(dbgs() << "Failed loading object file: " << Path124                      << "\nError: " << ErrMsg << "\n");125    return false;126  }127 128  object::ObjectFile *Obj = &ObjOrErr.get();129 130  auto processSymbolRange =131      [&](object::ObjectFile::symbol_iterator_range Range) -> EnumerateResult {132    for (const auto &Sym : Range) {133      if (shouldIgnoreSymbol(Sym, Opts.FilterFlags))134        continue;135 136      auto NameOrErr = Sym.getName();137      if (!NameOrErr) {138        consumeError(NameOrErr.takeError());139        continue;140      }141 142      StringRef Name = *NameOrErr;143      if (Name.empty())144        continue;145 146      EnumerateResult Res = OnEach(Name);147      if (Res != EnumerateResult::Continue)148        return Res;149    }150    return EnumerateResult::Continue;151  };152 153  EnumerateResult Res = processSymbolRange(Obj->symbols());154  if (Res != EnumerateResult::Continue)155    return Res == EnumerateResult::Stop;156 157  if (Obj->isELF()) {158    const auto *ElfObj = cast<object::ELFObjectFileBase>(Obj);159    Res = processSymbolRange(ElfObj->getDynamicSymbolIterators());160    if (Res != EnumerateResult::Continue)161      return Res == EnumerateResult::Stop;162  } else if (Obj->isCOFF()) {163    const auto *CoffObj = cast<object::COFFObjectFile>(Obj);164    for (auto I = CoffObj->export_directory_begin(),165              E = CoffObj->export_directory_end();166         I != E; ++I) {167      StringRef Name;168      if (I->getSymbolName(Name))169        continue;170      if (Name.empty())171        continue;172 173      EnumerateResult Res = OnEach(Name);174      if (Res != EnumerateResult::Continue)175        return Res == EnumerateResult::Stop;176    }177  } else if (Obj->isMachO()) {178  }179 180  return true;181}182 183class SymbolSearchContext {184public:185  SymbolSearchContext(SymbolQuery &Q) : Q(Q) {}186 187  bool hasSearched(const LibraryInfo *Lib) const { return Searched.count(Lib); }188 189  void markSearched(const LibraryInfo *Lib) { Searched.insert(Lib); }190 191  inline bool allResolved() const { return Q.allResolved(); }192 193  SymbolQuery &query() { return Q; }194 195private:196  SymbolQuery &Q;197  DenseSet<const LibraryInfo *> Searched;198};199 200void LibraryResolver::resolveSymbolsInLibrary(201    LibraryInfo &Lib, SymbolQuery &UnresolvedSymbols,202    const SymbolEnumeratorOptions &Opts) {203  LLVM_DEBUG(dbgs() << "Checking unresolved symbols "204                    << " in library : " << Lib.getFileName() << "\n";);205  StringSet<> DiscoveredSymbols;206 207  if (!UnresolvedSymbols.hasUnresolved()) {208    LLVM_DEBUG(dbgs() << "Skipping library: " << Lib.getFullPath()209                      << " — unresolved symbols exist.\n";);210    return;211  }212 213  bool HasEnumerated = false;214  auto enumerateSymbolsIfNeeded = [&]() {215    if (HasEnumerated)216      return;217 218    HasEnumerated = true;219 220    LLVM_DEBUG(dbgs() << "Enumerating symbols in library: " << Lib.getFullPath()221                      << "\n";);222    SymbolEnumerator::enumerateSymbols(223        Lib.getFullPath(),224        [&](StringRef sym) {225          DiscoveredSymbols.insert(sym);226          return EnumerateResult::Continue;227        },228        Opts);229  };230 231  if (!Lib.hasFilter()) {232    LLVM_DEBUG(dbgs() << "Building filter for library: " << Lib.getFullPath()233                      << "\n";);234    enumerateSymbolsIfNeeded();235    if (DiscoveredSymbols.empty()) {236      LLVM_DEBUG(dbgs() << "  No symbols and remove library : "237                        << Lib.getFullPath() << "\n";);238      LibMgr.removeLibrary(Lib.getFullPath());239      return;240    }241    SmallVector<StringRef> SymbolVec;242    SymbolVec.reserve(DiscoveredSymbols.size());243    for (const auto &KV : DiscoveredSymbols)244      SymbolVec.push_back(KV.first());245 246    Lib.ensureFilterBuilt(FB, SymbolVec);247    LLVM_DEBUG({248      dbgs() << "DiscoveredSymbols : " << DiscoveredSymbols.size() << "\n";249      for (const auto &KV : DiscoveredSymbols)250        dbgs() << "DiscoveredSymbols : " << KV.first() << "\n";251    });252  }253 254  const auto &Unresolved = UnresolvedSymbols.getUnresolvedSymbols();255  bool HadAnySym = false;256  LLVM_DEBUG(dbgs() << "Total unresolved symbols : " << Unresolved.size()257                    << "\n";);258  for (const auto &Sym : Unresolved) {259    if (Lib.mayContain(Sym)) {260      LLVM_DEBUG(dbgs() << "Checking symbol '" << Sym261                        << "' in library: " << Lib.getFullPath() << "\n";);262      enumerateSymbolsIfNeeded();263      if (DiscoveredSymbols.count(Sym) > 0) {264        LLVM_DEBUG(dbgs() << "  Resolved symbol: " << Sym265                          << " in library: " << Lib.getFullPath() << "\n";);266        UnresolvedSymbols.resolve(Sym, Lib.getFullPath());267        HadAnySym = true;268      }269    }270  }271 272  using LibraryState = LibraryManager::LibState;273  if (HadAnySym && Lib.getState() != LibraryState::Loaded)274    Lib.setState(LibraryState::Queried);275}276 277void LibraryResolver::searchSymbolsInLibraries(278    std::vector<std::string> &SymbolList, OnSearchComplete OnComplete,279    const SearchConfig &Config) {280  SymbolQuery Q(SymbolList);281 282  using LibraryState = LibraryManager::LibState;283  using LibraryType = PathType;284  auto tryResolveFrom = [&](LibraryState S, LibraryType K) {285    LLVM_DEBUG(dbgs() << "Trying resolve from state=" << static_cast<int>(S)286                      << " type=" << static_cast<int>(K) << "\n";);287 288    SymbolSearchContext Ctx(Q);289    while (!Ctx.allResolved()) {290      std::vector<std::shared_ptr<LibraryInfo>> Libs;291      LibMgr.getLibraries(S, K, Libs, [&](const LibraryInfo &Lib) {292        return !Ctx.hasSearched(&Lib);293      });294 295      if (Libs.empty() && !scanLibrariesIfNeeded(K, scanBatchSize))296        break; // no more new libs to scan297 298      for (auto &Lib : Libs) {299        // can use Async here?300        resolveSymbolsInLibrary(*Lib, Ctx.query(), Config.Options);301        Ctx.markSearched(Lib.get());302 303        if (Ctx.allResolved())304          return;305      }306    }307  };308 309  for (const auto &[St, Ty] : Config.Policy.Plan) {310    tryResolveFrom(St, Ty);311    if (Q.allResolved())312      break;313  }314 315  // done:316  LLVM_DEBUG({317    dbgs() << "Search complete.\n";318    for (const auto &r : Q.getAllResults())319      dbgs() << "Resolved Symbol:" << r->Name << " -> " << r->ResolvedLibPath320             << "\n";321  });322 323  OnComplete(Q);324}325 326bool LibraryResolver::scanLibrariesIfNeeded(PathType PK, size_t BatchSize) {327  LLVM_DEBUG(dbgs() << "LibraryResolver::scanLibrariesIfNeeded: Scanning for "328                    << (PK == PathType::User ? "User" : "System")329                    << " libraries\n";);330  if (!ScanHelper.leftToScan(PK))331    return false;332 333  LibraryScanner Scanner(ScanHelper, LibMgr, ShouldScanCall);334  Scanner.scanNext(PK, BatchSize);335  return true;336}337 338bool LibraryResolver::symbolExistsInLibrary(const LibraryInfo &Lib,339                                            StringRef SymName,340                                            std::vector<std::string> *AllSyms) {341  SymbolEnumeratorOptions Opts;342  return symbolExistsInLibrary(Lib, SymName, AllSyms, Opts);343}344 345bool LibraryResolver::symbolExistsInLibrary(346    const LibraryInfo &Lib, StringRef SymName,347    std::vector<std::string> *AllSyms, const SymbolEnumeratorOptions &Opts) {348  bool Found = false;349 350  SymbolEnumerator::enumerateSymbols(351      Lib.getFullPath(),352      [&](StringRef Sym) {353        if (AllSyms)354          AllSyms->emplace_back(Sym.str());355 356        if (Sym == SymName) {357          Found = true;358        }359 360        return EnumerateResult::Continue;361      },362      Opts);363 364  return Found;365}366 367} // end namespace llvm::orc368