Files
revng-revng/include/revng/EarlyFunctionAnalysis/CFGAnalyzer.h
Alessandro Di Federico 28a0fa5b7d DetectABI: run to fixed point and more
This commit switches the approach with which we run the ABI analyses: we
now run them until we reach a fixed point. This enables proper
interprocedural propagation of arguments and return values.

Basically, we now inject reads before call sites, so that, if a function
immediately calls another one, the arguments of the callee are
propagated to the caller.

This commit also updates the logic with which we propagate function
prototypes (and names) to callers. The main advantage of this, is that
function wrappers (in particular, PLT entries) now have the same name as
the function they wrap.
2023-12-12 10:05:22 +01:00

139 lines
4.3 KiB
C++

#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/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<MetaAddress, 4> *ReturnBlocks = nullptr;
OpaqueRegisterUser Clobberer;
public:
CallSummarizer(llvm::Module *M,
llvm::Function *PreCallHook,
llvm::Function *PostCallHook,
llvm::Function *RetHook,
llvm::GlobalVariable *SPCSV,
llvm::SmallSet<MetaAddress, 4> *ReturnBlocks);
public:
void handleCall(MetaAddress CallerBlock,
llvm::IRBuilder<> &Builder,
MetaAddress Callee,
const std::set<llvm::GlobalVariable *> &ClobberedRegisters,
const std::optional<int64_t> &MaybeFSO,
bool IsNoReturn,
bool IsTailCall,
llvm::Value *SymbolNamePointer) final;
void handlePostNoReturn(llvm::IRBuilder<> &Builder) final;
void
handleIndirectJump(llvm::IRBuilder<> &Builder,
MetaAddress Block,
const std::set<llvm::GlobalVariable *> &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;
const FunctionSummaryOracle &Oracle;
const TupleTree<model::Binary> &Binary;
llvm::SmallVector<llvm::GlobalVariable *, 16> 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<llvm::Type *> OpaqueBranchConditionsPool;
std::unique_ptr<llvm::raw_ostream> OutputAAWriter;
std::unique_ptr<llvm::raw_ostream> OutputIBI;
public:
CFGAnalyzer(llvm::Module &M,
GeneratedCodeBasicInfo &GCBI,
const TupleTree<model::Binary> &Binary,
const 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(llvm::BasicBlock *Entry);
OutlinedFunction outline(llvm::BasicBlock *Entry);
private:
static llvm::FunctionType *createCallMarkerType(llvm::Module &M);
static llvm::FunctionType *createRetMarkerType(llvm::Module &M);
private:
std::optional<UpcastablePointer<efa::FunctionEdgeBase>>
handleCall(llvm::CallInst *PreCallHookCall);
SortedVector<efa::BasicBlock> collectDirectCFG(OutlinedFunction *F);
void createIBIMarker(OutlinedFunction *F);
void opaqueBranchConditions(llvm::Function *F, llvm::IRBuilder<> &);
void materializePCValues(llvm::Function *F, llvm::IRBuilder<> &);
void runOptimizationPipeline(llvm::Function *F);
FunctionSummary milkInfo(OutlinedFunction *F,
SortedVector<efa::BasicBlock> &&CFG);
struct State {
llvm::Value *StackPointer;
llvm::Value *ReturnPC;
llvm::SmallVector<llvm::Value *, 16> CSVs;
};
State loadState(llvm::IRBuilder<> &Builder) const;
};
} // namespace efa