retdec
|
#include <decoder.h>
Public Member Functions | |
Decoder () | |
~Decoder () | |
virtual bool | runOnModule (llvm::Module &m) override |
bool | runOnModuleCustom (llvm::Module &m, Config *c, FileImage *o, DebugFormat *d, NameContainer *n, Abi *a) |
Static Public Attributes | |
static char | ID = 0 |
Private Types | |
using | ByteData = typename std::pair< const std::uint8_t *, std::size_t > |
Private Member Functions | |
bool | runCatcher () |
bool | run () |
void | initTranslator () |
void | initDryRunCsInstruction () |
void | initEnvironment () |
void | initEnvironmentAsm2LlvmMapping () |
void | initEnvironmentPseudoFunctions () |
void | initEnvironmentRegisters () |
void | initRanges () |
void | initAllowedRangesWithSegments () |
void | initAllowedRangesWithConfig () |
void | initJumpTargets () |
void | initJumpTargetsConfig () |
void | initJumpTargetsEntryPoint () |
void | initJumpTargetsExterns () |
void | initJumpTargetsImports () |
void | initJumpTargetsExports () |
void | initJumpTargetsDebug () |
void | initJumpTargetsSymbols () |
void | initConfigFunctions () |
void | initStaticCode () |
void | initVtables () |
void | decode () |
bool | getJumpTarget (JumpTarget &jt) |
void | decodeJumpTarget (const JumpTarget &jt) |
std::size_t | decodeJumpTargetDryRun (const JumpTarget &jt, ByteData bytes, bool strict=false) |
cs_mode | determineMode (cs_insn *insn, common::Address &target) |
capstone2llvmir::Capstone2LlvmIrTranslator::TranslationResultOne | translate (ByteData &bytes, common::Address &addr, llvm::IRBuilder<> &irb) |
bool | getJumpTargetsFromInstruction (common::Address addr, capstone2llvmir::Capstone2LlvmIrTranslator::TranslationResultOne &tr, std::size_t &rangeSize) |
common::Address | getJumpTarget (common::Address addr, llvm::CallInst *branchCall, llvm::Value *val) |
bool | getJumpTargetSwitch (common::Address addr, llvm::CallInst *branchCall, llvm::Value *val, SymbolicTree &st) |
bool | instructionBreaksBasicBlock (common::Address addr, capstone2llvmir::Capstone2LlvmIrTranslator::TranslationResultOne &tr) |
void | handleDelaySlotTypical (common::Address &addr, capstone2llvmir::Capstone2LlvmIrTranslator::TranslationResultOne &res, ByteData &bytes, llvm::IRBuilder<> &irb) |
void | handleDelaySlotLikely (common::Address &addr, capstone2llvmir::Capstone2LlvmIrTranslator::TranslationResultOne &res, ByteData &bytes, llvm::IRBuilder<> &irb) |
void | resolvePseudoCalls () |
void | finalizePseudoCalls () |
common::Address | getBasicBlockAddress (llvm::BasicBlock *b) |
common::Address | getBasicBlockEndAddress (llvm::BasicBlock *b) |
common::Address | getBasicBlockAddressAfter (common::Address a) |
llvm::BasicBlock * | getBasicBlockAtAddress (common::Address a) |
llvm::BasicBlock * | getBasicBlockBeforeAddress (common::Address a) |
llvm::BasicBlock * | getBasicBlockAfterAddress (common::Address a) |
llvm::BasicBlock * | getBasicBlockContainingAddress (common::Address a) |
llvm::BasicBlock * | createBasicBlock (common::Address a, llvm::Function *f, llvm::BasicBlock *insertAfter=nullptr) |
void | addBasicBlock (common::Address a, llvm::BasicBlock *b) |
common::Address | getFunctionAddress (llvm::Function *f) |
common::Address | getFunctionEndAddress (llvm::Function *f) |
common::Address | getFunctionAddressAfter (common::Address a) |
llvm::Function * | getFunctionAtAddress (common::Address a) |
llvm::Function * | getFunctionBeforeAddress (common::Address a) |
llvm::Function * | getFunctionAfterAddress (common::Address a) |
llvm::Function * | getFunctionContainingAddress (common::Address a) |
llvm::Function * | createFunction (common::Address a, bool declaration=false) |
void | addFunction (common::Address a, llvm::Function *f) |
void | addFunctionSize (llvm::Function *f, std::optional< std::size_t > sz) |
bool | patternsRecognize () |
bool | patternTerminatingCalls () |
bool | patternStaticallyLinked () |
std::size_t | decodeJumpTargetDryRun_x86 (const JumpTarget &jt, ByteData bytes, bool strict=false) |
std::size_t | decodeJumpTargetDryRun_arm (const JumpTarget &jt, ByteData bytes, bool strict=false) |
std::size_t | decodeJumpTargetDryRun_arm (const JumpTarget &jt, ByteData bytes, cs_mode mode, std::size_t &decodedSz, bool strict=false) |
void | patternsPseudoCall_arm (llvm::CallInst *&call, AsmInstruction &pAi) |
cs_mode | determineMode_arm (cs_insn *insn, common::Address &target) |
std::size_t | decodeJumpTargetDryRun_arm64 (const JumpTarget &jt, ByteData bytes, bool strict=false) |
void | patternsPseudoCall_arm64 (llvm::CallInst *&call, AsmInstruction &pAi) |
bool | disasm_mips (csh ce, cs_mode m, ByteData &bytes, uint64_t &a, cs_insn *i) |
std::size_t | decodeJumpTargetDryRun_mips (const JumpTarget &jt, ByteData bytes, bool strict=false) |
void | initializeGpReg_mips () |
std::size_t | decodeJumpTargetDryRun_ppc (const JumpTarget &jt, ByteData bytes, bool strict=false) |
llvm::CallInst * | transformToCall (llvm::CallInst *pseudo, llvm::Function *callee) |
llvm::CallInst * | transformToCondCall (llvm::CallInst *pseudo, llvm::Value *cond, llvm::Function *callee, llvm::BasicBlock *falseBb) |
llvm::ReturnInst * | transformToReturn (llvm::CallInst *pseudo) |
llvm::BranchInst * | transformToBranch (llvm::CallInst *pseudo, llvm::BasicBlock *branchee) |
llvm::BranchInst * | transformToCondBranch (llvm::CallInst *pseudo, llvm::Value *cond, llvm::BasicBlock *trueBb, llvm::BasicBlock *falseBb) |
llvm::SwitchInst * | transformToSwitch (llvm::CallInst *pseudo, llvm::Value *val, llvm::BasicBlock *defaultBb, const std::vector< llvm::BasicBlock * > &cases) |
llvm::GlobalVariable * | getCallReturnObject () |
void | getOrCreateCallTarget (common::Address addr, llvm::Function *&tFnc, llvm::BasicBlock *&tBb) |
void | getOrCreateBranchTarget (common::Address addr, llvm::BasicBlock *&tBb, llvm::Function *&tFnc, llvm::Instruction *from) |
bool | canSplitFunctionOn (llvm::BasicBlock *bb) |
bool | canSplitFunctionOn (common::Address addr, llvm::BasicBlock *bb, std::set< llvm::BasicBlock * > &newFncStarts) |
llvm::Function * | splitFunctionOn (common::Address addr) |
llvm::Function * | splitFunctionOn (common::Address addr, llvm::BasicBlock *bb) |
Private Attributes | |
std::map< common::Address, llvm::BasicBlock * > | _addr2bb |
std::map< llvm::BasicBlock *, common::Address > | _bb2addr |
std::map< common::Address, llvm::Function * > | _addr2fnc |
std::map< llvm::Function *, common::Address > | _fnc2addr |
std::map< llvm::Function *, std::size_t > | _fnc2sz |
llvm::Module * | _module = nullptr |
Config * | _config = nullptr |
FileImage * | _image = nullptr |
DebugFormat * | _debug = nullptr |
NameContainer * | _names = nullptr |
Llvm2CapstoneInsnMap * | _llvm2capstone = nullptr |
Abi * | _abi = nullptr |
std::unique_ptr< capstone2llvmir::Capstone2LlvmIrTranslator > | _c2l |
cs_insn * | _dryCsInsn = nullptr |
llvm::IRBuilder * | _irb |
RangesToDecode | _ranges |
JumpTargets | _jumpTargets |
std::set< std::string > | _externs |
Name of all extern functions gathered from object files. More... | |
std::set< common::Address > | _imports |
std::set< common::Address > | _exports |
std::set< common::Address > | _symbols |
std::map< common::Address, const common::Function * > | _debugFncs |
std::set< common::Address > | _staticFncs |
std::set< common::Address > | _vtableFncs |
std::set< llvm::Function * > | _terminatingFncs |
llvm::Function * | _entryPointFunction = nullptr |
std::map< common::Address, std::set< llvm::SwitchInst * > > | _switchTableStarts |
std::map< llvm::BasicBlock *, llvm::BasicBlock * > | _likelyBb2Target |
bool | _switchGenerated = false |
bool | _somethingDecoded = false |
|
private |
retdec::bin2llvmir::Decoder::Decoder | ( | ) |
retdec::bin2llvmir::Decoder::~Decoder | ( | ) |
|
private |
|
private |
|
private |
Size sz
is added only if function's f
size was not set so far. Use this function in more reliable, higher priority sources first.
|
private |
True
if it is allowed to split function on basic block bb
.TODO: The problem here is, that function may became unsplittable after it was split. What then? Merge them back together and transform calls to JUMP_OUTs? Or defer splits/calls/etc only after basic decoding of all functions is done? E.g. fnc1(): ... b lab_in_2 ...
fnc2(): (nothing decoded yet) ... // should not be split here, but it can, because flow from fnc2() // start does not exist yet. lab_in_2: ... fnc2 end
|
private |
True
if it is allowed to split function on basic block bb
.
|
private |
Create basic block at address a
in function f
right after basic block insertAfter
.
|
private |
Create function at address a
.
|
private |
|
private |
|
private |
Check if the given jump targets and bytes can/should be decoded.
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
f
.
|
private |
a
.
|
private |
a
.
|
private |
a
.
|
private |
a
.
|
private |
a
. I.e. a
is between basic blocks's start and end address.
|
private |
b
- the end address of the last instruction in the basic block.
|
private |
TODO: We should get registers based on the ABI the function is using, not the same register for all calls on an architecture.
|
private |
f
.
|
private |
|
private |
|
private |
a
.
|
private |
a
.
|
private |
a
. I.e. a
is between function's start and end address.
|
private |
f
.
|
private |
|
private |
|
private |
True
if this instruction ends basic block, false
otherwise.
|
private |
True
if switch recognized, false
otherwise.
|
private |
|
private |
Primary: try to create function for addr
target and fill tFnc
with the result. If successful, tBb
is also filled. Secondary: if function not created, try to create BB for addr
target and fill tBb
with the result.
|
private |
br cond, target_true, target_false delay_slot_likely_insn
==>
br cond, ds_likely_bb, target_false
ds_likely_bb: delay_slot_likely_insn br target_true target_false: ...
|
private |
; ASM branch insn ; ASM delay slot insn
==>
; ASM branch insn LLVM IR body without branch ; ASM delay slot insn LLVM IR body branch from prev insn
|
private |
|
private |
Initialize address ranges to decode from image segments/sections.
|
private |
|
private |
Initialize instruction used in dry run disassembly.
|
private |
Synchronize metadata between capstone2llvmir and bin2llvmir.
|
private |
Find out from capstone2llvmir which global is used for LLVM IR <-> Capstone ASM mapping.
|
private |
Set pseudo functions' names in LLVM IR and set them to config.
|
private |
Create config objects for HW registers. Initialize ABI with registers.
|
private |
|
private |
Find jump targets to decode.
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
Find address ranges to decode.
|
private |
|
private |
Initialize capstone2llvmir translator according to the architecture of file to decompile.
True
if error, false
otherwise.
|
private |
|
private |
|
private |
Recognize some ARM-specific patterns.
|
private |
|
private |
True
if function changed something in IR, false
otherwise.
|
private |
Sometimes, statically linked code detection does not recognize all statically linked functions. We search for the following patterns:
|
private |
True
if function changed something in IR, false
otherwise.
|
private |
|
private |
|
private |
|
overridevirtual |
bool retdec::bin2llvmir::Decoder::runOnModuleCustom | ( | llvm::Module & | m, |
Config * | c, | ||
FileImage * | o, | ||
DebugFormat * | d, | ||
NameContainer * | n, | ||
Abi * | a | ||
) |
|
private |
This can create new BB at addr
even if it then cannot split function on this new BB. Is this desirable behavior?
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
Name of all extern functions gathered from object files.
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
|
private |
Start of all recognized jump tables. TODO: use this to check that one table does not use labels from another. TODO: maybe we should also remove/fix cond branches to default labels before switches (this was done in the original cfg implementation. However, if we do it too soon, it will cause diff problems when comparing to IDA cfg dumps). We could do it after. Btw, we already have diff problem because default label is added to switch -> it has one more succ then cond branch in IDA (if default label is not in jump table).
|
private |
|
private |
|
private |
|
static |