// // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/Lift/LibTcg.h" #include "revng/Lift/Lift.h" #include "revng/Support/CommandLine.h" #include "revng/Support/IRHelpers.h" #include "revng/Support/ResourceFinder.h" #include "CodeGenerator.h" #include "PostLiftVerifyPass.h" using namespace llvm::cl; namespace { const char *EntryDescStr = "virtual address of the entry point where to start"; opt EntryPointAddress("entry", desc(EntryDescStr), value_desc("address"), cat(MainCategory)); alias A1("e", desc("Alias for -entry"), aliasopt(EntryPointAddress), cat(MainCategory)); } // namespace char LiftPass::ID; using Register = llvm::RegisterPass; static Register X("lift", "Lift Pass", true, true); struct ExternalFilePaths { std::string LibHelpers; std::string EarlyLinked; }; static ExternalFilePaths findExternalFilePaths(const model::Architecture::Values Architecture) { // What symbols from the revng namespace are actually used here? using namespace revng; const std::string ArchName = model::Architecture::getQEMUName(Architecture) .str(); ExternalFilePaths Paths = {}; // Note: here we use the declaration version of the helpers, i.e., where all // helper functions are just declarations. const std::string LibHelpersName = "/share/revng/" "libtcg-helpers-declarations-only-" + ArchName + ".bc"; auto OptionalHelpers = ResourceFinder.findFile(LibHelpersName); revng_assert(OptionalHelpers.has_value(), "Cannot find libtcg helpers"); Paths.LibHelpers = OptionalHelpers.value(); const std::string EarlyLinkedName = "/share/revng/early-linked-" + ArchName + ".ll"; auto OptionalEarlyLinked = ResourceFinder.findFile(EarlyLinkedName); revng_assert(OptionalEarlyLinked.has_value(), "Cannot find early-linked.ll"); Paths.EarlyLinked = OptionalEarlyLinked.value(); return Paths; } bool LiftPass::runOnModule(llvm::Module &M) { llvm::Task T(4, "Lift pass"); const auto &ModelWrapper = getAnalysis().get(); const TupleTree &Model = ModelWrapper.getReadOnlyModel(); T.advance("findFiles", false); const auto Paths = findExternalFilePaths(Model->Architecture()); // Look for the library in the system's paths T.advance("Load libtcg", false); auto TheLibTcg = LibTcg::get(Model->Architecture()); // Get access to raw binary data RawBinaryView &RawBinary = getAnalysis().get(); T.advance("Construct CodeGenerator", false); CodeGenerator Generator(RawBinary, &M, Model, Paths.LibHelpers, Paths.EarlyLinked, model::Architecture::x86_64); std::optional EntryPointAddressOptional; if (EntryPointAddress.getNumOccurrences() != 0) EntryPointAddressOptional = EntryPointAddress; T.advance("Translate", true); Generator.translate(TheLibTcg, EntryPointAddressOptional); sortModule(M); return false; } /// Map describing the jump targets in the LLVM module, each one is identified /// by its MetaAddress. The boolean value represents if the jump target has been /// discovered through harvesting (false) or successively through the list of /// model functions (true). using JumpTargetMap = std::map; template<> struct llvm::yaml::CustomMappingTraits { static void inputOne(IO &IO, StringRef Key, JumpTargetMap &Data) { MetaAddress Address = MetaAddress::fromString(Key); IO.mapRequired(Key.str().c_str(), Data[Address]); } static void output(IO &IO, JumpTargetMap &Data) { for (auto &[Key, Value] : Data) IO.mapRequired(Key.toString().c_str(), Value); } }; namespace revng::pypeline::piperuns { Lift::Lift(const class Model &Model, llvm::StringRef Config, llvm::StringRef DynamicConfig, const BinariesContainer &Binary, LLVMRootContainer &ModuleContainer) : TheModel(Model), Binary(Binary), ModuleContainer(ModuleContainer) { } CustomInvalidationData Lift::run() { llvm::Task T(6, "Lift"); const TupleTree &Model = TheModel.get(); T.advance("findFiles", false); const auto Paths = findExternalFilePaths(Model->Architecture()); // Look for the library in the system's paths T.advance("Load libtcg", false); auto TheLibTcg = LibTcg::get(Model->Architecture()); // Get access to raw binary data revng_assert(Binary.size() == 1); llvm::ArrayRef File = Binary.getFile(0); RawBinaryView RawBinary(*Model, { File.data(), File.size() }); llvm::Module &Module = ModuleContainer.getModule(); T.advance("Construct CodeGenerator", false); CodeGenerator Generator(RawBinary, &Module, Model, Paths.LibHelpers, Paths.EarlyLinked, model::Architecture::x86_64); std::optional EntryPointAddressOptional; if (EntryPointAddress.getNumOccurrences() != 0) EntryPointAddressOptional = EntryPointAddress; T.advance("Translate", true); Generator.translate(TheLibTcg, EntryPointAddressOptional); T.advance("Sort Module", true); sortModule(Module); T.advance("Verify Module", true); // TODO: convert this from a pass to a free-standing function PostLiftVerifyPass{}.runOnModule(Module); // TODO: substitute with strip-dead-debug-info once the old pipeline // is dropped pruneDICompileUnits(Module); // Compute invalidation data Buffer SerializedInvalidation; { auto [HasRoot, JumpTargets] = lift::internal::collectJumpTargets(Module); revng_assert(HasRoot); llvm::raw_svector_ostream OS(SerializedInvalidation.data()); serialize(OS, JumpTargets); } return { {}, { { ObjectID(), SerializedInvalidation } } }; } llvm::Error Lift::checkPrecondition(const class Model &Model) { const model::Binary &Binary = *Model.get().get(); return revng::joinErrors(lift::internal::checkPrecondition(Binary), RawBinaryView::checkPrecondition(Binary)); } std::vector> Lift::invalidate(const InvalidationData &Data, const ModelDiff &Diff) { auto LLVMModuleData = Data.at(1); revng_assert(LLVMModuleData.size() == 1); revng_assert(*std::get<0>(LLVMModuleData[0]) == ObjectID()); auto DataBuffer = std::get<1>(LLVMModuleData[0]); llvm::StringRef String(reinterpret_cast(DataBuffer.data()), DataBuffer.size()); auto JumpTargets = llvm::cantFail(fromString(String)); if (lift::internal::shouldInvalidateRoot(JumpTargets, Diff.get())) return { {}, { ObjectID() } }; else return {}; } } // namespace revng::pypeline::piperuns