From 51682eb024762afc487a8bb0a09cc9b92abc0730 Mon Sep 17 00:00:00 2001 From: Alessandro Di Federico Date: Tue, 27 Apr 2021 17:29:23 +0200 Subject: [PATCH] model::FunctionEdge: carve out CallEdge --- include/revng/Model/Binary.h | 94 +++++++++++++++++++++- lib/FunctionIsolation/EnforceABI.cpp | 23 +++--- lib/FunctionIsolation/IsolateFunctions.cpp | 8 +- lib/Model/Binary.cpp | 16 ++-- lib/StackAnalysis/StackAnalysis.cpp | 29 ++++--- 5 files changed, 132 insertions(+), 38 deletions(-) diff --git a/include/revng/Model/Binary.h b/include/revng/Model/Binary.h index c3770354d..461a456f9 100644 --- a/include/revng/Model/Binary.h +++ b/include/revng/Model/Binary.h @@ -9,6 +9,8 @@ #include "revng/ADT/KeyedObjectContainer.h" #include "revng/ADT/MutableSet.h" #include "revng/ADT/SortedVector.h" +#include "revng/ADT/UpcastablePointer.h" +#include "revng/ADT/UpcastablePointer/YAMLTraits.h" #include "revng/Model/TupleTree.h" #include "revng/Support/MetaAddress.h" #include "revng/Support/MetaAddress/KeyTraits.h" @@ -20,6 +22,7 @@ namespace model { class Function; class Binary; class FunctionEdge; +class CallEdge; class FunctionABIRegister; class BasicBlock; } // namespace model @@ -674,6 +677,26 @@ inline bool hasDestination(Values V) { } } +inline bool isCall(Values V) { + switch (V) { + case FunctionCall: + case IndirectCall: + case IndirectTailCall: + return true; + + case Invalid: + case DirectBranch: + case FakeFunctionCall: + case FakeFunctionReturn: + case Return: + case BrokenReturn: + case LongJmp: + case Killer: + case Unreachable: + return false; + } +} + } // namespace model::FunctionEdgeType namespace llvm::yaml { @@ -723,9 +746,10 @@ public: /// Edge target. If invalid, it's an indirect edge MetaAddress Destination; FunctionEdgeType::Values Type; - SortedVector Registers; public: + FunctionEdge() : + Destination(MetaAddress::invalid()), Type(FunctionEdgeType::Invalid) {} FunctionEdge(MetaAddress Destination, FunctionEdgeType::Values Type) : Destination(Destination), Type(Type) {} @@ -738,17 +762,62 @@ public: return ThisTie < OtherTie; } +public: + static constexpr const char *Tag = "!FunctionEdge"; + static bool classof(const FunctionEdge *A) { + return not FunctionEdgeType::isCall(A->Type); + } + bool verify() const debug_function; }; -INTROSPECTION_NS(model, FunctionEdge, Destination, Type, Registers); +INTROSPECTION_NS(model, FunctionEdge, Destination, Type); + +class model::CallEdge : public model::FunctionEdge { +public: + using Key = std::pair; + +public: + SortedVector Registers; + +public: + CallEdge() : + FunctionEdge(MetaAddress::invalid(), FunctionEdgeType::FunctionCall) {} + CallEdge(MetaAddress Destination, FunctionEdgeType::Values Type) : + FunctionEdge(Destination, Type) { + revng_assert(FunctionEdgeType::isCall(Type)); + } + +public: + static constexpr const char *Tag = "!CallEdge"; + static bool classof(const FunctionEdge *A) { + return FunctionEdgeType::isCall(A->Type); + } + +public: + bool verify() const debug_function; +}; +INTROSPECTION_NS(model, CallEdge, Destination, Type, Registers); + +template<> +struct concrete_types_traits { + using type = std::tuple; +}; + +template<> +class llvm::yaml::MappingTraits> + : public PolymorphicMappingTraits> {}; template<> struct llvm::yaml::MappingTraits : public TupleLikeMappingTraits {}; +template<> +struct llvm::yaml::MappingTraits + : public TupleLikeMappingTraits {}; + template<> struct llvm::yaml::ScalarTraits - : CompositeScalar {}; + : public CompositeScalar {}; template<> struct KeyedObjectTraits { @@ -762,6 +831,23 @@ struct KeyedObjectTraits { } }; +template<> +struct KeyedObjectTraits> { + using Key = model::FunctionEdge::Key; + static Key key(const UpcastablePointer &Obj) { + return { Obj->Destination, Obj->Type }; + } + + static UpcastablePointer fromKey(const Key &Obj) { + using ResultType = UpcastablePointer; + if (model::FunctionEdgeType::isCall(Obj.second)) { + return ResultType(new model::CallEdge(Obj.first, Obj.second)); + } else { + return ResultType(new model::FunctionEdge(Obj.first, Obj.second)); + } + } +}; + // // FunctionType // @@ -792,7 +878,7 @@ public: MetaAddress Start; MetaAddress End; std::string Name; - SortedVector Successors; + SortedVector> Successors; public: BasicBlock(const MetaAddress &Start) : Start(Start) {} diff --git a/lib/FunctionIsolation/EnforceABI.cpp b/lib/FunctionIsolation/EnforceABI.cpp index 8f6faf463..7acc8ec7a 100644 --- a/lib/FunctionIsolation/EnforceABI.cpp +++ b/lib/FunctionIsolation/EnforceABI.cpp @@ -83,11 +83,12 @@ static bool areCompatible(const model::FunctionABIRegister &LHS, and areCompatible(LHS.ReturnValue, RHS.ReturnValue); } -static StringRef areCompatible(const model::Function &Callee, - const model::FunctionEdge &CallSite) { +static StringRef +areCompatible(const model::Function &Callee, const model::CallEdge &Edge) { + for (const model::FunctionABIRegister &Register : Callee.Registers) { - auto It = CallSite.Registers.find(Register.Register); - if (It != CallSite.Registers.end() and not areCompatible(Register, *It)) { + auto It = Edge.Registers.find(Register.Register); + if (It != Edge.Registers.end() and not areCompatible(Register, *It)) { return model::Register::getName(Register.Register); } } @@ -116,7 +117,7 @@ private: void handleRegularFunctionCall(CallInst *Call); void generateCall(IRBuilder<> &Builder, Function *Callee, - const model::FunctionEdge &CallSite); + const model::CallEdge &CallSite); void handleRoot(); private: @@ -353,14 +354,12 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { // 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) { + const model::CallEdge *CallSite = nullptr; + for (const auto &Edge : Block.Successors) { using namespace model::FunctionEdgeType; - if (Edge.Type == FunctionCall or Edge.Type == IndirectCall - or Edge.Type == IndirectTailCall) { - CallSite = &Edge; + CallSite = dyn_cast(Edge.get()); + if (CallSite != nullptr) break; - } } if (DisableSafetyChecks or IsDirect) { @@ -433,7 +432,7 @@ void EnforceABIImpl::handleRegularFunctionCall(CallInst *Call) { void EnforceABIImpl::generateCall(IRBuilder<> &Builder, Function *Callee, - const model::FunctionEdge &CallSite) { + const model::CallEdge &CallSite) { revng_assert(Callee != nullptr); llvm::SmallVector ArgumentsTypes; diff --git a/lib/FunctionIsolation/IsolateFunctions.cpp b/lib/FunctionIsolation/IsolateFunctions.cpp index 8cc10281c..abc6cb84f 100644 --- a/lib/FunctionIsolation/IsolateFunctions.cpp +++ b/lib/FunctionIsolation/IsolateFunctions.cpp @@ -625,10 +625,10 @@ void IFI::handleBasicBlock(const model::BasicBlock &Block, // if any SuccessorsContainer ExpectedSuccessors; - for (const model::FunctionEdge &E : Block.Successors) { + for (const auto &E : Block.Successors) { // Ignore self-loops - if (E.Destination != Block.Start) { - ExpectedSuccessors[E] = 0; + if (E->Destination != Block.Start) { + ExpectedSuccessors[*E] = 0; } } @@ -646,7 +646,7 @@ void IFI::handleBasicBlock(const model::BasicBlock &Block, { raw_string_ostream StringStream(Buffer); yaml::Output YAMLOutput(StringStream); - for (model::FunctionEdge Edge : Block.Successors) { + for (auto Edge : Block.Successors) { YAMLOutput << Edge; } } diff --git a/lib/Model/Binary.cpp b/lib/Model/Binary.cpp index 2c92c61bd..81bb6e874 100644 --- a/lib/Model/Binary.cpp +++ b/lib/Model/Binary.cpp @@ -79,9 +79,9 @@ bool Binary::verify() const { // Ensure all the direct function calls target an existing function for (const BasicBlock &Block : F.CFG) { - for (const FunctionEdge &Edge : Block.Successors) { - if (Edge.Type == FunctionEdgeType::FunctionCall - and Functions.count(Edge.Destination) == 0) { + for (const auto &Edge : Block.Successors) { + if (Edge->Type == FunctionEdgeType::FunctionCall + and Functions.count(Edge->Destination) == 0) { return false; } } @@ -98,8 +98,8 @@ static FunctionCFG getGraph(const Function &F) { for (const BasicBlock &Block : F.CFG) { auto *Source = Graph.get(Block.Start); - for (const FunctionEdge &Edge : Block.Successors) { - switch (Edge.Type) { + for (const auto &Edge : Block.Successors) { + switch (Edge->Type) { case DirectBranch: case FakeFunctionCall: case FakeFunctionReturn: @@ -108,7 +108,7 @@ static FunctionCFG getGraph(const Function &F) { case IndirectTailCall: case LongJmp: case Unreachable: - Source->addSuccessor(Graph.get(Edge.Destination)); + Source->addSuccessor(Graph.get(Edge->Destination)); break; case FunctionCall: @@ -140,8 +140,8 @@ void Function::dumpCFG() const { bool Function::verify() const { // Verify blocks for (const BasicBlock &Block : CFG) - for (const FunctionEdge &Edge : Block.Successors) - if (not Edge.verify()) + for (const auto &Edge : Block.Successors) + if (not Edge->verify()) return false; // Populate graph diff --git a/lib/StackAnalysis/StackAnalysis.cpp b/lib/StackAnalysis/StackAnalysis.cpp index af0281428..5eeca61b3 100644 --- a/lib/StackAnalysis/StackAnalysis.cpp +++ b/lib/StackAnalysis/StackAnalysis.cpp @@ -165,7 +165,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, // Remap BranchType to FunctionEdgeType namespace FET = FunctionEdgeType; FET::Values EdgeType = FET::Invalid; - bool IsCall = false; switch (Branch) { case BranchType::Invalid: @@ -193,12 +192,10 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, break; case BranchType::HandledCall: - IsCall = true; EdgeType = FET::FunctionCall; break; case BranchType::IndirectCall: - IsCall = true; EdgeType = FET::IndirectCall; break; @@ -211,7 +208,6 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, break; case BranchType::IndirectTailCall: - IsCall = true; EdgeType = FET::IndirectTailCall; break; @@ -231,6 +227,8 @@ 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; @@ -244,18 +242,28 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, CurrentBlock.Name = JumpTargetBB->getName(); auto SuccessorsInserter = CurrentBlock.Successors.batch_insert(); + 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(Result); + }; + if (EdgeType == FET::DirectBranch) { // Handle direct branch auto Successors = GCBI.getSuccessors(BB); for (const MetaAddress &Destination : Successors.Addresses) - SuccessorsInserter.insert(FunctionEdge{ Destination, EdgeType }); + 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(FunctionEdge{ Destination, EdgeType }); + SuccessorsInserter.insert(MakeEdge(Destination, EdgeType)); } else if (IsCall) { // Handle call @@ -265,8 +273,9 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, Destination = getBasicBlockPC(Successor); // Record the edge in the CFG - - auto &Edge = SuccessorsInserter.insert({ Destination, EdgeType }); + auto TempEdge = MakeEdge(Destination, EdgeType); + const auto &Result = SuccessorsInserter.insert(TempEdge); + auto *Edge = llvm::cast(Result.get()); bool Found = false; for (const FunctionsSummary::CallSiteDescription &CSD : @@ -276,7 +285,7 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, revng_assert(not Found); Found = true; - auto Inserter = Edge.Registers.batch_insert(); + 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) @@ -297,7 +306,7 @@ void commitToModel(GeneratedCodeBasicInfo &GCBI, Destination = getBasicBlockPC(Successor); // Record the edge in the CFG - SuccessorsInserter.insert(FunctionEdge{ Destination, EdgeType }); + SuccessorsInserter.insert(MakeEdge(Destination, EdgeType)); } } }