From 941f247d30c447903107aa614ea46fb1e4019698 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Mon, 8 Apr 2019 21:50:48 +0000 Subject: [PATCH] [RuntimeDyld] Decouple RuntimeDyldChecker from RuntimeDyld. This will allow RuntimeDyldChecker (and rtdyld-check tests) to test a new JIT linker: JITLink (https://reviews.llvm.org/D58704). llvm-svn: 357947 --- .../llvm/ExecutionEngine/RuntimeDyld.h | 26 +- .../llvm/ExecutionEngine/RuntimeDyldChecker.h | 37 +- .../RuntimeDyld/RuntimeDyld.cpp | 86 +++-- .../RuntimeDyld/RuntimeDyldChecker.cpp | 319 ++++++------------ .../RuntimeDyld/RuntimeDyldCheckerImpl.h | 59 ++-- .../RuntimeDyld/RuntimeDyldELF.cpp | 3 - .../RuntimeDyld/RuntimeDyldImpl.h | 46 ++- llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp | 260 +++++++++++--- 8 files changed, 493 insertions(+), 343 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h b/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h index 2af9203c26a4..2d5420f194ad 100644 --- a/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -52,18 +52,20 @@ private: std::string ErrMsg; }; -class RuntimeDyldCheckerImpl; class RuntimeDyldImpl; class RuntimeDyld { - friend class RuntimeDyldCheckerImpl; - protected: // Change the address associated with a section when resolving relocations. // Any relocations already associated with the symbol will be re-resolved. void reassignSectionAddress(unsigned SectionID, uint64_t Addr); public: + + using NotifyStubEmittedFunction = + std::function; + /// Information about the loaded object. class LoadedObjectInfo : public llvm::LoadedObjectInfo { friend class RuntimeDyldImpl; @@ -184,6 +186,9 @@ public: /// and resolve relocatons based on where they put it). void *getSymbolLocalAddress(StringRef Name) const; + /// Get the section ID for the section containing the given symbol. + unsigned getSymbolSectionID(StringRef Name) const; + /// Get the target address and flags for the named symbol. /// This address is the one used for relocation. JITEvaluatedSymbol getSymbol(StringRef Name) const; @@ -204,6 +209,19 @@ public: /// This is the address which will be used for relocation resolution. void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress); + /// Returns the section's working memory. + StringRef getSectionContent(unsigned SectionID) const; + + /// If the section was loaded, return the section's load address, + /// otherwise return None. + uint64_t getSectionLoadAddress(unsigned SectionID) const; + + /// Set the NotifyStubEmitted callback. This is used for debugging + /// purposes. A callback is made for each stub that is generated. + void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) { + this->NotifyStubEmitted = std::move(NotifyStubEmitted); + } + /// Register any EH frame sections that have been loaded but not previously /// registered with the memory manager. Note, RuntimeDyld is responsible /// for identifying the EH frame and calling the memory manager with the @@ -265,7 +283,7 @@ private: MemoryManager &MemMgr; JITSymbolResolver &Resolver; bool ProcessAllSections; - RuntimeDyldCheckerImpl *Checker; + NotifyStubEmittedFunction NotifyStubEmitted; }; // Asynchronous JIT link for ORC. diff --git a/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h index ee925c219065..57193fb45c87 100644 --- a/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h +++ b/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h @@ -9,7 +9,10 @@ #ifndef LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H #define LLVM_EXECUTIONENGINE_RUNTIMEDYLDCHECKER_H +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/Support/Endian.h" #include #include @@ -69,16 +72,34 @@ class raw_ostream; /// class RuntimeDyldChecker { public: - RuntimeDyldChecker(RuntimeDyld &RTDyld, MCDisassembler *Disassembler, + + using IsSymbolValidFunction = std::function; + using GetSymbolAddressFunction = + std::function(StringRef Symbol)>; + using GetSymbolContentFunction = + std::function(StringRef Symbol)>; + using GetSectionLoadAddressFunction = + std::function(StringRef FileName, + StringRef SectionName)>; + using GetSectionContentFunction = + std::function(StringRef FileName, + StringRef SectionName)>; + using GetStubOffsetInSectionFunction = + std::function(StringRef FileName, + StringRef SectionName, + StringRef SymbolName)>; + + RuntimeDyldChecker(IsSymbolValidFunction IsSymbolValid, + GetSymbolAddressFunction GetSymbolAddress, + GetSymbolContentFunction GetSymbolContent, + GetSectionLoadAddressFunction GetSectionLoadAddresss, + GetSectionContentFunction GetSectionContent, + GetStubOffsetInSectionFunction GetStubOffsetInSection, + support::endianness Endianness, + MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, raw_ostream &ErrStream); ~RuntimeDyldChecker(); - // Get the associated RTDyld instance. - RuntimeDyld& getRTDyld(); - - // Get the associated RTDyld instance. - const RuntimeDyld& getRTDyld() const; - /// Check a single expression against the attached RuntimeDyld /// instance. bool check(StringRef CheckExpr) const; @@ -99,7 +120,7 @@ public: bool LocalAddress); /// If there is a section at the given local address, return its load - /// address, otherwise return none. + /// address, otherwise return none. Optional getSectionLoadAddress(void *LocalAddress) const; private: diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 589cdcbcb0d1..dee8ecda13ad 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -12,7 +12,6 @@ #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "RuntimeDyldCOFF.h" -#include "RuntimeDyldCheckerImpl.h" #include "RuntimeDyldELF.h" #include "RuntimeDyldImpl.h" #include "RuntimeDyldMachO.h" @@ -375,10 +374,34 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) { else return IOrErr.takeError(); - // If there is an attached checker, notify it about the stubs for this - // section so that they can be verified. - if (Checker) - Checker->registerStubMap(Obj.getFileName(), SectionID, Stubs); + // If there is a NotifyStubEmitted callback set, call it to register any + // stubs created for this section. + if (NotifyStubEmitted) { + StringRef FileName = Obj.getFileName(); + StringRef SectionName = Sections[SectionID].getName(); + for (auto &KV : Stubs) { + + auto &VR = KV.first; + uint64_t StubAddr = KV.second; + + // If this is a named stub, just call NotifyStubEmitted. + if (VR.SymbolName) { + NotifyStubEmitted(FileName, SectionName, VR.SymbolName, StubAddr); + continue; + } + + // Otherwise we will have to try a reverse lookup on the globla symbol table. + for (auto &GSTMapEntry : GlobalSymbolTable) { + StringRef SymbolName = GSTMapEntry.first(); + auto &GSTEntry = GSTMapEntry.second; + if (GSTEntry.getSectionID() == VR.SectionID && + GSTEntry.getOffset() == VR.Offset) { + NotifyStubEmitted(FileName, SectionName, SymbolName, StubAddr); + break; + } + } + } + } } // Process remaining sections @@ -721,9 +744,6 @@ Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, Addr += Size; } - if (Checker) - Checker->registerSection(Obj.getFileName(), SectionID); - return Error::success(); } @@ -840,9 +860,6 @@ RuntimeDyldImpl::emitSection(const ObjectFile &Obj, if (!IsRequired) Sections.back().setLoadAddress(0); - if (Checker) - Checker->registerSection(Obj.getFileName(), SectionID); - return SectionID; } @@ -1225,42 +1242,43 @@ RuntimeDyld::RuntimeDyld(RuntimeDyld::MemoryManager &MemMgr, // permissions are applied. Dyld = nullptr; ProcessAllSections = false; - Checker = nullptr; } RuntimeDyld::~RuntimeDyld() {} static std::unique_ptr -createRuntimeDyldCOFF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver, bool ProcessAllSections, - RuntimeDyldCheckerImpl *Checker) { +createRuntimeDyldCOFF( + Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver, bool ProcessAllSections, + RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { std::unique_ptr Dyld = RuntimeDyldCOFF::create(Arch, MM, Resolver); Dyld->setProcessAllSections(ProcessAllSections); - Dyld->setRuntimeDyldChecker(Checker); + Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); return Dyld; } static std::unique_ptr createRuntimeDyldELF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, JITSymbolResolver &Resolver, bool ProcessAllSections, - RuntimeDyldCheckerImpl *Checker) { + RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { std::unique_ptr Dyld = RuntimeDyldELF::create(Arch, MM, Resolver); Dyld->setProcessAllSections(ProcessAllSections); - Dyld->setRuntimeDyldChecker(Checker); + Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); return Dyld; } static std::unique_ptr -createRuntimeDyldMachO(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver, - bool ProcessAllSections, - RuntimeDyldCheckerImpl *Checker) { +createRuntimeDyldMachO( + Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver, + bool ProcessAllSections, + RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { std::unique_ptr Dyld = RuntimeDyldMachO::create(Arch, MM, Resolver); Dyld->setProcessAllSections(ProcessAllSections); - Dyld->setRuntimeDyldChecker(Checker); + Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); return Dyld; } @@ -1270,15 +1288,16 @@ RuntimeDyld::loadObject(const ObjectFile &Obj) { if (Obj.isELF()) Dyld = createRuntimeDyldELF(static_cast(Obj.getArch()), - MemMgr, Resolver, ProcessAllSections, Checker); + MemMgr, Resolver, ProcessAllSections, + std::move(NotifyStubEmitted)); else if (Obj.isMachO()) Dyld = createRuntimeDyldMachO( static_cast(Obj.getArch()), MemMgr, Resolver, - ProcessAllSections, Checker); + ProcessAllSections, std::move(NotifyStubEmitted)); else if (Obj.isCOFF()) Dyld = createRuntimeDyldCOFF( static_cast(Obj.getArch()), MemMgr, Resolver, - ProcessAllSections, Checker); + ProcessAllSections, std::move(NotifyStubEmitted)); else report_fatal_error("Incompatible object format!"); } @@ -1297,6 +1316,11 @@ void *RuntimeDyld::getSymbolLocalAddress(StringRef Name) const { return Dyld->getSymbolLocalAddress(Name); } +unsigned RuntimeDyld::getSymbolSectionID(StringRef Name) const { + assert(Dyld && "No RuntimeDyld instance attached"); + return Dyld->getSymbolSectionID(Name); +} + JITEvaluatedSymbol RuntimeDyld::getSymbol(StringRef Name) const { if (!Dyld) return nullptr; @@ -1335,6 +1359,16 @@ void RuntimeDyld::finalizeWithMemoryManagerLocking() { } } +StringRef RuntimeDyld::getSectionContent(unsigned SectionID) const { + assert(Dyld && "No Dyld instance attached"); + return Dyld->getSectionContent(SectionID); +} + +uint64_t RuntimeDyld::getSectionLoadAddress(unsigned SectionID) const { + assert(Dyld && "No Dyld instance attached"); + return Dyld->getSectionLoadAddress(SectionID); +} + void RuntimeDyld::registerEHFrames() { if (Dyld) Dyld->registerEHFrames(); diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index 28c8a69939eb..8ec6207ee708 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -8,15 +8,14 @@ #include "llvm/ExecutionEngine/RuntimeDyldChecker.h" #include "RuntimeDyldCheckerImpl.h" -#include "RuntimeDyldImpl.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCInst.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/MSVCErrorWorkarounds.h" #include "llvm/Support/Path.h" #include -#include #include #include @@ -665,25 +664,36 @@ private: bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { MCDisassembler *Dis = Checker.Disassembler; - StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); - ArrayRef SectionBytes(SectionMem.bytes_begin(), SectionMem.size()); + StringRef SymbolMem = Checker.getSymbolContent(Symbol); + ArrayRef SymbolBytes(SymbolMem.bytes_begin(), SymbolMem.size()); MCDisassembler::DecodeStatus S = - Dis->getInstruction(Inst, Size, SectionBytes, 0, nulls(), nulls()); + Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls(), nulls()); return (S == MCDisassembler::Success); } }; } -RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, - MCDisassembler *Disassembler, - MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) - : RTDyld(RTDyld), Disassembler(Disassembler), InstPrinter(InstPrinter), - ErrStream(ErrStream) { - RTDyld.Checker = this; -} +RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl( + IsSymbolValidFunction IsSymbolValid, + GetSymbolAddressFunction GetSymbolAddress, + GetSymbolContentFunction GetSymbolContent, + GetSectionLoadAddressFunction GetSectionLoadAddress, + GetSectionContentFunction GetSectionContent, + GetStubOffsetInSectionFunction GetStubOffsetInSection, + support::endianness Endianness, + MCDisassembler *Disassembler, + MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : IsSymbolValid(std::move(IsSymbolValid)), + GetSymbolAddress(std::move(GetSymbolAddress)), + GetSymbolContent(std::move(GetSymbolContent)), + GetSectionLoadAddress(std::move(GetSectionLoadAddress)), + GetSectionContent(std::move(GetSectionContent)), + GetStubOffsetInSection(std::move(GetStubOffsetInSection)), + Endianness(Endianness), Disassembler(Disassembler), + InstPrinter(InstPrinter), ErrStream(ErrStream) {} bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { CheckExpr = CheckExpr.trim(); @@ -728,243 +738,133 @@ bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, return DidAllTestsPass && (NumRules != 0); } -Expected RuntimeDyldCheckerImpl::lookup( - const JITSymbolResolver::LookupSet &Symbols) const { - -#ifdef _MSC_VER - using ExpectedLookupResult = MSVCPExpected; -#else - using ExpectedLookupResult = Expected; -#endif - - auto ResultP = std::make_shared>(); - auto ResultF = ResultP->get_future(); - - getRTDyld().Resolver.lookup( - Symbols, [=](Expected Result) { - ResultP->set_value(std::move(Result)); - }); - return ResultF.get(); -} - bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { - if (getRTDyld().getSymbol(Symbol)) - return true; - auto Result = lookup({Symbol}); - - if (!Result) { - logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); - return false; - } - - assert(Result->count(Symbol) && "Missing symbol result"); - return true; + return IsSymbolValid(Symbol); } uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { - return static_cast( - reinterpret_cast(getRTDyld().getSymbolLocalAddress(Symbol))); + auto Contents = GetSymbolContent(Symbol); + if (!Contents) { + logAllUnhandledErrors(Contents.takeError(), errs(), "RTDyldChecker: "); + return 0; + } + return static_cast(reinterpret_cast(Contents->data())); } uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { - if (auto InternalSymbol = getRTDyld().getSymbol(Symbol)) - return InternalSymbol.getAddress(); - - auto Result = lookup({Symbol}); - if (!Result) { - logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); + auto Addr = GetSymbolAddress(Symbol); + if (!Addr) { + logAllUnhandledErrors(Addr.takeError(), errs(), "RTDyldChecker: "); return 0; } - auto I = Result->find(Symbol); - assert(I != Result->end() && "Missing symbol result"); - return I->second.getAddress(); + + return *Addr; } uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, unsigned Size) const { uintptr_t PtrSizedAddr = static_cast(SrcAddr); assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); - uint8_t *Src = reinterpret_cast(PtrSizedAddr); - return getRTDyld().readBytesUnaligned(Src, Size); + void *Ptr = reinterpret_cast(PtrSizedAddr); + + switch (Size) { + case 1: + return support::endian::read(Ptr, Endianness); + case 2: + return support::endian::read(Ptr, Endianness); + case 4: + return support::endian::read(Ptr, Endianness); + case 8: + return support::endian::read(Ptr, Endianness); + } + llvm_unreachable("Unsupported read size"); } - -std::pair -RuntimeDyldCheckerImpl::findSectionAddrInfo(StringRef FileName, - StringRef SectionName) const { - - auto SectionMapItr = Stubs.find(FileName); - if (SectionMapItr == Stubs.end()) { - std::string ErrorMsg = "File '"; - ErrorMsg += FileName; - ErrorMsg += "' not found. "; - if (Stubs.empty()) - ErrorMsg += "No stubs registered."; - else { - ErrorMsg += "Available files are:"; - for (const auto& StubEntry : Stubs) { - ErrorMsg += " '"; - ErrorMsg += StubEntry.first; - ErrorMsg += "'"; - } - } - ErrorMsg += "\n"; - return std::make_pair(nullptr, ErrorMsg); +StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const { + auto Content = GetSymbolContent(Symbol); + if (!Content) { + logAllUnhandledErrors(Content.takeError(), errs(), "RTDyldChecker: "); + return StringRef(); } - - auto SectionInfoItr = SectionMapItr->second.find(SectionName); - if (SectionInfoItr == SectionMapItr->second.end()) - return std::make_pair(nullptr, - ("Section '" + SectionName + "' not found in file '" + - FileName + "'\n").str()); - - return std::make_pair(&SectionInfoItr->second, std::string("")); + return *Content; } std::pair RuntimeDyldCheckerImpl::getSectionAddr( StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { - const SectionAddressInfo *SectionInfo = nullptr; - { - std::string ErrorMsg; - std::tie(SectionInfo, ErrorMsg) = - findSectionAddrInfo(FileName, SectionName); - if (ErrorMsg != "") - return std::make_pair(0, ErrorMsg); + uint64_t Addr = 0; + std::string ErrMsg; + + // If this address is being looked up in "load" mode, return the content + // pointer. + if (IsInsideLoad) { + if (auto Content = GetSectionContent(FileName, SectionName)) + Addr = pointerToJITTargetAddress(Content->data()); + else { + raw_string_ostream ErrMsgStream(ErrMsg); + logAllUnhandledErrors(Content.takeError(), ErrMsgStream, + "RTDyldChecker: "); + } + return std::make_pair(Addr, std::move(ErrMsg)); } - unsigned SectionID = SectionInfo->SectionID; - uint64_t Addr; - if (IsInsideLoad) - Addr = static_cast(reinterpret_cast( - getRTDyld().Sections[SectionID].getAddress())); + // ... otherwise return the target pointer. + if (auto LoadAddr = GetSectionLoadAddress(FileName, SectionName)) + Addr = *LoadAddr; else - Addr = getRTDyld().Sections[SectionID].getLoadAddress(); + return std::make_pair(Addr, ("Section (" + FileName + ", " + + SectionName + ") does not exist").str()); - return std::make_pair(Addr, std::string("")); + return std::make_pair(Addr, std::move(ErrMsg)); } std::pair RuntimeDyldCheckerImpl::getStubAddrFor( StringRef FileName, StringRef SectionName, StringRef SymbolName, bool IsInsideLoad) const { - const SectionAddressInfo *SectionInfo = nullptr; - { - std::string ErrorMsg; - std::tie(SectionInfo, ErrorMsg) = - findSectionAddrInfo(FileName, SectionName); - if (ErrorMsg != "") - return std::make_pair(0, ErrorMsg); - } + auto SectionAddr = getSectionAddr(FileName, SectionName, IsInsideLoad); - unsigned SectionID = SectionInfo->SectionID; - const StubOffsetsMap &SymbolStubs = SectionInfo->StubOffsets; - auto StubOffsetItr = SymbolStubs.find(SymbolName); - if (StubOffsetItr == SymbolStubs.end()) - return std::make_pair(0, - ("Stub for symbol '" + SymbolName + "' not found. " - "If '" + SymbolName + "' is an internal symbol this " - "may indicate that the stub target offset is being " - "computed incorrectly.\n").str()); + if (!SectionAddr.second.empty()) + return SectionAddr; - uint64_t StubOffset = StubOffsetItr->second; + auto StubOffset = GetStubOffsetInSection(FileName, SectionName, SymbolName); - uint64_t Addr; - if (IsInsideLoad) { - uintptr_t SectionBase = reinterpret_cast( - getRTDyld().Sections[SectionID].getAddress()); - Addr = static_cast(SectionBase) + StubOffset; - } else { - uint64_t SectionBase = getRTDyld().Sections[SectionID].getLoadAddress(); - Addr = SectionBase + StubOffset; - } - - return std::make_pair(Addr, std::string("")); -} - -StringRef -RuntimeDyldCheckerImpl::getSubsectionStartingAt(StringRef Name) const { - RTDyldSymbolTable::const_iterator pos = - getRTDyld().GlobalSymbolTable.find(Name); - if (pos == getRTDyld().GlobalSymbolTable.end()) - return StringRef(); - const auto &SymInfo = pos->second; - uint8_t *SectionAddr = getRTDyld().getSectionAddress(SymInfo.getSectionID()); - return StringRef(reinterpret_cast(SectionAddr) + - SymInfo.getOffset(), - getRTDyld().Sections[SymInfo.getSectionID()].getSize() - - SymInfo.getOffset()); -} - -Optional -RuntimeDyldCheckerImpl::getSectionLoadAddress(void *LocalAddress) const { - for (auto &S : getRTDyld().Sections) { - if (S.getAddress() == LocalAddress) - return S.getLoadAddress(); - } - return Optional(); -} - -void RuntimeDyldCheckerImpl::registerSection( - StringRef FilePath, unsigned SectionID) { - StringRef FileName = sys::path::filename(FilePath); - const SectionEntry &Section = getRTDyld().Sections[SectionID]; - StringRef SectionName = Section.getName(); - - Stubs[FileName][SectionName].SectionID = SectionID; -} - -void RuntimeDyldCheckerImpl::registerStubMap( - StringRef FilePath, unsigned SectionID, - const RuntimeDyldImpl::StubMap &RTDyldStubs) { - StringRef FileName = sys::path::filename(FilePath); - const SectionEntry &Section = getRTDyld().Sections[SectionID]; - StringRef SectionName = Section.getName(); - - Stubs[FileName][SectionName].SectionID = SectionID; - - for (auto &StubMapEntry : RTDyldStubs) { - std::string SymbolName = ""; - - if (StubMapEntry.first.SymbolName) - SymbolName = StubMapEntry.first.SymbolName; - else { - // If this is a (Section, Offset) pair, do a reverse lookup in the - // global symbol table to find the name. - for (auto &GSTEntry : getRTDyld().GlobalSymbolTable) { - const auto &SymInfo = GSTEntry.second; - if (SymInfo.getSectionID() == StubMapEntry.first.SectionID && - SymInfo.getOffset() == - static_cast(StubMapEntry.first.Offset)) { - SymbolName = GSTEntry.first(); - break; - } - } + if (!StubOffset) { + std::string ErrMsg; + { + raw_string_ostream ErrMsgStream(ErrMsg); + logAllUnhandledErrors(StubOffset.takeError(), ErrMsgStream, + "RTDyldChecker: "); } - - if (SymbolName != "") - Stubs[FileName][SectionName].StubOffsets[SymbolName] = - StubMapEntry.second; + return std::make_pair((uint64_t)0, std::move(ErrMsg)); } + + return std::make_pair(SectionAddr.first + *StubOffset, ""); } -RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld, - MCDisassembler *Disassembler, - MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) - : Impl(make_unique(RTDyld, Disassembler, - InstPrinter, ErrStream)) {} +RuntimeDyldChecker::RuntimeDyldChecker( + IsSymbolValidFunction IsSymbolValid, + GetSymbolAddressFunction GetSymbolAddress, + GetSymbolContentFunction GetSymbolContent, + GetSectionLoadAddressFunction GetSectionLoadAddress, + GetSectionContentFunction GetSectionContent, + GetStubOffsetInSectionFunction GetStubOffsetInSection, + support::endianness Endianness, + MCDisassembler *Disassembler, + MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : Impl(make_unique( + std::move(IsSymbolValid), + std::move(GetSymbolAddress), + std::move(GetSymbolContent), + std::move(GetSectionLoadAddress), + std::move(GetSectionContent), + std::move(GetStubOffsetInSection), + Endianness, Disassembler, + InstPrinter, ErrStream)) {} RuntimeDyldChecker::~RuntimeDyldChecker() {} -RuntimeDyld& RuntimeDyldChecker::getRTDyld() { - return Impl->RTDyld; -} - -const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const { - return Impl->RTDyld; -} - bool RuntimeDyldChecker::check(StringRef CheckExpr) const { return Impl->check(CheckExpr); } @@ -979,8 +879,3 @@ RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, bool LocalAddress) { return Impl->getSectionAddr(FileName, SectionName, LocalAddress); } - -Optional -RuntimeDyldChecker::getSectionLoadAddress(void *LocalAddress) const { - return Impl->getSectionLoadAddress(LocalAddress); -} diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h index 988fac287197..0debd29cfd3c 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h @@ -15,14 +15,35 @@ namespace llvm { class RuntimeDyldCheckerImpl { friend class RuntimeDyldChecker; - friend class RuntimeDyldImpl; friend class RuntimeDyldCheckerExprEval; - friend class RuntimeDyldELF; + + using IsSymbolValidFunction = + RuntimeDyldChecker::IsSymbolValidFunction; + using GetSymbolAddressFunction = + RuntimeDyldChecker::GetSymbolAddressFunction; + using GetSymbolContentFunction = + RuntimeDyldChecker::GetSymbolContentFunction; + + using GetSectionLoadAddressFunction = + RuntimeDyldChecker::GetSectionLoadAddressFunction; + using GetSectionContentFunction = + RuntimeDyldChecker::GetSectionContentFunction; + + using GetStubOffsetInSectionFunction = + RuntimeDyldChecker::GetStubOffsetInSectionFunction; public: - RuntimeDyldCheckerImpl(RuntimeDyld &RTDyld, MCDisassembler *Disassembler, - MCInstPrinter *InstPrinter, - llvm::raw_ostream &ErrStream); + RuntimeDyldCheckerImpl( + IsSymbolValidFunction IsSymbolValid, + GetSymbolAddressFunction GetSymbolAddress, + GetSymbolContentFunction GetSymbolContent, + GetSectionLoadAddressFunction GetSectionLoadAddress, + GetSectionContentFunction GetSectionContent, + GetStubOffsetInSectionFunction GetStubOffsetInSection, + support::endianness Endianness, + MCDisassembler *Disassembler, + MCInstPrinter *InstPrinter, + llvm::raw_ostream &ErrStream); bool check(StringRef CheckExpr) const; bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const; @@ -30,15 +51,6 @@ public: private: // StubMap typedefs. - typedef std::map StubOffsetsMap; - struct SectionAddressInfo { - uint64_t SectionID; - StubOffsetsMap StubOffsets; - }; - typedef std::map SectionMap; - typedef std::map StubMap; - - RuntimeDyldImpl &getRTDyld() const { return *RTDyld.Dyld; } Expected lookup(const JITSymbolResolver::LookupSet &Symbols) const; @@ -48,9 +60,7 @@ private: uint64_t getSymbolRemoteAddr(StringRef Symbol) const; uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const; - std::pair findSectionAddrInfo( - StringRef FileName, - StringRef SectionName) const; + StringRef getSymbolContent(StringRef Symbol) const; std::pair getSectionAddr(StringRef FileName, StringRef SectionName, @@ -60,20 +70,19 @@ private: StringRef SectionName, StringRef Symbol, bool IsInsideLoad) const; - StringRef getSubsectionStartingAt(StringRef Name) const; Optional getSectionLoadAddress(void *LocalAddr) const; - void registerSection(StringRef FilePath, unsigned SectionID); - void registerStubMap(StringRef FilePath, unsigned SectionID, - const RuntimeDyldImpl::StubMap &RTDyldStubs); - - RuntimeDyld &RTDyld; + IsSymbolValidFunction IsSymbolValid; + GetSymbolAddressFunction GetSymbolAddress; + GetSymbolContentFunction GetSymbolContent; + GetSectionLoadAddressFunction GetSectionLoadAddress; + GetSectionContentFunction GetSectionContent; + GetStubOffsetInSectionFunction GetStubOffsetInSection; + support::endianness Endianness; MCDisassembler *Disassembler; MCInstPrinter *InstPrinter; llvm::raw_ostream &ErrStream; - - StubMap Stubs; }; } diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index f00c6d16b079..60041a45e2b8 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -1856,9 +1856,6 @@ Error RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj, Sections[GOTSectionID] = SectionEntry(".got", Addr, TotalSize, TotalSize, 0); - if (Checker) - Checker->registerSection(Obj.getFileName(), GOTSectionID); - // For now, initialize all GOT entries to zero. We'll fill them in as // needed when GOT-based relocations are applied. memset(Addr, 0, TotalSize); diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index a4f1c55ca394..615a7280a3ab 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -240,7 +240,6 @@ typedef StringMap RTDyldSymbolTable; class RuntimeDyldImpl { friend class RuntimeDyld::LoadedObjectInfo; - friend class RuntimeDyldCheckerImpl; protected: static const unsigned AbsoluteSymbolSection = ~0U; @@ -250,9 +249,6 @@ protected: // The symbol resolver to use for external symbols. JITSymbolResolver &Resolver; - // Attached RuntimeDyldChecker instance. Null if no instance attached. - RuntimeDyldCheckerImpl *Checker; - // A list of all sections emitted by the dynamic linker. These sections are // referenced in the code by means of their index in this list - SectionID. typedef SmallVector SectionList; @@ -312,20 +308,16 @@ protected: // the end of the list while the list is being processed. sys::Mutex lock; + using NotifyStubEmittedFunction = + RuntimeDyld::NotifyStubEmittedFunction; + NotifyStubEmittedFunction NotifyStubEmitted; + virtual unsigned getMaxStubSize() = 0; virtual unsigned getStubAlignment() = 0; bool HasError; std::string ErrorStr; - uint64_t getSectionLoadAddress(unsigned SectionID) const { - return Sections[SectionID].getLoadAddress(); - } - - uint8_t *getSectionAddress(unsigned SectionID) const { - return Sections[SectionID].getAddress(); - } - void writeInt16BE(uint8_t *Addr, uint16_t Value) { if (IsTargetLittleEndian) sys::swapByteOrder(Value); @@ -471,7 +463,7 @@ protected: public: RuntimeDyldImpl(RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver) - : MemMgr(MemMgr), Resolver(Resolver), Checker(nullptr), + : MemMgr(MemMgr), Resolver(Resolver), ProcessAllSections(false), HasError(false) { } @@ -481,13 +473,22 @@ public: this->ProcessAllSections = ProcessAllSections; } - void setRuntimeDyldChecker(RuntimeDyldCheckerImpl *Checker) { - this->Checker = Checker; - } - virtual std::unique_ptr loadObject(const object::ObjectFile &Obj) = 0; + uint64_t getSectionLoadAddress(unsigned SectionID) const { + return Sections[SectionID].getLoadAddress(); + } + + uint8_t *getSectionAddress(unsigned SectionID) const { + return Sections[SectionID].getAddress(); + } + + StringRef getSectionContent(unsigned SectionID) const { + return StringRef(reinterpret_cast(Sections[SectionID].getAddress()), + Sections[SectionID].getSize()); + } + uint8_t* getSymbolLocalAddress(StringRef Name) const { // FIXME: Just look up as a function for now. Overly simple of course. // Work in progress. @@ -501,6 +502,13 @@ public: return getSectionAddress(SymInfo.getSectionID()) + SymInfo.getOffset(); } + unsigned getSymbolSectionID(StringRef Name) const { + auto GSTItr = GlobalSymbolTable.find(Name); + if (GSTItr == GlobalSymbolTable.end()) + return ~0U; + return GSTItr->second.getSectionID(); + } + JITEvaluatedSymbol getSymbol(StringRef Name) const { // FIXME: Just look up as a function for now. Overly simple of course. // Work in progress. @@ -559,6 +567,10 @@ public: virtual bool isCompatibleFile(const ObjectFile &Obj) const = 0; + void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) { + this->NotifyStubEmitted = std::move(NotifyStubEmitted); + } + virtual void registerEHFrames(); void deregisterEHFrames(); diff --git a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp index 69d70e948081..5a5d035d27dd 100644 --- a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -29,9 +29,12 @@ #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" + +#include #include using namespace llvm; @@ -137,14 +140,50 @@ PrintAllocationRequests("print-alloc-requests", "manager by RuntimeDyld"), cl::Hidden); +ExitOnError ExitOnErr; + /* *** */ +using SectionIDMap = StringMap; +using FileToSectionIDMap = StringMap; + +void dumpFileToSectionIDMap(const FileToSectionIDMap &FileToSecIDMap) { + for (const auto &KV : FileToSecIDMap) { + llvm::dbgs() << "In " << KV.first() << "\n"; + for (auto &KV2 : KV.second) + llvm::dbgs() << " \"" << KV2.first() << "\" -> " << KV2.second << "\n"; + } +} + +Expected getSectionId(const FileToSectionIDMap &FileToSecIDMap, + StringRef FileName, StringRef SectionName) { + auto I = FileToSecIDMap.find(FileName); + if (I == FileToSecIDMap.end()) + return make_error("No file named " + FileName, + inconvertibleErrorCode()); + auto &SectionIDs = I->second; + auto J = SectionIDs.find(SectionName); + if (J == SectionIDs.end()) + return make_error("No section named \"" + SectionName + + "\" in file " + FileName, + inconvertibleErrorCode()); + return J->second; +} + // A trivial memory manager that doesn't do anything fancy, just uses the // support library allocation routines directly. class TrivialMemoryManager : public RTDyldMemoryManager { public: - SmallVector FunctionMemory; - SmallVector DataMemory; + struct SectionInfo { + SectionInfo(StringRef Name, sys::MemoryBlock MB, unsigned SectionID) + : Name(Name), MB(std::move(MB)), SectionID(SectionID) {} + std::string Name; + sys::MemoryBlock MB; + unsigned SectionID = ~0U; + }; + + SmallVector FunctionMemory; + SmallVector DataMemory; uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, @@ -153,6 +192,11 @@ public: unsigned SectionID, StringRef SectionName, bool IsReadOnly) override; + /// If non null, records subsequent Name -> SectionID mappings. + void setSectionIDsMap(SectionIDMap *SecIDMap) { + this->SecIDMap = SecIDMap; + } + void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true) override { return nullptr; @@ -192,7 +236,8 @@ public: SlabSize = Size; } - uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode) { + uint8_t *allocateFromSlab(uintptr_t Size, unsigned Alignment, bool isCode, + StringRef SectionName, unsigned SectionID) { Size = alignTo(Size, Alignment); if (CurrentSlabOffset + Size > SlabSize) report_fatal_error("Can't allocate enough memory. Tune --preallocate"); @@ -200,9 +245,9 @@ public: uintptr_t OldSlabOffset = CurrentSlabOffset; sys::MemoryBlock MB((void *)OldSlabOffset, Size); if (isCode) - FunctionMemory.push_back(MB); + FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID)); else - DataMemory.push_back(MB); + DataMemory.push_back(SectionInfo(SectionName, MB, SectionID)); CurrentSlabOffset += Size; return (uint8_t*)OldSlabOffset; } @@ -213,6 +258,7 @@ private: bool UsePreallocation = false; uintptr_t SlabSize = 0; uintptr_t CurrentSlabOffset = 0; + SectionIDMap *SecIDMap = nullptr; }; uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, @@ -223,8 +269,13 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, outs() << "allocateCodeSection(Size = " << Size << ", Alignment = " << Alignment << ", SectionName = " << SectionName << ")\n"; + dbgs() << " Registering code section \"" << SectionName << "\"\n"; + if (SecIDMap) + (*SecIDMap)[SectionName] = SectionID; + if (UsePreallocation) - return allocateFromSlab(Size, Alignment, true /* isCode */); + return allocateFromSlab(Size, Alignment, true /* isCode */, + SectionName, SectionID); std::error_code EC; sys::MemoryBlock MB = @@ -234,7 +285,7 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, EC); if (!MB.base()) report_fatal_error("MemoryManager allocation failed: " + EC.message()); - FunctionMemory.push_back(MB); + FunctionMemory.push_back(SectionInfo(SectionName, MB, SectionID)); return (uint8_t*)MB.base(); } @@ -247,8 +298,13 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, outs() << "allocateDataSection(Size = " << Size << ", Alignment = " << Alignment << ", SectionName = " << SectionName << ")\n"; + dbgs() << " Registering code section \"" << SectionName << "\"\n"; + if (SecIDMap) + (*SecIDMap)[SectionName] = SectionID; + if (UsePreallocation) - return allocateFromSlab(Size, Alignment, false /* isCode */); + return allocateFromSlab(Size, Alignment, false /* isCode */, SectionName, + SectionID); std::error_code EC; sys::MemoryBlock MB = @@ -258,7 +314,7 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, EC); if (!MB.base()) report_fatal_error("MemoryManager allocation failed: " + EC.message()); - DataMemory.push_back(MB); + DataMemory.push_back(SectionInfo(SectionName, MB, SectionID)); return (uint8_t*)MB.base(); } @@ -469,9 +525,11 @@ static int executeInput() { // Invalidate the instruction cache for each loaded function. for (auto &FM : MemMgr.FunctionMemory) { + auto &FM_MB = FM.MB; + // Make sure the memory is executable. // setExecutable will call InvalidateInstructionCache. - if (auto EC = sys::Memory::protectMappedMemory(FM, + if (auto EC = sys::Memory::protectMappedMemory(FM_MB, sys::Memory::MF_READ | sys::Memory::MF_EXEC)) ErrorAndExit("unable to mark function executable: '" + EC.message() + @@ -505,10 +563,10 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) { return 0; } -void applySpecificSectionMappings(RuntimeDyldChecker &Checker) { +void applySpecificSectionMappings(RuntimeDyld &Dyld, + const FileToSectionIDMap &FileToSecIDMap) { for (StringRef Mapping : SpecificSectionMappings) { - size_t EqualsIdx = Mapping.find_first_of("="); std::string SectionIDStr = Mapping.substr(0, EqualsIdx); size_t ComaIdx = Mapping.find_first_of(","); @@ -519,17 +577,10 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) { std::string FileName = SectionIDStr.substr(0, ComaIdx); std::string SectionName = SectionIDStr.substr(ComaIdx + 1); + unsigned SectionID = + ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName)); - uint64_t OldAddrInt; - std::string ErrorMsg; - std::tie(OldAddrInt, ErrorMsg) = - Checker.getSectionAddr(FileName, SectionName, true); - - if (ErrorMsg != "") - report_fatal_error(ErrorMsg); - - void* OldAddr = reinterpret_cast(static_cast(OldAddrInt)); - + auto* OldAddr = Dyld.getSectionContent(SectionID).data(); std::string NewAddrStr = Mapping.substr(EqualsIdx + 1); uint64_t NewAddr; @@ -537,7 +588,7 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) { report_fatal_error("Invalid section address in mapping '" + Mapping + "'."); - Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr); + Dyld.mapSectionAddress(OldAddr, NewAddr); } } @@ -553,21 +604,17 @@ void applySpecificSectionMappings(RuntimeDyldChecker &Checker) { // (e.g. 1 << 32) to stress-test stubs, GOTs, etc. // static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, - TrivialMemoryManager &MemMgr, - RuntimeDyldChecker &Checker) { + RuntimeDyld &Dyld, + TrivialMemoryManager &MemMgr) { // Set up a work list (section addr/size pairs). - typedef std::list> WorklistT; + typedef std::list WorklistT; WorklistT Worklist; for (const auto& CodeSection : MemMgr.FunctionMemory) - Worklist.push_back(std::make_pair(CodeSection.base(), CodeSection.size())); + Worklist.push_back(&CodeSection); for (const auto& DataSection : MemMgr.DataMemory) - Worklist.push_back(std::make_pair(DataSection.base(), DataSection.size())); - - // Apply any section-specific mappings that were requested on the command - // line. - applySpecificSectionMappings(Checker); + Worklist.push_back(&DataSection); // Keep an "already allocated" mapping of section target addresses to sizes. // Sections whose address mappings aren't specified on the command line will @@ -582,16 +629,16 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, I != E;) { WorklistT::iterator Tmp = I; ++I; - auto LoadAddr = Checker.getSectionLoadAddress(Tmp->first); - if (LoadAddr && - *LoadAddr != static_cast( - reinterpret_cast(Tmp->first))) { + auto LoadAddr = Dyld.getSectionLoadAddress((*Tmp)->SectionID); + + if (LoadAddr != static_cast( + reinterpret_cast((*Tmp)->MB.base()))) { // A section will have a LoadAddr of 0 if it wasn't loaded for whatever // reason (e.g. zero byte COFF sections). Don't include those sections in // the allocation map. - if (*LoadAddr != 0) - AlreadyAllocated[*LoadAddr] = Tmp->second; + if (LoadAddr != 0) + AlreadyAllocated[LoadAddr] = (*Tmp)->MB.size(); Worklist.erase(Tmp); } } @@ -609,19 +656,19 @@ static void remapSectionsAndSymbols(const llvm::Triple &TargetTriple, // Process any elements remaining in the worklist. while (!Worklist.empty()) { - std::pair CurEntry = Worklist.front(); + auto *CurEntry = Worklist.front(); Worklist.pop_front(); uint64_t NextSectionAddr = TargetAddrStart; for (const auto &Alloc : AlreadyAllocated) - if (NextSectionAddr + CurEntry.second + TargetSectionSep <= Alloc.first) + if (NextSectionAddr + CurEntry->MB.size() + TargetSectionSep <= Alloc.first) break; else NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep; - AlreadyAllocated[NextSectionAddr] = CurEntry.second; - Checker.getRTDyld().mapSectionAddress(CurEntry.first, NextSectionAddr); + Dyld.mapSectionAddress(CurEntry->MB.base(), NextSectionAddr); + AlreadyAllocated[NextSectionAddr] = CurEntry->MB.size(); } // Add dummy symbols to the memory manager. @@ -693,18 +740,116 @@ static int linkAndVerify() { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; doPreallocation(MemMgr); + + using StubOffsets = StringMap; + using SectionStubs = StringMap; + using FileStubs = StringMap; + + FileStubs StubMap; RuntimeDyld Dyld(MemMgr, MemMgr); Dyld.setProcessAllSections(true); - RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(), - llvm::dbgs()); + + Dyld.setNotifyStubEmitted( + [&StubMap](StringRef FilePath, StringRef SectionName, + StringRef SymbolName, uint32_t StubOffset) { + StubMap[sys::path::filename(FilePath)][SectionName][SymbolName] = + StubOffset; + }); + + auto GetSymbolAddress = + [&Dyld, &MemMgr](StringRef Symbol) -> Expected { + if (auto InternalSymbol = Dyld.getSymbol(Symbol)) + return InternalSymbol.getAddress(); + +#ifdef _MSC_VER + using ExpectedLookupResult = MSVCPExpected; +#else + using ExpectedLookupResult = Expected; +#endif + + auto ResultP = std::make_shared>(); + auto ResultF = ResultP->get_future(); + + MemMgr.lookup( + JITSymbolResolver::LookupSet({Symbol}), + [=](Expected Result) { + ResultP->set_value(std::move(Result)); + }); + + auto Result = ResultF.get(); + if (!Result) + return Result.takeError(); + + auto I = Result->find(Symbol); + assert(I != Result->end() && + "Expected symbol address if no error occurred"); + return I->second.getAddress(); + }; + + auto IsSymbolValid = + [&Dyld, GetSymbolAddress](StringRef Symbol) { + if (Dyld.getSymbol(Symbol)) + return true; + auto Addr = GetSymbolAddress(Symbol); + if (!Addr) { + logAllUnhandledErrors(Addr.takeError(), errs(), "RTDyldChecker: "); + return false; + } + return *Addr != 0; + }; + + FileToSectionIDMap FileToSecIDMap; + + auto GetSectionAddress = + [&Dyld, &FileToSecIDMap](StringRef FileName, StringRef SectionName) { + unsigned SectionID = + ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName)); + return Dyld.getSectionLoadAddress(SectionID); + }; + + auto GetSectionContent = + [&Dyld, &FileToSecIDMap](StringRef FileName, StringRef SectionName) { + unsigned SectionID = + ExitOnErr(getSectionId(FileToSecIDMap, FileName, SectionName)); + return Dyld.getSectionContent(SectionID); + }; + + + auto GetSymbolContents = + [&Dyld](StringRef Symbol) { + auto *SymAddr = static_cast(Dyld.getSymbolLocalAddress(Symbol)); + if (!SymAddr) + return StringRef(); + unsigned SectionID = Dyld.getSymbolSectionID(Symbol); + if (SectionID == ~0U) + return StringRef(); + StringRef SecContent = Dyld.getSectionContent(SectionID); + uint64_t SymSize = SecContent.size() - (SymAddr - SecContent.data()); + return StringRef(SymAddr, SymSize); + }; + + auto GetStubOffset = + [&StubMap](StringRef FileName, StringRef SectionName, StringRef SymbolName) -> Expected { + if (!StubMap.count(FileName)) + return make_error("File name not found", inconvertibleErrorCode()); + if (!StubMap[FileName].count(SectionName)) + return make_error("Section name not found", inconvertibleErrorCode()); + if (!StubMap[FileName][SectionName].count(SymbolName)) + return make_error("Symbol name not found", inconvertibleErrorCode()); + return StubMap[FileName][SectionName][SymbolName]; + }; + + // We will initialize this below once we have the first object file and can + // know the endianness. + std::unique_ptr Checker; // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); - for (auto &Filename : InputFileList) { + for (auto &InputFile : InputFileList) { // Load the input memory buffer. ErrorOr> InputBuffer = - MemoryBuffer::getFileOrSTDIN(Filename); + MemoryBuffer::getFileOrSTDIN(InputFile); if (std::error_code EC = InputBuffer.getError()) ErrorAndExit("unable to read input: '" + EC.message() + "'"); @@ -722,6 +867,22 @@ static int linkAndVerify() { ObjectFile &Obj = **MaybeObj; + if (!Checker) + Checker = + llvm::make_unique(IsSymbolValid, GetSymbolAddress, + GetSymbolContents, + GetSectionAddress, + GetSectionContent, GetStubOffset, + Obj.isLittleEndian() + ? support::little + : support::big, + Disassembler.get(), + InstPrinter.get(), dbgs()); + + auto FileName = sys::path::filename(InputFile); + dbgs() << "In " << FileName << ":\n"; + MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]); + // Load the object file Dyld.loadObject(Obj); if (Dyld.hasError()) { @@ -731,7 +892,8 @@ static int linkAndVerify() { // Re-map the section addresses into the phony target address space and add // dummy symbols. - remapSectionsAndSymbols(TheTriple, MemMgr, Checker); + applySpecificSectionMappings(Dyld, FileToSecIDMap); + remapSectionsAndSymbols(TheTriple, Dyld, MemMgr); // Resolve all the relocations we can. Dyld.resolveRelocations(); @@ -739,7 +901,7 @@ static int linkAndVerify() { // Register EH frames. Dyld.registerEHFrames(); - int ErrorCode = checkAllExpressions(Checker); + int ErrorCode = checkAllExpressions(*Checker); if (Dyld.hasError()) ErrorAndExit("RTDyld reported an error applying relocations:\n " + Dyld.getErrorString()); @@ -757,6 +919,8 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n"); + ExitOnErr.setBanner(std::string(argv[0]) + ": "); + switch (Action) { case AC_Execute: return executeInput();