diff options
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp')
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp | 354 |
1 files changed, 120 insertions, 234 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index 6eb6256080ff..ec31ea4e573c 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -1,23 +1,21 @@ //===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #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 <cctype> -#include <future> #include <memory> #include <utility> @@ -321,22 +319,22 @@ private: return std::make_pair(EvalResult(NextPC), RemainingExpr); } - // Evaluate a call to stub_addr. + // Evaluate a call to stub_addr/got_addr. // Look up and return the address of the stub for the given // (<file name>, <section name>, <symbol name>) tuple. // On success, returns a pair containing the stub address, plus the expression // remaining to be evaluated. - std::pair<EvalResult, StringRef> evalStubAddr(StringRef Expr, - ParseContext PCtx) const { + std::pair<EvalResult, StringRef> + evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const { if (!Expr.startswith("(")) return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); StringRef RemainingExpr = Expr.substr(1).ltrim(); // Handle file-name specially, as it may contain characters that aren't // legal for symbols. - StringRef FileName; + StringRef StubContainerName; size_t ComaIdx = RemainingExpr.find(','); - FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); + StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim(); RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); if (!RemainingExpr.startswith(",")) @@ -344,14 +342,6 @@ private: unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); RemainingExpr = RemainingExpr.substr(1).ltrim(); - StringRef SectionName; - std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); - - if (!RemainingExpr.startswith(",")) - return std::make_pair( - unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - StringRef Symbol; std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); @@ -362,8 +352,8 @@ private: uint64_t StubAddr; std::string ErrorMsg = ""; - std::tie(StubAddr, ErrorMsg) = Checker.getStubAddrFor( - FileName, SectionName, Symbol, PCtx.IsInsideLoad); + std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor( + StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr); if (ErrorMsg != "") return std::make_pair(EvalResult(ErrorMsg), ""); @@ -423,7 +413,9 @@ private: else if (Symbol == "next_pc") return evalNextPC(RemainingExpr, PCtx); else if (Symbol == "stub_addr") - return evalStubAddr(RemainingExpr, PCtx); + return evalStubOrGOTAddr(RemainingExpr, PCtx, true); + else if (Symbol == "got_addr") + return evalStubOrGOTAddr(RemainingExpr, PCtx, false); else if (Symbol == "section_addr") return evalSectionAddr(RemainingExpr, PCtx); @@ -534,6 +526,11 @@ private: uint64_t LoadAddr = LoadAddrExprResult.getValue(); + // If there is no error but the content pointer is null then this is a + // zero-fill symbol/section. + if (LoadAddr == 0) + return std::make_pair(0, RemainingExpr); + return std::make_pair( EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)), RemainingExpr); @@ -666,27 +663,29 @@ private: bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { MCDisassembler *Dis = Checker.Disassembler; - StringRef SectionMem = Checker.getSubsectionStartingAt(Symbol); - ArrayRef<uint8_t> SectionBytes( - reinterpret_cast<const uint8_t *>(SectionMem.data()), - SectionMem.size()); + StringRef SymbolMem = Checker.getSymbolContent(Symbol); + ArrayRef<uint8_t> 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, GetSymbolInfoFunction GetSymbolInfo, + GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, + MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : IsSymbolValid(std::move(IsSymbolValid)), + GetSymbolInfo(std::move(GetSymbolInfo)), + GetSectionInfo(std::move(GetSectionInfo)), + GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)), + Endianness(Endianness), Disassembler(Disassembler), + InstPrinter(InstPrinter), ErrStream(ErrStream) {} bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { CheckExpr = CheckExpr.trim(); @@ -731,242 +730,134 @@ bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, return DidAllTestsPass && (NumRules != 0); } -Expected<JITSymbolResolver::LookupResult> RuntimeDyldCheckerImpl::lookup( - const JITSymbolResolver::LookupSet &Symbols) const { - -#ifdef _MSC_VER - using ExpectedLookupResult = MSVCPExpected<JITSymbolResolver::LookupResult>; -#else - using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>; -#endif - - auto ResultP = std::make_shared<std::promise<ExpectedLookupResult>>(); - auto ResultF = ResultP->get_future(); - - getRTDyld().Resolver.lookup( - Symbols, [=](Expected<JITSymbolResolver::LookupResult> 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}); + return IsSymbolValid(Symbol); +} - if (!Result) { - logAllUnhandledErrors(Result.takeError(), errs(), "RTDyldChecker: "); - return false; +uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { + auto SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); + return 0; } - assert(Result->count(Symbol) && "Missing symbol result"); - return true; -} + if (SymInfo->isZeroFill()) + return 0; -uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { return static_cast<uint64_t>( - reinterpret_cast<uintptr_t>(getRTDyld().getSymbolLocalAddress(Symbol))); + reinterpret_cast<uintptr_t>(SymInfo->getContent().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 SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); return 0; } - auto I = Result->find(Symbol); - assert(I != Result->end() && "Missing symbol result"); - return I->second.getAddress(); + + return SymInfo->getTargetAddress(); } uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, unsigned Size) const { uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr); assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); - uint8_t *Src = reinterpret_cast<uint8_t*>(PtrSizedAddr); - return getRTDyld().readBytesUnaligned(Src, Size); + void *Ptr = reinterpret_cast<void*>(PtrSizedAddr); + + switch (Size) { + case 1: + return support::endian::read<uint8_t>(Ptr, Endianness); + case 2: + return support::endian::read<uint16_t>(Ptr, Endianness); + case 4: + return support::endian::read<uint32_t>(Ptr, Endianness); + case 8: + return support::endian::read<uint64_t>(Ptr, Endianness); + } + llvm_unreachable("Unsupported read size"); } - -std::pair<const RuntimeDyldCheckerImpl::SectionAddressInfo*, std::string> -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 SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + logAllUnhandledErrors(SymInfo.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 SymInfo->getContent(); } std::pair<uint64_t, std::string> 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); - } - - unsigned SectionID = SectionInfo->SectionID; - uint64_t Addr; - if (IsInsideLoad) - Addr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>( - getRTDyld().Sections[SectionID].getAddress())); - else - Addr = getRTDyld().Sections[SectionID].getLoadAddress(); - - return std::make_pair(Addr, std::string("")); -} - -std::pair<uint64_t, std::string> 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 SecInfo = GetSectionInfo(FileName, SectionName); + if (!SecInfo) { + std::string ErrMsg; + { + raw_string_ostream ErrMsgStream(ErrMsg); + logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream, + "RTDyldChecker: "); + } + return std::make_pair(0, std::move(ErrMsg)); } - 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 this address is being looked up in "load" mode, return the content + // pointer, otherwise return the target address. - uint64_t StubOffset = StubOffsetItr->second; + uint64_t Addr = 0; - uint64_t Addr; if (IsInsideLoad) { - uintptr_t SectionBase = reinterpret_cast<uintptr_t>( - getRTDyld().Sections[SectionID].getAddress()); - Addr = static_cast<uint64_t>(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<const char *>(SectionAddr) + - SymInfo.getOffset(), - getRTDyld().Sections[SymInfo.getSectionID()].getSize() - - SymInfo.getOffset()); -} - -Optional<uint64_t> -RuntimeDyldCheckerImpl::getSectionLoadAddress(void *LocalAddress) const { - for (auto &S : getRTDyld().Sections) { - if (S.getAddress() == LocalAddress) - return S.getLoadAddress(); - } - return Optional<uint64_t>(); -} - -void RuntimeDyldCheckerImpl::registerSection( - StringRef FilePath, unsigned SectionID) { - StringRef FileName = sys::path::filename(FilePath); - const SectionEntry &Section = getRTDyld().Sections[SectionID]; - StringRef SectionName = Section.getName(); + if (SecInfo->isZeroFill()) + Addr = 0; + else + Addr = pointerToJITTargetAddress(SecInfo->getContent().data()); + } else + Addr = SecInfo->getTargetAddress(); - Stubs[FileName][SectionName].SectionID = SectionID; + return std::make_pair(Addr, ""); } -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; +std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor( + StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad, + bool IsStubAddr) const { - for (auto &StubMapEntry : RTDyldStubs) { - std::string SymbolName = ""; + auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName) + : GetGOTInfo(StubContainerName, 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<uint64_t>(StubMapEntry.first.Offset)) { - SymbolName = GSTEntry.first(); - break; - } - } + if (!StubInfo) { + std::string ErrMsg; + { + raw_string_ostream ErrMsgStream(ErrMsg); + logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream, + "RTDyldChecker: "); } - - if (SymbolName != "") - Stubs[FileName][SectionName].StubOffsets[SymbolName] = - StubMapEntry.second; + return std::make_pair((uint64_t)0, std::move(ErrMsg)); } -} -RuntimeDyldChecker::RuntimeDyldChecker(RuntimeDyld &RTDyld, - MCDisassembler *Disassembler, - MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) - : Impl(make_unique<RuntimeDyldCheckerImpl>(RTDyld, Disassembler, - InstPrinter, ErrStream)) {} + uint64_t Addr = 0; -RuntimeDyldChecker::~RuntimeDyldChecker() {} + if (IsInsideLoad) { + if (StubInfo->isZeroFill()) + return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry"); + Addr = pointerToJITTargetAddress(StubInfo->getContent().data()); + } else + Addr = StubInfo->getTargetAddress(); -RuntimeDyld& RuntimeDyldChecker::getRTDyld() { - return Impl->RTDyld; + return std::make_pair(Addr, ""); } -const RuntimeDyld& RuntimeDyldChecker::getRTDyld() const { - return Impl->RTDyld; -} +RuntimeDyldChecker::RuntimeDyldChecker( + IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, + GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, + MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : Impl(::llvm::make_unique<RuntimeDyldCheckerImpl>( + std::move(IsSymbolValid), std::move(GetSymbolInfo), + std::move(GetSectionInfo), std::move(GetStubInfo), + std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter, + ErrStream)) {} + +RuntimeDyldChecker::~RuntimeDyldChecker() {} bool RuntimeDyldChecker::check(StringRef CheckExpr) const { return Impl->check(CheckExpr); @@ -982,8 +873,3 @@ RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, bool LocalAddress) { return Impl->getSectionAddr(FileName, SectionName, LocalAddress); } - -Optional<uint64_t> -RuntimeDyldChecker::getSectionLoadAddress(void *LocalAddress) const { - return Impl->getSectionLoadAddress(LocalAddress); -} |