decompiler
1.0.0
|
A class for generating the control-flow structure for a single function. More...
#include <flow.hh>
Classes | |
struct | VisitStat |
A helper function describing the number of bytes in a machine instruction and the starting p-code op. More... | |
Public Types | |
enum | { ignore_outofbounds = 1, ignore_unimplemented = 2, error_outofbounds = 4, error_unimplemented = 8, error_reinterpreted = 0x10, error_toomanyinstructions = 0x20, unimplemented_present = 0x40, baddata_present = 0x80, outofbounds_present = 0x100, reinterpreted_present = 0x200, toomanyinstructions_present = 0x400, possible_unreachable = 0x1000, flow_forinline = 0x2000, record_jumploads = 0x4000 } |
Public Member Functions | |
FlowInfo (Funcdata &d, PcodeOpBank &o, BlockGraph &b, vector< FuncCallSpecs *> &q) | |
Constructor. More... | |
FlowInfo (Funcdata &d, PcodeOpBank &o, BlockGraph &b, vector< FuncCallSpecs *> &q, const FlowInfo *op2) | |
Cloning constructor. More... | |
void | setRange (const Address &b, const Address &e) |
Establish the flow bounds. | |
void | setMaximumInstructions (uint4 max) |
Set the maximum number of instructions. | |
void | setFlags (uint4 val) |
Enable a specific option. | |
void | clearFlags (uint4 val) |
Disable a specific option. | |
PcodeOp * | target (const Address &addr) const |
Return first p-code op for instruction at given address. More... | |
PcodeOp * | branchTarget (PcodeOp *op) const |
Find the target referred to by a given BRANCH or CBRANCH. More... | |
void | generateOps (void) |
Generate raw control-flow from the function's base address. | |
void | generateBlocks (void) |
Generate basic blocks from the raw control-flow. | |
bool | testHardInlineRestrictions (Funcdata *inlinefd, PcodeOp *op, Address &retaddr) |
For in-lining using the hard model, make sure some restrictions are met. More... | |
bool | checkEZModel (void) const |
Check if this flow matches the EX in-lining model. More... | |
void | injectPcode (void) |
Perform substitution on any op that requires injection. More... | |
void | forwardRecursion (const FlowInfo &op2) |
Pull in-lining recursion information from another flow. More... | |
void | inlineClone (const FlowInfo &inlineflow, const Address &retaddr) |
Clone the given in-line flow into this flow using the hard model. More... | |
void | inlineEZClone (const FlowInfo &inlineflow, const Address &calladdr) |
Clone the given in-line flow into this flow using the EZ model. More... | |
int4 | getSize (void) const |
Get the number of bytes covered by the flow. | |
bool | hasInject (void) const |
Does this flow have injections. | |
bool | hasUnimplemented (void) const |
Does this flow have unimiplemented instructions. | |
bool | hasBadData (void) const |
Does this flow reach inaccessible data. | |
bool | hasOutOfBounds (void) const |
Does this flow out of bound. | |
bool | hasReinterpreted (void) const |
Does this flow reinterpret bytes. | |
bool | hasTooManyInstructions (void) const |
Does this flow have too many instructions. | |
bool | isFlowForInline (void) const |
Is this flow to be in-lined. | |
bool | doesJumpRecord (void) const |
Should jump table structure be recorded. | |
Private Member Functions | |
bool | hasPossibleUnreachable (void) const |
Are there possible unreachable ops. | |
void | setPossibleUnreachable (void) |
Mark that there may be unreachable ops. | |
void | clearProperties (void) |
Clear any discovered flow properties. | |
bool | seenInstruction (const Address &addr) const |
Has the given instruction (address) been seen in flow. | |
PcodeOp * | fallthruOp (PcodeOp *op) const |
Find fallthru pcode-op for given op. More... | |
void | newAddress (PcodeOp *from, const Address &to) |
Register a new (non fall-thru) flow target. More... | |
void | deleteRemainingOps (list< PcodeOp *>::const_iterator oiter) |
Delete any remaining ops at the end of the instruction. More... | |
PcodeOp * | xrefControlFlow (list< PcodeOp *>::const_iterator oiter, bool &startbasic, bool &isfallthru, FuncCallSpecs *fc) |
Analyze control-flow within p-code for a single instruction. More... | |
bool | processInstruction (const Address &curaddr, bool &startbasic) |
Generate p-code for a single machine instruction and process discovered flow information. More... | |
void | fallthru (void) |
Process (the next) sequence of instructions in fall-thru order. More... | |
PcodeOp * | findRelTarget (PcodeOp *op, Address &res) const |
Generate the target PcodeOp for a relative branch. More... | |
void | findUnprocessed (void) |
Add any remaining un-followed addresses to the unprocessed list. More... | |
void | dedupUnprocessed (void) |
Get rid of duplicates in the unprocessed list. More... | |
void | fillinBranchStubs (void) |
Fill-in artificial HALT p-code for unprocessed addresses. More... | |
void | collectEdges (void) |
Collect edges between basic blocks as PcodeOp to PcodeOp pairs. More... | |
void | splitBasic (void) |
Split raw p-code ops up into basic blocks. More... | |
void | connectBasic (void) |
Generate edges between basic blocks. More... | |
bool | setFallthruBound (Address &bound) |
Find end of the next unprocessed region. More... | |
void | handleOutOfBounds (const Address &fromaddr, const Address &toaddr) |
Generate warning message or throw exception for given flow that is out of bounds. More... | |
PcodeOp * | artificialHalt (const Address &addr, uint4 flag) |
Create an artificial halt p-code op. More... | |
void | reinterpreted (const Address &addr) |
Generate warning message or exception for a reinterpreted address. More... | |
bool | checkForFlowModification (FuncCallSpecs &fspecs) |
Check for modifications to flow at a call site given the recovered FuncCallSpecs. More... | |
void | queryCall (FuncCallSpecs &fspecs) |
Try to recover the Funcdata object corresponding to a given call. More... | |
bool | setupCallSpecs (PcodeOp *op, FuncCallSpecs *fc) |
Set up the FuncCallSpecs object for a new call site. More... | |
bool | setupCallindSpecs (PcodeOp *op, FuncCallSpecs *fc) |
Set up the FuncCallSpecs object for a new indirect call site. More... | |
void | xrefInlinedBranch (PcodeOp *op) |
Check for control-flow in a new injected p-code op. More... | |
void | doInjection (InjectPayload *payload, InjectContext &icontext, PcodeOp *op, FuncCallSpecs *fc) |
Inject the given payload into this flow. More... | |
void | injectUserOp (PcodeOp *op) |
Perform injection for a given user-defined p-code op. More... | |
bool | inlineSubFunction (FuncCallSpecs *fc) |
In-line the sub-function at the given call site. More... | |
bool | injectSubFunction (FuncCallSpecs *fc) |
Perform injection replacing the CALL at the given call site. More... | |
void | checkContainedCall (void) |
Check if any of the calls this function makes are to already traced data-flow. More... | |
void | checkMultistageJumptables (void) |
Look for changes in control-flow near indirect jumps that were discovered after the jumptable recovery. | |
void | recoverJumpTables (vector< JumpTable *> &newTables, vector< PcodeOp *> ¬reached) |
Recover jumptables for the current set of BRANCHIND ops using existing flow. More... | |
void | deleteCallSpec (FuncCallSpecs *fc) |
Remove the given call site from the list for this function. More... | |
void | truncateIndirectJump (PcodeOp *op, int4 failuremode) |
Treat indirect jump as indirect call that never returns. More... | |
Static Private Member Functions | |
static bool | isInArray (vector< PcodeOp *> &array, PcodeOp *op) |
Test if the given p-code op is a member of an array. More... | |
Private Attributes | |
Architecture * | glb |
Owner of the function. | |
Funcdata & | data |
The function being flow-followed. | |
PcodeOpBank & | obank |
Container for generated p-code. | |
BlockGraph & | bblocks |
Container for the control-flow graph. | |
vector< FuncCallSpecs * > & | qlst |
The list of discovered sub-function call sites. | |
PcodeEmitFd | emitter |
PCodeOp factory (configured to allocate into data and obank) | |
vector< Address > | unprocessed |
Addresses which are permanently unprocessed. | |
vector< Address > | addrlist |
Addresses to which there is flow. | |
vector< PcodeOp * > | tablelist |
List of BRANCHIND ops (preparing for jump table recovery) | |
vector< PcodeOp * > | injectlist |
List of p-code ops that need injection. | |
map< Address, VisitStat > | visited |
Map of machine instructions that have been visited so far. | |
list< PcodeOp * > | block_edge1 |
Source p-code op (Edges between basic blocks) | |
list< PcodeOp * > | block_edge2 |
Destination p-code op (Edges between basic blocks) | |
uint4 | insn_count |
Number of instructions flowed through. | |
uint4 | insn_max |
Maximum number of instructions. | |
Address | baddr |
Start of range in which we are allowed to flow. | |
Address | eaddr |
End of range in which we are allowed to flow. | |
Address | minaddr |
Start of actual function range. | |
Address | maxaddr |
End of actual function range. | |
bool | flowoverride_present |
Does the function have registered flow override instructions. | |
uint4 | flags |
Boolean options for flow following. | |
Funcdata * | inline_head |
First function in the in-lining chain. | |
set< Address > * | inline_recursion |
Active list of addresses for function that are in-lined. | |
set< Address > | inline_base |
Storage for addresses of functions that are in-lined. | |
A class for generating the control-flow structure for a single function.
Control-flow for the function is generated in two phases: the method generateOps() produces all the raw p-code ops for the function, and the method generateBlocks() organizes the p-code ops into basic blocks (PcodeBlockBasic). In generateOps(), p-code is generated for every machine instruction that is reachable starting with the entry point address of the function. All possible flow is followed, trimming flow at instructions that end with the formal RETURN p-code operation. CALL and CALLIND are treated as fall-through operations, and flow is not followed into the sub-function.
The class supports various options for handling corner cases during the flow following process, including how to handle:
In generateBlocks(), all previously generated PcodeOp instructions are assigned to a PcodeBlockBasic. These objects define the formal basic block structure of the function. Directed control-flow edges between the blocks are created at this time based on the flow of p-code.
A Funcdata object provided to the constructor holds:
The Translate object (provided by the Architecture owning the function) generates the raw p-code ops for a single instruction. This FlowInfo class also handles p-code injection triggers encountered during flow following, primarily using the architecture's PcodeInjectLibrary to resolve them.
anonymous enum |
ghidra::FlowInfo::FlowInfo | ( | Funcdata & | d, |
PcodeOpBank & | o, | ||
BlockGraph & | b, | ||
vector< FuncCallSpecs *> & | q | ||
) |
Constructor.
Prepare for tracing flow for a new function. The Funcdata object and references to its internal containers must be explicitly given.
d | is the new function to trace |
o | is the internal p-code container for the function |
b | is the internal basic block container |
q | is the internal container of call sites |
References data, emitter, flags, flowoverride_present, ghidra::Funcdata::getArch(), ghidra::Funcdata::getOverride(), glb, ghidra::Override::hasFlowOverride(), inline_head, inline_recursion, insn_count, insn_max, and ghidra::PcodeEmitFd::setFuncdata().
Referenced by seenInstruction().
ghidra::FlowInfo::FlowInfo | ( | Funcdata & | d, |
PcodeOpBank & | o, | ||
BlockGraph & | b, | ||
vector< FuncCallSpecs *> & | q, | ||
const FlowInfo * | op2 | ||
) |
Cloning constructor.
Prepare a new flow cloned from an existing flow. Configuration from the existing flow is copied, but the actual PcodeOps must already be cloned within the new function.
d | is the new function that has been cloned |
o | is the internal p-code container for the function |
b | is the internal basic block container |
q | is the internal container of call sites |
op2 | is the existing flow |
References addrlist, data, emitter, flags, flowoverride_present, ghidra::Funcdata::getArch(), ghidra::Funcdata::getOverride(), glb, ghidra::Override::hasFlowOverride(), inline_base, inline_head, inline_recursion, insn_count, insn_max, ghidra::PcodeEmitFd::setFuncdata(), unprocessed, and visited.
Create an artificial halt p-code op.
An artificial halt, is a special form of RETURN op. The op is annotated with the desired type of artificial halt.
addr | is the target address for the new p-code op |
flag | is the desired type |
References ghidra::CPUI_RETURN, data, ghidra::Funcdata::newConstant(), ghidra::Funcdata::newOp(), ghidra::Funcdata::opMarkHalt(), ghidra::Funcdata::opSetInput(), and ghidra::Funcdata::opSetOpcode().
Referenced by checkForFlowModification(), fillinBranchStubs(), processInstruction(), seenInstruction(), and truncateIndirectJump().
Find the target referred to by a given BRANCH or CBRANCH.
The code reference passed as the first parameter to the branch is examined, and the p-code op it refers to is returned. The reference may be a normal direct address or a relative offset. If no target p-code can be found, an exception is thrown.
op | is the given branch op |
References findRelTarget(), ghidra::Varnode::getAddr(), ghidra::PcodeOp::getIn(), and target().
Referenced by clearFlags(), and collectEdges().
|
private |
Check if any of the calls this function makes are to already traced data-flow.
If so, we change the CALL to a BRANCH and issue a warning. This situation is most likely due to a Position Indepent Code construction.
References ghidra::PcodeOp::code(), ghidra::CPUI_BRANCH, ghidra::CPUI_CALL, data, ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::getAddr(), ghidra::FuncCallSpecs::getEntryAddress(), ghidra::FuncCallSpecs::getFuncdata(), ghidra::PcodeOp::getInsertIter(), ghidra::FuncCallSpecs::getOp(), ghidra::Funcdata::newCodeRef(), obank, ghidra::Funcdata::opMarkStartBasic(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), ghidra::Address::printRaw(), qlst, target(), visited, ghidra::Funcdata::warning(), and ghidra::Funcdata::warningHeader().
Referenced by generateOps(), and seenInstruction().
bool ghidra::FlowInfo::checkEZModel | ( | void | ) | const |
Check if this flow matches the EX in-lining model.
A function is in the EZ model if it is a straight-line leaf function.
References ghidra::PcodeOpBank::beginDead(), ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::isCallOrBranch(), and obank.
Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().
|
private |
Check for modifications to flow at a call site given the recovered FuncCallSpecs.
The sub-function may be in-lined or never return.
fspecs | is the given call site |
References artificialHalt(), data, ghidra::PcodeOp::getAddr(), ghidra::FuncCallSpecs::getOp(), injectlist, ghidra::FuncProto::isInline(), ghidra::FuncProto::isNoReturn(), ghidra::PcodeOp::noreturn, ghidra::Funcdata::opDeadInsertAfter(), and ghidra::Funcdata::warning().
Referenced by seenInstruction(), setupCallindSpecs(), and setupCallSpecs().
|
private |
Collect edges between basic blocks as PcodeOp to PcodeOp pairs.
An edge is held as matching PcodeOp entries in block_edge1 and block_edge2. Edges are generated for fall-thru to a p-code op marked as the start of a basic block or for an explicit branch.
References bblocks, ghidra::PcodeOpBank::beginDead(), block_edge1, block_edge2, branchTarget(), ghidra::PcodeOp::code(), ghidra::CPUI_BRANCH, ghidra::CPUI_BRANCHIND, ghidra::CPUI_CBRANCH, ghidra::CPUI_RETURN, data, ghidra::PcodeOpBank::endDead(), fallthruOp(), ghidra::Funcdata::findJumpTable(), ghidra::JumpTable::getAddressByIndex(), ghidra::BlockGraph::getSize(), ghidra::PcodeOp::isMark(), ghidra::JumpTable::numEntries(), obank, ghidra::PcodeOp::setMark(), and target().
Referenced by generateBlocks(), and seenInstruction().
|
private |
Generate edges between basic blocks.
Directed edges between the PcodeBlockBasic objects are created based on the previously collected p-code op pairs in block_edge1 and block_edge2
References ghidra::BlockGraph::addEdge(), bblocks, block_edge1, block_edge2, and ghidra::PcodeOp::getParent().
Referenced by generateBlocks(), and seenInstruction().
|
private |
Get rid of duplicates in the unprocessed list.
The list is also sorted.
References unprocessed.
Referenced by fillinBranchStubs(), and seenInstruction().
|
private |
Remove the given call site from the list for this function.
fc | is the given call site (which is freed by this method) |
References qlst.
Referenced by injectPcode(), and seenInstruction().
|
private |
Delete any remaining ops at the end of the instruction.
(because they have been predetermined to be dead)
oiter | is the point within the raw p-code list where deletion should start |
References data, ghidra::PcodeOpBank::endDead(), obank, and ghidra::Funcdata::opDestroyRaw().
Referenced by seenInstruction(), and xrefControlFlow().
|
private |
Inject the given payload into this flow.
The injected p-code replaces the given op, and control-flow information is updated.
payload | is the specific injection payload |
icontext | is the specific context for the injection |
op | is the given p-code op being replaced by the payload |
fc | (if non-NULL) is information about the call site being in-lined |
References data, emitter, ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::getAddr(), ghidra::PcodeOp::getInsertIter(), ghidra::InjectPayload::getName(), ghidra::PcodeOp::getSeqNum(), ghidra::InjectPayload::inject(), ghidra::PcodeOp::isBlockStart(), ghidra::InjectPayload::isIncidentalCopy(), ghidra::PcodeOpBank::markIncidentalCopy(), ghidra::PcodeOpBank::moveSequenceDead(), obank, ghidra::Funcdata::opDestroyRaw(), ghidra::Funcdata::opMarkStartBasic(), visited, and xrefControlFlow().
Referenced by injectSubFunction(), injectUserOp(), and seenInstruction().
|
private |
Process (the next) sequence of instructions in fall-thru order.
The address at the top stack that still needs processing is popped. P-code is generated for instructions starting at this address until one no longer has fall-thru flow (or some other error occurs).
References addrlist, data, eaddr, handleOutOfBounds(), ghidra::Funcdata::opMarkStartBasic(), processInstruction(), setFallthruBound(), target(), and unprocessed.
Referenced by generateOps(), and seenInstruction().
Find fallthru pcode-op for given op.
For efficiency, this method assumes the given op can actually fall-thru.
op | is the given PcodeOp |
References ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::getAddr(), ghidra::PcodeOp::getInsertIter(), ghidra::PcodeOp::isInstructionStart(), obank, target(), and visited.
Referenced by collectEdges(), and seenInstruction().
|
private |
Fill-in artificial HALT p-code for unprocessed addresses.
A special form of RETURN instruction is generated for every address in the unprocessed list.
References artificialHalt(), data, dedupUnprocessed(), findUnprocessed(), ghidra::PcodeOp::missing, ghidra::Funcdata::opMarkStartBasic(), ghidra::Funcdata::opMarkStartInstruction(), and unprocessed.
Referenced by generateBlocks(), and seenInstruction().
Generate the target PcodeOp for a relative branch.
Assuming the given op is a relative branch, find the existing target PcodeOp if the branch is properly internal, or return the fall-thru address in res (which may not have PcodeOps generated for it yet) if the relative branch is really a branch to the next instruction. Otherwise an exception is thrown.
op | is the given branching p-code op |
res | is a reference to the fall-thru address being passed back |
References ghidra::PcodeOpBank::findOp(), ghidra::PcodeOp::getAddr(), ghidra::Varnode::getAddr(), ghidra::PcodeOp::getIn(), ghidra::AddrSpace::getName(), ghidra::Address::getSpace(), ghidra::PcodeOp::getTime(), obank, ghidra::Address::printRaw(), and visited.
Referenced by branchTarget(), seenInstruction(), and xrefControlFlow().
|
private |
Add any remaining un-followed addresses to the unprocessed list.
In the case where additional flow is truncated, run through the list of pending addresses, and if they don't have a p-code generated for them, add the Address to the unprocessed array.
References addrlist, data, ghidra::Funcdata::opMarkStartBasic(), seenInstruction(), target(), and unprocessed.
Referenced by fillinBranchStubs(), and seenInstruction().
void ghidra::FlowInfo::forwardRecursion | ( | const FlowInfo & | op2 | ) |
Pull in-lining recursion information from another flow.
When preparing p-code for an in-lined function, the generation process needs to be informed of in-lining that has already been performed. This method copies the in-lining information from the parent flow, prior to p-code generation.
op2 | is the parent flow |
References inline_head, and inline_recursion.
Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().
|
private |
Generate warning message or throw exception for given flow that is out of bounds.
fromaddr | is the source address of the flow (presumably in bounds) |
toaddr | is the given destination address that is out of bounds |
References data, error_outofbounds, flags, ghidra::Address::getShortcut(), hasOutOfBounds(), ignore_outofbounds, outofbounds_present, ghidra::Address::printRaw(), ghidra::Funcdata::warning(), and ghidra::Funcdata::warningHeader().
Referenced by fallthru(), newAddress(), and seenInstruction().
void ghidra::FlowInfo::injectPcode | ( | void | ) |
Perform substitution on any op that requires injection.
Types of substitution include:
Make sure to truncate recursion, and otherwise don't allow a sub-function to be in-lined more than once.
References ghidra::PcodeOp::code(), ghidra::CPUI_CALLOTHER, data, deleteCallSpec(), ghidra::Varnode::getAddr(), ghidra::Funcdata::getAddress(), ghidra::PcodeInjectLibrary::getCallFixupName(), ghidra::FuncCallSpecs::getFspecFromConst(), ghidra::PcodeOp::getIn(), ghidra::FuncProto::getInjectId(), ghidra::FuncCallSpecs::getName(), glb, injectlist, injectSubFunction(), injectUserOp(), inline_base, inline_head, inline_recursion, inlineSubFunction(), ghidra::FuncProto::isInline(), ghidra::Architecture::pcodeinjectlib, and ghidra::Funcdata::warningHeader().
Referenced by clearFlags(), generateOps(), and ghidra::Funcdata::truncatedFlow().
|
private |
Perform injection replacing the CALL at the given call site.
The call site must be previously marked with the injection id. The PcodeInjectLibrary is queried for the associated payload, which is then inserted into this flow, replacing the original CALL op.
fc | is the given call site |
References ghidra::InjectContext::clear(), doInjection(), ghidra::PcodeOp::getAddr(), ghidra::PcodeInjectLibrary::getCachedContext(), ghidra::FuncCallSpecs::getEntryAddress(), ghidra::FuncProto::getInjectId(), ghidra::FuncCallSpecs::getOp(), ghidra::InjectPayload::getParamShift(), ghidra::PcodeInjectLibrary::getPayload(), glb, ghidra::Architecture::pcodeinjectlib, and qlst.
Referenced by injectPcode(), and seenInstruction().
|
private |
Perform injection for a given user-defined p-code op.
The op must already be established as a user defined op with an associated injection
op | is the given PcodeOp |
References ghidra::InjectContext::clear(), doInjection(), ghidra::PcodeOp::getAddr(), ghidra::PcodeInjectLibrary::getCachedContext(), ghidra::PcodeOp::getIn(), ghidra::InjectedUserOp::getInjectId(), ghidra::Varnode::getOffset(), ghidra::UserOpManage::getOp(), ghidra::PcodeOp::getOut(), ghidra::PcodeInjectLibrary::getPayload(), ghidra::Varnode::getSize(), ghidra::Varnode::getSpace(), glb, ghidra::PcodeOp::numInput(), ghidra::Architecture::pcodeinjectlib, and ghidra::Architecture::userops.
Referenced by injectPcode(), and seenInstruction().
Clone the given in-line flow into this flow using the hard model.
Individual PcodeOps from the Funcdata being in-lined are cloned into the Funcdata for this flow, preserving their original address. Any RETURN op is replaced with jump to first address following the call site.
inlineflow | is the given in-line flow to clone |
retaddr | is the first address after the call site in this flow |
References addrlist, ghidra::Funcdata::beginOpDead(), ghidra::Funcdata::cloneOp(), ghidra::PcodeOp::code(), ghidra::CPUI_BRANCH, ghidra::CPUI_RETURN, data, ghidra::Funcdata::endOpDead(), ghidra::PcodeOp::getSeqNum(), ghidra::PcodeOp::isCallOrBranch(), ghidra::Address::isInvalid(), ghidra::Funcdata::newCodeRef(), ghidra::Funcdata::newOp(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), unprocessed, visited, and xrefInlinedBranch().
Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().
Clone the given in-line flow into this flow using the EZ model.
Individual PcodeOps from the Funcdata being in-lined are cloned into the Funcdata for this flow but are reassigned a new fixed address, and the RETURN op is eliminated.
inlineflow | is the given in-line flow to clone |
calladdr | is the fixed address assigned to the cloned PcodeOps |
References ghidra::Funcdata::beginOpDead(), ghidra::Funcdata::cloneOp(), ghidra::PcodeOp::code(), ghidra::CPUI_RETURN, data, ghidra::Funcdata::endOpDead(), ghidra::PcodeOp::getSeqNum(), and ghidra::SeqNum::getTime().
Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().
|
private |
In-line the sub-function at the given call site.
P-code is generated for the sub-function and then woven into this flow at the call site.
fc | is the given call site |
References data, ghidra::FuncCallSpecs::getFuncdata(), ghidra::FuncCallSpecs::getOp(), ghidra::Funcdata::inlineFlow(), and setPossibleUnreachable().
Referenced by injectPcode(), and seenInstruction().
Test if the given p-code op is a member of an array.
array | is the array of p-code ops to search |
op | is the given p-code op to search for |
Referenced by recoverJumpTables(), and seenInstruction().
Register a new (non fall-thru) flow target.
Check to see if the new target has been seen before. Otherwise add it to the list of addresses that need to be processed. Also check range bounds and update basic block information.
from | is the PcodeOp issuing the branch |
to | is the target address of the branch |
References addrlist, baddr, data, eaddr, ghidra::PcodeOp::getAddr(), handleOutOfBounds(), ghidra::Funcdata::opMarkStartBasic(), seenInstruction(), target(), and unprocessed.
Referenced by generateOps(), seenInstruction(), and xrefControlFlow().
|
private |
Generate p-code for a single machine instruction and process discovered flow information.
P-code is generated (to the raw dead list in PcodeOpBank). Errors for unimplemented instructions or inaccessible data are handled. The p-code is examined for control-flow, and annotations are made. The set of visited instructions and the set of addresses still needing to be processed are updated.
curaddr | is the address of the instruction to process |
startbasic | indicates of the instruction starts a basic block and passes back whether the next instruction does |
References addrlist, artificialHalt(), baddata_present, ghidra::PcodeOp::badinstruction, ghidra::PcodeOpBank::beginDead(), data, emitter, ghidra::PcodeOpBank::empty(), ghidra::PcodeOpBank::endDead(), error_toomanyinstructions, error_unimplemented, flags, flowoverride_present, ghidra::Override::getFlowOverride(), ghidra::Funcdata::getOverride(), glb, hasBadData(), hasTooManyInstructions(), hasUnimplemented(), ignore_unimplemented, insn_count, insn_max, ghidra::UnimplError::instruction_length, maxaddr, minaddr, ghidra::Override::NONE, obank, ghidra::Translate::oneInstruction(), ghidra::Funcdata::opMarkStartInstruction(), ghidra::Funcdata::overrideFlow(), ghidra::FlowInfo::VisitStat::seqnum, ghidra::FlowInfo::VisitStat::size, toomanyinstructions_present, ghidra::Architecture::translate, ghidra::PcodeOp::unimplemented, unimplemented_present, visited, ghidra::Funcdata::warning(), ghidra::Funcdata::warningHeader(), and xrefControlFlow().
Referenced by fallthru(), and seenInstruction().
|
private |
Try to recover the Funcdata object corresponding to a given call.
If there is an explicit target address for the given call site, attempt to look up the function and adjust information in the FuncCallSpecs call site object.
fspecs | is the call site object |
References ghidra::FuncProto::copyFlowEffects(), data, ghidra::FuncCallSpecs::getEntryAddress(), ghidra::Funcdata::getFuncProto(), ghidra::Scope::getParent(), ghidra::Funcdata::getScopeLocal(), ghidra::FuncProto::hasModel(), ghidra::FuncProto::isInline(), ghidra::Address::isInvalid(), ghidra::Scope::queryFunction(), and ghidra::FuncCallSpecs::setFuncdata().
Referenced by seenInstruction(), setupCallindSpecs(), and setupCallSpecs().
|
private |
Recover jumptables for the current set of BRANCHIND ops using existing flow.
This method passes back a list of JumpTable objects, one for each BRANCHIND in the current tablelist where the jumptable can be recovered. If a particular BRANCHIND cannot be recovered because the current partial control flow cannot legally reach it, the BRANCHIND is passed back in a separate list.
newTables | will hold the list of recovered JumpTables |
notreached | will hold the list of BRANCHIND ops that could not be reached |
References data, ghidra::PcodeOp::getAddr(), ghidra::Funcdata::getAddress(), ghidra::Funcdata::getName(), ghidra::Scope::getParent(), ghidra::Funcdata::getScopeLocal(), isFlowForInline(), isInArray(), ghidra::Address::printRaw(), ghidra::Funcdata::recoverJumpTable(), tablelist, and truncateIndirectJump().
Referenced by generateOps(), and seenInstruction().
|
private |
Generate warning message or exception for a reinterpreted address.
A set of bytes is reinterpreted if there are at least two different interpretations of the bytes as instructions.
addr | is the address of a byte previously interpreted as (the interior of) an instruction |
References data, error_reinterpreted, flags, ghidra::AddrSpace::getName(), ghidra::Address::getSpace(), ghidra::Address::printRaw(), reinterpreted_present, visited, and ghidra::Funcdata::warningHeader().
Referenced by seenInstruction(), and setFallthruBound().
|
private |
Find end of the next unprocessed region.
From the address at the top of the addrlist stack Figure out how far we could follow fall-thru instructions before hitting something we've already seen
bound | passes back the first address encountered that we have already seen |
References addrlist, data, eaddr, ghidra::Funcdata::opMarkStartBasic(), reinterpreted(), target(), and visited.
Referenced by fallthru(), and seenInstruction().
|
private |
Set up the FuncCallSpecs object for a new indirect call site.
The new FuncCallSpecs object is created and initialized based on the CALLIND op at the site. Any overriding prototype or control-flow may be examined and applied.
op | is the given CALLIND op |
fc | is non-NULL if injection is in progress and a cycle check needs to be made |
References ghidra::Override::applyIndirect(), ghidra::Override::applyPrototype(), checkForFlowModification(), ghidra::CPUI_CALL, data, ghidra::FuncCallSpecs::getEntryAddress(), ghidra::Funcdata::getOverride(), ghidra::Address::isInvalid(), ghidra::Funcdata::newVarnodeCallSpecs(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), qlst, queryCall(), and ghidra::FuncCallSpecs::setAddress().
Referenced by seenInstruction(), truncateIndirectJump(), xrefControlFlow(), and xrefInlinedBranch().
|
private |
Set up the FuncCallSpecs object for a new call site.
The new FuncCallSpecs object is created and initialized based on the CALL op at the site and any matching function in the symbol table. Any overriding prototype or control-flow is examined and applied.
op | is the given CALL op |
fc | is non-NULL if injection is in progress and a cycle check needs to be made |
References ghidra::Override::applyPrototype(), ghidra::FuncProto::cancelInjectId(), checkForFlowModification(), data, ghidra::FuncCallSpecs::getEntryAddress(), ghidra::Funcdata::getOverride(), ghidra::Funcdata::newVarnodeCallSpecs(), ghidra::Funcdata::opSetInput(), qlst, and queryCall().
Referenced by seenInstruction(), xrefControlFlow(), and xrefInlinedBranch().
|
private |
Split raw p-code ops up into basic blocks.
PcodeOp objects are moved out of the PcodeOpBank dead list into their assigned PcodeBlockBasic. Initial address ranges of instructions are recorded in the block. PcodeBlockBasic objects are created based on p-code ops that have been previously marked as start of basic block.
References bblocks, ghidra::PcodeOpBank::beginDead(), data, ghidra::PcodeOpBank::endDead(), ghidra::BlockBasic::endOp(), ghidra::SeqNum::getAddr(), ghidra::PcodeOp::getAddr(), ghidra::PcodeOp::getSeqNum(), ghidra::PcodeOp::isBlockStart(), ghidra::BlockGraph::newBlockBasic(), obank, ghidra::Funcdata::opInsert(), ghidra::Funcdata::setBasicBlockRange(), and ghidra::BlockGraph::setStartBlock().
Referenced by generateBlocks(), and seenInstruction().
Return first p-code op for instruction at given address.
The first p-code op associated with the machine instruction at the given address is returned. If the instruction generated no p-code, an attempt is made to fall-thru to the next instruction. If no p-code op is ultimately found, an exception is thrown.
addr | is the given address of the instruction |
References ghidra::PcodeOpBank::findOp(), ghidra::SeqNum::getAddr(), ghidra::AddrSpace::getName(), ghidra::Address::getSpace(), ghidra::Address::isInvalid(), obank, ghidra::Address::printRaw(), and visited.
Referenced by branchTarget(), checkContainedCall(), clearFlags(), collectEdges(), fallthru(), fallthruOp(), findUnprocessed(), newAddress(), setFallthruBound(), and ghidra::JumpTable::switchOver().
bool ghidra::FlowInfo::testHardInlineRestrictions | ( | Funcdata * | inlinefd, |
PcodeOp * | op, | ||
Address & | retaddr | ||
) |
For in-lining using the hard model, make sure some restrictions are met.
Pass back the distinct return address, unless the in-lined function doesn't return.
inlinefd | is the function being in-lined into this flow |
op | is CALL instruction at the site of the in-line |
retaddr | holds the passed back return address |
References data, ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::getAddr(), ghidra::Funcdata::getAddress(), ghidra::Funcdata::getFuncProto(), ghidra::PcodeOp::getInsertIter(), inline_head, inline_recursion, ghidra::FuncProto::isNoReturn(), obank, ghidra::Funcdata::opMarkStartBasic(), and ghidra::Funcdata::warning().
Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().
|
private |
Treat indirect jump as indirect call that never returns.
op | is the BRANCHIND operation to convert |
failuremode | is a code indicating the type of failure when trying to recover the jump table |
References artificialHalt(), ghidra::CPUI_CALLIND, data, ghidra::PcodeOp::getAddr(), ghidra::Funcdata::getCallSpecs(), ghidra::Funcdata::opDeadInsertAfter(), ghidra::Funcdata::opSetOpcode(), ghidra::FuncCallSpecs::setBadJumpTable(), setupCallindSpecs(), and ghidra::Funcdata::warning().
Referenced by recoverJumpTables(), and seenInstruction().
|
private |
Analyze control-flow within p-code for a single instruction.
Walk through the raw p-code (from the given iterator to the end of the list) looking for control flow operations (BRANCH,CBRANCH,BRANCHIND,CALL,CALLIND,RETURN) and add appropriate annotations (startbasic, callspecs, new addresses). As it iterates through the p-code, the method maintains a reference to a boolean indicating whether the current op is the start of a basic block. This value persists across calls. The method also passes back a boolean value indicating whether the instruction as a whole has fall-thru flow.
oiter | is the given iterator starting the list of p-code ops |
startbasic | is the reference holding whether the current op starts a basic block |
isfallthru | passes back if the instruction has fall-thru flow |
fc | if the p-code is generated from an injection, this holds the reference to the injecting sub-function |
References ghidra::PcodeOp::code(), ghidra::CPUI_BRANCH, ghidra::CPUI_BRANCHIND, ghidra::CPUI_CALL, ghidra::CPUI_CALLIND, ghidra::CPUI_CALLOTHER, ghidra::CPUI_CBRANCH, ghidra::CPUI_RETURN, data, deleteRemainingOps(), ghidra::PcodeOpBank::endDead(), findRelTarget(), ghidra::Varnode::getAddr(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::UserOpManage::getOp(), ghidra::PcodeOp::getTime(), glb, injectlist, newAddress(), obank, ghidra::Funcdata::opMarkStartBasic(), setupCallindSpecs(), setupCallSpecs(), tablelist, and ghidra::Architecture::userops.
Referenced by doInjection(), processInstruction(), and seenInstruction().
|
private |
Check for control-flow in a new injected p-code op.
If the given injected op is a CALL, CALLIND, or BRANCHIND, we need to add references to it in other flow tables.
op | is the given injected p-code op |
References ghidra::PcodeOp::code(), ghidra::CPUI_BRANCHIND, ghidra::CPUI_CALL, ghidra::CPUI_CALLIND, data, ghidra::Funcdata::linkJumpTable(), setupCallindSpecs(), setupCallSpecs(), and tablelist.
Referenced by inlineClone(), and seenInstruction().