mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Drop StackAnalysis
This commit is contained in:
@@ -60,9 +60,6 @@
|
||||
#include "revng/Support/MetaAddress.h"
|
||||
|
||||
#include "ABIAnalyses/ABIAnalysis.h"
|
||||
#include "Cache.h"
|
||||
#include "InterproceduralAnalysis.h"
|
||||
#include "Intraprocedural.h"
|
||||
|
||||
using llvm::ArrayRef;
|
||||
using llvm::BasicBlock;
|
||||
@@ -82,7 +79,6 @@ using GCBI = GeneratedCodeBasicInfo;
|
||||
using namespace llvm::cl;
|
||||
|
||||
static Logger<> CFEPLog("cfep");
|
||||
static Logger<> ClobberedLog("clobbered");
|
||||
static Logger<> StackAnalysisLog("stackanalysis");
|
||||
|
||||
struct BasicBlockNodeData {
|
||||
@@ -114,19 +110,11 @@ struct llvm::DOTGraphTraits<SmallCallGraph *>
|
||||
|
||||
namespace StackAnalysis {
|
||||
|
||||
const std::set<llvm::GlobalVariable *> EmptyCSVSet;
|
||||
|
||||
char StackAnalysis::ID = 0;
|
||||
|
||||
using RegisterABI = RegisterPass<StackAnalysis>;
|
||||
static RegisterABI Y("abi-analysis", "ABI Analysis Pass", true, true);
|
||||
|
||||
static opt<std::string> ABIAnalysisOutputPath("abi-analysis-output",
|
||||
desc("Destination path for the "
|
||||
"ABI Analysis Pass"),
|
||||
value_desc("path"),
|
||||
cat(MainCategory));
|
||||
|
||||
static opt<std::string> CallGraphOutputPath("cg-output",
|
||||
desc("Dump to disk the recovered "
|
||||
"call graph."),
|
||||
@@ -479,371 +467,6 @@ CFEPAnalyzer<FunctionOracle>::CFEPAnalyzer(llvm::Module &M,
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// Create all the model::Function
|
||||
//
|
||||
for (const auto &[Entry, FunctionSummary] : Summary.Functions) {
|
||||
if (Entry == nullptr)
|
||||
continue;
|
||||
|
||||
// Get the entry point address
|
||||
MetaAddress EntryPC = getBasicBlockPC(Entry);
|
||||
revng_assert(EntryPC.isValid());
|
||||
|
||||
model::Function &Function = Binary.Functions[EntryPC];
|
||||
|
||||
// Assign a name
|
||||
|
||||
using FT = model::FunctionType::Values;
|
||||
Function.Type = static_cast<FT>(FunctionSummary.Type);
|
||||
|
||||
if (Function.Type == model::FunctionType::Fake)
|
||||
continue;
|
||||
|
||||
// Build the function prototype
|
||||
auto NewType = makeType<RawFunctionType>();
|
||||
auto &FunctionType = *llvm::cast<RawFunctionType>(NewType.get());
|
||||
{
|
||||
auto ArgumentsInserter = FunctionType.Arguments.batch_insert();
|
||||
auto ReturnValuesInserter = FunctionType.ReturnValues.batch_insert();
|
||||
for (auto &[CSV, FRD] : FunctionSummary.RegisterSlots) {
|
||||
auto RegisterID = ABIRegister::fromCSVName(CSV->getName(), GCBI.arch());
|
||||
if (RegisterID == Register::Invalid or CSV == GCBI.spReg())
|
||||
continue;
|
||||
|
||||
llvm::Type *CSVType = CSV->getType()->getPointerElementType();
|
||||
auto CSVSize = CSVType->getIntegerBitWidth() / 8;
|
||||
NamedTypedRegister TR(RegisterID);
|
||||
TR.Type = {
|
||||
TheBinary.getPrimitiveType(PrimitiveTypeKind::Generic, CSVSize), {}
|
||||
};
|
||||
|
||||
if (model::RegisterState::shouldEmit(toRegisterState(FRD.Argument)))
|
||||
ArgumentsInserter.insert(TR);
|
||||
|
||||
if (model::RegisterState::shouldEmit(toRegisterState(FRD.ReturnValue)))
|
||||
ReturnValuesInserter.insert(TR);
|
||||
|
||||
// TODO: populate preserved registers
|
||||
}
|
||||
}
|
||||
|
||||
Function.Prototype = TheBinary.recordNewType(std::move(NewType));
|
||||
}
|
||||
|
||||
//
|
||||
// Populate the CFG
|
||||
//
|
||||
for (const auto &[Entry, FunctionSummary] : Summary.Functions) {
|
||||
if (Entry == nullptr)
|
||||
continue;
|
||||
MetaAddress EntryPC = getBasicBlockPC(Entry);
|
||||
|
||||
auto It = TheBinary.Functions.find(EntryPC);
|
||||
if (It == TheBinary.Functions.end())
|
||||
continue;
|
||||
|
||||
model::Function &Function = *It;
|
||||
|
||||
if (Function.Type == model::FunctionType::Fake)
|
||||
continue;
|
||||
|
||||
auto MakeEdge = [](MetaAddress Destination, FunctionEdgeType::Values Type) {
|
||||
FunctionEdge *Result = nullptr;
|
||||
if (FunctionEdgeType::isCall(Type))
|
||||
Result = new CallEdge(Destination, Type);
|
||||
else
|
||||
Result = new FunctionEdge(Destination, Type);
|
||||
return UpcastablePointer<FunctionEdge>(Result);
|
||||
};
|
||||
|
||||
// Handle the situation in which we found no basic blocks at all
|
||||
if (Function.Type == model::FunctionType::NoReturn
|
||||
and FunctionSummary.BasicBlocks.size() == 0) {
|
||||
auto &EntryNodeSuccessors = Function.CFG[EntryPC].Successors;
|
||||
auto Edge = MakeEdge(MetaAddress::invalid(), FunctionEdgeType::LongJmp);
|
||||
EntryNodeSuccessors.insert(Edge);
|
||||
}
|
||||
|
||||
for (auto &[BB, Branch] : FunctionSummary.BasicBlocks) {
|
||||
// Remap BranchType to FunctionEdgeType
|
||||
namespace FET = FunctionEdgeType;
|
||||
FET::Values EdgeType = FET::Invalid;
|
||||
|
||||
switch (Branch) {
|
||||
case BranchType::Invalid:
|
||||
case BranchType::FakeFunction:
|
||||
case BranchType::RegularFunction:
|
||||
case BranchType::NoReturnFunction:
|
||||
case BranchType::UnhandledCall:
|
||||
revng_abort();
|
||||
break;
|
||||
|
||||
case BranchType::InstructionLocalCFG:
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 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;
|
||||
auto SuccessorsInserter = CurrentBlock.Successors.batch_insert();
|
||||
|
||||
llvm::BasicBlock *Successor = BB->getSingleSuccessor();
|
||||
llvm::StringRef SymbolName;
|
||||
|
||||
MetaAddress Destination = MetaAddress::invalid();
|
||||
if (Successor != nullptr)
|
||||
Destination = getBasicBlockPC(Successor);
|
||||
|
||||
if (Destination.isValid()) {
|
||||
revng_assert(not JumpTargetBB->empty());
|
||||
auto *NewPCCall = getCallTo(&*Successor->begin(), "newpc");
|
||||
revng_assert(NewPCCall != nullptr);
|
||||
|
||||
// Extract symbol name if any
|
||||
auto *SymbolNameValue = NewPCCall->getArgOperand(4);
|
||||
if (not isa<llvm::ConstantPointerNull>(SymbolNameValue)) {
|
||||
llvm::Value *SymbolNameString = NewPCCall->getArgOperand(4);
|
||||
SymbolName = extractFromConstantStringPtr(SymbolNameString);
|
||||
revng_assert(SymbolName.size() != 0);
|
||||
}
|
||||
}
|
||||
|
||||
switch (Branch) {
|
||||
case BranchType::Invalid:
|
||||
case BranchType::FakeFunction:
|
||||
case BranchType::RegularFunction:
|
||||
case BranchType::NoReturnFunction:
|
||||
case BranchType::UnhandledCall:
|
||||
case BranchType::InstructionLocalCFG:
|
||||
revng_abort();
|
||||
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:
|
||||
EdgeType = FET::FunctionCall;
|
||||
break;
|
||||
|
||||
case BranchType::IndirectCall:
|
||||
if (SymbolName.size() == 0)
|
||||
EdgeType = FET::IndirectCall;
|
||||
else
|
||||
EdgeType = FET::FunctionCall;
|
||||
break;
|
||||
|
||||
case BranchType::Return:
|
||||
EdgeType = FET::Return;
|
||||
break;
|
||||
|
||||
case BranchType::BrokenReturn:
|
||||
EdgeType = FET::BrokenReturn;
|
||||
break;
|
||||
|
||||
case BranchType::IndirectTailCall:
|
||||
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::DirectBranch) {
|
||||
// Handle direct branch
|
||||
auto Successors = GCBI.getSuccessors(BB);
|
||||
for (const MetaAddress &Destination : Successors.Addresses)
|
||||
SuccessorsInserter.insert(MakeEdge(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(MakeEdge(Destination, EdgeType));
|
||||
|
||||
} else if (FunctionEdgeType::isCall(EdgeType)) {
|
||||
// Record the edge in the CFG
|
||||
auto TempEdge = MakeEdge(Destination, EdgeType);
|
||||
const auto &Result = SuccessorsInserter.insert(TempEdge);
|
||||
auto *Edge = llvm::cast<CallEdge>(Result.get());
|
||||
|
||||
const auto IDF = TheBinary.ImportedDynamicFunctions;
|
||||
bool IsDynamicCall = (not SymbolName.empty()
|
||||
and IDF.count(SymbolName.str()) != 0);
|
||||
if (IsDynamicCall) {
|
||||
// It's a dynamic function call
|
||||
revng_assert(EdgeType == model::FunctionEdgeType::FunctionCall);
|
||||
Edge->Destination = MetaAddress::invalid();
|
||||
Edge->DynamicFunction = SymbolName.str();
|
||||
|
||||
// The prototype is implicitly the one of the callee
|
||||
revng_assert(not Edge->Prototype.isValid());
|
||||
} else if (Destination.isValid()) {
|
||||
// It's a simple direct function call
|
||||
revng_assert(EdgeType == model::FunctionEdgeType::FunctionCall);
|
||||
|
||||
// The prototype is implicitly the one of the callee
|
||||
revng_assert(not Edge->Prototype.isValid());
|
||||
} else {
|
||||
// It's an indirect call: forge a new prototype
|
||||
auto NewType = makeType<RawFunctionType>();
|
||||
auto &CallType = *llvm::cast<RawFunctionType>(NewType.get());
|
||||
{
|
||||
auto ArgumentsInserter = CallType.Arguments.batch_insert();
|
||||
auto ReturnValuesInserter = CallType.ReturnValues.batch_insert();
|
||||
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;
|
||||
for (auto &[CSV, FCRD] : CSD.RegisterSlots) {
|
||||
auto RegisterID = ABIRegister::fromCSVName(CSV->getName(),
|
||||
GCBI.arch());
|
||||
if (RegisterID == model::Register::Invalid
|
||||
or CSV == GCBI.spReg())
|
||||
continue;
|
||||
|
||||
llvm::Type *CSVType = CSV->getType()->getPointerElementType();
|
||||
auto CSVSize = CSVType->getIntegerBitWidth() / 8;
|
||||
NamedTypedRegister TR(RegisterID);
|
||||
TR.Type = {
|
||||
TheBinary.getPrimitiveType(model::PrimitiveTypeKind::Generic,
|
||||
CSVSize),
|
||||
{}
|
||||
};
|
||||
|
||||
auto ArgumentState = toRegisterState(FCRD.Argument);
|
||||
if (model::RegisterState::shouldEmit(ArgumentState))
|
||||
ArgumentsInserter.insert(TR);
|
||||
|
||||
auto ReturnValueState = toRegisterState(FCRD.ReturnValue);
|
||||
if (model::RegisterState::shouldEmit(ReturnValueState))
|
||||
ReturnValuesInserter.insert(TR);
|
||||
|
||||
// TODO: populate preserved registers and FinalStackOffset
|
||||
}
|
||||
}
|
||||
revng_assert(Found);
|
||||
}
|
||||
|
||||
Edge->Prototype = TheBinary.recordNewType(std::move(NewType));
|
||||
}
|
||||
} else {
|
||||
// Handle other successors
|
||||
llvm::BasicBlock *Successor = BB->getSingleSuccessor();
|
||||
|
||||
// Record the edge in the CFG
|
||||
SuccessorsInserter.insert(MakeEdge(Destination, EdgeType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
revng_check(TheBinary.verify(true));
|
||||
}
|
||||
|
||||
static UpcastablePointer<model::Type>
|
||||
buildPrototype(GeneratedCodeBasicInfo &GCBI,
|
||||
model::Binary &Binary,
|
||||
@@ -2301,196 +1924,7 @@ bool StackAnalysis::runOnModule(Module &M) {
|
||||
// Finalize model
|
||||
finalizeModel(GCBI, Functions, ABIRegisters, Properties, Binary);
|
||||
|
||||
// Initialize the cache where all the results will be accumulated
|
||||
Cache TheCache(&F, &GCBI);
|
||||
|
||||
// Pool where the final results will be collected
|
||||
ResultsPool Results;
|
||||
|
||||
// First analyze all the `Force`d functions (i.e., with an explicit direct
|
||||
// call)
|
||||
for (CFEP &Function : Functions) {
|
||||
if (Function.Force) {
|
||||
auto &GCBI = getAnalysis<GeneratedCodeBasicInfoWrapperPass>().getGCBI();
|
||||
InterproceduralAnalysis SA(TheCache, GCBI);
|
||||
SA.run(Function.Entry, Results);
|
||||
}
|
||||
}
|
||||
|
||||
// Now analyze all the remaining candidates which are not already part of
|
||||
// another function
|
||||
std::set<BasicBlock *> Visited = Results.visitedBlocks();
|
||||
for (CFEP &Function : Functions) {
|
||||
if (not Function.Force and Visited.count(Function.Entry) == 0) {
|
||||
auto &GCBI = getAnalysis<GeneratedCodeBasicInfoWrapperPass>().getGCBI();
|
||||
InterproceduralAnalysis SA(TheCache, GCBI);
|
||||
SA.run(Function.Entry, Results);
|
||||
}
|
||||
}
|
||||
|
||||
for (CFEP &Function : Functions) {
|
||||
using IFS = IntraproceduralFunctionSummary;
|
||||
BasicBlock *Entry = Function.Entry;
|
||||
llvm::Optional<const IFS *> Cached = TheCache.get(Entry);
|
||||
revng_assert(Cached or TheCache.isFakeFunction(Entry));
|
||||
|
||||
// Has this function been analyzed already? If so, only now we register it
|
||||
// in the ResultsPool.
|
||||
FunctionType::Values Type;
|
||||
if (TheCache.isFakeFunction(Entry))
|
||||
Type = FunctionType::Fake;
|
||||
else if (TheCache.isNoReturnFunction(Entry))
|
||||
Type = FunctionType::NoReturn;
|
||||
else
|
||||
Type = FunctionType::Regular;
|
||||
|
||||
// Regular functions need to be composed by at least a basic block
|
||||
if (Cached) {
|
||||
const IFS *Summary = *Cached;
|
||||
if (Type == FunctionType::Regular)
|
||||
revng_assert(Summary->BranchesType.size() != 0);
|
||||
|
||||
Results.registerFunction(Entry, Type, Summary);
|
||||
} else {
|
||||
Results.registerFunction(Entry, Type, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
GrandResult = Results.finalize(&M, &TheCache);
|
||||
|
||||
if (ClobberedLog.isEnabled()) {
|
||||
for (auto &P : GrandResult.Functions) {
|
||||
ClobberedLog << getName(P.first) << ":";
|
||||
for (const llvm::GlobalVariable *CSV : P.second.ClobberedRegisters)
|
||||
ClobberedLog << " " << CSV->getName().data();
|
||||
ClobberedLog << DoLog;
|
||||
}
|
||||
}
|
||||
|
||||
if (StackAnalysisLog.isEnabled()) {
|
||||
std::stringstream Output;
|
||||
GrandResult.dump(&M, Output);
|
||||
TextRepresentation = Output.str();
|
||||
revng_log(StackAnalysisLog, TextRepresentation);
|
||||
}
|
||||
|
||||
revng_log(PassesLog, "Ending StackAnalysis");
|
||||
|
||||
if (ABIAnalysisOutputPath.getNumOccurrences() == 1) {
|
||||
std::ofstream Output;
|
||||
serialize(pathToStream(ABIAnalysisOutputPath, Output));
|
||||
}
|
||||
|
||||
#if 0
|
||||
commitToModel(GCBI, &F, GrandResult, Binary);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void StackAnalysis::serializeMetadata(Function &F,
|
||||
GeneratedCodeBasicInfo &GCBI) {
|
||||
using namespace llvm;
|
||||
|
||||
const FunctionsSummary &Summary = GrandResult;
|
||||
|
||||
LLVMContext &Context = getContext(&F);
|
||||
QuickMetadata QMD(Context);
|
||||
|
||||
// Temporary data structure so we can set all the `revng.func.member.of` in a
|
||||
// single shot at the end
|
||||
std::map<Instruction *, std::vector<Metadata *>> MemberOf;
|
||||
|
||||
// Loop over all the detected functions
|
||||
for (const auto &P : Summary.Functions) {
|
||||
BasicBlock *Entry = P.first;
|
||||
const FunctionsSummary::FunctionDescription &Function = P.second;
|
||||
|
||||
if (Entry == nullptr or Function.BasicBlocks.size() == 0)
|
||||
continue;
|
||||
|
||||
MetaAddress EntryPC = getBasicBlockPC(Entry);
|
||||
|
||||
//
|
||||
// Add `revng.func.entry`:
|
||||
// {
|
||||
// name,
|
||||
// address,
|
||||
// type,
|
||||
// { clobbered csv, ... },
|
||||
// { { csv, argument, return value }, ... }
|
||||
// }
|
||||
//
|
||||
auto *TypeMD = QMD.get(FunctionType::getName(Function.Type));
|
||||
|
||||
// Clobbered registers metadata
|
||||
std::vector<Metadata *> ClobberedMDs;
|
||||
for (GlobalVariable *ClobberedCSV : Function.ClobberedRegisters) {
|
||||
if (not GCBI.isServiceRegister(ClobberedCSV))
|
||||
ClobberedMDs.push_back(QMD.get(ClobberedCSV));
|
||||
}
|
||||
|
||||
// Register slots metadata
|
||||
std::vector<Metadata *> SlotMDs;
|
||||
for (auto &P : Function.RegisterSlots) {
|
||||
if (GCBI.isServiceRegister(P.first))
|
||||
continue;
|
||||
|
||||
auto *CSV = QMD.get(P.first);
|
||||
auto *Argument = QMD.get(P.second.Argument.valueName());
|
||||
auto *ReturnValue = QMD.get(P.second.ReturnValue.valueName());
|
||||
SlotMDs.push_back(QMD.tuple({ CSV, Argument, ReturnValue }));
|
||||
}
|
||||
|
||||
// Create revng.func.entry metadata
|
||||
MDTuple *FunctionMD = QMD.tuple({ QMD.get(getName(Entry)),
|
||||
QMD.get(GCBI.toConstant(EntryPC)),
|
||||
TypeMD,
|
||||
QMD.tuple(ClobberedMDs),
|
||||
QMD.tuple(SlotMDs) });
|
||||
Entry->getTerminator()->setMetadata("revng.func.entry", FunctionMD);
|
||||
|
||||
//
|
||||
// Create func.call
|
||||
//
|
||||
for (const FunctionsSummary::CallSiteDescription &CallSite :
|
||||
Function.CallSites) {
|
||||
Instruction *Call = CallSite.Call;
|
||||
|
||||
// Register slots metadata
|
||||
std::vector<Metadata *> SlotMDs;
|
||||
for (auto &P : CallSite.RegisterSlots) {
|
||||
if (GCBI.isServiceRegister(P.first))
|
||||
continue;
|
||||
|
||||
auto *CSV = QMD.get(P.first);
|
||||
auto *Argument = QMD.get(P.second.Argument.valueName());
|
||||
auto *ReturnValue = QMD.get(P.second.ReturnValue.valueName());
|
||||
SlotMDs.push_back(QMD.tuple({ CSV, Argument, ReturnValue }));
|
||||
}
|
||||
|
||||
Call->setMetadata("func.call", QMD.tuple(QMD.tuple(SlotMDs)));
|
||||
}
|
||||
|
||||
//
|
||||
// Create revng.func.member.of
|
||||
//
|
||||
|
||||
// Loop over all the basic blocks composing the function
|
||||
for (const auto &P : Function.BasicBlocks) {
|
||||
BasicBlock *BB = P.first;
|
||||
BranchType::Values Type = P.second;
|
||||
|
||||
auto *Pair = QMD.tuple({ FunctionMD, QMD.get(getName(Type)) });
|
||||
|
||||
// Register that this block is associated to this function
|
||||
MemberOf[BB->getTerminator()].push_back(Pair);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply `revng.func.member.of`
|
||||
for (auto &P : MemberOf)
|
||||
P.first->setMetadata("revng.func.member.of", QMD.tuple(P.second));
|
||||
}
|
||||
|
||||
} // namespace StackAnalysis
|
||||
|
||||
Reference in New Issue
Block a user