Files
Giacomo Vercesi 296eb9a76f Make SingleOutputPipe uniform to other piperuns
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.
2025-12-10 15:05:53 +01:00

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