Files
revng-revng/include/revng/EarlyFunctionAnalysis/ABIAnalysis.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

131 lines
3.9 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "revng/ABI/RegisterState.h"
#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h"
#include "revng/Model/Binary.h"
#include "revng/Support/Debug.h"
#include "revng/Support/MetaAddress.h"
namespace ABIAnalyses {
using RegisterStateMap = std::map<const llvm::GlobalVariable *,
abi::RegisterState::Values>;
class ABIAnalysesResults {
public:
struct CallSiteResults {
MetaAddress CalleeAddress;
RegisterStateMap ArgumentsRegisters;
RegisterStateMap ReturnValuesRegisters;
bool operator==(const CallSiteResults &Other) const = default;
};
public:
// Per function analysis
RegisterStateMap ArgumentsRegisters;
// Per call site analysis
std::map<BasicBlockID, CallSiteResults> CallSites;
// Per return analysis
std::map<BasicBlockID, RegisterStateMap> ReturnValuesRegisters;
RegisterStateMap FinalReturnValuesRegisters;
public:
bool operator==(const ABIAnalysesResults &Other) const = default;
public:
void combine(const ABIAnalysesResults &Other) {
auto HandleMap = [](RegisterStateMap &ThisMap,
const RegisterStateMap &OtherMap) {
for (auto &[GV, Value] : OtherMap) {
if (Value == abi::RegisterState::Yes)
ThisMap[GV] = Value;
}
};
HandleMap(ArgumentsRegisters, Other.ArgumentsRegisters);
HandleMap(FinalReturnValuesRegisters, Other.FinalReturnValuesRegisters);
for (auto &[OtherBlockID, OtherMap] : Other.ReturnValuesRegisters)
HandleMap(ReturnValuesRegisters[OtherBlockID], OtherMap);
for (auto &[OtherBlockID, OtherResults] : Other.CallSites) {
HandleMap(CallSites[OtherBlockID].ArgumentsRegisters,
OtherResults.ArgumentsRegisters);
HandleMap(CallSites[OtherBlockID].ReturnValuesRegisters,
OtherResults.ReturnValuesRegisters);
}
}
void normalize() {
auto HandleMap = [](RegisterStateMap &Map) {
for (auto &[CSV, Value] : Map) {
switch (Value) {
case abi::RegisterState::Yes:
case abi::RegisterState::YesOrDead:
case abi::RegisterState::Dead:
Value = abi::RegisterState::Yes;
break;
case abi::RegisterState::No:
case abi::RegisterState::NoOrDead:
case abi::RegisterState::Maybe:
case abi::RegisterState::Contradiction:
Value = abi::RegisterState::No;
break;
case abi::RegisterState::Invalid:
case abi::RegisterState::Count:
revng_abort();
}
}
};
HandleMap(ArgumentsRegisters);
HandleMap(FinalReturnValuesRegisters);
for (auto &[BlockID, Map] : ReturnValuesRegisters)
HandleMap(Map);
for (auto &[BlockID, Results] : CallSites) {
HandleMap(Results.ArgumentsRegisters);
HandleMap(Results.ReturnValuesRegisters);
}
}
public:
// Debug methods
void dump() const debug_function { dump(dbg, ""); }
template<typename T>
void dump(T &Output, const char *Prefix = "") const;
};
extern template void
ABIAnalyses::ABIAnalysesResults::dump<Logger<true>>(Logger<true> &,
const char *) const;
abi::RegisterState::Values combine(abi::RegisterState::Values,
abi::RegisterState::Values);
ABIAnalysesResults analyzeOutlinedFunction(llvm::Function *F,
const GeneratedCodeBasicInfo &,
llvm::Function *,
llvm::Function *,
llvm::Function *);
void finalizeReturnValues(ABIAnalysesResults &);
} // namespace ABIAnalyses