Subvariable flow into switch

This commit is contained in:
caheckman 2020-02-13 11:30:45 -05:00
parent e6f09b141b
commit 936f541e64
7 changed files with 164 additions and 67 deletions

View file

@ -484,6 +484,24 @@ inline uintb pcode_left(uintb val,int4 sa) {
return val << 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 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 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 extern uintb uintb_negate(uintb in,int4 size); ///< Negate the \e sized value

View file

@ -3373,7 +3373,7 @@ void ActionDeadCode::markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *>
if (vn->isAutoLive()) if (vn->isAutoLive())
consumeVal = ~((uintb)0); consumeVal = ~((uintb)0);
else else
consumeVal = minimalMask(vn->getNZMask()); consumeVal = minimalmask(vn->getNZMask());
pushConsumed(consumeVal,vn,worklist); pushConsumed(consumeVal,vn,worklist);
} }
} }
@ -3398,7 +3398,7 @@ uintb ActionDeadCode::gatherConsumedReturn(Funcdata &data)
if (returnOp->isDead()) continue; if (returnOp->isDead()) continue;
if (returnOp->numInput() > 1) { if (returnOp->numInput() > 1) {
Varnode *vn = returnOp->getIn(1); Varnode *vn = returnOp->getIn(1);
consumeVal |= minimalMask(vn->getNZMask()); consumeVal |= minimalmask(vn->getNZMask());
} }
} }
return consumeVal; return consumeVal;
@ -3455,11 +3455,21 @@ int4 ActionDeadCode::apply(Funcdata &data)
continue; continue;
} }
else if (!op->isAssignment()) { else if (!op->isAssignment()) {
if (op->code() == CPUI_RETURN) { OpCode opc = op->code();
if (opc == CPUI_RETURN) {
pushConsumed(~((uintb)0),op->getIn(0),worklist); pushConsumed(~((uintb)0),op->getIn(0),worklist);
for(i=1;i<op->numInput();++i) for(i=1;i<op->numInput();++i)
pushConsumed(returnConsume,op->getIn(i),worklist); 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 { else {
for(i=0;i<op->numInput();++i) for(i=0;i<op->numInput();++i)
pushConsumed(~((uintb)0),op->getIn(i),worklist); pushConsumed(~((uintb)0),op->getIn(i),worklist);

View file

@ -543,7 +543,6 @@ class ActionDeadCode : public Action {
static bool neverConsumed(Varnode *vn,Funcdata &data); static bool neverConsumed(Varnode *vn,Funcdata &data);
static void markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist); static void markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist);
static uintb gatherConsumedReturn(Funcdata &data); static uintb gatherConsumedReturn(Funcdata &data);
static uintb minimalMask(uintb val); ///< Calculate smallest mask that covers the given value
public: public:
ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const { virtual Action *clone(const ActionGroupList &grouplist) const {
@ -1077,20 +1076,4 @@ public:
inline bool TermOrder::additiveCompare(const PcodeOpEdge *op1,const PcodeOpEdge *op2) { inline bool TermOrder::additiveCompare(const PcodeOpEdge *op1,const PcodeOpEdge *op2) {
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode())); } 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 #endif

View file

@ -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 // Set the BRANCHIND input to be the unnormalized switch variable, so
// Treat unnormalized value as input CPUI_BRANCHIND // all the intervening code to calculate the final address is eliminated as dead.
// so it becomes literally the C switch statement
fd->opSetInput(indop,switchvn,0); fd->opSetInput(indop,switchvn,0);
return switchvn;
} }
bool JumpBasic::foldInGuards(Funcdata *fd,JumpTable *jump) 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; bool change = false;
for(int4 i=0;i<selectguards.size();++i) { for(int4 i=0;i<selectguards.size();++i) {
PcodeOp *cbranch = selectguards[i].getBranch(); 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 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) // 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->opSetInput(op,switchvn,0);
} }
fd->opDestroy(assistOp); // Get rid of the assist op (it has served its purpose) fd->opDestroy(assistOp); // Get rid of the assist op (it has served its purpose)
return switchvn;
} }
bool JumpAssisted::foldInGuards(Funcdata *fd,JumpTable *jump) bool JumpAssisted::foldInGuards(Funcdata *fd,JumpTable *jump)
@ -1972,6 +1968,7 @@ JumpTable::JumpTable(Architecture *g,Address ad)
jmodel = (JumpModel *)0; jmodel = (JumpModel *)0;
origmodel = (JumpModel *)0; origmodel = (JumpModel *)0;
indirect = (PcodeOp *)0; indirect = (PcodeOp *)0;
switchVarConsume = ~((uintb)0);
mostcommon = ~((uint4)0); mostcommon = ~((uint4)0);
maxtablesize = 1024; maxtablesize = 1024;
maxaddsub = 1; maxaddsub = 1;
@ -1988,6 +1985,7 @@ JumpTable::JumpTable(const JumpTable *op2)
jmodel = (JumpModel *)0; jmodel = (JumpModel *)0;
origmodel = (JumpModel *)0; origmodel = (JumpModel *)0;
indirect = (PcodeOp *)0; indirect = (PcodeOp *)0;
switchVarConsume = ~((uintb)0);
mostcommon = ~((uint4)0); mostcommon = ~((uint4)0);
maxtablesize = op2->maxtablesize; maxtablesize = op2->maxtablesize;
maxaddsub = op2->maxaddsub; maxaddsub = op2->maxaddsub;
@ -2081,7 +2079,7 @@ void JumpTable::addBlockToSwitch(BlockBasic *bl,uintb lab)
void JumpTable::switchOver(const FlowInfo &flow) void JumpTable::switchOver(const FlowInfo &flow)
{ // Convert absolute addresses to block indices {
FlowBlock *parent,*tmpbl; FlowBlock *parent,*tmpbl;
uint4 pos; uint4 pos;
int4 i,j,count,maxcount; 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) void JumpTable::trivialSwitchOver(void)
{ {
@ -2259,6 +2279,7 @@ void JumpTable::clear(void)
label.clear(); label.clear();
loadpoints.clear(); loadpoints.clear();
indirect = (PcodeOp *)0; indirect = (PcodeOp *)0;
switchVarConsume = ~((uintb)0);
recoverystage = 0; recoverystage = 0;
// -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent // -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent
} }

View file

@ -192,7 +192,22 @@ public:
virtual void buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const=0; 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 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 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 foldInGuards(Funcdata *fd,JumpTable *jump)=0;
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable)=0; virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable)=0;
virtual JumpModel *clone(JumpTable *jt) const=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 buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const;
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext) {} 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 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 foldInGuards(Funcdata *fd,JumpTable *jump) { return false; }
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; } virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; }
virtual JumpModel *clone(JumpTable *jt) const; virtual JumpModel *clone(JumpTable *jt) const;
@ -241,6 +256,16 @@ protected:
void findSmallestNormal(uint4 matchsize); void findSmallestNormal(uint4 matchsize);
void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize); void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize);
void markFoldableGuards(); 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); virtual bool foldInOneGuard(Funcdata *fd,GuardRecord &guard,JumpTable *jump);
public: public:
JumpBasic(JumpTable *jt) : JumpModel(jt) { jrange = (JumpValuesRange *)0; } 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 buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const;
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext); 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 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 foldInGuards(Funcdata *fd,JumpTable *jump);
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable); virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable);
virtual JumpModel *clone(JumpTable *jt) const; 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 buildAddresses(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable,vector<LoadTable> *loadpoints) const;
virtual void findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext) {} 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 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 foldInGuards(Funcdata *fd,JumpTable *jump);
virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; } virtual bool sanityCheck(Funcdata *fd,PcodeOp *indop,vector<Address> &addresstable) { return true; }
virtual JumpModel *clone(JumpTable *jt) const; virtual JumpModel *clone(JumpTable *jt) const;
virtual void clear(void) { assistOp = (PcodeOp *)0; switchvn = (Varnode *)0; } 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 { class JumpTable {
Architecture *glb; // Architecture under which this jumptable operates Architecture *glb; ///< Architecture under which this jump-table operates
JumpModel *jmodel,*origmodel; JumpModel *jmodel; ///< Current model of how the jump table is implemented in code
vector<Address> addresstable; // Raw addresses in the jumptable JumpModel *origmodel; ///< Initial jump table model, which may be incomplete
vector<uint4> blocktable; // Addresses converted to basic blocks vector<Address> addresstable; ///< Raw addresses in the jump-table
vector<uintb> label; vector<uint4> blocktable; ///< Addresses converted to basic blocks
vector<LoadTable> loadpoints; vector<uintb> label; ///< The case label for each explicit target
Address opaddress; // Absolute address of op vector<LoadTable> loadpoints; ///< Any recovered in-memory data for the jump-table
PcodeOp *indirect; // INDIRECT op referring to this jump table Address opaddress; ///< Absolute address of the INDIRECT jump
uint4 mostcommon; // Most common position in table PcodeOp *indirect; ///< CPUI_INDIRECT op referring linked to \b this jump-table
uint4 maxtablesize; // Maximum table size we allow to be built (sanity check) uintb switchVarConsume; ///< Bits of the switch variable being consumed
uint4 maxaddsub; // Maximum ADDs or SUBs to normalize uint4 mostcommon; ///< Index of the most common position in table, prior to deduping
uint4 maxleftright; // Maximum shifts to normalize uint4 maxtablesize; ///< Maximum table size we allow to be built (sanity check)
uint4 maxext; // Maximum extensions to normalize uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
int4 recoverystage; // 0=no stages, 1=needs additional stage, 2=complete uint4 maxleftright; ///< Maximum shifts to normalize
bool collectloads; uint4 maxext; ///< Maximum extensions to normalize
void recoverModel(Funcdata *fd); 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 trivialSwitchOver(void);
void sanityCheck(Funcdata *fd); void sanityCheck(Funcdata *fd); ///< Perform sanity check on recovered address targets
uint4 block2Position(const FlowBlock *bl) const; uint4 block2Position(const FlowBlock *bl) const;
static bool isReachable(PcodeOp *op); static bool isReachable(PcodeOp *op);
public: public:
JumpTable(Architecture *g,Address ad=Address()); JumpTable(Architecture *g,Address ad=Address()); ///< Constructor
JumpTable(const JumpTable *op2); JumpTable(const JumpTable *op2); ///< Copy constructor
~JumpTable(void); ~JumpTable(void); ///< Destructor
bool isSwitchedOver(void) const { return !blocktable.empty(); } bool isSwitchedOver(void) const { return !blocktable.empty(); } ///< Return \b true if addresses converted to basic-blocks
bool isRecovered(void) const { return !addresstable.empty(); } bool isRecovered(void) const { return !addresstable.empty(); } ///< Return \b true if a model has been recovered
bool isLabelled(void) const { return !label.empty(); } bool isLabelled(void) const { return !label.empty(); } ///< Return \b true if \e case labels are computed
bool isOverride(void) const; bool isOverride(void) const; ///< Return \b true if \b this table was manually overridden
bool isPossibleMultistage(void) const { return (addresstable.size()==1); } bool isPossibleMultistage(void) const { return (addresstable.size()==1); }
int4 getStage(void) const { return recoverystage; } int4 getStage(void) const { return recoverystage; }
int4 numEntries(void) const { return addresstable.size(); } 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; } int4 getMostCommon(void) const { return mostcommon; }
const Address &getOpAddress(void) const { return opaddress; } const Address &getOpAddress(void) const { return opaddress; }
PcodeOp *getIndirectOp(void) const { return indirect; } PcodeOp *getIndirectOp(void) const { return indirect; }
@ -395,10 +429,10 @@ public:
void setMostCommonBlock(uint4 bl) { mostcommon = bl; } void setMostCommonBlock(uint4 bl) { mostcommon = bl; }
void setLoadCollect(bool val) { collectloads = val; } void setLoadCollect(bool val) { collectloads = val; }
void addBlockToSwitch(BlockBasic *bl,uintb lab); void addBlockToSwitch(BlockBasic *bl,uintb lab);
void switchOver(const FlowInfo &flow); void switchOver(const FlowInfo &flow); ///< Convert absolute addresses to block indices
uintb getLabelByIndex(int4 index) const { return label[index]; } uintb getLabelByIndex(int4 index) const { return label[index]; } ///< Given a \e case index, get its label
void foldInNormalization(Funcdata *fd) { jmodel->foldInNormalization(fd,indirect); } void foldInNormalization(Funcdata *fd); ///< Hide the normalization code for the switch
bool foldInGuards(Funcdata *fd) { return jmodel->foldInGuards(fd,this); } bool foldInGuards(Funcdata *fd) { return jmodel->foldInGuards(fd,this); } ///< Hide any guard code for \b this switch
void recoverAddresses(Funcdata *fd); void recoverAddresses(Funcdata *fd);
void recoverMultistage(Funcdata *fd); void recoverMultistage(Funcdata *fd);
bool recoverLabels(Funcdata *fd); bool recoverLabels(Funcdata *fd);

View file

@ -340,6 +340,28 @@ bool SubvariableFlow::tryCallReturnPull(PcodeOp *op,ReplaceVarnode *rvn)
return true; 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 /// Try to trace the logical variable through descendant Varnodes
/// creating new nodes in the logical subgraph and updating the worklist. /// creating new nodes in the logical subgraph and updating the worklist.
/// \param rvn is the given subgraph variable to trace /// \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; if (!tryReturnPull(op,rvn,slot)) return false;
hcount += 1; hcount += 1;
break; break;
case CPUI_BRANCHIND:
if (!trySwitchPull(op, rvn)) return false;
hcount += 1;
break;
case CPUI_BOOL_NEGATE: case CPUI_BOOL_NEGATE:
case CPUI_BOOL_AND: case CPUI_BOOL_AND:
case CPUI_BOOL_OR: case CPUI_BOOL_OR:
@ -850,6 +876,10 @@ bool SubvariableFlow::traceForwardSext(ReplaceVarnode *rvn)
if (!tryReturnPull(op,rvn,slot)) return false; if (!tryReturnPull(op,rvn,slot)) return false;
hcount += 1; hcount += 1;
break; break;
case CPUI_BRANCHIND:
if (!trySwitchPull(op,rvn)) return false;
hcount += 1;
break;
default: default:
return false; return false;
} }
@ -1331,7 +1361,7 @@ void SubvariableFlow::doReplacement(void)
fd->opSetInput(pullop,getReplaceVarnode((*piter).in1),0); fd->opSetInput(pullop,getReplaceVarnode((*piter).in1),0);
fd->opSetInput(pullop,getReplaceVarnode((*piter).in2),1); 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); fd->opSetInput(pullop,getReplaceVarnode((*piter).in1),(*piter).slot);
} }
else if (type == 3) { else if (type == 3) {

View file

@ -62,7 +62,7 @@ class SubvariableFlow {
/// \brief Operation with a new logical value as (part of) input, but output Varnode is unchanged /// \brief Operation with a new logical value as (part of) input, but output Varnode is unchanged
class PatchRecord { 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/return/branchind 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)
@ -91,6 +91,7 @@ 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 trySwitchPull(PcodeOp *op,ReplaceVarnode *rvn);
bool traceForward(ReplaceVarnode *rvn); ///< Trace the logical data-flow forward for the given subgraph variable 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 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 bool traceForwardSext(ReplaceVarnode *rvn); ///< Trace logical data-flow forward assuming sign-extensions