GP-4332 Treat software break as non-returning call

This commit is contained in:
caheckman 2024-02-27 16:23:26 +00:00
parent 75beb82103
commit 5942e95994
4 changed files with 53 additions and 28 deletions

View file

@ -722,14 +722,37 @@ void FlowInfo::truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode)
else {
data.opSetOpcode(op,CPUI_CALLIND); // Turn jump into call
setupCallindSpecs(op,(FuncCallSpecs *)0);
if (mode != JumpTable::fail_thunk) // Unless the switch was a thunk mechanism
data.getCallSpecs(op)->setBadJumpTable(true); // Consider using special name for switch variable
FuncCallSpecs *fc = data.getCallSpecs(op);
uint4 returnType;
bool noParams;
if (mode == JumpTable::fail_thunk) {
returnType = 0;
noParams = false;
}
else if (mode == JumpTable::fail_callother) {
returnType = PcodeOp::noreturn;
fc->setNoReturn(true);
data.warning("Does not return", op->getAddr());
noParams = true;
}
else {
returnType = 0;
noParams = false;
fc->setBadJumpTable(true); // Consider using special name for switch variable
data.warning("Treating indirect jump as call",op->getAddr());
}
if (noParams) {
if (!fc->hasModel()) {
fc->setInternal(glb->defaultfp, glb->types->getTypeVoid());
fc->setInputLock(true);
fc->setOutputLock(true);
}
}
// Create an artificial return
PcodeOp *truncop = artificialHalt(op->getAddr(),0);
PcodeOp *truncop = artificialHalt(op->getAddr(),returnType);
data.opDeadInsertAfter(truncop,op);
data.warning("Treating indirect jump as call",op->getAddr());
}
}

View file

@ -521,7 +521,7 @@ public:
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 *recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *flow,JumpTable::RecoveryMode &mode);
bool earlyJumpTableFail(PcodeOp *op); ///< Try to determine, early, if jump-table analysis will fail
JumpTable::RecoveryMode earlyJumpTableFail(PcodeOp *op); ///< Try to determine, early, if jump-table analysis will fail
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
void removeJumpTable(JumpTable *jt); ///< Remove/delete the given jump-table

View file

@ -548,10 +548,10 @@ JumpTable::RecoveryMode Funcdata::stageJumpTable(Funcdata &partial,JumpTable *jt
/// 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.
/// the destination calculation, we know the jump-table analysis will fail and the failure mode is returned.
/// \param op is the BRANCHIND op
/// \return \b true if jump-table analysis is guaranteed to fail
bool Funcdata::earlyJumpTableFail(PcodeOp *op)
/// \return \b success if there is no early failure, or the failure mode otherwise
JumpTable::RecoveryMode Funcdata::earlyJumpTableFail(PcodeOp *op)
{
Varnode *vn = op->getIn(0);
@ -559,9 +559,9 @@ bool Funcdata::earlyJumpTableFail(PcodeOp *op)
list<PcodeOp *>::const_iterator startiter = beginOpDead();
int4 countMax = 8;
while(iter != startiter) {
if (vn->getSize() == 1) return false;
if (vn->getSize() == 1) return JumpTable::success;
countMax -= 1;
if (countMax < 0) return false; // Don't iterate too many times
if (countMax < 0) return JumpTable::success; // Don't iterate too many times
--iter;
op = *iter;
Varnode *outvn = op->getOut();
@ -575,33 +575,33 @@ bool Funcdata::earlyJumpTableFail(PcodeOp *op)
int4 id = (int4)op->getIn(0)->getOffset();
UserPcodeOp *userOp = glb->userops.getOp(id);
if (dynamic_cast<InjectedUserOp *>(userOp) != (InjectedUserOp *)0)
return false; // Don't try to back track through injection
return JumpTable::success; // Don't try to back track through injection
if (dynamic_cast<JumpAssistOp *>(userOp) != (JumpAssistOp *)0)
return false;
return JumpTable::success;
if (dynamic_cast<SegmentOp *>(userOp) != (SegmentOp *)0)
return false;
return JumpTable::success;
if (outhit)
return true; // Address formed via uninjected CALLOTHER, analysis will fail
return JumpTable::fail_callother; // 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
return JumpTable::success; // Don't try to back track through CALL
}
}
else if (op->isBranch())
return false; // Don't try to back track further
return JumpTable::success; // Don't try to back track further
else {
if (op->code() == CPUI_STORE) return false; // Don't try to back track through STORE
if (op->code() == CPUI_STORE) return JumpTable::success; // Don't try to back track through STORE
if (outhit)
return false; // Some special op (CPOOLREF, NEW, etc) generates address, don't assume failure
return JumpTable::success; // 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;
if (invn->getSize() != vn->getSize()) return JumpTable::success;
vn = invn; // Treat input as address
}
// Continue backtracking
@ -610,20 +610,20 @@ bool Funcdata::earlyJumpTableFail(PcodeOp *op)
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
return JumpTable::success;
if (!op->getIn(1)->isConstant()) return JumpTable::success; // Don't back-track thru binary op, don't assume failure
Varnode *invn = op->getIn(0);
if (invn->getSize() != vn->getSize()) return false;
if (invn->getSize() != vn->getSize()) return JumpTable::success;
vn = invn; // Treat input as address
}
// Continue backtracking
}
else {
if (outhit)
return false;
return JumpTable::success;
}
}
return false;
return JumpTable::success;
}
/// \brief Recover control-flow destinations for a BRANCHIND
@ -657,7 +657,8 @@ JumpTable *Funcdata::recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *fl
if ((flags & jumptablerecovery_dont)!=0)
return (JumpTable *)0; // Explicitly told not to recover jumptables
if (earlyJumpTableFail(op))
mode = earlyJumpTableFail(op);
if (mode != JumpTable::success)
return (JumpTable *)0;
JumpTable trialjt(glb);
mode = stageJumpTable(partial,&trialjt,op,flow);

View file

@ -528,11 +528,12 @@ class JumpTable {
public:
/// \brief Recovery status for a specific JumpTable
enum RecoveryMode {
success = 0, ///< JumpTable is fully recovered
success = 0, ///< JumpTable is fully recovered
fail_normal = 1, ///< Normal failure to recover
fail_thunk = 2, ///< Likely \b thunk
fail_noflow = 3, ///< No legal flow to BRANCHIND
fail_return = 4 ///< Likely \b return operation
fail_return = 4, ///< Likely \b return operation
fail_callother = 5 ///< Address formed by CALLOTHER
};
private:
/// \brief An address table index and its corresponding out-edge