decompiler  1.0.0
Classes | Public Types | Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
ghidra::FlowInfo Class Reference

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.
 
PcodeOptarget (const Address &addr) const
 Return first p-code op for instruction at given address. More...
 
PcodeOpbranchTarget (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.
 
PcodeOpfallthruOp (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...
 
PcodeOpxrefControlFlow (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...
 
PcodeOpfindRelTarget (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...
 
PcodeOpartificialHalt (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 *> &notreached)
 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

Architectureglb
 Owner of the function.
 
Funcdatadata
 The function being flow-followed.
 
PcodeOpBankobank
 Container for generated p-code.
 
BlockGraphbblocks
 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< Addressunprocessed
 Addresses which are permanently unprocessed.
 
vector< Addressaddrlist
 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, VisitStatvisited
 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.
 
Funcdatainline_head
 First function in the in-lining chain.
 
set< Address > * inline_recursion
 Active list of addresses for function that are in-lined.
 
set< Addressinline_base
 Storage for addresses of functions that are in-lined.
 

Detailed Description

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.

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
Enumerator
ignore_outofbounds 

Ignore/truncate flow into addresses out of the specified range.

ignore_unimplemented 

Treat unimplemented instructions as a NOP (no operation)

error_outofbounds 

Throw an exception for flow into addresses out of the specified range.

error_unimplemented 

Throw an exception for flow into unimplemented instructions.

error_reinterpreted 

Throw an exception for flow into previously encountered data at a difference cut.

error_toomanyinstructions 

Throw an exception if too many instructions are encountered.

unimplemented_present 

Indicate we have encountered unimplemented instructions.

baddata_present 

Indicate we have encountered flow into unaccessible data.

outofbounds_present 

Indicate we have encountered flow out of the specified range.

reinterpreted_present 

Indicate we have encountered reinterpreted data.

toomanyinstructions_present 

Indicate the maximum instruction threshold was reached.

possible_unreachable 

Indicate a CALL was converted to a BRANCH and some code may be unreachable.

flow_forinline 

Indicate flow is being generated to in-line (a function)

record_jumploads 

Indicate that any jump table recovery should record the table structure.

Constructor & Destructor Documentation

◆ FlowInfo() [1/2]

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.

Parameters
dis the new function to trace
ois the internal p-code container for the function
bis the internal basic block container
qis 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().

◆ FlowInfo() [2/2]

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.

Parameters
dis the new function that has been cloned
ois the internal p-code container for the function
bis the internal basic block container
qis the internal container of call sites
op2is 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.

Member Function Documentation

◆ artificialHalt()

PcodeOp * ghidra::FlowInfo::artificialHalt ( const Address addr,
uint4  flag 
)
private

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.

  • Bad instruction
  • Unimplemented instruction
  • Missing/truncated instruction
  • (Previous) call that never returns
Parameters
addris the target address for the new p-code op
flagis the desired type
Returns
the new p-code op

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().

◆ branchTarget()

PcodeOp * ghidra::FlowInfo::branchTarget ( PcodeOp op) const

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.

Parameters
opis the given branch op
Returns
the targetted p-code op

References findRelTarget(), ghidra::Varnode::getAddr(), ghidra::PcodeOp::getIn(), and target().

Referenced by clearFlags(), and collectEdges().

◆ checkContainedCall()

void ghidra::FlowInfo::checkContainedCall ( void  )
private

◆ checkEZModel()

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.

Returns
true if this flow contains no CALL or BRANCH ops

References ghidra::PcodeOpBank::beginDead(), ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::isCallOrBranch(), and obank.

Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().

◆ checkForFlowModification()

bool ghidra::FlowInfo::checkForFlowModification ( FuncCallSpecs fspecs)
private

Check for modifications to flow at a call site given the recovered FuncCallSpecs.

The sub-function may be in-lined or never return.

Parameters
fspecsis the given call site
Returns
true if the sub-function never returns

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().

◆ collectEdges()

void ghidra::FlowInfo::collectEdges ( void  )
private

◆ connectBasic()

void ghidra::FlowInfo::connectBasic ( void  )
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().

◆ dedupUnprocessed()

void ghidra::FlowInfo::dedupUnprocessed ( void  )
private

Get rid of duplicates in the unprocessed list.

The list is also sorted.

References unprocessed.

Referenced by fillinBranchStubs(), and seenInstruction().

◆ deleteCallSpec()

void ghidra::FlowInfo::deleteCallSpec ( FuncCallSpecs fc)
private

Remove the given call site from the list for this function.

Parameters
fcis the given call site (which is freed by this method)

References qlst.

Referenced by injectPcode(), and seenInstruction().

◆ deleteRemainingOps()

void ghidra::FlowInfo::deleteRemainingOps ( list< PcodeOp *>::const_iterator  oiter)
private

Delete any remaining ops at the end of the instruction.

(because they have been predetermined to be dead)

Parameters
oiteris 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().

◆ doInjection()

void ghidra::FlowInfo::doInjection ( InjectPayload payload,
InjectContext icontext,
PcodeOp op,
FuncCallSpecs fc 
)
private

Inject the given payload into this flow.

The injected p-code replaces the given op, and control-flow information is updated.

Parameters
payloadis the specific injection payload
icontextis the specific context for the injection
opis 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().

◆ fallthru()

void ghidra::FlowInfo::fallthru ( void  )
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().

◆ fallthruOp()

PcodeOp * ghidra::FlowInfo::fallthruOp ( PcodeOp op) const
private

Find fallthru pcode-op for given op.

For efficiency, this method assumes the given op can actually fall-thru.

Parameters
opis the given PcodeOp
Returns
the PcodeOp that fall-thru flow would reach (or NULL if there is no possible p-code op)

References ghidra::PcodeOpBank::endDead(), ghidra::PcodeOp::getAddr(), ghidra::PcodeOp::getInsertIter(), ghidra::PcodeOp::isInstructionStart(), obank, target(), and visited.

Referenced by collectEdges(), and seenInstruction().

◆ fillinBranchStubs()

void ghidra::FlowInfo::fillinBranchStubs ( void  )
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().

◆ findRelTarget()

PcodeOp * ghidra::FlowInfo::findRelTarget ( PcodeOp op,
Address res 
) const
private

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.

Parameters
opis the given branching p-code op
resis a reference to the fall-thru address being passed back
Returns
the target PcodeOp or NULL if the fall-thru address is passed back instead

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().

◆ findUnprocessed()

void ghidra::FlowInfo::findUnprocessed ( void  )
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().

◆ forwardRecursion()

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.

Parameters
op2is the parent flow

References inline_head, and inline_recursion.

Referenced by clearFlags(), and ghidra::Funcdata::inlineFlow().

◆ handleOutOfBounds()

void ghidra::FlowInfo::handleOutOfBounds ( const Address fromaddr,
const Address toaddr 
)
private

Generate warning message or throw exception for given flow that is out of bounds.

Parameters
fromaddris the source address of the flow (presumably in bounds)
toaddris 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().

◆ injectPcode()

void ghidra::FlowInfo::injectPcode ( void  )

◆ injectSubFunction()

bool ghidra::FlowInfo::injectSubFunction ( FuncCallSpecs fc)
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.

Parameters
fcis the given call site
Returns
true if the injection was successfully performed

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().

◆ injectUserOp()

void ghidra::FlowInfo::injectUserOp ( PcodeOp op)
private

◆ inlineClone()

void ghidra::FlowInfo::inlineClone ( const FlowInfo inlineflow,
const Address retaddr 
)

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.

Parameters
inlineflowis the given in-line flow to clone
retaddris 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().

◆ inlineEZClone()

void ghidra::FlowInfo::inlineEZClone ( const FlowInfo inlineflow,
const Address calladdr 
)

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.

Parameters
inlineflowis the given in-line flow to clone
calladdris 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().

◆ inlineSubFunction()

bool ghidra::FlowInfo::inlineSubFunction ( FuncCallSpecs fc)
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.

Parameters
fcis the given call site
Returns
true if the in-lining is successful

References data, ghidra::FuncCallSpecs::getFuncdata(), ghidra::FuncCallSpecs::getOp(), ghidra::Funcdata::inlineFlow(), and setPossibleUnreachable().

Referenced by injectPcode(), and seenInstruction().

◆ isInArray()

bool ghidra::FlowInfo::isInArray ( vector< PcodeOp *> &  array,
PcodeOp op 
)
staticprivate

Test if the given p-code op is a member of an array.

Parameters
arrayis the array of p-code ops to search
opis the given p-code op to search for
Returns
true if the op is a member of the array

Referenced by recoverJumpTables(), and seenInstruction().

◆ newAddress()

void ghidra::FlowInfo::newAddress ( PcodeOp from,
const Address to 
)
private

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.

Parameters
fromis the PcodeOp issuing the branch
tois 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().

◆ processInstruction()

bool ghidra::FlowInfo::processInstruction ( const Address curaddr,
bool &  startbasic 
)
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.

Parameters
curaddris the address of the instruction to process
startbasicindicates of the instruction starts a basic block and passes back whether the next instruction does
Returns
true if the processed instruction has a fall-thru flow

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().

◆ queryCall()

void ghidra::FlowInfo::queryCall ( FuncCallSpecs fspecs)
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.

Parameters
fspecsis 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().

◆ recoverJumpTables()

void ghidra::FlowInfo::recoverJumpTables ( vector< JumpTable *> &  newTables,
vector< PcodeOp *> &  notreached 
)
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.

Parameters
newTableswill hold the list of recovered JumpTables
notreachedwill 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().

◆ reinterpreted()

void ghidra::FlowInfo::reinterpreted ( const Address addr)
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.

Parameters
addris 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().

◆ setFallthruBound()

bool ghidra::FlowInfo::setFallthruBound ( Address bound)
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

Parameters
boundpasses back the first address encountered that we have already seen
Returns
false if the address has already been visited

References addrlist, data, eaddr, ghidra::Funcdata::opMarkStartBasic(), reinterpreted(), target(), and visited.

Referenced by fallthru(), and seenInstruction().

◆ setupCallindSpecs()

bool ghidra::FlowInfo::setupCallindSpecs ( PcodeOp op,
FuncCallSpecs fc 
)
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.

Parameters
opis the given CALLIND op
fcis non-NULL if injection is in progress and a cycle check needs to be made
Returns
true if it is discovered the sub-function never returns

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().

◆ setupCallSpecs()

bool ghidra::FlowInfo::setupCallSpecs ( PcodeOp op,
FuncCallSpecs fc 
)
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.

Parameters
opis the given CALL op
fcis non-NULL if injection is in progress and a cycle check needs to be made
Returns
true if it is discovered the sub-function never returns

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().

◆ splitBasic()

void ghidra::FlowInfo::splitBasic ( void  )
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().

◆ target()

PcodeOp * ghidra::FlowInfo::target ( const Address addr) const

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.

Parameters
addris the given address of the instruction
Returns
the targetted p-code op

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().

◆ testHardInlineRestrictions()

bool ghidra::FlowInfo::testHardInlineRestrictions ( Funcdata inlinefd,
PcodeOp op,
Address retaddr 
)

For in-lining using the hard model, make sure some restrictions are met.

  • Can only in-line the function once.
  • There must be a p-code op to return to.
  • There must be a distinct return address, so that the RETURN can be replaced with a BRANCH.

Pass back the distinct return address, unless the in-lined function doesn't return.

Parameters
inlinefdis the function being in-lined into this flow
opis CALL instruction at the site of the in-line
retaddrholds the passed back return address
Returns
true if all the hard model restrictions are met

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().

◆ truncateIndirectJump()

void ghidra::FlowInfo::truncateIndirectJump ( PcodeOp op,
int4  failuremode 
)
private

Treat indirect jump as indirect call that never returns.

Parameters
opis the BRANCHIND operation to convert
failuremodeis 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().

◆ xrefControlFlow()

PcodeOp * ghidra::FlowInfo::xrefControlFlow ( list< PcodeOp *>::const_iterator  oiter,
bool &  startbasic,
bool &  isfallthru,
FuncCallSpecs fc 
)
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.

Parameters
oiteris the given iterator starting the list of p-code ops
startbasicis the reference holding whether the current op starts a basic block
isfallthrupasses back if the instruction has fall-thru flow
fcif the p-code is generated from an injection, this holds the reference to the injecting sub-function
Returns
the last processed PcodeOp (or NULL if there were no ops in the instruction)

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().

◆ xrefInlinedBranch()

void ghidra::FlowInfo::xrefInlinedBranch ( PcodeOp op)
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.

Parameters
opis 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().


The documentation for this class was generated from the following files: