mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Making a couple more analyses STORE-based INDIRECT aware
This commit is contained in:
parent
29f207400d
commit
e8fb8b3a19
4 changed files with 284 additions and 104 deletions
|
@ -635,7 +635,7 @@ bool Funcdata::replaceVolatile(Varnode *vn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Check if the given Varnode only flows into INDIRECT ops
|
/// \brief Check if the given Varnode only flows into call-based INDIRECT ops
|
||||||
///
|
///
|
||||||
/// Flow is only followed through MULTIEQUAL ops.
|
/// Flow is only followed through MULTIEQUAL ops.
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
|
@ -654,8 +654,17 @@ bool Funcdata::checkIndirectUse(Varnode *vn)
|
||||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||||
PcodeOp *op = *iter;
|
PcodeOp *op = *iter;
|
||||||
OpCode opc = op->code();
|
OpCode opc = op->code();
|
||||||
if (opc == CPUI_INDIRECT) continue;
|
if (opc == CPUI_INDIRECT) {
|
||||||
if (opc == CPUI_MULTIEQUAL) {
|
if (op->isIndirectStore()) {
|
||||||
|
// INDIRECT from a STORE is not a negative result but continue to follow data-flow
|
||||||
|
Varnode *outvn = op->getOut();
|
||||||
|
if (!outvn->isMark()) {
|
||||||
|
vlist.push_back(outvn);
|
||||||
|
outvn->setMark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (opc == CPUI_MULTIEQUAL) {
|
||||||
Varnode *outvn = op->getOut();
|
Varnode *outvn = op->getOut();
|
||||||
if (!outvn->isMark()) {
|
if (!outvn->isMark()) {
|
||||||
vlist.push_back(outvn);
|
vlist.push_back(outvn);
|
||||||
|
@ -1294,11 +1303,12 @@ bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamT
|
||||||
/// \brief Test if the given trial Varnode is likely only used for parameter passing
|
/// \brief Test if the given trial Varnode is likely only used for parameter passing
|
||||||
///
|
///
|
||||||
/// Flow is followed from the Varnode itself and from ancestors the Varnode was copied from
|
/// Flow is followed from the Varnode itself and from ancestors the Varnode was copied from
|
||||||
/// to see if it hits anything other than the CALL operation.
|
/// to see if it hits anything other than the given CALL or RETURN operation.
|
||||||
/// \param maxlevel is the maximum number of times to recurse through ancestor copies
|
/// \param maxlevel is the maximum number of times to recurse through ancestor copies
|
||||||
/// \param invn is the given trial Varnode to test
|
/// \param invn is the given trial Varnode to test
|
||||||
|
/// \param op is the given CALL or RETURN
|
||||||
/// \param trial is the associated parameter trial object
|
/// \param trial is the associated parameter trial object
|
||||||
/// \return \b true if the Varnode is only used for the CALL
|
/// \return \b true if the Varnode is only used for the CALL/RETURN
|
||||||
bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
|
||||||
const PcodeOp *op,ParamTrial &trial) const
|
const PcodeOp *op,ParamTrial &trial) const
|
||||||
|
|
||||||
|
|
|
@ -2432,7 +2432,7 @@ void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,const vec
|
||||||
PcodeOp *op = vn->getDef();
|
PcodeOp *op = vn->getDef();
|
||||||
switch(op->code()) { // Distinguish ops where we can never predict an integer range
|
switch(op->code()) { // Distinguish ops where we can never predict an integer range
|
||||||
case CPUI_INDIRECT:
|
case CPUI_INDIRECT:
|
||||||
if (indirectAsCopy) {
|
if (indirectAsCopy || op->isIndirectStore()) {
|
||||||
Varnode *inVn = op->getIn(0);
|
Varnode *inVn = op->getIn(0);
|
||||||
if (!inVn->isMark()) {
|
if (!inVn->isMark()) {
|
||||||
newValueSet(inVn,0);
|
newValueSet(inVn,0);
|
||||||
|
|
|
@ -15,9 +15,14 @@
|
||||||
*/
|
*/
|
||||||
#include "subflow.hh"
|
#include "subflow.hh"
|
||||||
|
|
||||||
|
/// \brief Return \e slot of constant if INT_OR op sets all bits in mask, otherwise -1
|
||||||
|
///
|
||||||
|
/// \param orop is the given CPUI_INT_OR op
|
||||||
|
/// \param mask is the given mask
|
||||||
|
/// \return constant slot or -1
|
||||||
int4 SubvariableFlow::doesOrSet(PcodeOp *orop,uintb mask)
|
int4 SubvariableFlow::doesOrSet(PcodeOp *orop,uintb mask)
|
||||||
|
|
||||||
{ // Return index of constant if OR op sets bits in mask, otherwise -1
|
{
|
||||||
int4 index = (orop->getIn(1)->isConstant() ? 1 : 0);
|
int4 index = (orop->getIn(1)->isConstant() ? 1 : 0);
|
||||||
if (!orop->getIn(index)->isConstant())
|
if (!orop->getIn(index)->isConstant())
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -27,9 +32,14 @@ int4 SubvariableFlow::doesOrSet(PcodeOp *orop,uintb mask)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Return \e slot of constant if INT_AND op clears all bits in mask, otherwise -1
|
||||||
|
///
|
||||||
|
/// \param andop is the given CPUI_INT_AND op
|
||||||
|
/// \param mask is the given mask
|
||||||
|
/// \return constant slot or -1
|
||||||
int4 SubvariableFlow::doesAndClear(PcodeOp *andop,uintb mask)
|
int4 SubvariableFlow::doesAndClear(PcodeOp *andop,uintb mask)
|
||||||
|
|
||||||
{ // Return index of constant if AND op clears bits in mask, otherwise -1
|
{
|
||||||
int4 index = (andop->getIn(1)->isConstant() ? 1 : 0);
|
int4 index = (andop->getIn(1)->isConstant() ? 1 : 0);
|
||||||
if (!andop->getIn(index)->isConstant())
|
if (!andop->getIn(index)->isConstant())
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -39,9 +49,20 @@ int4 SubvariableFlow::doesAndClear(PcodeOp *andop,uintb mask)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Add the given Varnode as a new node in the logical subgraph
|
||||||
|
///
|
||||||
|
/// A new ReplaceVarnode object is created, representing the given Varnode within
|
||||||
|
/// the logical subgraph, and returned. If an object representing the Varnode already
|
||||||
|
/// exists it is returned. A mask describing the subset of bits within the Varnode
|
||||||
|
/// representing the logical value is also passed in. This method also determines if
|
||||||
|
/// the new node needs to be added to the worklist for continued tracing.
|
||||||
|
/// \param vn is the given Varnode holding the logical value
|
||||||
|
/// \param mask is the given mask describing the bits of the logical value
|
||||||
|
/// \param inworklist will hold \b true if the new node should be traced further
|
||||||
|
/// \return the new subgraph variable node
|
||||||
SubvariableFlow::ReplaceVarnode *SubvariableFlow::setReplacement(Varnode *vn,uintb mask,bool &inworklist)
|
SubvariableFlow::ReplaceVarnode *SubvariableFlow::setReplacement(Varnode *vn,uintb mask,bool &inworklist)
|
||||||
|
|
||||||
{ // Mark
|
{
|
||||||
ReplaceVarnode *res;
|
ReplaceVarnode *res;
|
||||||
if (vn->isMark()) { // Already seen before
|
if (vn->isMark()) { // Already seen before
|
||||||
map<Varnode *,ReplaceVarnode>::iterator iter;
|
map<Varnode *,ReplaceVarnode>::iterator iter;
|
||||||
|
@ -126,9 +147,15 @@ SubvariableFlow::ReplaceVarnode *SubvariableFlow::setReplacement(Varnode *vn,uin
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Create a logical subgraph operator node given its output variable node
|
||||||
|
///
|
||||||
|
/// \param opc is the opcode of the new logical operator
|
||||||
|
/// \param numparam is the number of parameters in the new operator
|
||||||
|
/// \param outrvn is the given output variable node
|
||||||
|
/// \return the new logical subgraph operator object
|
||||||
SubvariableFlow::ReplaceOp *SubvariableFlow::createOp(OpCode opc,int4 numparam,ReplaceVarnode *outrvn)
|
SubvariableFlow::ReplaceOp *SubvariableFlow::createOp(OpCode opc,int4 numparam,ReplaceVarnode *outrvn)
|
||||||
|
|
||||||
{ // Create record for replacement op, given its replacement varnode output
|
{
|
||||||
if (outrvn->def != (ReplaceOp *)0)
|
if (outrvn->def != (ReplaceOp *)0)
|
||||||
return outrvn->def;
|
return outrvn->def;
|
||||||
oplist.push_back(ReplaceOp());
|
oplist.push_back(ReplaceOp());
|
||||||
|
@ -142,9 +169,17 @@ SubvariableFlow::ReplaceOp *SubvariableFlow::createOp(OpCode opc,int4 numparam,R
|
||||||
return rop;
|
return rop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// \brief Create a logical subraph operator node given one of its input variable nodes
|
||||||
|
///
|
||||||
|
/// \param opc is the opcode of the new logical operator
|
||||||
|
/// \param numparam is the number of parameters in the new operator
|
||||||
|
/// \param inrvn is the given input variable node
|
||||||
|
/// \param slot is the input slot of the variable node
|
||||||
|
/// \return the new logical subgraph operator objects
|
||||||
SubvariableFlow::ReplaceOp *SubvariableFlow::createOpDown(OpCode opc,int4 numparam,PcodeOp *op,ReplaceVarnode *inrvn,int4 slot)
|
SubvariableFlow::ReplaceOp *SubvariableFlow::createOpDown(OpCode opc,int4 numparam,PcodeOp *op,ReplaceVarnode *inrvn,int4 slot)
|
||||||
|
|
||||||
{ // Create record for replacement op, given one of its input replacement varnodes
|
{
|
||||||
oplist.push_back(ReplaceOp());
|
oplist.push_back(ReplaceOp());
|
||||||
ReplaceOp *rop = &oplist.back();
|
ReplaceOp *rop = &oplist.back();
|
||||||
rop->op = op;
|
rop->op = op;
|
||||||
|
@ -157,9 +192,17 @@ SubvariableFlow::ReplaceOp *SubvariableFlow::createOpDown(OpCode opc,int4 numpar
|
||||||
return rop;
|
return rop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Convert a new INDIRECT op into the logically trimmed variant of the given original PcodeOp
|
||||||
|
///
|
||||||
|
/// This method assumes the original op was an \e indirect \e creation. The input and output
|
||||||
|
/// Varnode for the new INDIRECT are not provided by this method. It only provides the
|
||||||
|
/// \e indirect \e effect input and patches up any active parameter recovery process.
|
||||||
|
/// \param newop is the new INDIRECT op to convert
|
||||||
|
/// \param oldop is the original INDIRECT op
|
||||||
|
/// \param out is the subgraph output variable node of the new INDIRECT
|
||||||
void SubvariableFlow::patchIndirect(PcodeOp *newop,PcodeOp *oldop, ReplaceVarnode *out)
|
void SubvariableFlow::patchIndirect(PcodeOp *newop,PcodeOp *oldop, ReplaceVarnode *out)
|
||||||
|
|
||||||
{ // Finish converting -newop- into the logically trimmed variant of -oldop-
|
{
|
||||||
PcodeOp *indop = PcodeOp::getOpFromConst(oldop->getIn(1)->getAddr());
|
PcodeOp *indop = PcodeOp::getOpFromConst(oldop->getIn(1)->getAddr());
|
||||||
bool possibleout = !oldop->getIn(0)->isIndirectZero();
|
bool possibleout = !oldop->getIn(0)->isIndirectZero();
|
||||||
Varnode *outvn = getReplaceVarnode(out);
|
Varnode *outvn = getReplaceVarnode(out);
|
||||||
|
@ -176,9 +219,18 @@ void SubvariableFlow::patchIndirect(PcodeOp *newop,PcodeOp *oldop, ReplaceVarnod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if the given subgraph variable can act as a parameter to the given CALL op
|
||||||
|
///
|
||||||
|
/// We assume the variable flows as a parameter to the CALL. If the CALL doesn't lock the parameter
|
||||||
|
/// size, create a PatchRecord within the subgraph that allows the CALL to take the parameter
|
||||||
|
/// with its smaller logical size.
|
||||||
|
/// \param op is the given CALL op
|
||||||
|
/// \param rvn is the given subgraph variable acting as a parameter
|
||||||
|
/// \param slot is the input slot of the variable within the CALL
|
||||||
|
/// \return \b true if the parameter can be successfully trimmed to its logical size
|
||||||
bool SubvariableFlow::tryCallPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot)
|
bool SubvariableFlow::tryCallPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot)
|
||||||
|
|
||||||
{ // -rvn- is flowing as parameter to the call -op-, determine if we can still trim the varnode to its logical size
|
{
|
||||||
if (slot == 0) return false;
|
if (slot == 0) return false;
|
||||||
FuncCallSpecs *fc = fd->getCallSpecs(op);
|
FuncCallSpecs *fc = fd->getCallSpecs(op);
|
||||||
if (fc == (FuncCallSpecs *)0) return false;
|
if (fc == (FuncCallSpecs *)0) return false;
|
||||||
|
@ -194,9 +246,17 @@ bool SubvariableFlow::tryCallPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if the given subgraph variable can act as return value for the given RETURN op
|
||||||
|
///
|
||||||
|
/// We assume the variable flows the RETURN. If the return value size is not locked. Create a
|
||||||
|
/// PatchRecord within the subgraph that allows the RETURN to take a smaller logical value.
|
||||||
|
/// \param op is the given RETURN op
|
||||||
|
/// \param rvn is the given subgraph variable flowing to the RETURN
|
||||||
|
/// \param slot is the input slot of the subgraph variable
|
||||||
|
/// \return \b true if the return value can be successfully trimmed to its logical size
|
||||||
bool SubvariableFlow::tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot)
|
bool SubvariableFlow::tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot)
|
||||||
|
|
||||||
{ // -rvn- flows to CPUI_RETURN (is probably being returned by function), determine if we can trim varnode to logical size
|
{
|
||||||
if (slot == 0) return false; // Don't deal with actual return address container
|
if (slot == 0) return false; // Don't deal with actual return address container
|
||||||
if (fd->getFuncProto().isOutputLocked()) return false;
|
if (fd->getFuncProto().isOutputLocked()) return false;
|
||||||
|
|
||||||
|
@ -229,9 +289,16 @@ bool SubvariableFlow::tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine if the given subgraph variable can act as a \e created value for the given INDIRECT op
|
||||||
|
///
|
||||||
|
/// Check if the INDIRECT is an \e indirect \e creation and is not representing a locked return value.
|
||||||
|
/// If we can, create the INDIRECT node in the subgraph representing the logical \e indirect \e creation.
|
||||||
|
/// \param op is the given INDIRECT
|
||||||
|
/// \param rvn is the given subgraph variable acting as the output of the INDIRECT
|
||||||
|
/// \return \b true if we can successfully trim the value to its logical size
|
||||||
bool SubvariableFlow::tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn)
|
bool SubvariableFlow::tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // -rvn- is defined by a CALL op, check if the call is actively recovering the return value and if we can trim
|
{
|
||||||
if (!op->isIndirectCreation()) return false;
|
if (!op->isIndirectCreation()) return false;
|
||||||
PcodeOp *indop = PcodeOp::getOpFromConst(op->getIn(1)->getAddr());
|
PcodeOp *indop = PcodeOp::getOpFromConst(op->getIn(1)->getAddr());
|
||||||
FuncCallSpecs *fc = fd->getCallSpecs(indop);
|
FuncCallSpecs *fc = fd->getCallSpecs(indop);
|
||||||
|
@ -250,11 +317,13 @@ bool SubvariableFlow::tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to trace the logical variable through descendant Varnodes
|
||||||
|
/// creating new nodes in the logical subgraph and updating the worklist.
|
||||||
|
/// \param rvn is the given subgraph variable to trace
|
||||||
|
/// \return \b true if the logical value can be traced forward one level
|
||||||
bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
|
bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Try to trace logical variable through descendant varnodes
|
{
|
||||||
// updating list/map of replace_ops and replace_varnodes
|
|
||||||
// and the worklist
|
|
||||||
ReplaceOp *rop;
|
ReplaceOp *rop;
|
||||||
PcodeOp *op;
|
PcodeOp *op;
|
||||||
Varnode *outvn;
|
Varnode *outvn;
|
||||||
|
@ -508,11 +577,13 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trace the logical value backward through one PcodeOp adding new nodes to the
|
||||||
|
/// logical subgraph and updating the worklist.
|
||||||
|
/// \param rvn is the given logical value to trace
|
||||||
|
/// \return \b true if the logical value can be traced backward one level
|
||||||
bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn)
|
bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Trace backward through defining op one level
|
{
|
||||||
// Update worklist, varmap, and oplist
|
|
||||||
// return false if the trace is aborted
|
|
||||||
PcodeOp *op = rvn->vn->getDef();
|
PcodeOp *op = rvn->vn->getDef();
|
||||||
if (op == (PcodeOp *)0) return true; // If vn is input
|
if (op == (PcodeOp *)0) return true; // If vn is input
|
||||||
int4 sa;
|
int4 sa;
|
||||||
|
@ -647,6 +718,7 @@ bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CPUI_INDIRECT:
|
case CPUI_INDIRECT:
|
||||||
|
// TODO: This assumes that the INDIRECT is CALL-based. Add STORE-based logic.
|
||||||
if (aggressive) {
|
if (aggressive) {
|
||||||
if (tryCallReturnPull(op,rvn))
|
if (tryCallReturnPull(op,rvn))
|
||||||
return true;
|
return true;
|
||||||
|
@ -682,10 +754,13 @@ bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to trace the logical variable through descendant Varnodes, updating the logical subgraph.
|
||||||
|
/// We assume (and check) that the logical variable has always been sign extended (sextstate) into its container.
|
||||||
|
/// \param rvn is the given subgraph variable to trace
|
||||||
|
/// \return \b true if the logical value can successfully traced forward one level
|
||||||
bool SubvariableFlow::traceForwardSext(ReplaceVarnode *rvn)
|
bool SubvariableFlow::traceForwardSext(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Try to trace the logical variable through descendant varnodes, updating map of replacement ops and varnodes
|
{
|
||||||
// We assume (and check) that the logical variable has always been sign extended (sextstate) into its container
|
|
||||||
ReplaceOp *rop;
|
ReplaceOp *rop;
|
||||||
PcodeOp *op;
|
PcodeOp *op;
|
||||||
Varnode *outvn;
|
Varnode *outvn;
|
||||||
|
@ -767,10 +842,13 @@ bool SubvariableFlow::traceForwardSext(ReplaceVarnode *rvn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to trace the logical variable up through its defining op, updating the logical subgraph.
|
||||||
|
/// We assume (and check) that the logical variable has always been sign extended (sextstate) into its container.
|
||||||
|
/// \param rvn is the given subgraph variable to trace
|
||||||
|
/// \return \b true if the logical value can successfully traced backward one level
|
||||||
bool SubvariableFlow::traceBackwardSext(ReplaceVarnode *rvn)
|
bool SubvariableFlow::traceBackwardSext(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Trace backward through defining op, one level, update worklist and map
|
{
|
||||||
// We assume (and check) that the logical variable has always been sign extended (sextstate) into its container
|
|
||||||
PcodeOp *op = rvn->vn->getDef();
|
PcodeOp *op = rvn->vn->getDef();
|
||||||
if (op == (PcodeOp *)0) return true; // If vn is input
|
if (op == (PcodeOp *)0) return true; // If vn is input
|
||||||
ReplaceOp *rop;
|
ReplaceOp *rop;
|
||||||
|
@ -813,9 +891,20 @@ bool SubvariableFlow::traceBackwardSext(ReplaceVarnode *rvn)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SubvariableFlow::createLink(ReplaceOp *rop,uintb mask,int4 slot,
|
/// \brief Add a new variable to the logical subgraph as an input to the given operation
|
||||||
Varnode *vn)
|
///
|
||||||
{ // Add a new varnode (and the edge which traced to it) to the worklist
|
/// The subgraph is extended by the specified input edge, and a new variable node is created
|
||||||
|
/// if necessary or a preexisting node corresponding to the Varnode is used.
|
||||||
|
/// If the logical value described by the given mask cannot be made to line up with the
|
||||||
|
/// subgraph variable node, \b false is returned.
|
||||||
|
/// \param rop is the given operation
|
||||||
|
/// \param mask is the mask describing the logical value within the input Varnode
|
||||||
|
/// \param slot is the input slot of the Varnode to the operation
|
||||||
|
/// \param vn is the original input Varnode holding the logical value
|
||||||
|
/// \return \b true is the subgraph is successfully extended to the input
|
||||||
|
bool SubvariableFlow::createLink(ReplaceOp *rop,uintb mask,int4 slot,Varnode *vn)
|
||||||
|
|
||||||
|
{
|
||||||
bool inworklist;
|
bool inworklist;
|
||||||
ReplaceVarnode *rep = setReplacement(vn,mask,inworklist);
|
ReplaceVarnode *rep = setReplacement(vn,mask,inworklist);
|
||||||
if (rep == (ReplaceVarnode *)0) return false;
|
if (rep == (ReplaceVarnode *)0) return false;
|
||||||
|
@ -837,10 +926,19 @@ bool SubvariableFlow::createLink(ReplaceOp *rop,uintb mask,int4 slot,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Extend the logical subgraph through a given comparison operator if possible
|
||||||
|
///
|
||||||
|
/// Given the variable already in the subgraph that is compared and the other side of the
|
||||||
|
/// comparison, add the other side as a logical value to the subgraph and create a PatchRecord
|
||||||
|
/// for the comparison operation.
|
||||||
|
/// \param op is the given comparison operation
|
||||||
|
/// \param inrvn is the variable already in the logical subgraph
|
||||||
|
/// \param slot is the input slot to the comparison of the variable already in the subgraph
|
||||||
|
/// \param othervn is the Varnode holding the other side of the comparison
|
||||||
|
/// \return \b true if the logical subgraph can successfully be extended through the comparison
|
||||||
bool SubvariableFlow::createCompareBridge(PcodeOp *op,ReplaceVarnode *inrvn,int4 slot,Varnode *othervn)
|
bool SubvariableFlow::createCompareBridge(PcodeOp *op,ReplaceVarnode *inrvn,int4 slot,Varnode *othervn)
|
||||||
|
|
||||||
{ // Add a new varnode to the worklist based on subvariable flow crossing a comparison operator -op-
|
{
|
||||||
// -slot- is the slot of -inrvn- into the comparison. -othervn- is the other side of the comparison to be added
|
|
||||||
bool inworklist;
|
bool inworklist;
|
||||||
ReplaceVarnode *rep = setReplacement(othervn,inrvn->mask,inworklist);
|
ReplaceVarnode *rep = setReplacement(othervn,inrvn->mask,inworklist);
|
||||||
if (rep == (ReplaceVarnode *)0) return false;
|
if (rep == (ReplaceVarnode *)0) return false;
|
||||||
|
@ -855,6 +953,13 @@ bool SubvariableFlow::createCompareBridge(PcodeOp *op,ReplaceVarnode *inrvn,int4
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Add a constant variable node to the logical subgraph
|
||||||
|
///
|
||||||
|
/// Unlike other subgraph variable nodes, this one does not maintain a mirror with the original containing Varnode.
|
||||||
|
/// \param rop is the logical operation taking the constant as input
|
||||||
|
/// \param mask is the set of bits holding the logical value (within a bigger value)
|
||||||
|
/// \param slot is the input slot to the operation
|
||||||
|
/// \param val is the bigger constant value holding the logical value
|
||||||
SubvariableFlow::ReplaceVarnode *SubvariableFlow::addConstant(ReplaceOp *rop,uintb mask,
|
SubvariableFlow::ReplaceVarnode *SubvariableFlow::addConstant(ReplaceOp *rop,uintb mask,
|
||||||
uint4 slot,uintb val)
|
uint4 slot,uintb val)
|
||||||
{ // Add a constant to the replacement tree
|
{ // Add a constant to the replacement tree
|
||||||
|
@ -876,12 +981,15 @@ SubvariableFlow::ReplaceVarnode *SubvariableFlow::addConstant(ReplaceOp *rop,uin
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Create a new, non-shadowing, subgraph variable node as an operation output
|
||||||
|
///
|
||||||
|
/// The new node does not shadow a preexisting Varnode. Because the ReplaceVarnode record
|
||||||
|
/// is defined by rop (the -def- field is filled in) this can still be distinguished from a constant.
|
||||||
|
/// \param rop is the logical operation taking the new output
|
||||||
|
/// \param mask describes the logical value
|
||||||
void SubvariableFlow::createNewOut(ReplaceOp *rop,uintb mask)
|
void SubvariableFlow::createNewOut(ReplaceOp *rop,uintb mask)
|
||||||
|
|
||||||
{ // Create a varnode output in the replacement graph that
|
{
|
||||||
// does not shadow a preexisting varnode
|
|
||||||
// Because the ReplaceVarnode record is defined by rop
|
|
||||||
// (the -def- field is filled in) this can still be distinguished from a constant
|
|
||||||
newvarlist.push_back(ReplaceVarnode());
|
newvarlist.push_back(ReplaceVarnode());
|
||||||
ReplaceVarnode *res = &newvarlist.back();
|
ReplaceVarnode *res = &newvarlist.back();
|
||||||
res->vn = (Varnode *)0;
|
res->vn = (Varnode *)0;
|
||||||
|
@ -892,10 +1000,16 @@ void SubvariableFlow::createNewOut(ReplaceOp *rop,uintb mask)
|
||||||
res->def = rop;
|
res->def = rop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Mark an operation where a subgraph variable is naturally copied into the original data-flow
|
||||||
|
///
|
||||||
|
/// If the operations naturally takes the given logical value as input but the output
|
||||||
|
/// doesn't need to be traced as a logical value, a subgraph terminator (PatchRecord) is created
|
||||||
|
/// noting this. The original PcodeOp will be converted to a COPY.
|
||||||
|
/// \param pullop is the PcodeOp pulling the logical value out of the subgraph
|
||||||
|
/// \param rvn is the given subgraph variable holding the logical value
|
||||||
void SubvariableFlow::addTerminalPatch(PcodeOp *pullop,ReplaceVarnode *rvn)
|
void SubvariableFlow::addTerminalPatch(PcodeOp *pullop,ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Add a reference to the logical variable getting pulled
|
{
|
||||||
// out of container flow
|
|
||||||
patchlist.push_back(PatchRecord());
|
patchlist.push_back(PatchRecord());
|
||||||
patchlist.back().type = 0; // Ultimately gets converted to a COPY
|
patchlist.back().type = 0; // Ultimately gets converted to a COPY
|
||||||
patchlist.back().pullop = pullop; // Operation pulling the variable out
|
patchlist.back().pullop = pullop; // Operation pulling the variable out
|
||||||
|
@ -903,6 +1017,14 @@ void SubvariableFlow::addTerminalPatch(PcodeOp *pullop,ReplaceVarnode *rvn)
|
||||||
pullcount += 1; // a true terminal modification
|
pullcount += 1; // a true terminal modification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Mark an operation where a subgraph variable is naturally pulled into the original data-flow
|
||||||
|
///
|
||||||
|
/// If the operations naturally takes the given logical value as input but the output
|
||||||
|
/// doesn't need to be traced as a logical value, a subgraph terminator (PatchRecord) is created
|
||||||
|
/// noting this. The opcode of the operation will not change.
|
||||||
|
/// \param pullop is the PcodeOp pulling the logical value out of the subgraph
|
||||||
|
/// \param rvn is the given subgraph variable holding the logical value
|
||||||
|
/// \param slot is the input slot to the operation
|
||||||
void SubvariableFlow::addTerminalPatchSameOp(PcodeOp *pullop,ReplaceVarnode *rvn,int4 slot)
|
void SubvariableFlow::addTerminalPatchSameOp(PcodeOp *pullop,ReplaceVarnode *rvn,int4 slot)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -914,9 +1036,16 @@ void SubvariableFlow::addTerminalPatchSameOp(PcodeOp *pullop,ReplaceVarnode *rvn
|
||||||
pullcount += 1; // a true terminal modification
|
pullcount += 1; // a true terminal modification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Mark a subgraph bit variable flowing into an operation taking a boolean input
|
||||||
|
///
|
||||||
|
/// This doesn't count as a Varnode holding a logical value that needs to be patched (by itself).
|
||||||
|
/// A PatchRecord terminating the logical subgraph along the given edge is created.
|
||||||
|
/// \param pullup is the operation taking the boolean input
|
||||||
|
/// \param rvn is the given bit variable
|
||||||
|
/// \param slot is the input slot of the variable to the operation
|
||||||
void SubvariableFlow::addBooleanPatch(PcodeOp *pullop,ReplaceVarnode *rvn,int4 slot)
|
void SubvariableFlow::addBooleanPatch(PcodeOp *pullop,ReplaceVarnode *rvn,int4 slot)
|
||||||
|
|
||||||
{ // Add a reference to the logical bit variable, flowing into a boolean operation
|
{
|
||||||
patchlist.push_back(PatchRecord());
|
patchlist.push_back(PatchRecord());
|
||||||
patchlist.back().type = 2; // Make no change to the operator, just put in the new input
|
patchlist.back().type = 2; // Make no change to the operator, just put in the new input
|
||||||
patchlist.back().pullop = pullop; // Operation pulling the variable out
|
patchlist.back().pullop = pullop; // Operation pulling the variable out
|
||||||
|
@ -925,9 +1054,16 @@ void SubvariableFlow::addBooleanPatch(PcodeOp *pullop,ReplaceVarnode *rvn,int4 s
|
||||||
// this is not a true modification
|
// this is not a true modification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Mark a subgraph variable flowing to an operation that expands it by padding with zero bits.
|
||||||
|
///
|
||||||
|
/// Data-flow along the specified edge within the logical subgraph is terminated by added a PatchRecord.
|
||||||
|
/// This doesn't count as a logical value that needs to be patched (by itself).
|
||||||
|
/// \param rvn is the given subgraph variable
|
||||||
|
/// \param pushop is the operation that pads the variable
|
||||||
|
/// \param sa is the amount the logical value is shifted to the left
|
||||||
void SubvariableFlow::addSuggestedPatch(ReplaceVarnode *rvn,PcodeOp *pushop,int4 sa)
|
void SubvariableFlow::addSuggestedPatch(ReplaceVarnode *rvn,PcodeOp *pushop,int4 sa)
|
||||||
|
|
||||||
{ // Operations that expand the logical value to a larger value padded with zero bits
|
{
|
||||||
patchlist.push_back(PatchRecord());
|
patchlist.push_back(PatchRecord());
|
||||||
patchlist.back().type = 3;
|
patchlist.back().type = 3;
|
||||||
patchlist.back().in1 = rvn;
|
patchlist.back().in1 = rvn;
|
||||||
|
@ -938,9 +1074,16 @@ void SubvariableFlow::addSuggestedPatch(ReplaceVarnode *rvn,PcodeOp *pushop,int4
|
||||||
// This is not a true modification because the output is still the expanded size
|
// This is not a true modification because the output is still the expanded size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Mark subgraph variables flowing into a comparison operation
|
||||||
|
///
|
||||||
|
/// The operation accomplishes the logical comparison by comparing the larger containers.
|
||||||
|
/// A PatchRecord is created indicating that data-flow from the subgraph terminates at the comparison.
|
||||||
|
/// \param in1 is the first logical value to the comparison
|
||||||
|
/// \param in2 is the second logical value
|
||||||
|
/// \param op is the comparison operation
|
||||||
void SubvariableFlow::addComparePatch(ReplaceVarnode *in1,ReplaceVarnode *in2,PcodeOp *op)
|
void SubvariableFlow::addComparePatch(ReplaceVarnode *in1,ReplaceVarnode *in2,PcodeOp *op)
|
||||||
|
|
||||||
{ // Operations that accomplish the logical comparison by comparing the larger container
|
{
|
||||||
patchlist.push_back(PatchRecord());
|
patchlist.push_back(PatchRecord());
|
||||||
patchlist.back().type = 1;
|
patchlist.back().type = 1;
|
||||||
patchlist.back().pullop = op;
|
patchlist.back().pullop = op;
|
||||||
|
@ -949,10 +1092,15 @@ void SubvariableFlow::addComparePatch(ReplaceVarnode *in1,ReplaceVarnode *in2,Pc
|
||||||
pullcount += 1;
|
pullcount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Replace an input Varnode in the subgraph with a temporary register
|
||||||
|
///
|
||||||
|
/// This is used to avoid overlapping input Varnode errors. The temporary register
|
||||||
|
/// is typically short lived and gets quickly eliminated in favor of the new
|
||||||
|
/// logically sized Varnode.
|
||||||
|
/// \param rvn is the logical variable to replace
|
||||||
void SubvariableFlow::replaceInput(ReplaceVarnode *rvn)
|
void SubvariableFlow::replaceInput(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Replace input in the subgraph with temporaries, so
|
{
|
||||||
// we don't get overlapping varnode errors
|
|
||||||
Varnode *newvn = fd->newUnique(rvn->vn->getSize());
|
Varnode *newvn = fd->newUnique(rvn->vn->getSize());
|
||||||
newvn = fd->setInputVarnode(newvn);
|
newvn = fd->setInputVarnode(newvn);
|
||||||
fd->totalReplace(rvn->vn,newvn);
|
fd->totalReplace(rvn->vn,newvn);
|
||||||
|
@ -960,10 +1108,15 @@ void SubvariableFlow::replaceInput(ReplaceVarnode *rvn)
|
||||||
rvn->vn = newvn;
|
rvn->vn = newvn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Decide if we use the same memory range of the original Varnode for the logical replacement
|
||||||
|
///
|
||||||
|
/// Usually the logical Varnode can use the \e true storage bytes that hold the value,
|
||||||
|
/// but there are a few corner cases where we want to use a new temporary register to hold the value.
|
||||||
|
/// \param rvn is the subgraph variable
|
||||||
|
/// \return \b true if the same memory range can be used to hold the value
|
||||||
bool SubvariableFlow::useSameAddress(ReplaceVarnode *rvn)
|
bool SubvariableFlow::useSameAddress(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Decide whether we use (a portion of) the same memory location
|
{
|
||||||
// of the original varnode when creating its replacement
|
|
||||||
if (rvn->vn->isInput()) return true;
|
if (rvn->vn->isInput()) return true;
|
||||||
// If we trim an addrtied varnode, because of required merges, we increase chance of conflicting forms for one variable
|
// If we trim an addrtied varnode, because of required merges, we increase chance of conflicting forms for one variable
|
||||||
if (rvn->vn->isAddrTied()) return false;
|
if (rvn->vn->isAddrTied()) return false;
|
||||||
|
@ -980,9 +1133,13 @@ bool SubvariableFlow::useSameAddress(ReplaceVarnode *rvn)
|
||||||
return false; // If more of the varnode is consumed than is in just this flow
|
return false; // If more of the varnode is consumed than is in just this flow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Calculcate address of replacement Varnode for given subgraph variable node
|
||||||
|
///
|
||||||
|
/// \param rvn is the given subgraph variable node
|
||||||
|
/// \return the address of the new logical Varnode
|
||||||
Address SubvariableFlow::getReplacementAddress(ReplaceVarnode *rvn) const
|
Address SubvariableFlow::getReplacementAddress(ReplaceVarnode *rvn) const
|
||||||
|
|
||||||
{ // Calculcate the starting address for the replacement varnode of -rvn-
|
{
|
||||||
Address addr = rvn->vn->getAddr();
|
Address addr = rvn->vn->getAddr();
|
||||||
int4 sa = leastsigbit_set(rvn->mask) / 8; // Number of bytes value is shifted into container
|
int4 sa = leastsigbit_set(rvn->mask) / 8; // Number of bytes value is shifted into container
|
||||||
if (addr.isBigEndian())
|
if (addr.isBigEndian())
|
||||||
|
@ -992,11 +1149,15 @@ Address SubvariableFlow::getReplacementAddress(ReplaceVarnode *rvn) const
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Build the logical Varnode which will replace its original containing Varnode
|
||||||
|
///
|
||||||
|
/// This is the main routine for converting a logical variable in the subgraph into
|
||||||
|
/// an actual Varnode object.
|
||||||
|
/// \param rvn is the logical variable
|
||||||
|
/// \return the (new or existing) Varnode object
|
||||||
Varnode *SubvariableFlow::getReplaceVarnode(ReplaceVarnode *rvn)
|
Varnode *SubvariableFlow::getReplaceVarnode(ReplaceVarnode *rvn)
|
||||||
|
|
||||||
{ // Get the actual varnode associated with a replacement varnode
|
{
|
||||||
// either by recycling a previously built one or creating
|
|
||||||
// one on the spot
|
|
||||||
if (rvn->replacement != (Varnode *)0)
|
if (rvn->replacement != (Varnode *)0)
|
||||||
return rvn->replacement;
|
return rvn->replacement;
|
||||||
// Only a constant if BOTH replacement and vn fields are null
|
// Only a constant if BOTH replacement and vn fields are null
|
||||||
|
@ -1021,6 +1182,10 @@ Varnode *SubvariableFlow::getReplaceVarnode(ReplaceVarnode *rvn)
|
||||||
return rvn->replacement;
|
return rvn->replacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The subgraph is extended from the variable node at the top of the worklist.
|
||||||
|
/// Data-flow is traced forward and backward one level, possibly extending the subgraph
|
||||||
|
/// and adding new nodes to the worklist.
|
||||||
|
/// \return \b true if the node was successfully processed
|
||||||
bool SubvariableFlow::processNextWork(void)
|
bool SubvariableFlow::processNextWork(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,69 +13,74 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
/// \file subflow.hh
|
||||||
|
/// \brief Classes for reducing/splitting Varnodes containing smaller logical values
|
||||||
#ifndef __SUBVARIABLE_FLOW__
|
#ifndef __SUBVARIABLE_FLOW__
|
||||||
#define __SUBVARIABLE_FLOW__
|
#define __SUBVARIABLE_FLOW__
|
||||||
|
|
||||||
#include "funcdata.hh"
|
#include "funcdata.hh"
|
||||||
|
|
||||||
// Structures for splitting big varnodes carrying smaller logical
|
/// \brief Class for shrinking big Varnodes carrying smaller logical values
|
||||||
// variables. Given a root within the syntax tree and dimensions
|
///
|
||||||
// of a logical variable, this class traces the flow of this
|
/// Given a root within the syntax tree and dimensions
|
||||||
// logical variable through its containing varnodes. It then
|
/// of a logical variable, this class traces the flow of this
|
||||||
// creates a subgraph of this flow, where there is a correspondence
|
/// logical variable through its containing Varnodes. It then
|
||||||
// between nodes in the subgraph and nodes in the original graph
|
/// creates a subgraph of this flow, where there is a correspondence
|
||||||
// containing the logical variable. When doReplacement is called,
|
/// between nodes in the subgraph and nodes in the original graph
|
||||||
// this subgraph is duplicated as a new separate piece within the
|
/// containing the logical variable. When doReplacement is called,
|
||||||
// syntax tree. Ops are replaced to reflect the manipulation of
|
/// this subgraph is duplicated as a new separate piece within the
|
||||||
// of the logical variable, rather than the containing variable.
|
/// syntax tree. Ops are replaced to reflect the manipulation of
|
||||||
// Operations in the original graph which pluck out the logical
|
/// of the logical variable, rather than the containing variable.
|
||||||
// variable from the containing variable, are replaced with copies
|
/// Operations in the original graph which pluck out the logical
|
||||||
// from the corresponding node in the new section of the graph,
|
/// variable from the containing variable, are replaced with copies
|
||||||
// which frequently causes the operations on the original container
|
/// from the corresponding node in the new section of the graph,
|
||||||
// varnodes to becomes deadcode.
|
/// which frequently causes the operations on the original container
|
||||||
|
/// Varnodes to becomes dead code.
|
||||||
class SubvariableFlow {
|
class SubvariableFlow {
|
||||||
class ReplaceOp;
|
class ReplaceOp;
|
||||||
|
/// \brief Placeholder node for Varnode holding a smaller logical value
|
||||||
class ReplaceVarnode {
|
class ReplaceVarnode {
|
||||||
friend class SubvariableFlow;
|
friend class SubvariableFlow;
|
||||||
Varnode *vn; // Varnode being split
|
Varnode *vn; ///< Varnode being shrunk
|
||||||
Varnode *replacement; // The new subvariable varnode
|
Varnode *replacement; ///< The new smaller Varnode
|
||||||
uintb mask; // Bits of the logical subvariable
|
uintb mask; ///< Bits making up the logical sub-variable
|
||||||
uintb val; // Value of constant (vn==NULL)
|
uintb val; ///< Value of constant (when vn==NULL)
|
||||||
ReplaceOp *def; // Defining op for new varnode
|
ReplaceOp *def; ///< Defining op for new Varnode
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Placeholder node for PcodeOp operating on smaller logical values
|
||||||
class ReplaceOp {
|
class ReplaceOp {
|
||||||
friend class SubvariableFlow;
|
friend class SubvariableFlow;
|
||||||
PcodeOp *op; // op getting paralleled
|
PcodeOp *op; ///< op getting paralleled
|
||||||
PcodeOp *replacement; // The new op
|
PcodeOp *replacement; ///< The new op
|
||||||
OpCode opc; // type of new op
|
OpCode opc; ///< Opcode of the new op
|
||||||
int4 numparams;
|
int4 numparams; ///< Number of parameters in (new) op
|
||||||
ReplaceVarnode *output; // varnode output
|
ReplaceVarnode *output; ///< Varnode output
|
||||||
vector<ReplaceVarnode *> input; // varnode inputs
|
vector<ReplaceVarnode *> input; ///< Varnode inputs
|
||||||
};
|
};
|
||||||
|
|
||||||
class PatchRecord { // Operation where logical value is part of input, but output remains as is
|
/// \brief Operation with a new logical value as (part of) input, but output Varnode is unchanged
|
||||||
|
class PatchRecord {
|
||||||
friend class SubvariableFlow;
|
friend class SubvariableFlow;
|
||||||
int4 type; // 0=COPY 1=compare 2=call 3=AND/SHIFT
|
int4 type; ///< 0=COPY 1=compare 2=call 3=AND/SHIFT
|
||||||
PcodeOp *pullop; // Op being affected
|
PcodeOp *pullop; ///< Op being affected
|
||||||
ReplaceVarnode *in1; // The logical variable input
|
ReplaceVarnode *in1; ///< The logical variable input
|
||||||
ReplaceVarnode *in2; // (optional second parameter)
|
ReplaceVarnode *in2; ///< (optional second parameter)
|
||||||
int4 slot; // slot being affected or other parameter
|
int4 slot; ///< slot being affected or other parameter
|
||||||
};
|
};
|
||||||
|
|
||||||
int4 flowsize; // Size of the data-flow
|
int4 flowsize; ///< Size of the lgoical data-flow in bytes
|
||||||
int4 bitsize; // Number of bits in logical variable
|
int4 bitsize; ///< Number of bits in logical variable
|
||||||
bool returnsTraversed; // Have we tried to flow logical value across CPUI_RETURNs
|
bool returnsTraversed; ///< Have we tried to flow logical value across CPUI_RETURNs
|
||||||
bool aggressive; // Do we "know" initial seed point must be a sub variable
|
bool aggressive; ///< Do we "know" initial seed point must be a sub variable
|
||||||
bool sextrestrictions; // Check for logical variables that are always sign extended into their container
|
bool sextrestrictions; ///< Check for logical variables that are always sign extended into their container
|
||||||
Funcdata *fd;
|
Funcdata *fd; ///< Containing function
|
||||||
map<Varnode *,ReplaceVarnode> varmap;
|
map<Varnode *,ReplaceVarnode> varmap; ///< Map from original Varnodes to the overlaying subgraph nodes
|
||||||
list<ReplaceVarnode> newvarlist;
|
list<ReplaceVarnode> newvarlist; ///< Storage for subgraph variable nodes
|
||||||
list<ReplaceOp> oplist;
|
list<ReplaceOp> oplist; ///< Storage for subgraph op nodes
|
||||||
list<PatchRecord> patchlist; // Operations getting patched (but no flow thru)
|
list<PatchRecord> patchlist; ///< Operations getting patched (but with no flow thru)
|
||||||
vector<ReplaceVarnode *> worklist;
|
vector<ReplaceVarnode *> worklist; ///< Subgraph variable nodes still needing to be traced
|
||||||
int4 pullcount; // Number of instructions pulling out the logical value
|
int4 pullcount; ///< Number of instructions pulling out the logical value
|
||||||
static int4 doesOrSet(PcodeOp *orop,uintb mask);
|
static int4 doesOrSet(PcodeOp *orop,uintb mask);
|
||||||
static int4 doesAndClear(PcodeOp *andop,uintb mask);
|
static int4 doesAndClear(PcodeOp *andop,uintb mask);
|
||||||
Address getReplacementAddress(ReplaceVarnode *rvn) const;
|
Address getReplacementAddress(ReplaceVarnode *rvn) const;
|
||||||
|
@ -86,10 +91,10 @@ class SubvariableFlow {
|
||||||
bool tryCallPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
|
bool tryCallPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
|
||||||
bool tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
|
bool tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
|
||||||
bool tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn);
|
bool tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn);
|
||||||
bool traceForward(ReplaceVarnode *rvn);
|
bool traceForward(ReplaceVarnode *rvn); ///< Trace the logical data-flow forward for the given subgraph variable
|
||||||
bool traceBackward(ReplaceVarnode *rvn);
|
bool traceBackward(ReplaceVarnode *rvn); ///< Trace the logical data-flow backward for the given subgraph variable
|
||||||
bool traceForwardSext(ReplaceVarnode *rvn);
|
bool traceForwardSext(ReplaceVarnode *rvn); ///< Trace logical data-flow forward assuming sign-extensions
|
||||||
bool traceBackwardSext(ReplaceVarnode *rvn);
|
bool traceBackwardSext(ReplaceVarnode *rvn); ///< Trace logical data-flow backward assuming sign-extensions
|
||||||
bool createLink(ReplaceOp *rop,uintb mask,int4 slot,Varnode *vn);
|
bool createLink(ReplaceOp *rop,uintb mask,int4 slot,Varnode *vn);
|
||||||
bool createCompareBridge(PcodeOp *op,ReplaceVarnode *inrvn,int4 slot,Varnode *othervn);
|
bool createCompareBridge(PcodeOp *op,ReplaceVarnode *inrvn,int4 slot,Varnode *othervn);
|
||||||
void addTerminalPatch(PcodeOp *pullop,ReplaceVarnode *rvn);
|
void addTerminalPatch(PcodeOp *pullop,ReplaceVarnode *rvn);
|
||||||
|
@ -102,7 +107,7 @@ class SubvariableFlow {
|
||||||
void replaceInput(ReplaceVarnode *rvn);
|
void replaceInput(ReplaceVarnode *rvn);
|
||||||
bool useSameAddress(ReplaceVarnode *rvn);
|
bool useSameAddress(ReplaceVarnode *rvn);
|
||||||
Varnode *getReplaceVarnode(ReplaceVarnode *rvn);
|
Varnode *getReplaceVarnode(ReplaceVarnode *rvn);
|
||||||
bool processNextWork(void);
|
bool processNextWork(void); ///< Extend the subgraph from the next node in the worklist
|
||||||
public:
|
public:
|
||||||
SubvariableFlow(Funcdata *f,Varnode *root,uintb mask,bool aggr,bool sext);
|
SubvariableFlow(Funcdata *f,Varnode *root,uintb mask,bool aggr,bool sext);
|
||||||
bool doTrace(void);
|
bool doTrace(void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue