mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
296eb9a76f
Make the interface required by `SingleOutputPipe` similar to other piperuns by requiring a constructor, the use of `PipeRunArgument`s and the implementation of a non-static `run` function.
225 lines
5.7 KiB
C++
225 lines
5.7 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "revng/Lift/LoadBinaryPass.h"
|
|
#include "revng/PipeboxCommon/BinariesContainer.h"
|
|
#include "revng/PipeboxCommon/LLVMContainer.h"
|
|
#include "revng/PipeboxCommon/Model.h"
|
|
#include "revng/Pipeline/ExecutionContext.h"
|
|
#include "revng/Pipes/FunctionPass.h"
|
|
#include "revng/Support/Debug.h"
|
|
|
|
namespace JTReason {
|
|
|
|
// TODO: move me to another header file
|
|
/// Reason for registering a jump target
|
|
enum Values {
|
|
/// PC after an helper (e.g., a syscall)
|
|
PostHelper = 1,
|
|
/// Obtained from a direct store to the PC
|
|
DirectJump = 2,
|
|
/// Obtained digging in global data
|
|
GlobalData = 4,
|
|
/// Fallthrough of multiple instructions in the immediately preceding bytes
|
|
AmbiguousInstruction = 8,
|
|
/// Stored in the PC
|
|
PCStore = 16,
|
|
/// Stored in memory
|
|
MemoryStore = 32,
|
|
/// Obtained digging in global data, but never used. Likely a function
|
|
/// pointer
|
|
UnusedGlobalData = 64,
|
|
/// This JT is the target of a call instruction.
|
|
Callee = 128,
|
|
/// A load has been performed from this address
|
|
LoadAddress = 256,
|
|
/// Obtained as the fallthrough of a function call
|
|
ReturnAddress = 512,
|
|
/// Obtained from a function symbol
|
|
FunctionSymbol = 1024,
|
|
/// Immediate value in the IR, usually a return address
|
|
SimpleLiteral = 2048,
|
|
/// This jump target has been discovered *after* we added all the entry
|
|
/// addresses of model::Functions
|
|
DependsOnModelFunction = SimpleLiteral << 1,
|
|
LastReason = DependsOnModelFunction
|
|
};
|
|
|
|
inline const char *getName(Values Reason) {
|
|
switch (Reason) {
|
|
case PostHelper:
|
|
return "PostHelper";
|
|
case DirectJump:
|
|
return "DirectJump";
|
|
case GlobalData:
|
|
return "GlobalData";
|
|
case AmbiguousInstruction:
|
|
return "AmbiguousInstruction";
|
|
case PCStore:
|
|
return "PCStore";
|
|
case MemoryStore:
|
|
return "MemoryStore";
|
|
case UnusedGlobalData:
|
|
return "UnusedGlobalData";
|
|
case Callee:
|
|
return "Callee";
|
|
case LoadAddress:
|
|
return "LoadAddress";
|
|
case ReturnAddress:
|
|
return "ReturnAddress";
|
|
case FunctionSymbol:
|
|
return "FunctionSymbol";
|
|
case SimpleLiteral:
|
|
return "SimpleLiteral";
|
|
case DependsOnModelFunction:
|
|
return "DependsOnModelFunction";
|
|
}
|
|
|
|
revng_abort();
|
|
}
|
|
|
|
inline Values fromName(llvm::StringRef ReasonName) {
|
|
if (ReasonName == "PostHelper")
|
|
return PostHelper;
|
|
else if (ReasonName == "DirectJump")
|
|
return DirectJump;
|
|
else if (ReasonName == "GlobalData")
|
|
return GlobalData;
|
|
else if (ReasonName == "AmbiguousInstruction")
|
|
return AmbiguousInstruction;
|
|
else if (ReasonName == "PCStore")
|
|
return PCStore;
|
|
else if (ReasonName == "MemoryStore")
|
|
return MemoryStore;
|
|
else if (ReasonName == "UnusedGlobalData")
|
|
return UnusedGlobalData;
|
|
else if (ReasonName == "Callee")
|
|
return Callee;
|
|
else if (ReasonName == "LoadAddress")
|
|
return LoadAddress;
|
|
else if (ReasonName == "ReturnAddress")
|
|
return ReturnAddress;
|
|
else if (ReasonName == "FunctionSymbol")
|
|
return FunctionSymbol;
|
|
else if (ReasonName == "SimpleLiteral")
|
|
return SimpleLiteral;
|
|
else if (ReasonName == "DependsOnModelFunction")
|
|
return DependsOnModelFunction;
|
|
else
|
|
revng_abort();
|
|
}
|
|
|
|
inline bool hasReason(uint32_t Reasons, Values ToCheck) {
|
|
return (Reasons & static_cast<uint32_t>(ToCheck)) != 0;
|
|
}
|
|
|
|
} // namespace JTReason
|
|
|
|
namespace KillReason {
|
|
|
|
enum Values {
|
|
NonKiller,
|
|
KillerSyscall,
|
|
EndlessLoop,
|
|
LeadsToKiller
|
|
};
|
|
|
|
inline llvm::StringRef getName(Values Reason) {
|
|
switch (Reason) {
|
|
case NonKiller:
|
|
return "NonKiller";
|
|
case KillerSyscall:
|
|
return "KillerSyscall";
|
|
case EndlessLoop:
|
|
return "EndlessLoop";
|
|
case LeadsToKiller:
|
|
return "LeadsToKiller";
|
|
}
|
|
|
|
revng_abort("Unexpected reason");
|
|
}
|
|
|
|
inline Values fromName(llvm::StringRef Name) {
|
|
if (Name == "NonKiller")
|
|
return NonKiller;
|
|
if (Name == "KillerSyscall")
|
|
return KillerSyscall;
|
|
else if (Name == "EndlessLoop")
|
|
return EndlessLoop;
|
|
else if (Name == "LeadsToKiller")
|
|
return LeadsToKiller;
|
|
else
|
|
revng_abort("Unexpected name");
|
|
}
|
|
|
|
} // namespace KillReason
|
|
|
|
class LiftPass : public llvm::ModulePass {
|
|
public:
|
|
static char ID;
|
|
|
|
public:
|
|
LiftPass() : llvm::ModulePass(ID) {}
|
|
|
|
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
|
|
AU.addRequired<LoadBinaryWrapperPass>();
|
|
AU.addRequired<LoadModelWrapperPass>();
|
|
AU.addRequired<pipeline::LoadExecutionContextPass>();
|
|
}
|
|
|
|
bool runOnModule(llvm::Module &M) override;
|
|
};
|
|
|
|
namespace revng::lift::internal {
|
|
|
|
llvm::Error checkPrecondition(const model::Binary &Model);
|
|
|
|
std::tuple<bool, std::map<MetaAddress, bool>>
|
|
collectJumpTargets(const llvm::Module &);
|
|
|
|
bool shouldInvalidateRoot(const std::map<MetaAddress, bool> &JumpTargets,
|
|
const TupleTreeDiff<model::Binary> &Diff);
|
|
|
|
} // namespace revng::lift::internal
|
|
|
|
namespace revng::pypeline::piperuns {
|
|
|
|
class Lift {
|
|
public:
|
|
static constexpr llvm::StringRef Name = "lift";
|
|
using Arguments = TypeList<
|
|
PipeRunArgument<const BinariesContainer, "Input", "Input binaries to lift">,
|
|
PipeRunArgument<LLVMRootContainer,
|
|
"Output",
|
|
"LLVM Module containing the lifted binaries",
|
|
Access::Write>>;
|
|
|
|
private:
|
|
const Model &TheModel;
|
|
const BinariesContainer &Binary;
|
|
LLVMRootContainer &ModuleContainer;
|
|
|
|
public:
|
|
Lift(const class Model &Model,
|
|
llvm::StringRef Config,
|
|
llvm::StringRef DynamicConfig,
|
|
const BinariesContainer &Binary,
|
|
LLVMRootContainer &ModuleContainer);
|
|
|
|
CustomInvalidationData run();
|
|
|
|
public:
|
|
static llvm::Error checkPrecondition(const class Model &Model);
|
|
|
|
static std::vector<std::set<ObjectID>>
|
|
invalidate(const InvalidationData &Data, const ModelDiff &Diff);
|
|
};
|
|
|
|
} // namespace revng::pypeline::piperuns
|