Files
revng-revng/lib/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.cpp
Ivan Krysak 7d235f4fd0 Enforce licence header consistency
Also do some basic cleanup: capitalize first letters, add `.`
at the end of the sentences, and so on.
2023-07-03 15:23:10 +00:00

163 lines
5.7 KiB
C++

/// \file CollectFunctionsFromUnusedAddressesPass.cpp
/// Collect the function entry points from unused addresses.
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "boost/icl/interval_set.hpp"
#include "boost/icl/right_open_interval.hpp"
#include "llvm/IR/Module.h"
#include "revng/EarlyFunctionAnalysis/CollectFunctionsFromUnusedAddressesPass.h"
#include "revng/EarlyFunctionAnalysis/FunctionMetadataCache.h"
using namespace llvm;
using CFFUAWrapperPass = CollectFunctionsFromUnusedAddressesWrapperPass;
char CFFUAWrapperPass::ID = 0;
using Register = llvm::RegisterPass<CFFUAWrapperPass>;
static Register Y("collect-functions-from-unused-addresses",
"Functions from unused addresses collection pass",
true,
true);
static Logger<> Log("functions-from-unused-addresses-collection");
class CFFUAImpl {
public:
CFFUAImpl(llvm::Module &M,
GeneratedCodeBasicInfo &GCBI,
model::Binary &Binary) :
M(M), GCBI(GCBI), Binary(Binary) {}
void run(FunctionMetadataCache &MDCache) {
loadAllCFGs(MDCache);
collectFunctionsFromUnusedAddresses();
}
private:
void loadAllCFGs(FunctionMetadataCache &MDCache) {
for (auto &Function : Binary.Functions()) {
llvm::BasicBlock *Entry = GCBI.getBlockAt(Function.Entry());
llvm::Instruction *Term = Entry->getTerminator();
auto *FMMDNode = Term->getMetadata(FunctionMetadataMDName);
revng_assert(FMMDNode != nullptr);
const efa::FunctionMetadata &FM = MDCache.getFunctionMetadata(Entry);
for (const efa::BasicBlock &Block : FM.ControlFlowGraph()) {
auto Start = Block.ID().start();
auto End = Block.End();
revng_log(Log,
"Registering as used range [" << Start.toString() << ", "
<< End.toString() << ")");
UsedRanges += interval::right_open(Start, End);
}
}
}
void collectFunctionsFromUnusedAddresses() {
using namespace llvm;
Function &Root = *M.getFunction("root");
for (BasicBlock &BB : Root) {
if (getType(&BB) != BlockType::JumpTargetBlock)
continue;
MetaAddress Entry = getBasicBlockAddress(getJumpTargetBlock(&BB));
if (Binary.Functions().find(Entry) != Binary.Functions().end())
continue;
uint32_t Reasons = GCBI.getJTReasons(&BB);
bool IsUnusedGlobalData = hasReason(Reasons, JTReason::UnusedGlobalData);
bool IsDirectJump = hasReason(Reasons, JTReason::DirectJump);
bool IsMemoryStore = hasReason(Reasons, JTReason::MemoryStore);
bool IsPCStore = hasReason(Reasons, JTReason::PCStore);
bool IsReturnAddress = hasReason(Reasons, JTReason::ReturnAddress);
bool IsLoadAddress = hasReason(Reasons, JTReason::LoadAddress);
bool IsPartOfOtherCFG = UsedRanges.find(Entry) != UsedRanges.end();
revng_log(Log,
Entry.toString()
<< "\n"
<< " IsUnusedGlobalData: " << IsUnusedGlobalData << "\n"
<< " IsDirectJump: " << IsDirectJump << "\n"
<< " IsMemoryStore: " << IsMemoryStore << "\n"
<< " IsPCStore: " << IsPCStore << "\n"
<< " IsReturnAddress: " << IsReturnAddress << "\n"
<< " IsLoadAddress: " << IsLoadAddress << "\n"
<< " IsPartOfOtherCFG: " << IsPartOfOtherCFG << "\n");
// Look for unused global data or address stored in memory that are never
// written directly to the PC. Also, ignore code for which we already have
// a direct jump or is part of the CFG of another function. Also, ignore
// addresses that are return addresses.
if ((IsUnusedGlobalData or (IsMemoryStore and not IsPCStore))
and not IsPartOfOtherCFG and not IsDirectJump
and not IsReturnAddress) {
if (IsLoadAddress) {
revng_log(Log,
"Ignoring " << Entry.toString()
<< " since it's target of a memory operation");
} else {
if (IsMemoryStore and not IsUnusedGlobalData) {
revng_log(Log,
"Creating function due to memory store at "
<< Entry.toString());
}
Binary.Functions()[Entry];
revng_log(Log,
"Found function from unused addresses: "
<< BB.getName().str());
}
}
}
}
private:
using interval_set = boost::icl::interval_set<MetaAddress>;
using interval = boost::icl::interval<MetaAddress>;
private:
llvm::Module &M;
GeneratedCodeBasicInfo &GCBI;
model::Binary &Binary;
interval_set UsedRanges;
};
bool CFFUAWrapperPass::runOnModule(llvm::Module &M) {
auto &LMWP = getAnalysis<LoadModelWrapperPass>().get();
auto &GCBI = getAnalysis<GeneratedCodeBasicInfoWrapperPass>().getGCBI();
CFFUAImpl Impl(M, GCBI, *LMWP.getWriteableModel());
Impl.run(getAnalysis<FunctionMetadataCachePass>().get());
return false;
}
llvm::PreservedAnalyses
CollectFunctionsFromUnusedAddressesPass::run(llvm::Module &M,
llvm::ModuleAnalysisManager &MAM) {
auto *LM = MAM.getCachedResult<LoadModelAnalysis>(M);
if (!LM)
return llvm::PreservedAnalyses::all();
auto &GCBI = MAM.getResult<GeneratedCodeBasicInfoAnalysis>(M);
CFFUAImpl Impl(M, GCBI, *LM->getWriteableModel());
Impl.run(*MAM.getCachedResult<FunctionMetadataCacheAnalysis>(M));
return llvm::PreservedAnalyses::all();
}
void CFFUAWrapperPass::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<LoadModelWrapperPass>();
AU.addRequired<FunctionMetadataCachePass>();
AU.addRequired<GeneratedCodeBasicInfoWrapperPass>();
}