diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -628,6 +628,9 @@ return static_cast(TargetFlags) & Flags; } + /// Get the target flags of this Symbol. + TargetFlagsType getTargetFlags() const { return TargetFlags; } + /// Set the target flags for this Symbol. void setTargetFlags(TargetFlagsType Flags) { assert(Flags <= 1 && "Add more bits to store more than single flag"); diff --git a/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h --- a/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h +++ b/llvm/include/llvm/ExecutionEngine/RuntimeDyldChecker.h @@ -12,6 +12,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/Support/Endian.h" +#include "llvm/TargetParser/SubtargetFeature.h" +#include "llvm/TargetParser/Triple.h" #include #include @@ -29,6 +31,9 @@ class RuntimeDyldCheckerImpl; class raw_ostream; +/// Holds target-specific properties for a symbol. +using TargetFlagsType = uint8_t; + /// RuntimeDyld invariant checker for verifying that RuntimeDyld has /// correctly applied relocations. /// @@ -83,6 +88,12 @@ : ContentPtr(Content.data()), Size(Content.size()), TargetAddress(TargetAddress) {} + /// Constructor for symbols/sections with content and TargetFlag. + MemoryRegionInfo(ArrayRef Content, JITTargetAddress TargetAddress, + TargetFlagsType TargetFlags) + : ContentPtr(Content.data()), Size(Content.size()), + TargetAddress(TargetAddress), TargetFlags(TargetFlags) {} + /// Constructor for zero-fill symbols/sections. MemoryRegionInfo(uint64_t Size, JITTargetAddress TargetAddress) : Size(Size), TargetAddress(TargetAddress) {} @@ -127,10 +138,22 @@ /// Return the target address for this region. JITTargetAddress getTargetAddress() const { return TargetAddress; } + /// Check whether the given target flags are set for this Symbol. + bool hasTargetFlags(TargetFlagsType Flags) const { + return static_cast(TargetFlags) & Flags; + } + + /// Set the target flags for this Symbol. + void setTargetFlags(TargetFlagsType Flags) { + assert(Flags <= 0xFF && "Add more bits to store more than single flag"); + TargetFlags = Flags; + } + private: const char *ContentPtr = nullptr; uint64_t Size = 0; JITTargetAddress TargetAddress = 0; + TargetFlagsType TargetFlags = 0; }; using IsSymbolValidFunction = std::function; @@ -148,9 +171,8 @@ GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, GetGOTInfoFunction GetGOTInfo, - support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - raw_ostream &ErrStream); + support::endianness Endianness, Triple &TT, + SubtargetFeatures &TF, raw_ostream &ErrStream); ~RuntimeDyldChecker(); /// Check a single expression against the attached RuntimeDyld diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -10,9 +10,16 @@ #include "RuntimeDyldCheckerImpl.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MSVCErrorWorkarounds.h" #include "llvm/Support/MemoryBuffer.h" @@ -284,7 +291,22 @@ << "'. Instruction has only " << format("%i", Inst.getNumOperands()) << " operands.\nInstruction is:\n "; - Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); + auto isSymThumb = Checker.hasTargetFlag(Symbol, 0x1); + if (!isSymThumb) { + logAllUnhandledErrors(isSymThumb.takeError(), errs(), + "Error checking target flag: "); + return std::make_pair(EvalResult(ErrMsgStream.str()), ""); + } + if (Checker.TT.getArch() == Triple::arm) + assert(*isSymThumb == Checker.TT.isThumb()); + auto InstPrinter = Checker.getInstPrinter(Checker.TT); + if (auto E = InstPrinter.takeError()) { + errs() << "Error obtaining instruction printer: " + << toString(std::move(E)) << "\n"; + return std::make_pair(EvalResult(ErrMsgStream.str()), + ""); // Return false or take appropriate action. + } + Inst.dump_pretty(ErrMsgStream, InstPrinter.get().get()); return std::make_pair(EvalResult(ErrMsgStream.str()), ""); } @@ -294,7 +316,23 @@ raw_string_ostream ErrMsgStream(ErrMsg); ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '" << Symbol << "' is not an immediate.\nInstruction is:\n "; - Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); + + auto isSymThumb = Checker.hasTargetFlag(Symbol, 0x1); + if (!isSymThumb) { + logAllUnhandledErrors(isSymThumb.takeError(), errs(), + "Error checking target flag: "); + return std::make_pair(EvalResult(ErrMsgStream.str()), ""); + } + if (Checker.TT.getArch() == Triple::arm) + assert(*isSymThumb == Checker.TT.isThumb()); + auto InstPrinter = Checker.getInstPrinter(Checker.TT); + if (auto E = InstPrinter.takeError()) { + errs() << "Error obtaining instruction printer: " + << toString(std::move(E)) << "\n"; + return std::make_pair(EvalResult(ErrMsgStream.str()), + ""); // Return false or take appropriate action. + } + Inst.dump_pretty(ErrMsgStream, InstPrinter.get().get()); return std::make_pair(EvalResult(ErrMsgStream.str()), ""); } @@ -687,13 +725,33 @@ bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size, int64_t Offset) const { - MCDisassembler *Dis = Checker.Disassembler; + + auto isSymThumb = Checker.hasTargetFlag(Symbol, 0x1); + if (!isSymThumb) { + logAllUnhandledErrors(isSymThumb.takeError(), errs(), + "Error checking target flag: "); + return false; + } + if (Checker.TT.getArch() == Triple::arm && isSymThumb) + Checker.TT.setArchName("thumbv7"); + + if (Checker.TT.getArch() == Triple::arm) + assert(*isSymThumb == Checker.TT.isThumb()); + + auto Dis = Checker.getDisassembler(Checker.TT, Checker.TF); + + if (auto E = Dis.takeError()) { + errs() << "Error obtaining disassembler: " << toString(std::move(E)) + << "\n"; + return false; // Return false or take appropriate action. + } + StringRef SymbolMem = Checker.getSymbolContent(Symbol); ArrayRef SymbolBytes(SymbolMem.bytes_begin() + Offset, SymbolMem.size() - Offset); MCDisassembler::DecodeStatus S = - Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls()); + Dis.get()->getInstruction(Inst, Size, SymbolBytes, 0, nulls()); return (S == MCDisassembler::Success); } @@ -703,15 +761,13 @@ RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl( IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, - GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, Triple &TT, + SubtargetFeatures &TF, 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) {} + Endianness(Endianness), TT(TT), TF(TF), ErrStream(ErrStream) {} bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { CheckExpr = CheckExpr.trim(); @@ -766,6 +822,93 @@ return DidAllTestsPass && (NumRules != 0); } +Expected> +RuntimeDyldCheckerImpl::getDisassembler( + const Triple &TT, const SubtargetFeatures &Features) const { + auto TripleName = TT.str(); + std::string ErrorStr; + const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr); + if (!TheTarget) + return make_error("Error accessing target '" + TripleName + + "': " + ErrorStr, + inconvertibleErrorCode()); + + std::unique_ptr STI( + TheTarget->createMCSubtargetInfo(TripleName, "", TF.getString())); + if (!STI) + return make_error("Unable to create subtarget for " + + TripleName, + inconvertibleErrorCode()); + + std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return make_error("Unable to create target register info " + "for " + + TripleName, + inconvertibleErrorCode()); + + MCTargetOptions MCOptions; + std::unique_ptr MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); + if (!MAI) + return make_error("Unable to create target asm info " + + TripleName, + inconvertibleErrorCode()); + + auto Ctx = std::make_unique(Triple(TripleName), MAI.get(), + MRI.get(), STI.get()); + + std::unique_ptr Disassembler( + TheTarget->createMCDisassembler(*STI, *Ctx)); + if (!Disassembler) + return make_error("Unable to create disassembler for " + + TripleName, + inconvertibleErrorCode()); + + return std::move(Disassembler); +} + +Expected> +RuntimeDyldCheckerImpl::getInstPrinter(const Triple &TT) const { + auto TripleName = TT.str(); + std::string ErrorStr; + const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, ErrorStr); + if (!TheTarget) + return make_error("Error accessing target '" + TripleName + + "': " + ErrorStr, + inconvertibleErrorCode()); + + std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return make_error("Unable to create target register info " + "for " + + TripleName, + inconvertibleErrorCode()); + + MCTargetOptions MCOptions; + std::unique_ptr MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); + if (!MAI) + return make_error("Unable to create target asm info " + + TripleName, + inconvertibleErrorCode()); + + std::unique_ptr MII(TheTarget->createMCInstrInfo()); + if (!MII) + return make_error("Unable to create instruction info for" + + TripleName, + inconvertibleErrorCode()); + + std::unique_ptr InstPrinter( + TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI)); + if (!InstPrinter) + return make_error("Unable to create instruction printer for" + + TripleName, + inconvertibleErrorCode()); + + return std::move(InstPrinter); +} + bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { return IsSymbolValid(Symbol); } @@ -822,6 +965,15 @@ return {SymInfo->getContent().data(), SymInfo->getContent().size()}; } +Expected RuntimeDyldCheckerImpl::hasTargetFlag(StringRef Symbol, + uint8_t Flag) const { + auto SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + return SymInfo.takeError(); + } + return SymInfo->hasTargetFlags(Flag); +} + std::pair RuntimeDyldCheckerImpl::getSectionAddr( StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { @@ -884,14 +1036,12 @@ RuntimeDyldChecker::RuntimeDyldChecker( IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, - GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, Triple &TT, + SubtargetFeatures &TF, raw_ostream &ErrStream) : Impl(::std::make_unique( std::move(IsSymbolValid), std::move(GetSymbolInfo), std::move(GetSectionInfo), std::move(GetStubInfo), - std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter, - ErrStream)) {} + std::move(GetGOTInfo), Endianness, TT, TF, ErrStream)) {} RuntimeDyldChecker::~RuntimeDyldChecker() = default; diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h @@ -25,17 +25,23 @@ using GetGOTInfoFunction = RuntimeDyldChecker::GetGOTInfoFunction; public: - RuntimeDyldCheckerImpl( - IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, - GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, - GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - llvm::raw_ostream &ErrStream); + RuntimeDyldCheckerImpl(IsSymbolValidFunction IsSymbolValid, + GetSymbolInfoFunction GetSymbolInfo, + GetSectionInfoFunction GetSectionInfo, + GetStubInfoFunction GetStubInfo, + GetGOTInfoFunction GetGOTInfo, + support::endianness Endianness, Triple &TT, + SubtargetFeatures &TF, llvm::raw_ostream &ErrStream); bool check(StringRef CheckExpr) const; bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const; private: + Expected> + getDisassembler(const Triple &TT, const SubtargetFeatures &Features) const; + + Expected> + getInstPrinter(const Triple &TT) const; // StubMap typedefs. @@ -49,6 +55,8 @@ StringRef getSymbolContent(StringRef Symbol) const; + Expected hasTargetFlag(StringRef Symbol, uint8_t Flag) const; + std::pair getSectionAddr(StringRef FileName, StringRef SectionName, bool IsInsideLoad) const; @@ -65,8 +73,8 @@ GetStubInfoFunction GetStubInfo; GetGOTInfoFunction GetGOTInfo; support::endianness Endianness; - MCDisassembler *Disassembler; - MCInstPrinter *InstPrinter; + Triple &TT; + SubtargetFeatures &TF; llvm::raw_ostream &ErrStream; }; } diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp --- a/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink-elf.cpp @@ -145,7 +145,8 @@ SectionContainsZeroFill = true; } else { S.SymbolInfos[Sym->getName()] = {Sym->getSymbolContent(), - Sym->getAddress().getValue()}; + Sym->getAddress().getValue(), + Sym->getTargetFlags()}; SectionContainsContent = true; } } diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp --- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp +++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp @@ -1856,15 +1856,12 @@ std::move(MAI), std::move(Ctx), std::move(Disassembler), std::move(MII), std::move(MIA), std::move(InstPrinter)}; } - -static Error runChecks(Session &S) { +static Error runChecks(Session &S, Triple TT, SubtargetFeatures Features) { if (CheckFiles.empty()) return Error::success(); LLVM_DEBUG(dbgs() << "Running checks...\n"); - auto TI = getTargetInfo(S.ES.getTargetTriple(), S.Features); - auto IsSymbolValid = [&S](StringRef Symbol) { return S.isSymbolRegistered(Symbol); }; @@ -1888,7 +1885,7 @@ RuntimeDyldChecker Checker( IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetGOTInfo, S.ES.getTargetTriple().isLittleEndian() ? support::little : support::big, - TI.Disassembler.get(), TI.InstPrinter.get(), dbgs()); + TT, Features, dbgs()); std::string CheckLineStart = "# " + CheckName + ":"; for (auto &CheckFile : CheckFiles) { @@ -2000,7 +1997,7 @@ auto [TT, Features] = getFirstFileTripleAndFeatures(); ExitOnErr(sanitizeArguments(TT, argv[0])); - auto S = ExitOnErr(Session::Create(std::move(TT), std::move(Features))); + auto S = ExitOnErr(Session::Create(TT, Features)); enableStatistics(*S, !OrcRuntime.empty()); @@ -2036,7 +2033,7 @@ exit(1); } - ExitOnErr(runChecks(*S)); + ExitOnErr(runChecks(*S, std::move(TT), std::move(Features))); int Result = 0; if (!NoExec) { diff --git a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp --- a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -973,11 +973,12 @@ ObjectFile &Obj = **MaybeObj; + SubtargetFeatures Features = SubtargetFeatures(); if (!Checker) Checker = std::make_unique( IsSymbolValid, GetSymbolInfo, GetSectionInfo, GetStubInfo, GetStubInfo, Obj.isLittleEndian() ? support::little : support::big, - Disassembler.get(), InstPrinter.get(), dbgs()); + TheTriple, Features, dbgs()); auto FileName = sys::path::filename(InputFile); MemMgr.setSectionIDsMap(&FileToSecIDMap[FileName]);