brintos

brintos / llvm-project-archived public Read only

0
0
Text · 37.5 KiB · 922241e Raw
1059 lines · cpp
1//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//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// This is a testing tool for use with the MC-JIT LLVM components.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/StringMap.h"14#include "llvm/DebugInfo/DIContext.h"15#include "llvm/DebugInfo/DWARF/DWARFContext.h"16#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"17#include "llvm/ExecutionEngine/RuntimeDyld.h"18#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"19#include "llvm/MC/MCAsmInfo.h"20#include "llvm/MC/MCContext.h"21#include "llvm/MC/MCDisassembler/MCDisassembler.h"22#include "llvm/MC/MCInstPrinter.h"23#include "llvm/MC/MCInstrInfo.h"24#include "llvm/MC/MCRegisterInfo.h"25#include "llvm/MC/MCSubtargetInfo.h"26#include "llvm/MC/MCTargetOptions.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Object/SymbolSize.h"29#include "llvm/Support/CommandLine.h"30#include "llvm/Support/DynamicLibrary.h"31#include "llvm/Support/FileSystem.h"32#include "llvm/Support/InitLLVM.h"33#include "llvm/Support/MSVCErrorWorkarounds.h"34#include "llvm/Support/Memory.h"35#include "llvm/Support/MemoryBuffer.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/TargetSelect.h"38#include "llvm/Support/Timer.h"39#include "llvm/Support/raw_ostream.h"40 41#include <future>42#include <list>43 44using namespace llvm;45using namespace llvm::object;46 47static cl::OptionCategory RTDyldCategory("RTDyld Options");48 49static cl::list<std::string> InputFileList(cl::Positional,50                                           cl::desc("<input files>"),51                                           cl::cat(RTDyldCategory));52 53enum ActionType {54  AC_Execute,55  AC_PrintObjectLineInfo,56  AC_PrintLineInfo,57  AC_PrintDebugLineInfo,58  AC_Verify59};60 61static cl::opt<ActionType> Action(62    cl::desc("Action to perform:"), cl::init(AC_Execute),63    cl::values(64        clEnumValN(AC_Execute, "execute",65                   "Load, link, and execute the inputs."),66        clEnumValN(AC_PrintLineInfo, "printline",67                   "Load, link, and print line information for each function."),68        clEnumValN(AC_PrintDebugLineInfo, "printdebugline",69                   "Load, link, and print line information for each function "70                   "using the debug object"),71        clEnumValN(AC_PrintObjectLineInfo, "printobjline",72                   "Like -printlineinfo but does not load the object first"),73        clEnumValN(AC_Verify, "verify",74                   "Load, link and verify the resulting memory image.")),75    cl::cat(RTDyldCategory));76 77static cl::opt<std::string>78    EntryPoint("entry", cl::desc("Function to call as entry point."),79               cl::init("_main"), cl::cat(RTDyldCategory));80 81static cl::list<std::string> Dylibs("dylib", cl::desc("Add library."),82                                    cl::cat(RTDyldCategory));83 84static cl::list<std::string> InputArgv("args", cl::Positional,85                                       cl::desc("<program arguments>..."),86                                       cl::PositionalEatsArgs,87                                       cl::cat(RTDyldCategory));88 89static cl::opt<std::string>90    TripleName("triple", cl::desc("Target triple for disassembler"),91               cl::cat(RTDyldCategory));92 93static cl::opt<std::string>94    MCPU("mcpu",95         cl::desc("Target a specific cpu type (-mcpu=help for details)"),96         cl::value_desc("cpu-name"), cl::init(""), cl::cat(RTDyldCategory));97 98static cl::list<std::string>99    CheckFiles("check",100               cl::desc("File containing RuntimeDyld verifier checks."),101               cl::cat(RTDyldCategory));102 103static cl::opt<uint64_t>104    PreallocMemory("preallocate",105                   cl::desc("Allocate memory upfront rather than on-demand"),106                   cl::init(0), cl::cat(RTDyldCategory));107 108static cl::opt<uint64_t> TargetAddrStart(109    "target-addr-start",110    cl::desc("For -verify only: start of phony target address "111             "range."),112    cl::init(4096), // Start at "page 1" - no allocating at "null".113    cl::Hidden, cl::cat(RTDyldCategory));114 115static cl::opt<uint64_t> TargetAddrEnd(116    "target-addr-end",117    cl::desc("For -verify only: end of phony target address range."),118    cl::init(~0ULL), cl::Hidden, cl::cat(RTDyldCategory));119 120static cl::opt<uint64_t> TargetSectionSep(121    "target-section-sep",122    cl::desc("For -verify only: Separation between sections in "123             "phony target address space."),124    cl::init(0), cl::Hidden, cl::cat(RTDyldCategory));125 126static cl::list<std::string>127    SpecificSectionMappings("map-section",128                            cl::desc("For -verify only: Map a section to a "129                                     "specific address."),130                            cl::Hidden, cl::cat(RTDyldCategory));131 132static cl::list<std::string> DummySymbolMappings(133    "dummy-extern",134    cl::desc("For -verify only: Inject a symbol into the extern "135             "symbol table."),136    cl::Hidden, cl::cat(RTDyldCategory));137 138static cl::opt<bool> PrintAllocationRequests(139    "print-alloc-requests",140    cl::desc("Print allocation requests made to the memory "141             "manager by RuntimeDyld"),142    cl::Hidden, cl::cat(RTDyldCategory));143 144static cl::opt<bool> ShowTimes("show-times",145                               cl::desc("Show times for llvm-rtdyld phases"),146                               cl::init(false), cl::cat(RTDyldCategory));147 148ExitOnError ExitOnErr;149 150struct RTDyldTimers {151  TimerGroup RTDyldTG{"llvm-rtdyld timers", "timers for llvm-rtdyld phases"};152  Timer LoadObjectsTimer{"load", "time to load/add object files", RTDyldTG};153  Timer LinkTimer{"link", "time to link object files", RTDyldTG};154  Timer RunTimer{"run", "time to execute jitlink'd code", RTDyldTG};155};156 157std::unique_ptr<RTDyldTimers> Timers;158 159/* *** */160 161using SectionIDMap = StringMap<unsigned>;162using FileToSectionIDMap = StringMap<SectionIDMap>;163 164void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) {165  for (const auto &KV : FileToSecIDMap) {166    llvm::dbgs() << "In " << KV.first() << "\n";167    for (auto &KV2 : KV.second)168      llvm::dbgs() << "  \"" << KV2.first() << "\" -> " << KV2.second << "\n";169  }170}171 172Expected<unsigned> getSectionId(const FileToSectionIDMap &FileToSecIDMap,173                                StringRef FileName, StringRef SectionName) {174  auto I = FileToSecIDMap.find(FileName);175  if (I == FileToSecIDMap.end())176    return make_error<StringError>("No file named " + FileName,177                                   inconvertibleErrorCode());178  auto &SectionIDs = I->second;179  auto J = SectionIDs.find(SectionName);180  if (J == SectionIDs.end())181    return make_error<StringError>("No section named \"" + SectionName +182                                   "\" in file " + FileName,183                                   inconvertibleErrorCode());184  return J->second;185}186 187// A trivial memory manager that doesn't do anything fancy, just uses the188// support library allocation routines directly.189class TrivialMemoryManager : public RTDyldMemoryManager {190public:191  struct SectionInfo {192    SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID)193        : Name(std::string(Name)), MB(std::move(MB)), SectionID(SectionID) {}194    std::string Name;195    sys::MemoryBlock MB;196    unsigned SectionID = ~0U;197  };198 199  SmallVector<SectionInfo, 16> FunctionMemory;200  SmallVector<SectionInfo, 16> DataMemory;201 202  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,203                               unsigned SectionID,204                               StringRef SectionName) override;205  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,206                               unsigned SectionID, StringRef SectionName,207                               bool IsReadOnly) override;208  TrivialMemoryManager::TLSSection209  allocateTLSSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,210                     StringRef SectionName) override;211 212  /// If non null, records subsequent Name -> SectionID mappings.213  void setSectionIDsMap(SectionIDMap *SecIDMap) {214    this->SecIDMap = SecIDMap;215  }216 217  void *getPointerToNamedFunction(const std::string &Name,218                                  bool AbortOnFailure = true) override {219    return nullptr;220  }221 222  bool finalizeMemory(std::string *ErrMsg) override { return false; }223 224  void addDummySymbol(const std::string &Name, uint64_t Addr) {225    DummyExterns[Name] = Addr;226  }227 228  JITSymbol findSymbol(const std::string &Name) override {229    auto I = DummyExterns.find(Name);230 231    if (I != DummyExterns.end())232      return JITSymbol(I->second, JITSymbolFlags::Exported);233 234    if (auto Sym = RTDyldMemoryManager::findSymbol(Name))235      return Sym;236    else if (auto Err = Sym.takeError())237      ExitOnErr(std::move(Err));238    else239      ExitOnErr(make_error<StringError>("Could not find definition for \"" +240                                            Name + "\"",241                                        inconvertibleErrorCode()));242    llvm_unreachable("Should have returned or exited by now");243  }244 245  void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,246                        size_t Size) override {}247  void deregisterEHFrames() override {}248 249  void preallocateSlab(uint64_t Size) {250    std::error_code EC;251    sys::MemoryBlock MB =252      sys::Memory::allocateMappedMemory(Size, nullptr,253                                        sys::Memory::MF_READ |254                                        sys::Memory::MF_WRITE,255                                        EC);256    if (!MB.base())257      report_fatal_error(Twine("Can't allocate enough memory: ") +258                         EC.message());259 260    PreallocSlab = MB;261    UsePreallocation = true;262    SlabSize = Size;263  }264 265  uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode,266                            StringRef SectionName, unsigned SectionID) {267    Size = alignTo(Size, Alignment);268    if (CurrentSlabOffset + Size > SlabSize)269      report_fatal_error("Can't allocate enough memory. Tune --preallocate");270 271    uintptr_t OldSlabOffset = CurrentSlabOffset;272    sys::MemoryBlock MB((void *)OldSlabOffset, Size);273    if (isCode)274      FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));275    else276      DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));277    CurrentSlabOffset += Size;278    return (uint8_t*)OldSlabOffset;279  }280 281private:282  std::map<std::string, uint64_t> DummyExterns;283  sys::MemoryBlock PreallocSlab;284  bool UsePreallocation = false;285  uintptr_t SlabSize = 0;286  uintptr_t CurrentSlabOffset = 0;287  SectionIDMap *SecIDMap = nullptr;288#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)289  unsigned UsedTLSStorage = 0;290#endif291};292 293uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,294                                                   unsigned Alignment,295                                                   unsigned SectionID,296                                                   StringRef SectionName) {297  if (PrintAllocationRequests)298    outs() << "allocateCodeSection(Size = " << Size << ", Alignment = "299           << Alignment << ", SectionName = " << SectionName << ")\n";300 301  if (SecIDMap)302    (*SecIDMap)[SectionName] = SectionID;303 304  if (UsePreallocation)305    return allocateFromSlab(Size, Alignment, true /* isCode */,306                            SectionName, SectionID);307 308  std::error_code EC;309  sys::MemoryBlock MB =310    sys::Memory::allocateMappedMemory(Size, nullptr,311                                      sys::Memory::MF_READ |312                                      sys::Memory::MF_WRITE,313                                      EC);314  if (!MB.base())315    report_fatal_error(Twine("MemoryManager allocation failed: ") +316                       EC.message());317  FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID));318  return (uint8_t*)MB.base();319}320 321uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,322                                                   unsigned Alignment,323                                                   unsigned SectionID,324                                                   StringRef SectionName,325                                                   bool IsReadOnly) {326  if (PrintAllocationRequests)327    outs() << "allocateDataSection(Size = " << Size << ", Alignment = "328           << Alignment << ", SectionName = " << SectionName << ")\n";329 330  if (SecIDMap)331    (*SecIDMap)[SectionName] = SectionID;332 333  if (UsePreallocation)334    return allocateFromSlab(Size, Alignment, false /* isCode */, SectionName,335                            SectionID);336 337  std::error_code EC;338  sys::MemoryBlock MB =339    sys::Memory::allocateMappedMemory(Size, nullptr,340                                      sys::Memory::MF_READ |341                                      sys::Memory::MF_WRITE,342                                      EC);343  if (!MB.base())344    report_fatal_error(Twine("MemoryManager allocation failed: ") +345                       EC.message());346  DataMemory.push_back(SectionInfo(SectionName, MB, SectionID));347  return (uint8_t*)MB.base();348}349 350// In case the execution needs TLS storage, we define a very small TLS memory351// area here that will be used in allocateTLSSection().352#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)353extern "C" {354alignas(16) __attribute__((visibility("hidden"), tls_model("initial-exec"),355                           used)) thread_local char LLVMRTDyldTLSSpace[16];356}357#endif358 359TrivialMemoryManager::TLSSection360TrivialMemoryManager::allocateTLSSection(uintptr_t Size, unsigned Alignment,361                                         unsigned SectionID,362                                         StringRef SectionName) {363#if defined(__x86_64__) && defined(__ELF__) && defined(__linux__)364  if (Size + UsedTLSStorage > sizeof(LLVMRTDyldTLSSpace)) {365    return {};366  }367 368  // Get the offset of the TLSSpace in the TLS block by using a tpoff369  // relocation here.370  int64_t TLSOffset;371  asm("leaq LLVMRTDyldTLSSpace@tpoff, %0" : "=r"(TLSOffset));372 373  TLSSection Section;374  // We use the storage directly as the initialization image. This means that375  // when a new thread is spawned after this allocation, it will not be376  // initialized correctly. This means, llvm-rtdyld will only support TLS in a377  // single thread.378  Section.InitializationImage =379      reinterpret_cast<uint8_t *>(LLVMRTDyldTLSSpace + UsedTLSStorage);380  Section.Offset = TLSOffset + UsedTLSStorage;381 382  UsedTLSStorage += Size;383 384  return Section;385#else386  return {};387#endif388}389 390static const char *ProgramName;391 392static void ErrorAndExit(const Twine &Msg) {393  errs() << ProgramName << ": error: " << Msg << "\n";394  exit(1);395}396 397static void loadDylibs() {398  for (const std::string &Dylib : Dylibs) {399    if (!sys::fs::is_regular_file(Dylib))400      report_fatal_error(Twine("Dylib not found: '") + Dylib + "'.");401    std::string ErrMsg;402    if (sys::DynamicLibrary::LoadLibraryPermanently(Dylib.c_str(), &ErrMsg))403      report_fatal_error(Twine("Error loading '") + Dylib + "': " + ErrMsg);404  }405}406 407/* *** */408 409static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {410  assert(LoadObjects || !UseDebugObj);411 412  // Load any dylibs requested on the command line.413  loadDylibs();414 415  // If we don't have any input files, read from stdin.416  if (!InputFileList.size())417    InputFileList.push_back("-");418  for (auto &File : InputFileList) {419    // Instantiate a dynamic linker.420    TrivialMemoryManager MemMgr;421    RuntimeDyld Dyld(MemMgr, MemMgr);422 423    // Load the input memory buffer.424 425    ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =426        MemoryBuffer::getFileOrSTDIN(File);427    if (std::error_code EC = InputBuffer.getError())428      ErrorAndExit("unable to read input: '" + EC.message() + "'");429 430    Expected<std::unique_ptr<ObjectFile>> MaybeObj(431      ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));432 433    if (!MaybeObj) {434      std::string Buf;435      raw_string_ostream OS(Buf);436      logAllUnhandledErrors(MaybeObj.takeError(), OS);437      OS.flush();438      ErrorAndExit("unable to create object file: '" + Buf + "'");439    }440 441    ObjectFile &Obj = **MaybeObj;442 443    OwningBinary<ObjectFile> DebugObj;444    std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;445    ObjectFile *SymbolObj = &Obj;446    if (LoadObjects) {447      // Load the object file448      LoadedObjInfo =449        Dyld.loadObject(Obj);450 451      if (Dyld.hasError())452        ErrorAndExit(Dyld.getErrorString());453 454      // Resolve all the relocations we can.455      Dyld.resolveRelocations();456 457      if (UseDebugObj) {458        DebugObj = LoadedObjInfo->getObjectForDebug(Obj);459        SymbolObj = DebugObj.getBinary();460        LoadedObjInfo.reset();461      }462    }463 464    std::unique_ptr<DIContext> Context = DWARFContext::create(465        *SymbolObj, DWARFContext::ProcessDebugRelocations::Process,466        LoadedObjInfo.get());467 468    std::vector<std::pair<SymbolRef, uint64_t>> SymAddr =469        object::computeSymbolSizes(*SymbolObj);470 471    // Use symbol info to iterate functions in the object.472    for (const auto &P : SymAddr) {473      object::SymbolRef Sym = P.first;474      Expected<SymbolRef::Type> TypeOrErr = Sym.getType();475      if (!TypeOrErr) {476        // TODO: Actually report errors helpfully.477        consumeError(TypeOrErr.takeError());478        continue;479      }480      SymbolRef::Type Type = *TypeOrErr;481      if (Type == object::SymbolRef::ST_Function) {482        Expected<StringRef> Name = Sym.getName();483        if (!Name) {484          // TODO: Actually report errors helpfully.485          consumeError(Name.takeError());486          continue;487        }488        Expected<uint64_t> AddrOrErr = Sym.getAddress();489        if (!AddrOrErr) {490          // TODO: Actually report errors helpfully.491          consumeError(AddrOrErr.takeError());492          continue;493        }494        uint64_t Addr = *AddrOrErr;495 496        object::SectionedAddress Address;497 498        uint64_t Size = P.second;499        // If we're not using the debug object, compute the address of the500        // symbol in memory (rather than that in the unrelocated object file)501        // and use that to query the DWARFContext.502        if (!UseDebugObj && LoadObjects) {503          auto SecOrErr = Sym.getSection();504          if (!SecOrErr) {505            // TODO: Actually report errors helpfully.506            consumeError(SecOrErr.takeError());507            continue;508          }509          object::section_iterator Sec = *SecOrErr;510          Address.SectionIndex = Sec->getIndex();511          uint64_t SectionLoadAddress =512            LoadedObjInfo->getSectionLoadAddress(*Sec);513          if (SectionLoadAddress != 0)514            Addr += SectionLoadAddress - Sec->getAddress();515        } else if (auto SecOrErr = Sym.getSection())516          Address.SectionIndex = SecOrErr.get()->getIndex();517 518        outs() << "Function: " << *Name << ", Size = " << Size519               << ", Addr = " << Addr << "\n";520 521        Address.Address = Addr;522        DILineInfoTable Lines =523            Context->getLineInfoForAddressRange(Address, Size);524        for (auto &D : Lines) {525          outs() << "  Line info @ " << D.first - Addr << ": "526                 << D.second.FileName << ", line:" << D.second.Line << "\n";527        }528      }529    }530  }531 532  return 0;533}534 535static void doPreallocation(TrivialMemoryManager &MemMgr) {536  // Allocate a slab of memory upfront, if required. This is used if537  // we want to test small code models.538  if (static_cast<intptr_t>(PreallocMemory) < 0)539    report_fatal_error("Pre-allocated bytes of memory must be a positive integer.");540 541  // FIXME: Limit the amount of memory that can be preallocated?542  if (PreallocMemory != 0)543    MemMgr.preallocateSlab(PreallocMemory);544}545 546static int executeInput() {547  // Load any dylibs requested on the command line.548  loadDylibs();549 550  // Instantiate a dynamic linker.551  TrivialMemoryManager MemMgr;552  doPreallocation(MemMgr);553  RuntimeDyld Dyld(MemMgr, MemMgr);554 555  // If we don't have any input files, read from stdin.556  if (!InputFileList.size())557    InputFileList.push_back("-");558  {559    TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);560    for (auto &File : InputFileList) {561      // Load the input memory buffer.562      ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =563          MemoryBuffer::getFileOrSTDIN(File);564      if (std::error_code EC = InputBuffer.getError())565        ErrorAndExit("unable to read input: '" + EC.message() + "'");566      Expected<std::unique_ptr<ObjectFile>> MaybeObj(567          ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));568 569      if (!MaybeObj) {570        std::string Buf;571        raw_string_ostream OS(Buf);572        logAllUnhandledErrors(MaybeObj.takeError(), OS);573        OS.flush();574        ErrorAndExit("unable to create object file: '" + Buf + "'");575      }576 577      ObjectFile &Obj = **MaybeObj;578 579      // Load the object file580      Dyld.loadObject(Obj);581      if (Dyld.hasError()) {582        ErrorAndExit(Dyld.getErrorString());583      }584    }585  }586 587  {588    TimeRegion TR(Timers ? &Timers->LinkTimer : nullptr);589    // Resove all the relocations we can.590    // FIXME: Error out if there are unresolved relocations.591    Dyld.resolveRelocations();592  }593 594  // Get the address of the entry point (_main by default).595  void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint);596  if (!MainAddress)597    ErrorAndExit("no definition for '" + EntryPoint + "'");598 599  // Invalidate the instruction cache for each loaded function.600  for (auto &FM : MemMgr.FunctionMemory) {601 602    auto &FM_MB = FM.MB;603 604    // Make sure the memory is executable.605    // setExecutable will call InvalidateInstructionCache.606    if (auto EC = sys::Memory::protectMappedMemory(FM_MB,607                                                   sys::Memory::MF_READ |608                                                   sys::Memory::MF_EXEC))609      ErrorAndExit("unable to mark function executable: '" + EC.message() +610                   "'");611  }612 613  // Dispatch to _main().614  errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";615 616  int (*Main)(int, const char**) =617    (int(*)(int,const char**)) uintptr_t(MainAddress);618  std::vector<const char *> Argv;619  // Use the name of the first input object module as argv[0] for the target.620  Argv.push_back(InputFileList[0].data());621  for (auto &Arg : InputArgv)622    Argv.push_back(Arg.data());623  Argv.push_back(nullptr);624  int Result = 0;625  {626    TimeRegion TR(Timers ? &Timers->RunTimer : nullptr);627    Result = Main(Argv.size() - 1, Argv.data());628  }629 630  return Result;631}632 633static int checkAllExpressions(RuntimeDyldChecker &Checker) {634  for (const auto& CheckerFileName : CheckFiles) {635    ErrorOr<std::unique_ptr<MemoryBuffer>> CheckerFileBuf =636        MemoryBuffer::getFileOrSTDIN(CheckerFileName);637    if (std::error_code EC = CheckerFileBuf.getError())638      ErrorAndExit("unable to read input '" + CheckerFileName + "': " +639                   EC.message());640 641    if (!Checker.checkAllRulesInBuffer("# rtdyld-check:",642                                       CheckerFileBuf.get().get()))643      ErrorAndExit("some checks in '" + CheckerFileName + "' failed");644  }645  return 0;646}647 648void applySpecificSectionMappings(RuntimeDyld &Dyld,649                                  const FileToSectionIDMap &FileToSecIDMap) {650 651  for (StringRef Mapping : SpecificSectionMappings) {652    size_t EqualsIdx = Mapping.find_first_of('=');653    std::string SectionIDStr = std::string(Mapping.substr(0, EqualsIdx));654    size_t ComaIdx = Mapping.find_first_of(',');655 656    if (ComaIdx == StringRef::npos)657      report_fatal_error("Invalid section specification '" + Mapping +658                         "'. Should be '<file name>,<section name>=<addr>'");659 660    std::string FileName = SectionIDStr.substr(0, ComaIdx);661    std::string SectionName = SectionIDStr.substr(ComaIdx + 1);662    unsigned SectionID =663      ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName));664 665    auto* OldAddr = Dyld.getSectionContent(SectionID).data();666    std::string NewAddrStr = std::string(Mapping.substr(EqualsIdx + 1));667    uint64_t NewAddr;668 669    if (StringRef(NewAddrStr).getAsInteger(0, NewAddr))670      report_fatal_error("Invalid section address in mapping '" + Mapping +671                         "'.");672 673    Dyld.mapSectionAddress(OldAddr, NewAddr);674  }675}676 677// Scatter sections in all directions!678// Remaps section addresses for -verify mode. The following command line options679// can be used to customize the layout of the memory within the phony target's680// address space:681// -target-addr-start <s> -- Specify where the phony target address range starts.682// -target-addr-end   <e> -- Specify where the phony target address range ends.683// -target-section-sep <d> -- Specify how big a gap should be left between the684//                            end of one section and the start of the next.685//                            Defaults to zero. Set to something big686//                            (e.g. 1 << 32) to stress-test stubs, GOTs, etc.687//688static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple,689                                    RuntimeDyld &Dyld,690                                    TrivialMemoryManager &MemMgr) {691 692  // Set up a work list (section addr/size pairs).693  typedef std::list<const TrivialMemoryManager::SectionInfo*> WorklistT;694  WorklistT Worklist;695 696  for (const auto& CodeSection : MemMgr.FunctionMemory)697    Worklist.push_back(&CodeSection);698  for (const auto& DataSection : MemMgr.DataMemory)699    Worklist.push_back(&DataSection);700 701  // Keep an "already allocated" mapping of section target addresses to sizes.702  // Sections whose address mappings aren't specified on the command line will703  // allocated around the explicitly mapped sections while maintaining the704  // minimum separation.705  std::map<uint64_t, uint64_t> AlreadyAllocated;706 707  // Move the previously applied mappings (whether explicitly specified on the708  // command line, or implicitly set by RuntimeDyld) into the already-allocated709  // map.710  for (WorklistT::iterator I = Worklist.begin(), E = Worklist.end();711       I != E;) {712    WorklistT::iterator Tmp = I;713    ++I;714 715    auto LoadAddr = Dyld.getSectionLoadAddress((*Tmp)->SectionID);716 717    if (LoadAddr != static_cast<uint64_t>(718          reinterpret_cast<uintptr_t>((*Tmp)->MB.base()))) {719      // A section will have a LoadAddr of 0 if it wasn't loaded for whatever720      // reason (e.g. zero byte COFF sections). Don't include those sections in721      // the allocation map.722      if (LoadAddr != 0)723        AlreadyAllocated[LoadAddr] = (*Tmp)->MB.allocatedSize();724      Worklist.erase(Tmp);725    }726  }727 728  // If the -target-addr-end option wasn't explicitly passed, then set it to a729  // sensible default based on the target triple.730  if (TargetAddrEnd.getNumOccurrences() == 0) {731    if (TargetTriple.isArch16Bit())732      TargetAddrEnd = (1ULL << 16) - 1;733    else if (TargetTriple.isArch32Bit())734      TargetAddrEnd = (1ULL << 32) - 1;735    // TargetAddrEnd already has a sensible default for 64-bit systems, so736    // there's nothing to do in the 64-bit case.737  }738 739  // Process any elements remaining in the worklist.740  while (!Worklist.empty()) {741    auto *CurEntry = Worklist.front();742    Worklist.pop_front();743 744    uint64_t NextSectionAddr = TargetAddrStart;745 746    for (const auto &Alloc : AlreadyAllocated)747      if (NextSectionAddr + CurEntry->MB.allocatedSize() + TargetSectionSep <=748          Alloc.first)749        break;750      else751        NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep;752 753    Dyld.mapSectionAddress(CurEntry->MB.base(), NextSectionAddr);754    AlreadyAllocated[NextSectionAddr] = CurEntry->MB.allocatedSize();755  }756 757  // Add dummy symbols to the memory manager.758  for (const auto &Mapping : DummySymbolMappings) {759    size_t EqualsIdx = Mapping.find_first_of('=');760 761    if (EqualsIdx == StringRef::npos)762      report_fatal_error(Twine("Invalid dummy symbol specification '") +763                         Mapping + "'. Should be '<symbol name>=<addr>'");764 765    std::string Symbol = Mapping.substr(0, EqualsIdx);766    std::string AddrStr = Mapping.substr(EqualsIdx + 1);767 768    uint64_t Addr;769    if (StringRef(AddrStr).getAsInteger(0, Addr))770      report_fatal_error(Twine("Invalid symbol mapping '") + Mapping + "'.");771 772    MemMgr.addDummySymbol(Symbol, Addr);773  }774}775 776// Load and link the objects specified on the command line, but do not execute777// anything. Instead, attach a RuntimeDyldChecker instance and call it to778// verify the correctness of the linked memory.779static int linkAndVerify() {780 781  // Check for missing triple.782  if (TripleName == "")783    ErrorAndExit("-triple required when running in -verify mode.");784 785  // Look up the target and build the disassembler.786  Triple TheTriple(Triple::normalize(TripleName));787  std::string ErrorStr;788  const Target *TheTarget =789    TargetRegistry::lookupTarget("", TheTriple, ErrorStr);790  if (!TheTarget)791    ErrorAndExit("Error accessing target '" + TripleName + "': " + ErrorStr);792 793  TripleName = TheTriple.getTriple();794 795  std::unique_ptr<MCSubtargetInfo> STI(796      TheTarget->createMCSubtargetInfo(TheTriple, MCPU, ""));797  if (!STI)798    ErrorAndExit("Unable to create subtarget info!");799 800  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));801  if (!MRI)802    ErrorAndExit("Unable to create target register info!");803 804  MCTargetOptions MCOptions;805  std::unique_ptr<MCAsmInfo> MAI(806      TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));807  if (!MAI)808    ErrorAndExit("Unable to create target asm info!");809 810  MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get());811 812  std::unique_ptr<MCDisassembler> Disassembler(813    TheTarget->createMCDisassembler(*STI, Ctx));814  if (!Disassembler)815    ErrorAndExit("Unable to create disassembler!");816 817  std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());818  if (!MII)819    ErrorAndExit("Unable to create target instruction info!");820 821  std::unique_ptr<MCInstPrinter> InstPrinter(822      TheTarget->createMCInstPrinter(TheTriple, 0, *MAI, *MII, *MRI));823 824  // Load any dylibs requested on the command line.825  loadDylibs();826 827  // Instantiate a dynamic linker.828  TrivialMemoryManager MemMgr;829  doPreallocation(MemMgr);830 831  struct StubID {832    unsigned SectionID;833    uint32_t Offset;834  };835  using StubInfos = StringMap<StubID>;836  using StubContainers = StringMap<StubInfos>;837 838  StubContainers StubMap;839  RuntimeDyld Dyld(MemMgr, MemMgr);840  Dyld.setProcessAllSections(true);841 842  Dyld.setNotifyStubEmitted([&StubMap](StringRef FilePath,843                                       StringRef SectionName,844                                       StringRef SymbolName, unsigned SectionID,845                                       uint32_t StubOffset) {846    std::string ContainerName =847        (sys::path::filename(FilePath) + "/" + SectionName).str();848    StubMap[ContainerName][SymbolName] = {SectionID, StubOffset};849  });850 851  auto GetSymbolInfo =852      [&Dyld, &MemMgr](853          StringRef Symbol) -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {854    RuntimeDyldChecker::MemoryRegionInfo SymInfo;855 856    // First get the target address.857    if (auto InternalSymbol = Dyld.getSymbol(Symbol))858      SymInfo.setTargetAddress(InternalSymbol.getAddress());859    else {860      // Symbol not found in RuntimeDyld. Fall back to external lookup.861#ifdef _MSC_VER862      using ExpectedLookupResult =863          MSVCPExpected<JITSymbolResolver::LookupResult>;864#else865      using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>;866#endif867 868      auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>();869      auto ResultF = ResultP->get_future();870 871      MemMgr.lookup(JITSymbolResolver::LookupSet({Symbol}),872                    [=](Expected<JITSymbolResolver::LookupResult> Result) {873                      ResultP->set_value(std::move(Result));874                    });875 876      auto Result = ResultF.get();877      if (!Result)878        return Result.takeError();879 880      auto I = Result->find(Symbol);881      assert(I != Result->end() &&882             "Expected symbol address if no error occurred");883      SymInfo.setTargetAddress(I->second.getAddress());884    }885 886    // Now find the symbol content if possible (otherwise leave content as a887    // default-constructed StringRef).888    if (auto *SymAddr = Dyld.getSymbolLocalAddress(Symbol)) {889      unsigned SectionID = Dyld.getSymbolSectionID(Symbol);890      if (SectionID != ~0U) {891        char *CSymAddr = static_cast<char *>(SymAddr);892        StringRef SecContent = Dyld.getSectionContent(SectionID);893        uint64_t SymSize = SecContent.size() - (CSymAddr - SecContent.data());894        SymInfo.setContent(ArrayRef<char>(CSymAddr, SymSize));895        SymInfo.setTargetFlags(896            Dyld.getSymbol(Symbol).getFlags().getTargetFlags());897      }898    }899    return SymInfo;900  };901 902  auto IsSymbolValid = [&Dyld, GetSymbolInfo](StringRef Symbol) {903    if (Dyld.getSymbol(Symbol))904      return true;905    auto SymInfo = GetSymbolInfo(Symbol);906    if (!SymInfo) {907      logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: ");908      return false;909    }910    return SymInfo->getTargetAddress() != 0;911  };912 913  FileToSectionIDMap FileToSecIDMap;914 915  auto GetSectionInfo = [&Dyld, &FileToSecIDMap](StringRef FileName,916                                                 StringRef SectionName)917      -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {918    auto SectionID = getSectionId(FileToSecIDMap, FileName, SectionName);919    if (!SectionID)920      return SectionID.takeError();921    RuntimeDyldChecker::MemoryRegionInfo SecInfo;922    SecInfo.setTargetAddress(Dyld.getSectionLoadAddress(*SectionID));923    StringRef SecContent = Dyld.getSectionContent(*SectionID);924    SecInfo.setContent(ArrayRef<char>(SecContent));925    return SecInfo;926  };927 928  auto GetStubInfo = [&Dyld, &StubMap](StringRef StubContainer,929                                       StringRef SymbolName,930                                       StringRef KindNameFilter)931      -> Expected<RuntimeDyldChecker::MemoryRegionInfo> {932    auto SMIt = StubMap.find(StubContainer);933    if (SMIt == StubMap.end())934      return make_error<StringError>("Stub container not found: " +935                                         StubContainer,936                                     inconvertibleErrorCode());937    auto It = SMIt->second.find(SymbolName);938    if (It == SMIt->second.end())939      return make_error<StringError>("Symbol name " + SymbolName +940                                         " in stub container " + StubContainer,941                                     inconvertibleErrorCode());942    auto &SI = It->second;943    RuntimeDyldChecker::MemoryRegionInfo StubMemInfo;944    StubMemInfo.setTargetAddress(Dyld.getSectionLoadAddress(SI.SectionID) +945                                 SI.Offset);946    StringRef SecContent =947        Dyld.getSectionContent(SI.SectionID).substr(SI.Offset);948    StubMemInfo.setContent(ArrayRef<char>(SecContent));949    return StubMemInfo;950  };951 952  auto GetGOTInfo = [&GetStubInfo](StringRef StubContainer,953                                   StringRef SymbolName) {954    return GetStubInfo(StubContainer, SymbolName, "");955  };956 957  // We will initialize this below once we have the first object file and can958  // know the endianness.959  std::unique_ptr<RuntimeDyldChecker> Checker;960 961  // If we don't have any input files, read from stdin.962  if (!InputFileList.size())963    InputFileList.push_back("-");964  for (auto &InputFile : InputFileList) {965    // Load the input memory buffer.966    ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =967        MemoryBuffer::getFileOrSTDIN(InputFile);968 969    if (std::error_code EC = InputBuffer.getError())970      ErrorAndExit("unable to read input: '" + EC.message() + "'");971 972    Expected<std::unique_ptr<ObjectFile>> MaybeObj(973      ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));974 975    if (!MaybeObj) {976      std::string Buf;977      raw_string_ostream OS(Buf);978      logAllUnhandledErrors(MaybeObj.takeError(), OS);979      OS.flush();980      ErrorAndExit("unable to create object file: '" + Buf + "'");981    }982 983    ObjectFile &Obj = **MaybeObj;984 985    if (!Checker)986      Checker = std::make_unique<RuntimeDyldChecker>(987          IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo,988          Obj.isLittleEndian() ? llvm::endianness::little989                               : llvm::endianness::big,990          TheTriple, MCPU, SubtargetFeatures(), dbgs());991 992    auto FileName = sys::path::filename(InputFile);993    MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);994 995    // Load the object file996    Dyld.loadObject(Obj);997    if (Dyld.hasError()) {998      ErrorAndExit(Dyld.getErrorString());999    }1000  }1001 1002  // Re-map the section addresses into the phony target address space and add1003  // dummy symbols.1004  applySpecificSectionMappings(Dyld, FileToSecIDMap);1005  remapSectionsAndSymbols(TheTriple, Dyld, MemMgr);1006 1007  // Resolve all the relocations we can.1008  Dyld.resolveRelocations();1009 1010  // Register EH frames.1011  Dyld.registerEHFrames();1012 1013  int ErrorCode = checkAllExpressions(*Checker);1014  if (Dyld.hasError())1015    ErrorAndExit("RTDyld reported an error applying relocations:\n  " +1016                 Dyld.getErrorString());1017 1018  return ErrorCode;1019}1020 1021int main(int argc, char **argv) {1022  InitLLVM X(argc, argv);1023  ProgramName = argv[0];1024 1025  llvm::InitializeAllTargetInfos();1026  llvm::InitializeAllTargetMCs();1027  llvm::InitializeAllDisassemblers();1028 1029  cl::HideUnrelatedOptions({&RTDyldCategory, &getColorCategory()});1030  cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");1031 1032  ExitOnErr.setBanner(std::string(argv[0]) + ": ");1033 1034  Timers = ShowTimes ? std::make_unique<RTDyldTimers>() : nullptr;1035 1036  int Result = 0;1037  switch (Action) {1038  case AC_Execute:1039    Result = executeInput();1040    break;1041  case AC_PrintDebugLineInfo:1042    Result =1043        printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ true);1044    break;1045  case AC_PrintLineInfo:1046    Result =1047        printLineInfoForInput(/* LoadObjects */ true, /* UseDebugObj */ false);1048    break;1049  case AC_PrintObjectLineInfo:1050    Result =1051        printLineInfoForInput(/* LoadObjects */ false, /* UseDebugObj */ false);1052    break;1053  case AC_Verify:1054    Result = linkAndVerify();1055    break;1056  }1057  return Result;1058}1059