mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Subvariable flow into switch
This commit is contained in:
parent
e6f09b141b
commit
936f541e64
7 changed files with 164 additions and 67 deletions
|
@ -484,6 +484,24 @@ inline uintb pcode_left(uintb val,int4 sa) {
|
|||
return val << sa;
|
||||
}
|
||||
|
||||
/// \brief Calculate smallest mask that covers the given value
|
||||
///
|
||||
/// Calculcate a mask that covers either the least significant byte, uint2, uint4, or uint8,
|
||||
/// whatever is smallest.
|
||||
/// \param val is the given value
|
||||
/// \return the minimal mask
|
||||
inline uintb minimalmask(uintb val)
|
||||
|
||||
{
|
||||
if (val > 0xffffffff)
|
||||
return ~((uintb)0);
|
||||
if (val > 0xffff)
|
||||
return 0xffffffff;
|
||||
if (val > 0xff)
|
||||
return 0xffff;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
extern bool signbit_negative(uintb val,int4 size); ///< Return true if the sign-bit is set
|
||||
extern uintb calc_mask(int4 size); ///< Calculate a mask for a given byte size
|
||||
extern uintb uintb_negate(uintb in,int4 size); ///< Negate the \e sized value
|
||||
|
|
|
@ -3373,7 +3373,7 @@ void ActionDeadCode::markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *>
|
|||
if (vn->isAutoLive())
|
||||
consumeVal = ~((uintb)0);
|
||||
else
|
||||
consumeVal = minimalMask(vn->getNZMask());
|
||||
consumeVal = minimalmask(vn->getNZMask());
|
||||
pushConsumed(consumeVal,vn,worklist);
|
||||
}
|
||||
}
|
||||
|
@ -3398,7 +3398,7 @@ uintb ActionDeadCode::gatherConsumedReturn(Funcdata &data)
|
|||
if (returnOp->isDead()) continue;
|
||||
if (returnOp->numInput() > 1) {
|
||||
Varnode *vn = returnOp->getIn(1);
|
||||
consumeVal |= minimalMask(vn->getNZMask());
|
||||
consumeVal |= minimalmask(vn->getNZMask());
|
||||
}
|
||||
}
|
||||
return consumeVal;
|
||||
|
@ -3455,11 +3455,21 @@ int4 ActionDeadCode::apply(Funcdata &data)
|
|||
continue;
|
||||
}
|
||||
else if (!op->isAssignment()) {
|
||||
if (op->code() == CPUI_RETURN) {
|
||||
OpCode opc = op->code();
|
||||
if (opc == CPUI_RETURN) {
|
||||
pushConsumed(~((uintb)0),op->getIn(0),worklist);
|
||||
for(i=1;i<op->numInput();++i)
|
||||
pushConsumed(returnConsume,op->getIn(i),worklist);
|
||||
}
|
||||
else if (opc == CPUI_BRANCHIND) {
|
||||
JumpTable *jt = data.findJumpTable(op);
|
||||
uintb mask;
|
||||
if (jt != (JumpTable *)0)
|
||||
mask = jt->getSwitchVarConsume();
|
||||
else
|
||||
mask = ~((uintb)0);
|
||||
pushConsumed(mask,op->getIn(0),worklist);
|
||||
}
|
||||
else {
|
||||
for(i=0;i<op->numInput();++i)
|
||||
pushConsumed(~((uintb)0),op->getIn(i),worklist);
|
||||
|
|
|
@ -543,7 +543,6 @@ class ActionDeadCode : public Action {
|
|||
static bool neverConsumed(Varnode *vn,Funcdata &data);
|
||||
static void markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist);
|
||||
static uintb gatherConsumedReturn(Funcdata &data);
|
||||
static uintb minimalMask(uintb val); ///< Calculate smallest mask that covers the given value
|
||||
public:
|
||||
ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
|
@ -1077,20 +1076,4 @@ public:
|
|||
inline bool TermOrder::additiveCompare(const PcodeOpEdge *op1,const PcodeOpEdge *op2) {
|
||||
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode())); }
|
||||
|
||||
/// Calculcate a mask that covers either the least significant byte, uint2, uint4, or uint8,
|
||||
/// whatever is smallest.
|
||||
/// \param val is the given value
|
||||
/// \return the minimal mask
|
||||
inline uintb ActionDeadCode::minimalMask(uintb val)
|
||||
|
||||
{
|
||||
if (val > 0xffffffff)
|
||||
return ~((uintb)0);
|
||||
if (val > 0xffff)
|
||||
return 0xffffffff;
|
||||
if (val > 0xff)
|
||||
return 0xffff;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1219,23 +1219,18 @@ void JumpBasic::buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<ui
|
|||
}
|
||||
}
|
||||
|
||||
void JumpBasic::foldInNormalization(Funcdata *fd,PcodeOp *indop)
|
||||
Varnode *JumpBasic::foldInNormalization(Funcdata *fd,PcodeOp *indop)
|
||||
|
||||
{ // Assume normalized and unnormalized values are found
|
||||
// Fold normalization pcode into indirect branch
|
||||
// Treat unnormalized value as input CPUI_BRANCHIND
|
||||
// so it becomes literally the C switch statement
|
||||
{
|
||||
// Set the BRANCHIND input to be the unnormalized switch variable, so
|
||||
// all the intervening code to calculate the final address is eliminated as dead.
|
||||
fd->opSetInput(indop,switchvn,0);
|
||||
return switchvn;
|
||||
}
|
||||
|
||||
bool JumpBasic::foldInGuards(Funcdata *fd,JumpTable *jump)
|
||||
|
||||
{ // We now think of the BRANCHIND as encompassing
|
||||
// the guard function, so we "disarm" the guard
|
||||
// instructions by making the guard condition
|
||||
// always false. If the simplification removes
|
||||
// the unusable branches, we are left with only
|
||||
// one path through the switch
|
||||
{
|
||||
bool change = false;
|
||||
for(int4 i=0;i<selectguards.size();++i) {
|
||||
PcodeOp *cbranch = selectguards[i].getBranch();
|
||||
|
@ -1825,7 +1820,7 @@ void JumpAssisted::buildLabels(Funcdata *fd,vector<Address> &addresstable,vector
|
|||
label.push_back(0xBAD1ABE1); // Add fake label to match the defaultAddress
|
||||
}
|
||||
|
||||
void JumpAssisted::foldInNormalization(Funcdata *fd,PcodeOp *indop)
|
||||
Varnode *JumpAssisted::foldInNormalization(Funcdata *fd,PcodeOp *indop)
|
||||
|
||||
{
|
||||
// Replace all outputs of jumpassist op with switchvn (including BRANCHIND)
|
||||
|
@ -1837,6 +1832,7 @@ void JumpAssisted::foldInNormalization(Funcdata *fd,PcodeOp *indop)
|
|||
fd->opSetInput(op,switchvn,0);
|
||||
}
|
||||
fd->opDestroy(assistOp); // Get rid of the assist op (it has served its purpose)
|
||||
return switchvn;
|
||||
}
|
||||
|
||||
bool JumpAssisted::foldInGuards(Funcdata *fd,JumpTable *jump)
|
||||
|
@ -1972,6 +1968,7 @@ JumpTable::JumpTable(Architecture *g,Address ad)
|
|||
jmodel = (JumpModel *)0;
|
||||
origmodel = (JumpModel *)0;
|
||||
indirect = (PcodeOp *)0;
|
||||
switchVarConsume = ~((uintb)0);
|
||||
mostcommon = ~((uint4)0);
|
||||
maxtablesize = 1024;
|
||||
maxaddsub = 1;
|
||||
|
@ -1988,6 +1985,7 @@ JumpTable::JumpTable(const JumpTable *op2)
|
|||
jmodel = (JumpModel *)0;
|
||||
origmodel = (JumpModel *)0;
|
||||
indirect = (PcodeOp *)0;
|
||||
switchVarConsume = ~((uintb)0);
|
||||
mostcommon = ~((uint4)0);
|
||||
maxtablesize = op2->maxtablesize;
|
||||
maxaddsub = op2->maxaddsub;
|
||||
|
@ -2081,7 +2079,7 @@ void JumpTable::addBlockToSwitch(BlockBasic *bl,uintb lab)
|
|||
|
||||
void JumpTable::switchOver(const FlowInfo &flow)
|
||||
|
||||
{ // Convert absolute addresses to block indices
|
||||
{
|
||||
FlowBlock *parent,*tmpbl;
|
||||
uint4 pos;
|
||||
int4 i,j,count,maxcount;
|
||||
|
@ -2116,6 +2114,28 @@ void JumpTable::switchOver(const FlowInfo &flow)
|
|||
}
|
||||
}
|
||||
|
||||
/// Eliminate any code involved in actually computing the destination address so
|
||||
/// it looks like the CPUI_BRANCHIND operation does it all internally.
|
||||
/// \param fd is the function containing \b this switch
|
||||
void JumpTable::foldInNormalization(Funcdata *fd)
|
||||
|
||||
{
|
||||
Varnode *switchvn = jmodel->foldInNormalization(fd,indirect);
|
||||
if (switchvn != (Varnode *)0) {
|
||||
// If possible, mark up the switch variable as not fully consumed so that
|
||||
// subvariable flow can truncate it.
|
||||
switchVarConsume = minimalmask(switchvn->getNZMask());
|
||||
if (switchVarConsume >= calc_mask(switchvn->getSize())) { // If mask covers everything
|
||||
if (switchvn->isWritten()) {
|
||||
PcodeOp *op = switchvn->getDef();
|
||||
if (op->code() == CPUI_INT_SEXT) { // Check for a signed extension
|
||||
switchVarConsume = calc_mask(op->getIn(0)->getSize()); // Assume the extension is not consumed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JumpTable::trivialSwitchOver(void)
|
||||
|
||||
{
|
||||
|
@ -2259,6 +2279,7 @@ void JumpTable::clear(void)
|
|||
label.clear();
|
||||
loadpoints.clear();
|
||||
indirect = (PcodeOp *)0;
|
||||
switchVarConsume = ~((uintb)0);
|
||||
recoverystage = 0;
|
||||
// -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent
|
||||
}
|
||||
|
|
|
@ -192,7 +192,22 @@ public:
|
|||
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const=0;
|
||||
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext)=0;
|
||||
virtual void buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<uintb> &label,const JumpModel *orig) const=0;
|
||||
virtual void foldInNormalization(Funcdata *fd,PcodeOp *indop)=0;
|
||||
|
||||
/// \brief Do normalization of the given switch specific to \b this model.
|
||||
///
|
||||
/// The PcodeOp machinery is removed so it looks like the CPUI_BRANCHIND simply takes the
|
||||
/// switch variable as an input Varnode and automatically interprets its values to reach
|
||||
/// the correct destination.
|
||||
/// \param fd is the function containing the switch
|
||||
/// \param indop is the given switch as a CPUI_BRANCHIND
|
||||
/// \return the Varnode holding the final unnormalized switch variable
|
||||
virtual Varnode *foldInNormalization(Funcdata *fd,PcodeOp *indop)=0;
|
||||
|
||||
/// \brief Eliminate any \e guard code involved in computing the switch destination
|
||||
///
|
||||
/// We now think of the BRANCHIND as encompassing any guard function.
|
||||
/// \param fd is the function containing the switch
|
||||
/// \param jump is the JumpTable owning \b this model.
|
||||
virtual bool foldInGuards(Funcdata *fd,JumpTable *jump)=0;
|
||||
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable)=0;
|
||||
virtual JumpModel *clone(JumpTable *jt) const=0;
|
||||
|
@ -213,7 +228,7 @@ public:
|
|||
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const;
|
||||
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext) {}
|
||||
virtual void buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<uintb> &label,const JumpModel *orig) const;
|
||||
virtual void foldInNormalization(Funcdata *fd,PcodeOp *indop) {}
|
||||
virtual Varnode *foldInNormalization(Funcdata *fd,PcodeOp *indop) { return (Varnode *)0; }
|
||||
virtual bool foldInGuards(Funcdata *fd,JumpTable *jump) { return false; }
|
||||
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; }
|
||||
virtual JumpModel *clone(JumpTable *jt) const;
|
||||
|
@ -241,6 +256,16 @@ protected:
|
|||
void findSmallestNormal(uint4 matchsize);
|
||||
void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize);
|
||||
void markFoldableGuards();
|
||||
|
||||
/// \brief Eliminate the given guard to \b this switch
|
||||
///
|
||||
/// We \e disarm the guard instructions by making the guard condition
|
||||
/// always \b false. If the simplification removes the unusable branches,
|
||||
/// we are left with only one path through the switch.
|
||||
/// \param fd is the function containing the switch
|
||||
/// \param guard is a description of the particular guard mechanism
|
||||
/// \param jump is the JumpTable owning \b this model
|
||||
/// \return \b true if a change was made to data-flow
|
||||
virtual bool foldInOneGuard(Funcdata *fd,GuardRecord &guard,JumpTable *jump);
|
||||
public:
|
||||
JumpBasic(JumpTable *jt) : JumpModel(jt) { jrange = (JumpValuesRange *)0; }
|
||||
|
@ -253,7 +278,7 @@ public:
|
|||
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const;
|
||||
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext);
|
||||
virtual void buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<uintb> &label,const JumpModel *orig) const;
|
||||
virtual void foldInNormalization(Funcdata *fd,PcodeOp *indop);
|
||||
virtual Varnode *foldInNormalization(Funcdata *fd,PcodeOp *indop);
|
||||
virtual bool foldInGuards(Funcdata *fd,JumpTable *jump);
|
||||
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable);
|
||||
virtual JumpModel *clone(JumpTable *jt) const;
|
||||
|
@ -341,45 +366,54 @@ public:
|
|||
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const;
|
||||
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext) {}
|
||||
virtual void buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<uintb> &label,const JumpModel *orig) const;
|
||||
virtual void foldInNormalization(Funcdata *fd,PcodeOp *indop);
|
||||
virtual Varnode *foldInNormalization(Funcdata *fd,PcodeOp *indop);
|
||||
virtual bool foldInGuards(Funcdata *fd,JumpTable *jump);
|
||||
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; }
|
||||
virtual JumpModel *clone(JumpTable *jt) const;
|
||||
virtual void clear(void) { assistOp = (PcodeOp *)0; switchvn = (Varnode *)0; }
|
||||
};
|
||||
|
||||
/// \brief A map from values to control-flow targets within a function
|
||||
///
|
||||
/// A JumpTable is attached to a specific CPUI_BRANCHIND and encapsulates all
|
||||
/// the information necessary to model the indirect jump as a \e switch statement.
|
||||
/// It knows how to map from specific switch variable values to the destination
|
||||
/// \e case block and how to label the value.
|
||||
class JumpTable {
|
||||
Architecture *glb; // Architecture under which this jumptable operates
|
||||
JumpModel *jmodel,*origmodel;
|
||||
vector<Address> addresstable; // Raw addresses in the jumptable
|
||||
vector<uint4> blocktable; // Addresses converted to basic blocks
|
||||
vector<uintb> label;
|
||||
vector<LoadTable> loadpoints;
|
||||
Address opaddress; // Absolute address of op
|
||||
PcodeOp *indirect; // INDIRECT op referring to this jump table
|
||||
uint4 mostcommon; // Most common position in table
|
||||
uint4 maxtablesize; // Maximum table size we allow to be built (sanity check)
|
||||
uint4 maxaddsub; // Maximum ADDs or SUBs to normalize
|
||||
uint4 maxleftright; // Maximum shifts to normalize
|
||||
uint4 maxext; // Maximum extensions to normalize
|
||||
int4 recoverystage; // 0=no stages, 1=needs additional stage, 2=complete
|
||||
bool collectloads;
|
||||
void recoverModel(Funcdata *fd);
|
||||
Architecture *glb; ///< Architecture under which this jump-table operates
|
||||
JumpModel *jmodel; ///< Current model of how the jump table is implemented in code
|
||||
JumpModel *origmodel; ///< Initial jump table model, which may be incomplete
|
||||
vector<Address> addresstable; ///< Raw addresses in the jump-table
|
||||
vector<uint4> blocktable; ///< Addresses converted to basic blocks
|
||||
vector<uintb> label; ///< The case label for each explicit target
|
||||
vector<LoadTable> loadpoints; ///< Any recovered in-memory data for the jump-table
|
||||
Address opaddress; ///< Absolute address of the INDIRECT jump
|
||||
PcodeOp *indirect; ///< CPUI_INDIRECT op referring linked to \b this jump-table
|
||||
uintb switchVarConsume; ///< Bits of the switch variable being consumed
|
||||
uint4 mostcommon; ///< Index of the most common position in table, prior to deduping
|
||||
uint4 maxtablesize; ///< Maximum table size we allow to be built (sanity check)
|
||||
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
|
||||
uint4 maxleftright; ///< Maximum shifts to normalize
|
||||
uint4 maxext; ///< Maximum extensions to normalize
|
||||
int4 recoverystage; ///< 0=no stages, 1=needs additional stage, 2=complete
|
||||
bool collectloads; ///< Set to \b true if information about in-memory model data is/should be collected
|
||||
void recoverModel(Funcdata *fd); ///< Attempt recovery of the jump-table model
|
||||
void trivialSwitchOver(void);
|
||||
void sanityCheck(Funcdata *fd);
|
||||
void sanityCheck(Funcdata *fd); ///< Perform sanity check on recovered address targets
|
||||
uint4 block2Position(const FlowBlock *bl) const;
|
||||
static bool isReachable(PcodeOp *op);
|
||||
public:
|
||||
JumpTable(Architecture *g,Address ad=Address());
|
||||
JumpTable(const JumpTable *op2);
|
||||
~JumpTable(void);
|
||||
bool isSwitchedOver(void) const { return !blocktable.empty(); }
|
||||
bool isRecovered(void) const { return !addresstable.empty(); }
|
||||
bool isLabelled(void) const { return !label.empty(); }
|
||||
bool isOverride(void) const;
|
||||
JumpTable(Architecture *g,Address ad=Address()); ///< Constructor
|
||||
JumpTable(const JumpTable *op2); ///< Copy constructor
|
||||
~JumpTable(void); ///< Destructor
|
||||
bool isSwitchedOver(void) const { return !blocktable.empty(); } ///< Return \b true if addresses converted to basic-blocks
|
||||
bool isRecovered(void) const { return !addresstable.empty(); } ///< Return \b true if a model has been recovered
|
||||
bool isLabelled(void) const { return !label.empty(); } ///< Return \b true if \e case labels are computed
|
||||
bool isOverride(void) const; ///< Return \b true if \b this table was manually overridden
|
||||
bool isPossibleMultistage(void) const { return (addresstable.size()==1); }
|
||||
int4 getStage(void) const { return recoverystage; }
|
||||
int4 numEntries(void) const { return addresstable.size(); }
|
||||
uintb getSwitchVarConsume(void) const { return switchVarConsume; } ///< Get bits of switch variable consumed by \b this table
|
||||
int4 getMostCommon(void) const { return mostcommon; }
|
||||
const Address &getOpAddress(void) const { return opaddress; }
|
||||
PcodeOp *getIndirectOp(void) const { return indirect; }
|
||||
|
@ -395,10 +429,10 @@ public:
|
|||
void setMostCommonBlock(uint4 bl) { mostcommon = bl; }
|
||||
void setLoadCollect(bool val) { collectloads = val; }
|
||||
void addBlockToSwitch(BlockBasic *bl,uintb lab);
|
||||
void switchOver(const FlowInfo &flow);
|
||||
uintb getLabelByIndex(int4 index) const { return label[index]; }
|
||||
void foldInNormalization(Funcdata *fd) { jmodel->foldInNormalization(fd,indirect); }
|
||||
bool foldInGuards(Funcdata *fd) { return jmodel->foldInGuards(fd,this); }
|
||||
void switchOver(const FlowInfo &flow); ///< Convert absolute addresses to block indices
|
||||
uintb getLabelByIndex(int4 index) const { return label[index]; } ///< Given a \e case index, get its label
|
||||
void foldInNormalization(Funcdata *fd); ///< Hide the normalization code for the switch
|
||||
bool foldInGuards(Funcdata *fd) { return jmodel->foldInGuards(fd,this); } ///< Hide any guard code for \b this switch
|
||||
void recoverAddresses(Funcdata *fd);
|
||||
void recoverMultistage(Funcdata *fd);
|
||||
bool recoverLabels(Funcdata *fd);
|
||||
|
|
|
@ -340,6 +340,28 @@ bool SubvariableFlow::tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn)
|
|||
return true;
|
||||
}
|
||||
|
||||
/// \brief Determine if the subgraph variable can act as a switch variable for the given BRANCHIND
|
||||
///
|
||||
/// We query the JumpTable associated with the BRANCHIND to see if its switch variable
|
||||
/// can be trimmed as indicated by the logical flow.
|
||||
/// \param op is the given BRANCHIND op
|
||||
/// \param rvn is the subgraph variable flowing to the BRANCHIND
|
||||
/// \return \b true if the switch variable can be successfully trimmed to its logical size
|
||||
bool SubvariableFlow::trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn)
|
||||
|
||||
{
|
||||
if ((rvn->mask & 1) == 0) return false; // Logical value must be justified
|
||||
if ((rvn->vn->getConsume()&~rvn->mask)!=0) // If there's something outside the mask being consumed
|
||||
return false; // we can't trim
|
||||
patchlist.push_back(PatchRecord());
|
||||
patchlist.back().type = 2;
|
||||
patchlist.back().pullop = op;
|
||||
patchlist.back().in1 = rvn;
|
||||
patchlist.back().slot = 0;
|
||||
pullcount += 1; // A true terminal modification
|
||||
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
|
||||
|
@ -573,6 +595,10 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
|
|||
if (!tryReturnPull(op,rvn,slot)) return false;
|
||||
hcount += 1;
|
||||
break;
|
||||
case CPUI_BRANCHIND:
|
||||
if (!trySwitchPull(op, rvn)) return false;
|
||||
hcount += 1;
|
||||
break;
|
||||
case CPUI_BOOL_NEGATE:
|
||||
case CPUI_BOOL_AND:
|
||||
case CPUI_BOOL_OR:
|
||||
|
@ -850,6 +876,10 @@ bool SubvariableFlow::traceForwardSext(ReplaceVarnode *rvn)
|
|||
if (!tryReturnPull(op,rvn,slot)) return false;
|
||||
hcount += 1;
|
||||
break;
|
||||
case CPUI_BRANCHIND:
|
||||
if (!trySwitchPull(op,rvn)) return false;
|
||||
hcount += 1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -1331,7 +1361,7 @@ void SubvariableFlow::doReplacement(void)
|
|||
fd->opSetInput(pullop,getReplaceVarnode((*piter).in1),0);
|
||||
fd->opSetInput(pullop,getReplaceVarnode((*piter).in2),1);
|
||||
}
|
||||
else if (type == 2) { // A call parameter or return value
|
||||
else if (type == 2) { // A call parameter, return value, or switch variable
|
||||
fd->opSetInput(pullop,getReplaceVarnode((*piter).in1),(*piter).slot);
|
||||
}
|
||||
else if (type == 3) {
|
||||
|
|
|
@ -62,7 +62,7 @@ class SubvariableFlow {
|
|||
/// \brief Operation with a new logical value as (part of) input, but output Varnode is unchanged
|
||||
class PatchRecord {
|
||||
friend class SubvariableFlow;
|
||||
int4 type; ///< 0=COPY 1=compare 2=call 3=AND/SHIFT
|
||||
int4 type; ///< 0=COPY 1=compare 2=call/return/branchind 3=AND/SHIFT
|
||||
PcodeOp *pullop; ///< Op being affected
|
||||
ReplaceVarnode *in1; ///< The logical variable input
|
||||
ReplaceVarnode *in2; ///< (optional second parameter)
|
||||
|
@ -91,6 +91,7 @@ class SubvariableFlow {
|
|||
bool tryCallPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
|
||||
bool tryReturnPull(PcodeOp *op,ReplaceVarnode *rvn,int4 slot);
|
||||
bool tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn);
|
||||
bool trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn);
|
||||
bool traceForward(ReplaceVarnode *rvn); ///< Trace the logical data-flow forward for the given subgraph variable
|
||||
bool traceBackward(ReplaceVarnode *rvn); ///< Trace the logical data-flow backward for the given subgraph variable
|
||||
bool traceForwardSext(ReplaceVarnode *rvn); ///< Trace logical data-flow forward assuming sign-extensions
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue