mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
723ae8d801
Move member declaration to the top of the class definition of `GeneratedCodeBasicInfo` and initialize primitive members. Merge the `run` method into the constructor since all uses have them happening close to each other.
184 lines
5.4 KiB
C++
184 lines
5.4 KiB
C++
/// Implements the GeneratedCodeBasicInfo pass which provides basic information
|
|
/// about the translated code (e.g., which CSV is the PC).
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <queue>
|
|
#include <set>
|
|
|
|
#include "llvm/ADT/DepthFirstIterator.h"
|
|
#include "llvm/IR/CFG.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "revng/ADT/RecursiveCoroutine.h"
|
|
#include "revng/BasicAnalyses/GeneratedCodeBasicInfo.h"
|
|
#include "revng/Model/LoadModelPass.h"
|
|
#include "revng/Support/Debug.h"
|
|
|
|
using namespace llvm;
|
|
|
|
AnalysisKey GeneratedCodeBasicInfoAnalysis::Key;
|
|
|
|
char GeneratedCodeBasicInfoWrapperPass::ID = 0;
|
|
using RegisterGCBI = RegisterPass<GeneratedCodeBasicInfoWrapperPass>;
|
|
static RegisterGCBI X("gcbi", "Generated Code Basic Info", true, true);
|
|
|
|
GeneratedCodeBasicInfo::GeneratedCodeBasicInfo(const model::Binary &Binary,
|
|
llvm::Module &M) :
|
|
Binary(Binary) {
|
|
|
|
RootFunction = M.getFunction("root");
|
|
NewPC = getIRHelper("newpc", M);
|
|
|
|
revng_log(PassesLog, "Starting GeneratedCodeBasicInfo");
|
|
|
|
using namespace model::Architecture;
|
|
auto Architecture = Binary.Architecture();
|
|
PC = M.getGlobalVariable(getPCCSVName(Architecture), true);
|
|
SP = M.getGlobalVariable(getCSVName(getStackPointer(Architecture)), true);
|
|
auto ReturnAddressRegister = getReturnAddressRegister(Architecture);
|
|
if (ReturnAddressRegister != model::Register::Invalid)
|
|
RA = M.getGlobalVariable(getCSVName(ReturnAddressRegister), true);
|
|
|
|
for (model::Register::Values Register : registers(Architecture)) {
|
|
GlobalVariable *CSV = M.getGlobalVariable(getCSVName(Register), true);
|
|
ABIRegisters.push_back(CSV);
|
|
ABIRegistersSet.insert(CSV);
|
|
}
|
|
|
|
Type *PCType = PC->getValueType();
|
|
PCRegSize = M.getDataLayout().getTypeAllocSize(PCType);
|
|
|
|
for (GlobalVariable &CSV : FunctionTags::CSV.globals(&M))
|
|
CSVs.push_back(&CSV);
|
|
|
|
revng_log(PassesLog, "Ending GeneratedCodeBasicInfo");
|
|
}
|
|
|
|
void GeneratedCodeBasicInfo::parseRoot() {
|
|
revng_assert(RootFunction != nullptr);
|
|
revng_assert(not RootFunction->isDeclaration());
|
|
|
|
if (RootParsed)
|
|
return;
|
|
RootParsed = true;
|
|
|
|
for (BasicBlock &BB : *RootFunction) {
|
|
if (!BB.empty()) {
|
|
switch (getType(&BB)) {
|
|
case BlockType::RootDispatcherBlock:
|
|
revng_assert(Dispatcher == nullptr);
|
|
Dispatcher = &BB;
|
|
break;
|
|
|
|
case BlockType::DispatcherFailureBlock:
|
|
revng_assert(DispatcherFail == nullptr);
|
|
DispatcherFail = &BB;
|
|
break;
|
|
|
|
case BlockType::AnyPCBlock:
|
|
revng_assert(AnyPC == nullptr);
|
|
AnyPC = &BB;
|
|
break;
|
|
|
|
case BlockType::UnexpectedPCBlock:
|
|
revng_assert(UnexpectedPC == nullptr);
|
|
UnexpectedPC = &BB;
|
|
break;
|
|
|
|
case BlockType::JumpTargetBlock: {
|
|
auto *Call = cast<CallInst>(&*BB.begin());
|
|
revng_assert(getCalledFunction(Call) == NewPC);
|
|
JumpTargets[addressFromNewPC(Call)] = &BB;
|
|
break;
|
|
}
|
|
case BlockType::RootDispatcherHelperBlock:
|
|
case BlockType::IndirectBranchDispatcherHelperBlock:
|
|
case BlockType::EntryPoint:
|
|
case BlockType::ExternalJumpsHandlerBlock:
|
|
case BlockType::TranslatedBlock:
|
|
// Nothing to do here
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SmallVector<std::pair<BasicBlock *, bool>, 4>
|
|
GeneratedCodeBasicInfo::blocksByPCRange(MetaAddress Start, MetaAddress End) {
|
|
SmallVector<std::pair<BasicBlock *, bool>, 4> Result;
|
|
|
|
BasicBlock *StartBB = getBlockAt(Start);
|
|
|
|
df_iterator_default_set<BasicBlock *> Visited;
|
|
for (BasicBlock *BB : depth_first_ext(StartBB, Visited)) {
|
|
// Detect if this basic block is a boundary
|
|
enum {
|
|
Unknown,
|
|
Yes,
|
|
No
|
|
} IsBoundary = Unknown;
|
|
|
|
auto SuccBegin = succ_begin(BB);
|
|
auto SuccEnd = succ_end(BB);
|
|
if (SuccBegin == SuccEnd) {
|
|
// This basic blocks ends with an `UnreachableInst`
|
|
IsBoundary = Yes;
|
|
} else {
|
|
for (BasicBlock *Successor : make_range(SuccBegin, SuccEnd)) {
|
|
|
|
// Ignore unexpectedpc
|
|
if (getType(Successor) == BlockType::UnexpectedPCBlock)
|
|
continue;
|
|
|
|
auto SuccessorMA = getBasicBlockAddress(Successor);
|
|
if (not isPartOfRootDispatcher(Successor)
|
|
and (SuccessorMA.isInvalid()
|
|
or (SuccessorMA.address() >= Start.address()
|
|
and SuccessorMA.address() < End.address()))) {
|
|
revng_assert(IsBoundary != Yes);
|
|
IsBoundary = No;
|
|
} else {
|
|
revng_assert(IsBoundary != No);
|
|
IsBoundary = Yes;
|
|
Visited.insert(Successor);
|
|
}
|
|
}
|
|
}
|
|
|
|
revng_assert(IsBoundary != Unknown);
|
|
|
|
Result.emplace_back(BB, IsBoundary == Yes);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
GeneratedCodeBasicInfo
|
|
GeneratedCodeBasicInfoAnalysis::run(Module &M, ModuleAnalysisManager &MAM) {
|
|
auto &LMA = MAM.getResult<LoadModelAnalysis>(M);
|
|
GeneratedCodeBasicInfo GCBI(*LMA.getReadOnlyModel(), M);
|
|
return GCBI;
|
|
}
|
|
|
|
GeneratedCodeBasicInfo
|
|
GeneratedCodeBasicInfoAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
|
|
auto &LMA = FAM.getResult<LoadModelAnalysis>(F);
|
|
GeneratedCodeBasicInfo GCBI(*LMA.getReadOnlyModel(), *F.getParent());
|
|
return GCBI;
|
|
}
|
|
|
|
bool GeneratedCodeBasicInfoWrapperPass::runOnModule(Module &M) {
|
|
auto &LMA = getAnalysis<LoadModelWrapperPass>().get();
|
|
GCBI.reset(new GeneratedCodeBasicInfo(*LMA.getReadOnlyModel(), M));
|
|
return false;
|
|
}
|
|
|
|
void GeneratedCodeBasicInfoWrapperPass::releaseMemory() {
|
|
GCBI.reset();
|
|
}
|