#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "llvm/ADT/SmallVector.h" #include "revng/EarlyFunctionAnalysis/CallHandler.h" #include "revng/EarlyFunctionAnalysis/Outliner.h" #include "revng/EarlyFunctionAnalysis/TemporaryOpaqueFunction.h" #include "revng/Model/Binary.h" #include "revng/Support/IRBuilder.h" #include "revng/Support/OpaqueFunctionsPool.h" #include "revng/Support/OpaqueRegisterUser.h" class GeneratedCodeBasicInfo; class ProgramCounterHandler; class FunctionSummaryOracle; namespace llvm { class Module; class GlobalVariable; class Function; } // namespace llvm namespace efa { class CallSummarizer : public CallHandler { private: llvm::Module *M = nullptr; llvm::Function *PreCallHook = nullptr; llvm::Function *PostCallHook = nullptr; llvm::Function *RetHook = nullptr; llvm::GlobalVariable *SPCSV = nullptr; llvm::SmallSet *ReturnBlocks = nullptr; OpaqueRegisterUser Clobberer; public: CallSummarizer(llvm::Module *M, llvm::Function *PreCallHook, llvm::Function *PostCallHook, llvm::Function *RetHook, llvm::GlobalVariable *SPCSV, llvm::SmallSet *ReturnBlocks); public: void handleCall(MetaAddress CallerBlock, revng::IRBuilder &Builder, MetaAddress Callee, const CSVSet &ClobberedRegisters, const std::optional &MaybeFSO, bool IsNoReturn, bool IsTailCall, llvm::Value *SymbolNamePointer) final; void handlePostNoReturn(revng::IRBuilder &Builder, const llvm::DebugLoc &DbgLocation) final; void handleIndirectJump(revng::IRBuilder &Builder, MetaAddress Block, const CSVSet &ClobberedRegisters, llvm::Value *SymbolNamePointer) final; }; /// This class, given an Oracle, analyzes a function returning its CFG, the set /// of callee saved registers, whether it's noreturn or not and its final stack /// offset class CFGAnalyzer { private: llvm::Module &M; GeneratedCodeBasicInfo &GCBI; const ProgramCounterHandler *PCH = nullptr; FunctionSummaryOracle &Oracle; const TupleTree &Binary; llvm::SmallVector ABICSVs; /// PreCallHook and PostCallHook mark the presence of an original function /// call, and surround a basic block containing the registers clobbered by the /// function called. They take the MetaAddress of the callee and the /// call-site. TemporaryOpaqueFunction PreCallHook; TemporaryOpaqueFunction PostCallHook; TemporaryOpaqueFunction RetHook; Outliner Outliner; OpaqueFunctionsPool OpaqueBranchConditionsPool; std::unique_ptr OutputAAWriter; std::unique_ptr OutputIBI; public: CFGAnalyzer(llvm::Module &M, GeneratedCodeBasicInfo &GCBI, const TupleTree &Binary, FunctionSummaryOracle &Oracle); public: llvm::Function *preCallHook() const { return PreCallHook.get(); } llvm::Function *postCallHook() const { return PostCallHook.get(); } llvm::Function *retHook() const { return RetHook.get(); } const auto &abiCSVs() const { return ABICSVs; } public: FunctionSummary analyze(const MetaAddress &Entry); OutlinedFunction outline(const MetaAddress &Entry); private: static llvm::FunctionType *createCallMarkerType(llvm::Module &M); static llvm::FunctionType *createRetMarkerType(llvm::Module &M); private: std::optional> handleCall(llvm::CallInst *PreCallHookCall); SortedVector collectDirectCFG(OutlinedFunction *F); void createIBIMarker(OutlinedFunction *F); void opaqueBranchConditions(llvm::Function *F, revng::IRBuilder &); void materializePCValues(llvm::Function *F, revng::IRBuilder &); void runOptimizationPipeline(llvm::Function *F); FunctionSummary milkInfo(OutlinedFunction *F, SortedVector &&CFG); struct State { llvm::Value *StackPointer; llvm::Value *ReturnPC; llvm::SmallVector CSVs; }; State loadState(revng::IRBuilder &Builder) const; }; } // namespace efa