Import the model's type system

This commit introduces the type system of the model along with several
various other improvements to the model and its users.

* Introduce the type system.
* Introduce possibility to tag certain fields in the model as to be
  optional during YAML serialization.
* All the `Name` fields have been replaced in favor of `CustomName` plus
  a `name` method that will use `CustomName` if available, or an
  automatically generated name otherwise.
* Make TupleTreeReferences behavior more robust: now you either need to
  have a valid pointer to `Root` and a `Path` or be default constructed
  (`nullptr` for `Root` and an empty `Path`). Any other configuration is
  invalid.
* The type system introduces `RawFunctionType`: this superseds the
  previous way in which we were specifying arguments and return
  values. Users of such information have been updated accordingly.
This commit is contained in:
Alessandro Di Federico
2021-07-15 11:55:31 +02:00
parent 0f8fa271d9
commit fd30d3de42
16 changed files with 3074 additions and 329 deletions
+95 -36
View File
@@ -124,14 +124,13 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
model::Binary &TheBinary) {
using namespace model;
//
// Create all the model::Function
//
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());
@@ -141,8 +140,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
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);
@@ -150,20 +147,54 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
if (Function.Type == model::FunctionType::Fake)
continue;
// Populate arguments and return values
// Build the function prototype
auto NewType = makeType<RawFunctionType>();
auto &FunctionType = *llvm::cast<RawFunctionType>(NewType.get());
{
auto Inserter = Function.Registers.batch_insert();
auto ArgumentsInserter = FunctionType.Arguments.batch_insert();
auto ReturnValuesInserter = FunctionType.ReturnValues.batch_insert();
for (auto &[CSV, FRD] : FunctionSummary.RegisterSlots) {
auto ID = ABIRegister::fromCSVName(CSV->getName(), GCBI.arch());
if (ID == model::Register::Invalid)
auto RegisterID = ABIRegister::fromCSVName(CSV->getName(), GCBI.arch());
if (RegisterID == Register::Invalid or CSV == GCBI.spReg())
continue;
FunctionABIRegister TheRegister(ID);
TheRegister.Argument = toRegisterState(FRD.Argument);
TheRegister.ReturnValue = toRegisterState(FRD.ReturnValue);
Inserter.insert(TheRegister);
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))
@@ -247,8 +278,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
if (EdgeType == FET::Invalid)
continue;
bool IsCall = FunctionEdgeType::isCall(EdgeType);
// Identify Source address
auto [Source, Size] = getPC(BB->getTerminator());
Source += Size;
@@ -259,7 +288,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
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) {
@@ -275,7 +303,7 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
for (const auto &[_, Destination] : make_range(First, Last))
SuccessorsInserter.insert(MakeEdge(Destination, EdgeType));
} else if (IsCall) {
} else if (FunctionEdgeType::isCall(EdgeType)) {
// Handle call
llvm::BasicBlock *Successor = BB->getSingleSuccessor();
MetaAddress Destination = MetaAddress::invalid();
@@ -287,26 +315,57 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
const auto &Result = SuccessorsInserter.insert(TempEdge);
auto *Edge = llvm::cast<CallEdge>(Result.get());
bool Found = false;
for (const FunctionsSummary::CallSiteDescription &CSD :
FunctionSummary.CallSites) {
if (not CSD.Call->isTerminator() or CSD.Call->getParent() != BB)
continue;
if (Destination.isValid()) {
// If it's a direct call, inherit the prototype from the callee
model::Function &Callee = TheBinary.Functions.at(Destination);
Edge->Prototype = Callee.Prototype;
} 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;
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(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));
}
revng_assert(Found);
} else {
// Handle other successors
@@ -321,7 +380,7 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI,
}
}
revng_check(TheBinary.verify());
revng_check(TheBinary.verify(true));
}
bool StackAnalysis::runOnModule(Module &M) {