Merge remote-tracking branch 'origin/GP-2866_SwitchAnalysisFilter' into patch

This commit is contained in:
Ryan Kurtz 2023-01-06 08:05:11 -05:00
commit 1e8c575671
2 changed files with 80 additions and 0 deletions

View file

@ -511,6 +511,7 @@ public:
JumpTable *linkJumpTable(PcodeOp *op); ///< Link jump-table with a given BRANCHIND JumpTable *linkJumpTable(PcodeOp *op); ///< Link jump-table with a given BRANCHIND
JumpTable *findJumpTable(const PcodeOp *op) const; ///< Find a jump-table associated with a given BRANCHIND JumpTable *findJumpTable(const PcodeOp *op) const; ///< Find a jump-table associated with a given BRANCHIND
JumpTable *installJumpTable(const Address &addr); ///< Install a new jump-table for the given Address JumpTable *installJumpTable(const Address &addr); ///< Install a new jump-table for the given Address
bool earlyJumpTableFail(PcodeOp *op); ///< Try to determine, early, if jump-table analysis will fail
JumpTable *recoverJumpTable(PcodeOp *op,FlowInfo *flow,int4 &failuremode); JumpTable *recoverJumpTable(PcodeOp *op,FlowInfo *flow,int4 &failuremode);
int4 numJumpTables(void) const { return jumpvec.size(); } ///< Get the number of jump-tables for \b this function int4 numJumpTables(void) const { return jumpvec.size(); } ///< Get the number of jump-tables for \b this function
JumpTable *getJumpTable(int4 i) { return jumpvec[i]; } ///< Get the i-th jump-table JumpTable *getJumpTable(int4 i) { return jumpvec[i]; } ///< Get the i-th jump-table

View file

@ -545,6 +545,83 @@ int4 Funcdata::stageJumpTable(JumpTable *jt,PcodeOp *op,FlowInfo *flow)
return 0; return 0;
} }
/// Backtrack from the BRANCHIND, looking for ops that might affect the destination.
/// If a CALLOTHER, which is not injected/inlined in some way, is in the flow path of
/// the destination calculation, we know the jump-table analysis will fail and return \b true.
/// \param op is the BRANCHIND op
/// \return \b true if jump-table analysis is guaranteed to fail
bool Funcdata::earlyJumpTableFail(PcodeOp *op)
{
Varnode *vn = op->getIn(0);
list<PcodeOp *>::const_iterator iter = op->insertiter;
list<PcodeOp *>::const_iterator startiter = beginOpDead();
int4 countMax = 8;
while(iter != startiter) {
if (vn->getSize() == 1) return false;
countMax -= 1;
if (countMax < 0) return false; // Don't iterate too many times
--iter;
op = *iter;
Varnode *outvn = op->getOut();
bool outhit = false;
if (outvn != (Varnode *)0)
outhit = vn->intersects(*outvn);
if (op->getEvalType() == PcodeOp::special) {
if (op->isCall()) {
OpCode opc = op->code();
if (opc == CPUI_CALLOTHER) {
int4 id = (int4)op->getIn(0)->getOffset();
InjectedUserOp *userOp = dynamic_cast<InjectedUserOp *>(glb->userops.getOp(id));
if (userOp != (InjectedUserOp *)0) {
return false; // Don't try to back track through injection
}
if (outhit)
return true; // Address formed via uninjected CALLOTHER, analysis will fail
// Assume CALLOTHER will not interfere with address and continue backtracking
}
else {
// CALL or CALLIND - Output has not been established yet
return false; // Don't try to back track through CALL
}
}
else if (op->isBranch())
return false; // Don't try to back track further
else {
if (op->code() == CPUI_STORE) return false; // Don't try to back track through STORE
if (outhit)
return false; // Some special op (CPOOLREF, NEW, etc) generates address, don't assume failure
// Assume special will not interfere with address and continue backtracking
}
}
else if (op->getEvalType() == PcodeOp::unary) {
if (outhit) {
Varnode *invn = op->getIn(0);
if (invn->getSize() != vn->getSize()) return false;
vn = invn; // Treat input as address
}
// Continue backtracking
}
else if (op->getEvalType() == PcodeOp::binary) {
if (outhit) {
OpCode opc = op->code();
if (opc != CPUI_INT_ADD && opc != CPUI_INT_SUB && opc != CPUI_INT_XOR)
return false;
if (!op->getIn(1)->isConstant()) return false; // Don't back-track thru binary op, don't assume failure
Varnode *invn = op->getIn(0);
if (invn->getSize() != vn->getSize()) return false;
vn = invn; // Treat input as address
}
// Continue backtracking
}
else {
if (outhit)
return false;
}
}
return false;
}
/// \brief Recover destinations for a BRANCHIND by analyzing nearby data and control-flow /// \brief Recover destinations for a BRANCHIND by analyzing nearby data and control-flow
/// ///
/// This is the high-level entry point for jump-table/switch recovery. In short, a /// This is the high-level entry point for jump-table/switch recovery. In short, a
@ -577,6 +654,8 @@ JumpTable *Funcdata::recoverJumpTable(PcodeOp *op,FlowInfo *flow,int4 &failuremo
if ((flags & jumptablerecovery_dont)!=0) if ((flags & jumptablerecovery_dont)!=0)
return (JumpTable *)0; // Explicitly told not to recover jumptables return (JumpTable *)0; // Explicitly told not to recover jumptables
if (earlyJumpTableFail(op))
return (JumpTable *)0;
JumpTable trialjt(glb); JumpTable trialjt(glb);
failuremode = stageJumpTable(&trialjt,op,flow); failuremode = stageJumpTable(&trialjt,op,flow);
if (failuremode != 0) if (failuremode != 0)