decompiler
1.0.0
|
Class for splitting data-flow on laned registers. More...
#include <subflow.hh>
Classes | |
class | WorkNode |
Description of a large Varnode that needs to be traced (in the worklist) More... | |
Public Member Functions | |
LaneDivide (Funcdata *f, Varnode *root, const LaneDescription &desc, bool allowDowncast) | |
Constructor. More... | |
bool | doTrace (void) |
Trace lanes as far as possible from the root Varnode. More... | |
Public Member Functions inherited from ghidra::TransformManager | |
TransformManager (Funcdata *f) | |
Constructor. | |
virtual | ~TransformManager (void) |
Destructor. | |
virtual bool | preserveAddress (Varnode *vn, int4 bitSize, int4 lsbOffset) const |
Should the address of the given Varnode be preserved when constructing a piece. More... | |
Funcdata * | getFunction (void) const |
Get function being transformed. | |
void | clearVarnodeMarks (void) |
Clear mark for all Varnodes in the map. | |
TransformVar * | newPreexistingVarnode (Varnode *vn) |
Make placeholder for preexisting Varnode. More... | |
TransformVar * | newUnique (int4 size) |
Make placeholder for new unique space Varnode. More... | |
TransformVar * | newConstant (int4 size, int4 lsbOffset, uintb val) |
Make placeholder for constant Varnode. More... | |
TransformVar * | newIop (Varnode *vn) |
Make placeholder for special iop constant. More... | |
TransformVar * | newPiece (Varnode *vn, int4 bitSize, int4 lsbOffset) |
Make placeholder for piece of a Varnode. More... | |
TransformVar * | newSplit (Varnode *vn, const LaneDescription &description) |
Create placeholder nodes splitting a Varnode into its lanes. More... | |
TransformVar * | newSplit (Varnode *vn, const LaneDescription &description, int4 numLanes, int4 startLane) |
Create placeholder nodes splitting a Varnode into a subset of lanes in the given description. More... | |
TransformOp * | newOpReplace (int4 numParams, OpCode opc, PcodeOp *replace) |
Create a new placeholder op intended to replace an existing op. More... | |
TransformOp * | newOp (int4 numParams, OpCode opc, TransformOp *follow) |
Create a new placeholder op that will not replace an existing op. More... | |
TransformOp * | newPreexistingOp (int4 numParams, OpCode opc, PcodeOp *originalOp) |
Create a new placeholder op for an existing PcodeOp. More... | |
TransformVar * | getPreexistingVarnode (Varnode *vn) |
Get (or create) placeholder for preexisting Varnode. More... | |
TransformVar * | getPiece (Varnode *vn, int4 bitSize, int4 lsbOffset) |
Get (or create) placeholder piece. More... | |
TransformVar * | getSplit (Varnode *vn, const LaneDescription &description) |
Find (or create) placeholder nodes splitting a Varnode into its lanes. More... | |
TransformVar * | getSplit (Varnode *vn, const LaneDescription &description, int4 numLanes, int4 startLane) |
Find (or create) placeholder nodes splitting a Varnode into a subset of lanes from a description. More... | |
void | opSetInput (TransformOp *rop, TransformVar *rvn, int4 slot) |
Mark given variable as input to given op. More... | |
void | opSetOutput (TransformOp *rop, TransformVar *rvn) |
Mark given variable as output of given op. More... | |
void | apply (void) |
Apply the full transform to the function. | |
Private Member Functions | |
TransformVar * | setReplacement (Varnode *vn, int4 numLanes, int4 skipLanes) |
Find or build the placeholder objects for a Varnode that needs to be split into lanes. More... | |
void | buildUnaryOp (OpCode opc, PcodeOp *op, TransformVar *inVars, TransformVar *outVars, int4 numLanes) |
Build unary op placeholders with the same opcode across a set of lanes. More... | |
void | buildBinaryOp (OpCode opc, PcodeOp *op, TransformVar *in0Vars, TransformVar *in1Vars, TransformVar *outVars, int4 numLanes) |
Build binary op placeholders with the same opcode across a set of lanes. More... | |
bool | buildPiece (PcodeOp *op, TransformVar *outVars, int4 numLanes, int4 skipLanes) |
Convert a CPUI_PIECE operation into copies between placeholders, given the output lanes. More... | |
bool | buildMultiequal (PcodeOp *op, TransformVar *outVars, int4 numLanes, int4 skipLanes) |
Split a given CPUI_MULTIEQUAL operation into placeholders given the output lanes. More... | |
bool | buildStore (PcodeOp *op, int4 numLanes, int4 skipLanes) |
Split a given CPUI_STORE operation into a sequence of STOREs of individual lanes. More... | |
bool | buildLoad (PcodeOp *op, TransformVar *outVars, int4 numLanes, int4 skipLanes) |
Split a given CPUI_LOAD operation into a sequence of LOADs of individual lanes. More... | |
bool | buildRightShift (PcodeOp *op, TransformVar *outVars, int4 numLanes, int4 skipLanes) |
Check that a CPUI_INT_RIGHT respects the lanes then generate lane placeholders. More... | |
bool | traceForward (TransformVar *rvn, int4 numLanes, int4 skipLanes) |
Push the logical lanes forward through any PcodeOp reading the given variable. More... | |
bool | traceBackward (TransformVar *rvn, int4 numLanes, int4 skipLanes) |
Pull the logical lanes back through the defining PcodeOp of the given variable. More... | |
bool | processNextWork (void) |
Process the next Varnode on the work list. More... | |
Private Attributes | |
LaneDescription | description |
Global description of lanes that need to be split. | |
vector< WorkNode > | workList |
List of Varnodes still left to trace. | |
bool | allowSubpieceTerminator |
true if we allow lanes to be cast (via SUBPIECE) to a smaller integer size | |
Additional Inherited Members | |
Static Public Member Functions inherited from ghidra::TransformManager | |
static bool | preexistingGuard (int4 slot, TransformVar *rvn) |
Should newPreexistingOp be called. More... | |
Class for splitting data-flow on laned registers.
From a root Varnode and a description of its lanes, trace data-flow as far as possible through the function, propagating each lane, using the doTrace() method. Then using the apply() method, data-flow can be split, making each lane in every traced register into an explicit Varnode
ghidra::LaneDivide::LaneDivide | ( | Funcdata * | f, |
Varnode * | root, | ||
const LaneDescription & | desc, | ||
bool | allowDowncast | ||
) |
Constructor.
f | is the function being transformed |
root | is the root Varnode to start tracing lanes from |
desc | is a description of the lanes on the root Varnode |
allowDowncast | is true if we all SUBPIECE to be treated as terminating |
References allowSubpieceTerminator, ghidra::LaneDescription::getNumLanes(), and setReplacement().
|
private |
Build binary op placeholders with the same opcode across a set of lanes.
We assume the input and output placeholder variables have already been collected
opc | is the desired opcode for the new op placeholders |
op | is the PcodeOp getting replaced |
in0Vars | is the array of input[0] variables, 1 for each binary op |
in1Vars | is the array of input[1] variables, 1 for each binar op |
outVars | is the array of output variables, 1 for each binary op |
numLanes | is the number of binary ops to create |
References ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::opSetInput(), and ghidra::TransformManager::opSetOutput().
|
private |
Split a given CPUI_LOAD operation into a sequence of LOADs of individual lanes.
A new pointer is constructed for each individual lane into a temporary, then a LOAD is created using the pointer that loads an individual lane.
op | is the given CPUI_LOAD PcodeOp |
outVars | is the output placeholders for the LOAD |
numLanes | is the number of lanes the LOAD is split into |
skipLanes | is the starting lane (within the global description) of the value being loaded |
References ghidra::CPUI_INT_ADD, ghidra::CPUI_LOAD, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), ghidra::TransformManager::getPreexistingVarnode(), ghidra::Varnode::getSize(), ghidra::Varnode::getSpaceFromConst(), ghidra::AddrSpace::isBigEndian(), ghidra::Varnode::isConstant(), ghidra::Varnode::isFree(), ghidra::TransformManager::newConstant(), ghidra::TransformManager::newOp(), ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::newUnique(), ghidra::TransformManager::opSetInput(), and ghidra::TransformManager::opSetOutput().
|
private |
Split a given CPUI_MULTIEQUAL operation into placeholders given the output lanes.
Model the single given CPUI_MULTIEQUAL as a sequence of smaller MULTIEQUALs on each individual lane. Return false if the operation cannot be modeled as naturally.
op | is the original CPUI_MULTIEQUAL PcodeOp |
outVars | is the placeholder variables making up the lanes of the output |
numLanes | is the number of lanes in the output |
skipLanes | is the index of the least significant output lane within the global description |
References ghidra::CPUI_MULTIEQUAL, ghidra::PcodeOp::getIn(), ghidra::TransformManager::newOpReplace(), ghidra::PcodeOp::numInput(), ghidra::TransformManager::opSetInput(), ghidra::TransformManager::opSetOutput(), and ghidra::SubfloatFlow::setReplacement().
|
private |
Convert a CPUI_PIECE operation into copies between placeholders, given the output lanes.
Model the given CPUI_PIECE either as either copies from preexisting Varnodes into the output lanes, or as copies from placeholder variables into the output lanes. Return false if the operation cannot be modeled as natural copies between lanes.
op | is the original CPUI_PIECE PcodeOp |
outVars | is the placeholder variables making up the lanes of the output |
numLanes | is the number of lanes in the output |
skipLanes | is the index of the least significant output lane within the global description |
References ghidra::CPUI_COPY, ghidra::PcodeOp::getIn(), ghidra::TransformManager::getPreexistingVarnode(), ghidra::Varnode::getSize(), ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::opSetInput(), ghidra::TransformManager::opSetOutput(), and ghidra::SubfloatFlow::setReplacement().
|
private |
Check that a CPUI_INT_RIGHT respects the lanes then generate lane placeholders.
For the given lane scheme, check that the RIGHT shift is copying whole lanes to each other. If so, generate the placeholder COPYs that model the shift.
op | is the given CPUI_INT_RIGHT PcodeOp |
outVars | is the output placeholders for the RIGHT shift |
numLanes | is the number of lanes the shift is split into |
skipLanes | is the starting lane (within the global description) of the value being loaded |
References ghidra::CPUI_COPY, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::isConstant(), ghidra::TransformManager::newConstant(), ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::opSetInput(), ghidra::TransformManager::opSetOutput(), and ghidra::SubfloatFlow::setReplacement().
|
private |
Split a given CPUI_STORE operation into a sequence of STOREs of individual lanes.
A new pointer is constructed for each individual lane into a temporary, then a STORE is created using the pointer that stores an individual lane.
op | is the given CPUI_STORE PcodeOp |
numLanes | is the number of lanes the STORE is split into |
skipLanes | is the starting lane (within the global description) of the value being stored |
References ghidra::CPUI_INT_ADD, ghidra::CPUI_STORE, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::TransformManager::getPreexistingVarnode(), ghidra::Varnode::getSize(), ghidra::Varnode::getSpaceFromConst(), ghidra::AddrSpace::isBigEndian(), ghidra::Varnode::isConstant(), ghidra::Varnode::isFree(), ghidra::TransformManager::newConstant(), ghidra::TransformManager::newOp(), ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::newUnique(), ghidra::TransformManager::opSetInput(), ghidra::TransformManager::opSetOutput(), and ghidra::SubfloatFlow::setReplacement().
|
private |
Build unary op placeholders with the same opcode across a set of lanes.
We assume the input and output placeholder variables have already been collected
opc | is the desired opcode for the new op placeholders |
op | is the PcodeOp getting replaced |
inVars | is the array of input variables, 1 for each unary op |
outVars | is the array of output variables, 1 for each unary op |
numLanes | is the number of unary ops to create |
References ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::opSetInput(), and ghidra::TransformManager::opSetOutput().
bool ghidra::LaneDivide::doTrace | ( | void | ) |
Trace lanes as far as possible from the root Varnode.
Push the lanes around from the root, setting up the explicit transforms as we go. If at any point, the lanes cannot be naturally pushed, return false.
References ghidra::TransformManager::clearVarnodeMarks(), processNextWork(), and workList.
|
private |
Process the next Varnode on the work list.
References ghidra::SubfloatFlow::traceBackward(), and ghidra::SubfloatFlow::traceForward().
Referenced by doTrace().
|
private |
Find or build the placeholder objects for a Varnode that needs to be split into lanes.
The Varnode is split based on the given subset of the lane description. Constants can be split. Decide if the Varnode needs to go into the work list. If the Varnode cannot be acceptably split, return null.
vn | is the Varnode that needs to be split |
numLanes | is the number of lanes in the subset |
skipLanes | is the start (least significant) lane in the subset |
References ghidra::Datatype::getMetatype(), ghidra::TransformManager::getSplit(), ghidra::Varnode::getType(), ghidra::Varnode::isConstant(), ghidra::Varnode::isFree(), ghidra::Varnode::isMark(), ghidra::Varnode::isTypeLock(), ghidra::TransformManager::newSplit(), ghidra::Varnode::setMark(), and ghidra::TYPE_PARTIALSTRUCT.
Referenced by LaneDivide().
|
private |
Pull the logical lanes back through the defining PcodeOp of the given variable.
Determine if the logical lanes can be pulled back naturally, and create placeholder variables and ops representing the logical data-flow. Update the worklist with any new Varnodes that the lanes get pulled back into.
rvn | is the placeholder variable to pull back |
numLanes | is the number of lanes represented by the placeholder variable |
skipLanes | is the index of the starting lane within the global description of the placeholder variable |
References ghidra::PcodeOp::code(), ghidra::CPUI_COPY, ghidra::CPUI_INT_AND, ghidra::CPUI_INT_NEGATE, ghidra::CPUI_INT_OR, ghidra::CPUI_INT_RIGHT, ghidra::CPUI_INT_XOR, ghidra::CPUI_LOAD, ghidra::CPUI_MULTIEQUAL, ghidra::CPUI_PIECE, ghidra::CPUI_SUBPIECE, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::TransformVar::getOriginal(), ghidra::Varnode::getSize(), and ghidra::SubfloatFlow::setReplacement().
|
private |
Push the logical lanes forward through any PcodeOp reading the given variable.
Determine if the logical lanes can be pushed forward naturally, and create placeholder variables and ops representing the logical data-flow. Update the worklist with any new Varnodes that the lanes get pushed into.
rvn | is the placeholder variable to push forward from |
numLanes | is the number of lanes represented by the placeholder variable |
skipLanes | is the index of the starting lane within the global description of the placeholder variable |
References ghidra::Varnode::beginDescend(), ghidra::PcodeOp::code(), ghidra::CPUI_COPY, ghidra::CPUI_INT_AND, ghidra::CPUI_INT_NEGATE, ghidra::CPUI_INT_OR, ghidra::CPUI_INT_RIGHT, ghidra::CPUI_INT_XOR, ghidra::CPUI_MULTIEQUAL, ghidra::CPUI_PIECE, ghidra::CPUI_STORE, ghidra::CPUI_SUBPIECE, ghidra::Varnode::endDescend(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::TransformVar::getOriginal(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::Varnode::isConstant(), ghidra::Varnode::isMark(), ghidra::TransformManager::newConstant(), ghidra::TransformManager::newPreexistingOp(), ghidra::TransformManager::opSetInput(), and ghidra::SubfloatFlow::setReplacement().