Let FunctionIsolation and EnforceABI use the Model

This commit is contained in:
Alessandro Di Federico
2021-02-19 09:39:49 +01:00
parent 0f7de0c2e0
commit 27b58695a1
20 changed files with 1389 additions and 1407 deletions
-1
View File
@@ -163,7 +163,6 @@ copy_to_build_and_install(FILES
share/revng
runtime/support.c
runtime/support.h
include/revng/Runtime/commonconstants.h
scripts/clang-format-style-file)
configure_file(runtime/early-linked.c "${CMAKE_BINARY_DIR}/share/revng/early-linked.c" COPYONLY)
@@ -236,7 +236,7 @@ public:
llvm::BasicBlock *getJumpTargetBlock(llvm::BasicBlock *BB);
MetaAddress getJumpTarget(llvm::BasicBlock *BB) {
return getPCFromNewPC(&*getJumpTargetBlock(BB)->begin());
return getPCFromNewPC(getJumpTargetBlock(BB));
}
bool isJump(llvm::BasicBlock *BB) const {
@@ -22,6 +22,7 @@ public:
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.addRequired<GeneratedCodeBasicInfoWrapperPass>();
AU.addRequired<LoadModelPass>();
AU.setPreservesAll();
}
};
@@ -9,6 +9,7 @@
#include "llvm/Pass.h"
#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h"
#include "revng/Model/LoadModelPass.h"
class IsolateFunctions : public llvm::ModulePass {
public:
@@ -22,5 +23,6 @@ public:
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<GeneratedCodeBasicInfoWrapperPass>();
AU.addRequired<LoadModelPass>();
}
};
-22
View File
@@ -1,22 +0,0 @@
#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
/// \brief Type of generated message for debugging exceptions at runtime when
/// function isolation is applied
typedef enum {
/// Unexpected control flow at the end of a translated basic block
StandardTranslatedBlock,
/// Unexpected control flow at the end of a non-translated basic block (anypc
/// or unexpectedpc)
StandardNonTranslatedBlock,
/// Expected and actual return address after function call not matching
BadReturnAddress,
/// Call to the function dispatcher with a PC not corresponding to any
/// function entry block
FunctionDispatcherFallBack,
/// Execution has reached the return address of a noreturn function call
ReturnFromNoReturn
} Reason;
@@ -10,6 +10,7 @@
#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h"
#include "revng/FunctionCallIdentification/FunctionCallIdentification.h"
#include "revng/Model/LoadModelPass.h"
#include "revng/StackAnalysis/FunctionsSummary.h"
namespace StackAnalysis {
@@ -29,6 +30,7 @@ public:
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<GeneratedCodeBasicInfoWrapperPass>();
AU.addRequired<LoadModelPass>();
}
bool runOnModule(llvm::Module &M) override;
@@ -79,7 +79,7 @@ public:
public:
std::array<llvm::GlobalVariable *, 4> pcCSVs() const {
return { AddressCSV, EpochCSV, AddressSpaceCSV, TypeCSV };
return { EpochCSV, AddressSpaceCSV, TypeCSV, AddressCSV };
}
/// \brief Hook for the emission of a store to a CSV
+64 -10
View File
@@ -14,6 +14,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/ELF.h"
#include "revng/Model/Binary.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
@@ -23,32 +24,85 @@ class GlobalVariable;
class ABIRegister {
private:
llvm::StringRef Name;
llvm::StringRef QemuName;
model::Register::Values ID;
unsigned MContextIndex;
public:
static const unsigned NotInMContext = std::numeric_limits<unsigned>::max();
public:
ABIRegister(llvm::StringRef Name, unsigned MContextIndex) :
Name(Name), QemuName(Name), MContextIndex(MContextIndex) {}
ABIRegister(model::Register::Values ID) :
ID(ID), MContextIndex(NotInMContext) {}
ABIRegister(llvm::StringRef Name) :
Name(Name), QemuName(Name), MContextIndex(NotInMContext) {}
ABIRegister(model::Register::Values ID, unsigned MContextIndex) :
ID(ID), MContextIndex(MContextIndex) {}
ABIRegister(llvm::StringRef Name, llvm::StringRef QemuName) :
Name(Name), QemuName(QemuName), MContextIndex(NotInMContext) {}
model::Register::Values id() const { return ID; }
llvm::StringRef name() const { return Name; }
llvm::StringRef name() const { return model::Register::getRegisterName(ID); }
llvm::StringRef qemuName() const { return QemuName; }
llvm::StringRef csvName() const { return toCSVName(ID); }
bool inMContext() const { return MContextIndex != NotInMContext; }
unsigned mcontextIndex() const {
revng_assert(inMContext());
return MContextIndex;
}
public:
static llvm::StringRef toCSVName(model::Register::Values ID) {
using namespace model::Register;
switch (ID) {
case Invalid:
revng_abort();
case xmm0_x86_64:
return "state_0x8558";
case xmm1_x86_64:
return "state_0x8598";
case xmm2_x86_64:
return "state_0x85d8";
case xmm3_x86_64:
return "state_0x8618";
case xmm4_x86_64:
return "state_0x8658";
case xmm5_x86_64:
return "state_0x8698";
case xmm6_x86_64:
return "state_0x86d8";
case xmm7_x86_64:
return "state_0x8718";
default:
return model::Register::getRegisterName(ID);
}
}
static model::Register::Values
fromCSVName(llvm::StringRef Name, llvm::Triple::ArchType Arch) {
using namespace model::Register;
if (Arch == llvm::Triple::x86_64) {
if (Name == "state_0x8558") {
return xmm0_x86_64;
} else if (Name == "state_0x8598") {
return xmm1_x86_64;
} else if (Name == "state_0x85d8") {
return xmm2_x86_64;
} else if (Name == "state_0x8618") {
return xmm3_x86_64;
} else if (Name == "state_0x8658") {
return xmm4_x86_64;
} else if (Name == "state_0x8698") {
return xmm5_x86_64;
} else if (Name == "state_0x86d8") {
return xmm6_x86_64;
} else if (Name == "state_0x8718") {
return xmm7_x86_64;
}
}
return model::Register::fromRegisterName(Name, Arch);
}
};
namespace JTReason {
+1
View File
@@ -7,5 +7,6 @@ revng_add_analyses_library_internal(revngFunctionIsolation
IsolateFunctions.cpp)
target_link_libraries(revngFunctionIsolation
revngModel
revngStackAnalysis
revngSupport)
+193 -248
View File
@@ -17,7 +17,6 @@
#include "revng/ADT/LazySmallBitVector.h"
#include "revng/ADT/SmallMap.h"
#include "revng/FunctionIsolation/EnforceABI.h"
#include "revng/StackAnalysis/FunctionsSummary.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/OpaqueFunctionsPool.h"
@@ -47,43 +46,55 @@ static cl::opt<bool> DisableSafetyChecks("disable-enforce-abi-safety-checks",
cl::cat(MainCategory),
cl::init(false));
static bool shouldEmit(FunctionRegisterArgument V) {
switch (V.value()) {
case FunctionRegisterArgument::Yes:
return true;
default:
return false;
}
static bool shouldEmit(model::RegisterState::Values V) {
return (V == model::RegisterState::Yes or V == model::RegisterState::YesOrDead
or V == model::RegisterState::Dead);
}
static bool shouldEmit(FunctionCallRegisterArgument V) {
switch (V.value()) {
case FunctionCallRegisterArgument::Yes:
case FunctionCallRegisterArgument::Dead:
static bool areCompatible(model::RegisterState::Values LHS,
model::RegisterState::Values RHS) {
using namespace model::RegisterState;
if (LHS == RHS or LHS == Maybe or RHS == Maybe)
return true;
default:
switch (LHS) {
case NoOrDead:
return RHS == No or RHS == Dead;
case YesOrDead:
return RHS == Yes or RHS == Dead;
case No:
return RHS == NoOrDead;
case Yes:
return RHS == YesOrDead;
case Dead:
return RHS == NoOrDead or RHS == YesOrDead;
case Contradiction:
return false;
case Invalid:
default:
revng_abort();
}
revng_abort();
}
static bool shouldEmit(FunctionReturnValue V) {
switch (V.value()) {
case FunctionReturnValue::YesOrDead:
return true;
default:
return false;
}
static bool areCompatible(const model::FunctionABIRegister &LHS,
const model::FunctionABIRegister &RHS) {
return areCompatible(LHS.Argument, RHS.Argument)
and areCompatible(LHS.ReturnValue, RHS.ReturnValue);
}
static bool shouldEmit(FunctionCallReturnValue V) {
switch (V.value()) {
case FunctionCallReturnValue::YesOrDead:
case FunctionCallReturnValue::Yes:
case FunctionCallReturnValue::Dead:
return true;
default:
return false;
static StringRef areCompatible(const model::Function &Callee,
const model::FunctionEdge &CallSite) {
for (const model::FunctionABIRegister &Register : Callee.Registers) {
auto It = CallSite.Registers.find(Register.Register);
if (It != CallSite.Registers.end() and not areCompatible(Register, *It)) {
return model::Register::getName(Register.Register);
}
}
return StringRef();
}
class HelperCallSite {
@@ -132,30 +143,33 @@ private:
class EnforceABIImpl {
public:
EnforceABIImpl(Module &M, const GeneratedCodeBasicInfo &GCBI) :
EnforceABIImpl(Module &M,
GeneratedCodeBasicInfo &GCBI,
const model::Binary &Binary) :
M(M),
GCBI(GCBI),
FunctionDispatcher(M.getFunction("function_dispatcher")),
Context(M.getContext()),
IndirectPlaceholderPool(&M, false) {}
IndirectPlaceholderPool(&M, false),
Binary(Binary) {}
void run();
private:
FunctionsSummary::FunctionDescription handleFunction(Function &F);
Function *handleFunction(Function &F, const model::Function &FunctionModel);
void handleRegularFunctionCall(CallInst *Call);
void handleHelperFunctionCall(CallInst *Call);
void generateCall(IRBuilder<> &Builder,
Function *Callee,
FunctionsSummary::CallSiteDescription &CallSite);
const model::FunctionEdge &CallSite);
void replaceCSVsWithAlloca();
void handleRoot();
private:
Module &M;
const GeneratedCodeBasicInfo &GCBI;
std::map<Function *, FunctionsSummary::FunctionDescription> FunctionsMap;
GeneratedCodeBasicInfo &GCBI;
std::map<Function *, const model::Function *> FunctionsMap;
std::map<Function *, Function *> OldToNew;
Function *FunctionDispatcher;
Function *OpaquePC;
@@ -163,12 +177,14 @@ private:
std::map<HelperCallSite, Function *> HelperCallSites;
std::map<GlobalVariable *, unsigned> CSVToIndex;
OpaqueFunctionsPool<FunctionType *> IndirectPlaceholderPool;
const model::Binary &Binary;
};
bool EnforceABI::runOnModule(Module &M) {
auto &GCBI = getAnalysis<GeneratedCodeBasicInfoWrapperPass>().getGCBI();
const model::Binary &Binary = getAnalysis<LoadModelPass>().getReadOnlyModel();
EnforceABIImpl Impl(M, GCBI);
EnforceABIImpl Impl(M, GCBI, Binary);
Impl.run();
return false;
}
@@ -284,6 +300,12 @@ createHelperWrapper(Function *Helper,
}
void EnforceABIImpl::run() {
// Assign an index to each CSV
unsigned I = 0;
for (GlobalVariable *CSV : GCBI.csvs()) {
CSVToIndex[CSV] = I;
I++;
}
// Declare an opaque function used later to obtain a value to store in the
// local %pc alloca, so that we don't incur in error when removing the bad
@@ -297,81 +319,45 @@ void EnforceABIImpl::run() {
OpaquePC->addFnAttr(Attribute::NoUnwind);
OpaquePC->addFnAttr(Attribute::ReadOnly);
// Collect functions we need to handle
std::vector<Function *> Functions;
for (Function &F : M)
if (F.getName().startswith("bb."))
Functions.push_back(&F);
std::vector<Function *> OldFunctions;
for (const model::Function &FunctionModel : Binary.Functions) {
if (FunctionModel.Type == model::FunctionType::Fake)
continue;
// Recreate the functions with the appropriate set of arguments
for (Function *F : Functions) {
const FunctionDescription &Descriptor = handleFunction(*F);
auto *NewFunction = cast<Function>(Descriptor.Function);
FunctionsMap[NewFunction] = Descriptor;
OldToNew[F] = NewFunction;
revng_assert(FunctionModel.Name.size() != 0);
Function *OldFunction = M.getFunction(FunctionModel.Name);
revng_assert(OldFunction != nullptr);
OldFunctions.push_back(OldFunction);
Function *NewFunction = handleFunction(*OldFunction, FunctionModel);
FunctionsMap[NewFunction] = &FunctionModel;
OldToNew[OldFunction] = NewFunction;
}
unsigned I = 0;
for (GlobalVariable *CSV : GCBI.csvs()) {
CSVToIndex[CSV] = I;
I++;
}
// Collect the list of function calls we intend to handle
std::vector<CallInst *> RegularFunctionCalls;
std::vector<CallInst *> HelperFunctionCalls;
for (auto &P : FunctionsMap) {
Function &F = *cast<Function>(P.second.Function);
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
auto *FuncCall = I.getMetadata("func.call");
if (FuncCall != nullptr) {
CallInst *Call = cast<CallInst>(&I);
if (isCallToHelper(Call)) {
HelperFunctionCalls.push_back(Call);
} else {
RegularFunctionCalls.push_back(Call);
}
}
auto *Call = dyn_cast<CallInst>(&I);
if (Call == nullptr or isMarker(Call))
continue;
Value *CalledValue = Call->getCalledValue();
Function *Callee = cast_or_null<Function>(skipCasts(CalledValue));
if (Callee != nullptr and Callee->isIntrinsic())
continue;
if (FuncCall == nullptr) {
BasicBlock *BB = Call->getParent();
dbg << "Call " << getName(Call) << " ("
<< "in function " << getName(BB->getParent())
<< ", with unique predecessor "
<< getName(BB->getUniquePredecessor()) << ")"
<< " to " << getName(Callee) << " (now "
<< getName(OldToNew[Callee]) << ")"
<< " doesn't have func.call metadata\n";
// revng_abort();
continue;
}
if (Callee == nullptr)
continue;
}
}
}
auto IsInIsolatedFunction = [this](Instruction *I) -> bool {
return FunctionsMap.count(I->getParent()->getParent()) != 0;
};
// Handle function calls in isolated functions
for (CallInst *Call : RegularFunctionCalls)
std::vector<CallInst *> RegularCalls;
for (auto *F : OldFunctions)
for (User *U : F->users())
if (auto *Call = dyn_cast<CallInst>(skipCasts(U)))
if (IsInIsolatedFunction(Call))
RegularCalls.push_back(Call);
for (CallInst *Call : RegularCalls)
handleRegularFunctionCall(Call);
// Handle function calls to helpers in isolated functions
for (CallInst *Call : HelperFunctionCalls)
std::vector<CallInst *> HelperCalls;
for (Function &F : M.functions())
if (isHelper(&F))
for (User *U : F.users())
if (auto *Call = dyn_cast<CallInst>(skipCasts(U)))
if (IsInIsolatedFunction(Call))
HelperCalls.push_back(Call);
for (CallInst *Call : HelperCalls)
handleHelperFunctionCall(Call);
// Handle invoke instructions in `root`
@@ -387,9 +373,12 @@ void EnforceABIImpl::run() {
BasicBlock::Create(Context, "", FunctionDispatcher));
}
// Drop all the old functions
for (Function *Function : Functions)
Function->eraseFromParent();
// Drop all the old functions, after we stole all of its blocks
for (Function *OldFunction : OldFunctions) {
for (User *U : OldFunction->users())
cast<Instruction>(U)->getParent()->dump();
OldFunction->eraseFromParent();
}
// Quick and dirty DCE
for (auto &P : FunctionsMap) {
@@ -412,12 +401,10 @@ void EnforceABIImpl::run() {
BB->eraseFromParent();
}
bool Invalid;
{
if (VerifyLog.isEnabled()) {
raw_os_ostream Stream(dbg);
Invalid = verifyModule(M, &Stream);
revng_assert(not verifyModule(M, &Stream));
}
revng_assert(not Invalid);
}
void EnforceABIImpl::handleRoot() {
@@ -427,26 +414,26 @@ void EnforceABIImpl::handleRoot() {
for (BasicBlock &BB : *Root) {
// Find invoke instruction
auto It = BB.begin();
auto End = BB.end();
if (It == End)
continue;
auto *Invoke = dyn_cast<InvokeInst>(&*It);
It++;
auto *Invoke = dyn_cast<InvokeInst>(BB.getTerminator());
if (It != End or Invoke == nullptr)
if (Invoke == nullptr)
continue;
revng_assert(BB.size() == 1);
Function *Callee = OldToNew.at(Invoke->getCalledFunction());
FunctionsSummary::FunctionDescription &Function = FunctionsMap.at(Callee);
const model::Function *Function = FunctionsMap.at(Callee);
// Collect arguments
IRBuilder<> Builder(Invoke);
std::vector<Value *> Arguments;
for (auto &P : Function.RegisterSlots) {
GlobalVariable *CSV = P.first;
if (shouldEmit(P.second.Argument))
for (const model::FunctionABIRegister &Register : Function->Registers) {
if (shouldEmit(Register.Argument)) {
auto Name = ABIRegister::toCSVName(Register.Register);
GlobalVariable *CSV = M.getGlobalVariable(Name, true);
revng_assert(CSV != nullptr);
Arguments.push_back(Builder.CreateLoad(CSV));
}
}
// Create the new invoke with the appropriate arguments
@@ -463,41 +450,25 @@ void EnforceABIImpl::handleRoot() {
}
}
FunctionsSummary::FunctionDescription
EnforceABIImpl::handleFunction(Function &F) {
QuickMetadata QMD(Context);
auto *Tuple = cast<MDTuple>(F.getMetadata("revng.func.entry"));
FunctionDescription Description;
Function *EnforceABIImpl::handleFunction(Function &OldFunction,
const model::Function &FunctionModel) {
SmallVector<Type *, 8> ArgumentsTypes;
SmallVector<GlobalVariable *, 8> ArgumentCSVs;
SmallVector<Type *, 8> ReturnTypes;
SmallVector<GlobalVariable *, 8> ReturnCSVs;
auto OperandsRange = QMD.extract<MDTuple *>(Tuple, 4)->operands();
for (const MDOperand &Operand : OperandsRange) {
auto *SlotTuple = cast<MDTuple>(Operand.get());
auto *CSV = cast<GlobalVariable>(QMD.extract<Constant *>(SlotTuple, 0));
StringRef ArgumentName = QMD.extract<StringRef>(SlotTuple, 1);
auto Argument = FunctionRegisterArgument::fromName(ArgumentName);
StringRef ReturnValueName = QMD.extract<StringRef>(SlotTuple, 2);
auto ReturnValue = FunctionReturnValue::fromName(ReturnValueName);
Description.RegisterSlots[CSV] = FunctionRegisterDescription{ Argument,
ReturnValue };
for (const model::FunctionABIRegister &Register : FunctionModel.Registers) {
auto Name = ABIRegister::toCSVName(Register.Register);
auto *CSV = cast<GlobalVariable>(M.getGlobalVariable(Name, true));
// Collect arguments
if (shouldEmit(Argument)) {
if (shouldEmit(Register.Argument)) {
ArgumentsTypes.push_back(CSV->getType()->getPointerElementType());
ArgumentCSVs.push_back(CSV);
}
// Collect return values
if (shouldEmit(ReturnValue)) {
if (shouldEmit(Register.ReturnValue)) {
ReturnTypes.push_back(CSV->getType()->getPointerElementType());
ReturnCSVs.push_back(CSV);
}
@@ -517,22 +488,18 @@ EnforceABIImpl::handleFunction(Function &F) {
auto *NewFunction = Function::Create(NewType,
GlobalValue::ExternalLinkage,
"",
F.getParent());
NewFunction->takeName(&F);
NewFunction->copyAttributesFrom(&F);
NewFunction->setMetadata("revng.func.entry",
F.getMetadata("revng.func.entry"));
Description.Function = NewFunction;
OldFunction.getParent());
NewFunction->takeName(&OldFunction);
NewFunction->copyAttributesFrom(&OldFunction);
{
unsigned I = 0;
for (Argument &Argument : NewFunction->args())
Argument.setName(ArgumentCSVs[I++]->getName());
}
// Set argument names
unsigned I = 0;
for (Argument &Argument : NewFunction->args())
Argument.setName(ArgumentCSVs[I++]->getName());
// Steal body from the old function
std::vector<BasicBlock *> Body;
for (BasicBlock &BB : F)
for (BasicBlock &BB : OldFunction)
Body.push_back(&BB);
auto &NewBody = NewFunction->getBasicBlockList();
for (BasicBlock *BB : Body) {
@@ -545,12 +512,8 @@ EnforceABIImpl::handleFunction(Function &F) {
// Store arguments to CSVs
BasicBlock &Entry = NewFunction->getEntryBlock();
IRBuilder<> StoreBuilder(Entry.getTerminator());
unsigned I = 0;
for (Argument &TheArgument : NewFunction->args()) {
auto *CSV = ArgumentCSVs[I];
for (const auto &[TheArgument, CSV] : zip(NewFunction->args(), ArgumentCSVs))
StoreBuilder.CreateStore(&TheArgument, CSV);
I++;
}
// Build the return value
if (ReturnCSVs.size() != 0) {
@@ -571,7 +534,7 @@ EnforceABIImpl::handleFunction(Function &F) {
}
}
return Description;
return NewFunction;
}
void EnforceABIImpl::handleHelperFunctionCall(CallInst *Call) {
@@ -605,15 +568,10 @@ void EnforceABIImpl::handleHelperFunctionCall(CallInst *Call) {
//
IRBuilder<> Builder(Call);
SmallVector<Value *, 16> NewArguments;
// Initialize the new set of arguments with the old ones
unsigned I = 0;
for (Value *V : make_range(Call->arg_begin(), Call->arg_end())) {
auto *Ty = HelperType->getParamType(I);
NewArguments.push_back(Builder.CreateBitOrPointerCast(V, Ty));
I++;
}
SmallVector<Value *, 16> NewArguments;
for (auto [Argument, Type] : zip(Call->args(), HelperType->params()))
NewArguments.push_back(Builder.CreateBitOrPointerCast(Argument, Type));
// Add arguments read
for (GlobalVariable *CSV : UsedCSVs.Read)
@@ -650,54 +608,38 @@ void EnforceABIImpl::handleHelperFunctionCall(CallInst *Call) {
}
void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) {
Function *Caller = Call->getParent()->getParent();
const model::Function &FunctionModel = *FunctionsMap.at(Caller);
revng_assert(Call->getParent()->getParent()->getName() == FunctionModel.Name);
Function *Callee = cast<Function>(skipCasts(Call->getCalledValue()));
bool IsDirect = (Callee != FunctionDispatcher);
if (IsDirect)
Callee = OldToNew.at(Callee);
using namespace StackAnalysis;
QuickMetadata QMD(Context);
// Temporary variable we're going to populate using metadata
CallSiteDescription CallSite(Call, nullptr);
auto *FuncCall = cast<MDTuple>(Call->getMetadata("func.call"));
//
// Collect arguments and return values
//
auto *Slots = cast<MDTuple>(QMD.extract<MDTuple *>(FuncCall, 0));
for (const MDOperand &Operand : Slots->operands()) {
auto *SlotTuple = cast<MDTuple>(Operand.get());
auto *CSV = cast<GlobalVariable>(QMD.extract<Constant *>(SlotTuple, 0));
StringRef ArgumentName = QMD.extract<StringRef>(SlotTuple, 1);
auto Argument = FunctionCallRegisterArgument::fromName(ArgumentName);
StringRef ReturnValueName = QMD.extract<StringRef>(SlotTuple, 2);
auto ReturnValue = FunctionCallReturnValue::fromName(ReturnValueName);
CallSite.RegisterSlots[CSV] = FunctionCallRegisterDescription{
Argument, ReturnValue
};
// Identify the corresponding call site in the model
MetaAddress BasicBlockAddress = GCBI.getJumpTarget(Call->getParent());
const model::BasicBlock &Block = FunctionModel.CFG.at(BasicBlockAddress);
const model::FunctionEdge *CallSite = nullptr;
for (const model::FunctionEdge &Edge : Block.Successors) {
using namespace model::FunctionEdgeType;
if (Edge.Type == FunctionCall or Edge.Type == IndirectCall
or Edge.Type == IndirectTailCall) {
CallSite = &Edge;
break;
}
}
if (DisableSafetyChecks or IsDirect) {
// The callee is a well-known callee, generate a direct call
IRBuilder<> Builder(Call);
generateCall(Builder, Callee, CallSite);
generateCall(Builder, Callee, *CallSite);
// Create an additional store to the local %pc, so that the optimizer cannot
// do stuff with llvm.assume.
revng_assert(OpaquePC != nullptr);
auto *OpaqueValue = Builder.CreateCall(OpaquePC);
// The store here is done in the global CSV, since the
// `replaceCSVsWithAlloca` method pass after us, and place the corresponding
// alloca here.
Value *PCCSV = GCBI.pcReg();
Builder.CreateStore(OpaqueValue, PCCSV);
Builder.CreateStore(Builder.CreateCall(OpaquePC), GCBI.pcReg());
} else {
// If it's an indirect call, enumerate all the compatible callees and
@@ -710,55 +652,56 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) {
BeforeSplit->getTerminator()->eraseFromParent();
IRBuilder<> Builder(BeforeSplit);
Value *PCCSV = GCBI.pcReg();
Value *PC = Builder.CreateLoad(PCCSV);
BasicBlock *UnexpectedPC = findByBlockType(AfterSplit->getParent(),
BlockType::UnexpectedPCBlock);
revng_assert(UnexpectedPC != nullptr);
SwitchInst *Switch = Builder.CreateSwitch(PC, UnexpectedPC);
unsigned I = 0;
ProgramCounterHandler::DispatcherTargets Targets;
unsigned Count = 0;
for (auto &P : FunctionsMap) {
Function *F = P.first;
FunctionDescription &Description = P.second;
for (auto &[F, FunctionModel] : FunctionsMap) {
EnforceABILog << " " << F->getName().data() << " ";
if (GlobalVariable *CSV = CallSite.isCompatibleWith(Description)) {
EnforceABILog << "[No: " << CSV->getName().data() << "]";
// Check compatibility
StringRef IncompatibleCSV = areCompatible(*FunctionModel, *CallSite);
bool Incompatible = not IncompatibleCSV.empty();
if (Incompatible) {
EnforceABILog << "[No: " << IncompatibleCSV.data() << "]";
} else {
EnforceABILog << "[Yes]";
Count++;
auto *Tuple = cast<MDTuple>(F->getMetadata("revng.func.entry"));
revng_assert(Tuple != nullptr);
auto PC = MetaAddress::fromConstant(QMD.extract<Constant *>(Tuple, 1));
// Create the basic block containing the call
auto *Case = BasicBlock::Create(Context,
"",
BeforeSplit->getParent(),
AfterSplit);
auto *Ty = cast<IntegerType>(PCCSV->getType()->getPointerElementType());
Switch->addCase(ConstantInt::get(Ty, PC.asPC()), Case);
Builder.SetInsertPoint(Case);
generateCall(Builder, F, CallSite);
generateCall(Builder, F, *CallSite);
Builder.CreateBr(AfterSplit);
// Record for inline dispatcher
Targets.push_back({ FunctionModel->Entry, Case });
}
EnforceABILog << DoLog;
I++;
}
// Actually create the inline dispatcher
Builder.SetInsertPoint(BeforeSplit);
GCBI.programCounterHandler()->buildDispatcher(Targets,
Builder,
UnexpectedPC,
{});
EnforceABILog << Count << " functions" << DoLog;
}
// Drop the original call
Call->eraseFromParent();
}
void EnforceABIImpl::generateCall(IRBuilder<> &Builder,
Function *Callee,
CallSiteDescription &CallSite) {
const model::FunctionEdge &CallSite) {
revng_assert(Callee != nullptr);
llvm::SmallVector<Type *, 8> ArgumentsTypes;
@@ -771,15 +714,15 @@ void EnforceABIImpl::generateCall(IRBuilder<> &Builder,
revng_assert(DisableSafetyChecks);
// Collect arguments, returns and their type.
for (auto &P : CallSite.RegisterSlots) {
GlobalVariable *CSV = P.first;
if (shouldEmit(P.second.Argument)) {
for (const model::FunctionABIRegister &Register : CallSite.Registers) {
auto Name = ABIRegister::toCSVName(Register.Register);
GlobalVariable *CSV = M.getGlobalVariable(Name, true);
if (shouldEmit(Register.Argument)) {
ArgumentsTypes.push_back(CSV->getType()->getPointerElementType());
Arguments.push_back(Builder.CreateLoad(CSV));
}
if (shouldEmit(P.second.ReturnValue)) {
if (shouldEmit(Register.ReturnValue)) {
ReturnTypes.push_back(CSV->getType()->getPointerElementType());
ReturnCSVs.push_back(CSV);
}
@@ -804,32 +747,34 @@ void EnforceABIImpl::generateCall(IRBuilder<> &Builder,
} else {
// Additional debug checks if we are not emitting an indirect call.
BasicBlock *InsertBlock = Builder.GetInsertPoint()->getParent();
revng_log(EnforceABILog,
"Emitting call to " << getName(Callee) << " from "
<< getName(CallSite.Call));
<< getName(InsertBlock));
FunctionDescription &Function = FunctionsMap.at(Callee);
revng_assert(Function.Function != nullptr
and Function.Function->getName().startswith("bb."));
if (GlobalVariable *CSV = CallSite.isCompatibleWith(Function)) {
dbg << (CallSite.Call == nullptr ? "nullptr" :
getName(CallSite.Call).data())
<< " -> "
const model::Function *FunctionModel = FunctionsMap.at(Callee);
revng_assert(Callee->getName().startswith("bb."));
StringRef IncompatibleCSV = areCompatible(*FunctionModel, CallSite);
bool Incompatible = not IncompatibleCSV.empty();
if (Incompatible) {
dbg << getName(InsertBlock) << " -> "
<< (Callee == nullptr ? "nullptr" : Callee->getName().data()) << ": "
<< CSV->getName().data() << "\n";
<< IncompatibleCSV.data() << "\n";
revng_abort();
}
// Collect arguments, returns and their type.
for (auto &P : Function.RegisterSlots) {
GlobalVariable *CSV = P.first;
for (const model::FunctionABIRegister &Register :
FunctionModel->Registers) {
auto Name = ABIRegister::toCSVName(Register.Register);
GlobalVariable *CSV = M.getGlobalVariable(Name, true);
if (shouldEmit(P.second.Argument)) {
if (shouldEmit(Register.Argument)) {
ArgumentsTypes.push_back(CSV->getType()->getPointerElementType());
Arguments.push_back(Builder.CreateLoad(CSV));
}
if (shouldEmit(P.second.ReturnValue)) {
if (shouldEmit(Register.ReturnValue)) {
ReturnTypes.push_back(CSV->getType()->getPointerElementType());
ReturnCSVs.push_back(CSV);
}
@@ -916,15 +861,15 @@ void EnforceABIImpl::replaceCSVsWithAlloca() {
// Ignore it if it's not a CSV
auto CSVPosIt = CSVPosition.find(CSV);
if (CSVPosIt == CSVPosition.end())
continue;
auto CSVPos = CSVPosIt->second;
CSVMaps[CSVPos][&F] = Alloca;
if (CSVPosIt != CSVPosition.end()) {
auto CSVPos = CSVPosIt->second;
CSVMaps[CSVPos][&F] = Alloca;
}
}
Separator->eraseFromParent();
}
// Substitute the uses of the GlobalVariables representing the CSVs with the
// dedicate AllocaInst that were created in each Function.
for (GlobalVariable *CSV : GCBI.csvs()) {
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -59,7 +59,8 @@ revng_add_analyses_library_internal(revngStackAnalysis
target_link_libraries(revngStackAnalysis
revngBasicAnalyses
revngSupport)
revngSupport
revngModel)
target_include_directories(revngStackAnalysis
PRIVATE
+266 -4
View File
@@ -12,9 +12,13 @@
#include <sstream>
#include <vector>
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h"
#include "revng/Model/Binary.h"
#include "revng/StackAnalysis/StackAnalysis.h"
#include "revng/Support/CommandLine.h"
#include "revng/Support/IRHelpers.h"
@@ -65,6 +69,258 @@ static opt<std::string> ABIAnalysisOutputPath("abi-analysis-output",
value_desc("path"),
cat(MainCategory));
template<bool FunctionCall>
static model::RegisterState::Values
toRegisterState(RegisterArgument<FunctionCall> RA) {
switch (RA.value()) {
case RegisterArgument<FunctionCall>::NoOrDead:
return model::RegisterState::NoOrDead;
case RegisterArgument<FunctionCall>::Maybe:
return model::RegisterState::Maybe;
case RegisterArgument<FunctionCall>::Yes:
return model::RegisterState::Yes;
case RegisterArgument<FunctionCall>::Dead:
return model::RegisterState::Dead;
case RegisterArgument<FunctionCall>::Contradiction:
return model::RegisterState::Contradiction;
case RegisterArgument<FunctionCall>::No:
return model::RegisterState::No;
}
revng_abort();
}
static model::RegisterState::Values toRegisterState(FunctionReturnValue RV) {
switch (RV.value()) {
case FunctionReturnValue::No:
return model::RegisterState::No;
case FunctionReturnValue::NoOrDead:
return model::RegisterState::NoOrDead;
case FunctionReturnValue::YesOrDead:
return model::RegisterState::YesOrDead;
case FunctionReturnValue::Maybe:
return model::RegisterState::Maybe;
case FunctionReturnValue::Contradiction:
return model::RegisterState::Contradiction;
}
revng_abort();
}
static model::RegisterState::Values
toRegisterState(FunctionCallReturnValue RV) {
switch (RV.value()) {
case FunctionCallReturnValue::No:
return model::RegisterState::No;
case FunctionCallReturnValue::NoOrDead:
return model::RegisterState::NoOrDead;
case FunctionCallReturnValue::YesOrDead:
return model::RegisterState::YesOrDead;
case FunctionCallReturnValue::Yes:
return model::RegisterState::Yes;
case FunctionCallReturnValue::Dead:
return model::RegisterState::Dead;
case FunctionCallReturnValue::Maybe:
return model::RegisterState::Maybe;
case FunctionCallReturnValue::Contradiction:
return model::RegisterState::Contradiction;
}
revng_abort();
}
void commitToModel(GeneratedCodeBasicInfo &GCBI,
Function *F,
const FunctionsSummary &Summary,
model::Binary &TheBinary);
void commitToModel(GeneratedCodeBasicInfo &GCBI,
Function *F,
const FunctionsSummary &Summary,
model::Binary &TheBinary) {
using namespace model;
for (const auto &[Entry, FunctionSummary] : Summary.Functions) {
if (Entry == nullptr)
continue;
//
// Initialize model::Function
//
// Get the entry point address
MetaAddress EntryPC = getBasicBlockPC(Entry);
revng_assert(EntryPC.isValid());
// Create the function
revng_assert(TheBinary.Functions.count(EntryPC) == 0);
model::Function &Function = TheBinary.Functions[EntryPC];
// Assign a name
Function.Name = Entry->getName();
revng_assert(Function.Name.size() != 0);
using FT = model::FunctionType::Values;
Function.Type = static_cast<FT>(FunctionSummary.Type);
// Populate arguments and return values
{
auto Inserter = Function.Registers.batch_insert();
for (auto &[CSV, FRD] : FunctionSummary.RegisterSlots) {
auto ID = ABIRegister::fromCSVName(CSV->getName(), GCBI.arch());
if (ID == model::Register::Invalid)
continue;
FunctionABIRegister TheRegister(ID);
TheRegister.Argument = toRegisterState(FRD.Argument);
TheRegister.ReturnValue = toRegisterState(FRD.ReturnValue);
Inserter.insert(TheRegister);
}
}
for (auto &[BB, Branch] : FunctionSummary.BasicBlocks) {
// Remap BranchType to FunctionEdgeType
namespace FET = FunctionEdgeType;
FET::Values EdgeType = FET::Invalid;
bool IsCall = false;
switch (Branch) {
case BranchType::Invalid:
case BranchType::FakeFunction:
case BranchType::RegularFunction:
case BranchType::NoReturnFunction:
case BranchType::UnhandledCall:
revng_abort();
break;
case BranchType::InstructionLocalCFG:
EdgeType = FET::Invalid;
break;
case BranchType::FunctionLocalCFG:
EdgeType = FET::DirectBranch;
break;
case BranchType::FakeFunctionCall:
EdgeType = FET::FakeFunctionCall;
break;
case BranchType::FakeFunctionReturn:
EdgeType = FET::FakeFunctionReturn;
break;
case BranchType::HandledCall:
IsCall = true;
EdgeType = FET::FunctionCall;
break;
case BranchType::IndirectCall:
IsCall = true;
EdgeType = FET::IndirectCall;
break;
case BranchType::Return:
EdgeType = FET::Return;
break;
case BranchType::BrokenReturn:
EdgeType = FET::BrokenReturn;
break;
case BranchType::IndirectTailCall:
IsCall = true;
EdgeType = FET::IndirectTailCall;
break;
case BranchType::LongJmp:
EdgeType = FET::LongJmp;
break;
case BranchType::Killer:
EdgeType = FET::Killer;
break;
case BranchType::Unreachable:
EdgeType = FET::Unreachable;
break;
}
if (EdgeType == FET::Invalid)
continue;
// Identify Source address
auto [Source, Size] = getPC(BB->getTerminator());
Source += Size;
revng_assert(Source.isValid());
// Identify Destination address
llvm::BasicBlock *JumpTargetBB = GCBI.getJumpTargetBlock(BB);
MetaAddress JumpTargetAddress = GCBI.getPCFromNewPC(JumpTargetBB);
model::BasicBlock &CurrentBlock = Function.CFG[JumpTargetAddress];
CurrentBlock.End = Source;
CurrentBlock.Name = JumpTargetBB->getName();
auto SuccessorsInserter = CurrentBlock.Successors.batch_insert();
if (EdgeType == FET::DirectBranch) {
// Handle direct branch
auto Successors = GCBI.getSuccessors(BB);
for (const MetaAddress &Destination : Successors.Addresses)
SuccessorsInserter.insert(FunctionEdge{ Destination, EdgeType });
} else if (EdgeType == FET::FakeFunctionReturn) {
// Handle fake function return
auto [First, Last] = FunctionSummary.FakeReturns.equal_range(BB);
revng_assert(First != Last);
for (const auto &[_, Destination] : make_range(First, Last))
SuccessorsInserter.insert(FunctionEdge{ Destination, EdgeType });
} else if (IsCall) {
// Handle call
llvm::BasicBlock *Successor = BB->getSingleSuccessor();
MetaAddress Destination = MetaAddress::invalid();
if (Successor != nullptr)
Destination = getBasicBlockPC(Successor);
// Record the edge in the CFG
auto &Edge = SuccessorsInserter.insert({ Destination, EdgeType });
bool Found = false;
for (const FunctionsSummary::CallSiteDescription &CSD :
FunctionSummary.CallSites) {
if (not CSD.Call->isTerminator() or CSD.Call->getParent() != BB)
continue;
revng_assert(not Found);
Found = true;
auto Inserter = Edge.Registers.batch_insert();
for (auto &[CSV, FCRD] : CSD.RegisterSlots) {
auto ID = ABIRegister::fromCSVName(CSV->getName(), GCBI.arch());
if (ID == model::Register::Invalid)
continue;
FunctionABIRegister TheRegister(ID);
TheRegister.Argument = toRegisterState(FCRD.Argument);
TheRegister.ReturnValue = toRegisterState(FCRD.ReturnValue);
Inserter.insert(TheRegister);
}
}
revng_assert(Found);
} else {
// Handle other successors
llvm::BasicBlock *Successor = BB->getSingleSuccessor();
MetaAddress Destination = MetaAddress::invalid();
if (Successor != nullptr)
Destination = getBasicBlockPC(Successor);
// Record the edge in the CFG
SuccessorsInserter.insert(FunctionEdge{ Destination, EdgeType });
}
}
}
revng_check(TheBinary.verify());
}
template<bool AnalyzeABI>
bool StackAnalysis<AnalyzeABI>::runOnModule(Module &M) {
Function &F = *M.getFunction("root");
@@ -73,6 +329,8 @@ bool StackAnalysis<AnalyzeABI>::runOnModule(Module &M) {
auto &GCBI = getAnalysis<GeneratedCodeBasicInfoWrapperPass>().getGCBI();
auto &LMP = getAnalysis<LoadModelPass>();
// The stack analysis works function-wise. We consider two sets of functions:
// first (Force == true) those that are highly likely to be real functions
// (i.e., they have a direct call) and then (Force == false) all the remaining
@@ -177,10 +435,7 @@ bool StackAnalysis<AnalyzeABI>::runOnModule(Module &M) {
}
}
std::stringstream Output;
GrandResult = Results.finalize(&M, &TheCache);
GrandResult.dump(&M, Output);
TextRepresentation = Output.str();
if (ClobberedLog.isEnabled()) {
for (auto &P : GrandResult.Functions) {
@@ -191,7 +446,12 @@ bool StackAnalysis<AnalyzeABI>::runOnModule(Module &M) {
}
}
revng_log(StackAnalysisLog, TextRepresentation);
if (StackAnalysisLog.isEnabled()) {
std::stringstream Output;
GrandResult.dump(&M, Output);
TextRepresentation = Output.str();
revng_log(StackAnalysisLog, TextRepresentation);
}
revng_log(PassesLog, "Ending StackAnalysis");
@@ -204,6 +464,8 @@ bool StackAnalysis<AnalyzeABI>::runOnModule(Module &M) {
serialize(pathToStream(StackAnalysisOutputPath, Output));
}
commitToModel(GCBI, &F, GrandResult, LMP.getWriteableModel());
return false;
}
+17 -54
View File
@@ -28,7 +28,7 @@ int arch_prctl(int code, unsigned long *addr);
#endif
#include "revng/Runtime/commonconstants.h"
#include "revng/Runtime/PrintPlainMetaAddress.h"
#include "support.h"
@@ -245,15 +245,18 @@ void g_free(void *memory) {
return free(memory);
}
void unknownPC() {
void unknownPC(PlainMetaAddress *PC) {
int arg;
const char *error = "Unknown PC\n";
write(2, error, strlen(error));
fprintf(stderr, "Unknown PC:");
fprint_metaaddress(stderr, PC);
fprintf(stderr, "\n");
for (arg = 0; arg < saved_argc; arg++) {
write(2, saved_argv[arg], strlen(saved_argv[arg]));
write(2, " ", 1);
}
write(2, "\n", 1);
abort();
}
@@ -451,58 +454,18 @@ int main(int argc, char *argv[]) {
root((target_reg) stack);
}
// Helper function to debug informations when an exception is about to be
// raised
void exception_warning(Reason Code,
target_reg Source,
target_reg Target,
target_reg ExpectedDestination) {
switch (Code) {
case StandardTranslatedBlock:
fprintf(stderr,
"Unexpected control-flow in isolated function: "
"0x%" TARGET_REG_FORMAT " -> 0x%" TARGET_REG_FORMAT "\n",
Source,
Target);
break;
case StandardNonTranslatedBlock:
fprintf(stderr,
"Unexpected control-flow in isolated function after unexpectedpc "
"or anypc block: 0x%" TARGET_REG_FORMAT "\n",
Target);
break;
case BadReturnAddress:
fprintf(stderr,
"Expected and actual fallthrough after ret not corresponding: "
"0x%" TARGET_REG_FORMAT " / 0x%" TARGET_REG_FORMAT "\n",
Target,
ExpectedDestination);
break;
case FunctionDispatcherFallBack:
fprintf(stderr,
"Erroneous call to function dispatcher: "
"0x%" TARGET_REG_FORMAT "\n",
Target);
break;
case ReturnFromNoReturn:
fprintf(stderr,
"Execution has return from a noreturn call: "
"0x%" TARGET_REG_FORMAT "\n",
Source);
break;
default:
assert(0 && "Reason code not supported");
}
}
// Helper function used to raise an exception
noreturn void raise_exception_helper(Reason Code,
target_reg Source,
target_reg Target,
target_reg ExpectedDestination) {
noreturn void raise_exception_helper(const char *reason,
PlainMetaAddress *source,
PlainMetaAddress *destination) {
// Call the exception debug helper
exception_warning(Code, Source, Target, ExpectedDestination);
// Dump information about the exception
fprintf(stderr, "Exception: %s", reason);
fprintf(stderr, " (");
fprint_metaaddress(stderr, source);
fprintf(stderr, " -> ");
fprint_metaaddress(stderr, source);
fprintf(stderr, ")\n");
// Declare the exception object
static struct _Unwind_Exception exc;
+2 -1
View File
@@ -185,7 +185,8 @@ def build_opt_args(args):
return (prefix + [relative(get_command("opt"))]
+ interleave(roots, "-load")
+ args)
+ args
+ ["-serialize-model"])
def split_dash_dash(args):
if not args:
+1 -1
View File
@@ -52,7 +52,7 @@ macro(artifact_handler CATEGORY INPUT_FILE CONFIGURATION OUTPUT TARGET_NAME)
set(TEST_NAME test-lifted-${CATEGORY}-${ANALYSIS}-${TARGET_NAME})
add_test(NAME ${TEST_NAME}
COMMAND sh -c "./bin/revng opt --${ANALYSIS_OPT_${ANALYSIS}} --${ANALYSIS_OPT_${ANALYSIS}}-output=${ANALYSIS_OUTPUT} ${OUTPUT} -o /dev/null \
COMMAND sh -c "./bin/revng opt --${ANALYSIS_OPT_${ANALYSIS}} --${ANALYSIS_OPT_${ANALYSIS}}-output=${ANALYSIS_OUTPUT} ${OUTPUT} --debug-log=stackanalysis -o /dev/null \
&& ${ANALYSIS_DIFF_${ANALYSIS}} ${REFERENCE} ${ANALYSIS_OUTPUT}")
set_tests_properties(${TEST_NAME} PROPERTIES LABELS "analysis;${CATEGORY};${CONFIGURATION};${ANALYSIS}")
@@ -4,11 +4,11 @@
"slots" : [
{
"argument" : "Maybe",
"slot" : "rax"
"slot" : "rdx"
},
{
"return_value" : "Maybe",
"slot" : "rdx"
"slot" : "rax"
}
]
}
+42 -48
View File
@@ -228,6 +228,7 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
using RD = RelocationDescription;
using namespace llvm::ELF;
using namespace model::Register;
Architecture::RelocationTypesMap RelocationTypes;
auto Arch = TheBinary->getArch();
@@ -250,8 +251,8 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
RelocationTypes[R_386_GLOB_DAT] = RD(RD::SymbolRelative);
RelocationTypes[R_386_COPY] = RD(RD::LabelOnly, RD::TargetValue);
ABIRegisters = { { "eax" }, { "ebx" }, { "ecx" }, { "edx" },
{ "esi" }, { "edi" }, { "ebp" }, { "esp" } };
ABIRegisters = { { eax_x86 }, { ebx_x86 }, { ecx_x86 }, { edx_x86 },
{ esi_x86 }, { edi_x86 }, { ebp_x86 }, { esp_x86 } };
BasicBlockEndingPattern = "\xcc";
@@ -303,30 +304,16 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
// REGISTER_OFFSET(RIP);
// TODO: here we're hardcoding the offsets in the QEMU struct
ABIRegisters = { { "rax", 0xD },
{ "rbx", 0xB },
{ "rcx", 0xE },
{ "rdx", 0xC },
{ "rbp", 0xA },
{ "rsp", 0xF },
{ "rsi", 0x9 },
{ "rdi", 0x8 },
{ "r8", 0x0 },
{ "r9", 0x1 },
{ "r10", 0x2 },
{ "r11", 0x3 },
{ "r12", 0x4 },
{ "r13", 0x5 },
{ "r14", 0x6 },
{ "r15", 0x7 },
{ "xmm0", "state_0x8558" },
{ "xmm1", "state_0x8598" },
{ "xmm2", "state_0x85d8" },
{ "xmm3", "state_0x8618" },
{ "xmm4", "state_0x8658" },
{ "xmm5", "state_0x8698" },
{ "xmm6", "state_0x86d8" },
{ "xmm7", "state_0x8718" } };
ABIRegisters = {
{ rax_x86_64, 0xD }, { rbx_x86_64, 0xB }, { rcx_x86_64, 0xE },
{ rdx_x86_64, 0xC }, { rbp_x86_64, 0xA }, { rsp_x86_64, 0xF },
{ rsi_x86_64, 0x9 }, { rdi_x86_64, 0x8 }, { r8_x86_64, 0x0 },
{ r9_x86_64, 0x1 }, { r10_x86_64, 0x2 }, { r11_x86_64, 0x3 },
{ r12_x86_64, 0x4 }, { r13_x86_64, 0x5 }, { r14_x86_64, 0x6 },
{ r15_x86_64, 0x7 }, { xmm0_x86_64 }, { xmm1_x86_64 },
{ xmm2_x86_64 }, { xmm3_x86_64 }, { xmm4_x86_64 },
{ xmm5_x86_64 }, { xmm6_x86_64 }, { xmm7_x86_64 }
};
WriteRegisterAsm = "movq $0, %REGISTER";
ReadRegisterAsm = "movq %REGISTER, $0";
JumpAsm = "jmpq *$0";
@@ -355,9 +342,10 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
0x1, // exit
0xb // execve
};
ABIRegisters = { { "r0" }, { "r1" }, { "r2" }, { "r3" }, { "r4" },
{ "r5" }, { "r6" }, { "r7" }, { "r8" }, { "r9" },
{ "r10" }, { "r11" }, { "r12" }, { "r13" }, { "r14" } };
ABIRegisters = { { r0_arm }, { r1_arm }, { r2_arm }, { r3_arm },
{ r4_arm }, { r5_arm }, { r6_arm }, { r7_arm },
{ r8_arm }, { r9_arm }, { r10_arm }, { r11_arm },
{ r12_arm }, { r13_arm }, { r14_arm } };
PCMContextIndex = 18;
HasRelocationAddend = false;
@@ -383,13 +371,16 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
0x5d, // exit
0xdd // execve
};
ABIRegisters = { { "x0" }, { "x1" }, { "x2" }, { "x3" }, { "x4" },
{ "x5" }, { "x6" }, { "x7" }, { "x8" }, { "x9" },
{ "x10" }, { "x11" }, { "x12" }, { "x13" }, { "x14" },
{ "x15" }, { "x16" }, { "x17" }, { "x18" }, { "x19" },
{ "x20" }, { "x21" }, { "x22" }, { "x23" }, { "x24" },
{ "x25" }, { "x26" }, { "x27" }, { "x28" }, { "x29" },
{ "lr" }, { "sp" } };
ABIRegisters = {
{ x0_aarch64 }, { x1_aarch64 }, { x2_aarch64 }, { x3_aarch64 },
{ x4_aarch64 }, { x5_aarch64 }, { x6_aarch64 }, { x7_aarch64 },
{ x8_aarch64 }, { x9_aarch64 }, { x10_aarch64 }, { x11_aarch64 },
{ x12_aarch64 }, { x13_aarch64 }, { x14_aarch64 }, { x15_aarch64 },
{ x16_aarch64 }, { x17_aarch64 }, { x18_aarch64 }, { x19_aarch64 },
{ x20_aarch64 }, { x21_aarch64 }, { x22_aarch64 }, { x23_aarch64 },
{ x24_aarch64 }, { x25_aarch64 }, { x26_aarch64 }, { x27_aarch64 },
{ x28_aarch64 }, { x29_aarch64 }, { lr_aarch64 }, { sp_aarch64 }
};
HasRelocationAddend = false;
// ret
@@ -409,11 +400,11 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
0xfab // execve
};
DelaySlotSize = 1;
ABIRegisters = {
{ "v0" }, { "v1" }, { "a0" }, { "a1" }, { "a2" }, { "a3" },
{ "s0" }, { "s1" }, { "s2" }, { "s3" }, { "s4" }, { "s5" },
{ "s6" }, { "s7" }, { "gp" }, { "sp" }, { "fp" }, { "ra" }
};
ABIRegisters = { { v0_mips }, { v1_mips }, { a0_mips }, { a1_mips },
{ a2_mips }, { a3_mips }, { s0_mips }, { s1_mips },
{ s2_mips }, { s3_mips }, { s4_mips }, { s5_mips },
{ s6_mips }, { s7_mips }, { gp_mips }, { sp_mips },
{ fp_mips }, { ra_mips } };
HasRelocationAddend = false;
@@ -448,13 +439,16 @@ BinaryFile::BinaryFile(std::string FilePath, uint64_t PreferedBaseAddress) :
RelocationTypes[R_390_GLOB_DAT] = RD(RD::SymbolRelative);
RelocationTypes[R_390_COPY] = RD(RD::LabelOnly, RD::TargetValue);
ABIRegisters = { { "r0" }, { "r1" }, { "r2" }, { "r3" }, { "r4" },
{ "r5" }, { "r6" }, { "r7" }, { "r8" }, { "r9" },
{ "r10" }, { "r11" }, { "r12" }, { "r13" }, { "r14" },
{ "r15" }, { "f0" }, { "f1" }, { "f2" }, { "f3" },
{ "f4" }, { "f5" }, { "f6" }, { "f7" }, { "f8" },
{ "f9" }, { "f10" }, { "f11" }, { "f12" }, { "f13" },
{ "f14" }, { "f15" } };
ABIRegisters = {
{ r0_systemz }, { r1_systemz }, { r2_systemz }, { r3_systemz },
{ r4_systemz }, { r5_systemz }, { r6_systemz }, { r7_systemz },
{ r8_systemz }, { r9_systemz }, { r10_systemz }, { r11_systemz },
{ r12_systemz }, { r13_systemz }, { r14_systemz }, { r15_systemz },
{ f0_systemz }, { f1_systemz }, { f2_systemz }, { f3_systemz },
{ f4_systemz }, { f5_systemz }, { f6_systemz }, { f7_systemz },
{ f8_systemz }, { f9_systemz }, { f10_systemz }, { f11_systemz },
{ f12_systemz }, { f13_systemz }, { f14_systemz }, { f15_systemz }
};
break;
+1 -1
View File
@@ -955,7 +955,7 @@ void CodeGenerator::translate(Optional<uint64_t> RawVirtualAddress) {
const SmallVector<ABIRegister, 20> &ABIRegisters = Arch.abiRegisters();
SmallVector<Metadata *, 20> ABIRegMetadata;
for (auto Register : ABIRegisters)
ABIRegMetadata.push_back(MDString::get(Context, Register.name()));
ABIRegMetadata.push_back(MDString::get(Context, Register.csvName()));
auto *Tuple = MDTuple::get(Context,
{
+2 -2
View File
@@ -55,7 +55,7 @@ BasicBlock *ExternalJumpsHandler::createReturnFromExternal() {
// Deserialize the ABI registers
for (const ABIRegister &Register : Arch.abiRegisters()) {
GlobalVariable *CSV = TheModule.getGlobalVariable(Register.qemuName());
GlobalVariable *CSV = TheModule.getGlobalVariable(Register.csvName());
// Not all the registers have a corresponding CSV
if (CSV != nullptr) {
@@ -122,7 +122,7 @@ BasicBlock *ExternalJumpsHandler::createSerializeAndJumpOut() {
// Serialize ABI CSVs
for (const ABIRegister &Register : Arch.abiRegisters()) {
GlobalVariable *CSV = TheModule.getGlobalVariable(Register.qemuName());
GlobalVariable *CSV = TheModule.getGlobalVariable(Register.csvName());
// Not all the registers have a corresponding CSV
if (CSV == nullptr)