mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
161 lines
5.7 KiB
C++
161 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/ControlFlowGraphCache.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(ControlFlowGraphCache &MDCache) {
|
|
loadAllCFGs(MDCache);
|
|
collectFunctionsFromUnusedAddresses();
|
|
}
|
|
|
|
private:
|
|
void loadAllCFGs(ControlFlowGraphCache &MDCache) {
|
|
for (auto &Function : Binary.Functions()) {
|
|
llvm::BasicBlock *Entry = GCBI.getBlockAt(Function.Entry());
|
|
llvm::Instruction *Term = Entry->getTerminator();
|
|
|
|
const efa::ControlFlowGraph &FM = MDCache.getControlFlowGraph(Function
|
|
.Entry());
|
|
for (const efa::BasicBlock &Block : FM.Blocks()) {
|
|
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().tryGet(Entry) != nullptr)
|
|
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<ControlFlowGraphCachePass>().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<ControlFlowGraphCacheAnalysis>(M));
|
|
return llvm::PreservedAnalyses::all();
|
|
}
|
|
|
|
void CFFUAWrapperPass::getAnalysisUsage(llvm::AnalysisUsage &AU) const {
|
|
AU.setPreservesAll();
|
|
AU.addRequired<LoadModelWrapperPass>();
|
|
AU.addRequired<ControlFlowGraphCachePass>();
|
|
AU.addRequired<GeneratedCodeBasicInfoWrapperPass>();
|
|
}
|