mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
798af62b87
Re-organize the variants of `libtcg-helpers-*.bc` as such: * `libtcg-helpers-full-$ARCH.bc`: unchanged, contains all helper function with their bodies and all CSVs. * `libtcg-helpers-declarations-only-$ARCH.bc`: all helper functions have been turned to declarations. All CSVs (except a couple of special ones) have been dropped. * `libtcg-helpers-to-inline-$ARCH.bc`: only functions with the `revng_inline` section retain their body. Only CSVs that are used by these functions are present. Lift now loads only the `declarations-only` variant of helpers, as their body is not required until `inline-helpers`. In `inline-helpers` the `to-inline` variant is loaded and linked, which then allows the helpers to be inlined.
212 lines
7.0 KiB
C++
212 lines
7.0 KiB
C++
//
|
|
// 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<unsigned long long> 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<LiftPass>;
|
|
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<LoadModelWrapperPass>().get();
|
|
const TupleTree<model::Binary> &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<LoadBinaryWrapperPass>().get();
|
|
|
|
T.advance("Construct CodeGenerator", false);
|
|
CodeGenerator Generator(RawBinary,
|
|
&M,
|
|
Model,
|
|
Paths.LibHelpers,
|
|
Paths.EarlyLinked,
|
|
model::Architecture::x86_64);
|
|
|
|
std::optional<uint64_t> 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<MetaAddress, bool>;
|
|
|
|
template<>
|
|
struct llvm::yaml::CustomMappingTraits<JumpTargetMap> {
|
|
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::Binary> &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<char> 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<uint64_t> 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<std::set<ObjectID>> 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<const char *>(DataBuffer.data()),
|
|
DataBuffer.size());
|
|
auto JumpTargets = llvm::cantFail(fromString<JumpTargetMap>(String));
|
|
|
|
if (lift::internal::shouldInvalidateRoot(JumpTargets, Diff.get()))
|
|
return { {}, { ObjectID() } };
|
|
else
|
|
return {};
|
|
}
|
|
|
|
} // namespace revng::pypeline::piperuns
|