/// \file GeneratedCodeBasicInfo.cpp /// 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 #include #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; static RegisterGCBI X("gcbi", "Generated Code Basic Info", true, true); void GeneratedCodeBasicInfo::run(Module &M) { 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(&*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, 4> GeneratedCodeBasicInfo::blocksByPCRange(MetaAddress Start, MetaAddress End) { SmallVector, 4> Result; BasicBlock *StartBB = getBlockAt(Start); df_iterator_default_set 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(M); GeneratedCodeBasicInfo GCBI(*LMA.getReadOnlyModel()); GCBI.run(M); return GCBI; } GeneratedCodeBasicInfo GeneratedCodeBasicInfoAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { auto &LMA = FAM.getResult(F); GeneratedCodeBasicInfo GCBI(*LMA.getReadOnlyModel()); GCBI.run(*F.getParent()); return GCBI; } bool GeneratedCodeBasicInfoWrapperPass::runOnModule(Module &M) { auto &LMA = getAnalysis().get(); GCBI.reset(new GeneratedCodeBasicInfo(*LMA.getReadOnlyModel())); GCBI->run(M); return false; } void GeneratedCodeBasicInfoWrapperPass::releaseMemory() { GCBI.reset(); }