Merge remote-tracking branch 'origin/GP-3441_IndirectSwitchVar' into

patch (Closes #5307)
This commit is contained in:
Ryan Kurtz 2023-05-23 11:34:28 -04:00
commit e23198b563
6 changed files with 116 additions and 2 deletions

View file

@ -2122,6 +2122,57 @@ int4 ActionLikelyTrash::apply(Funcdata &data)
return 0;
}
/// Test if the path to the given BRANCHIND originates from a constant but passes through INDIRECT operations.
/// This indicates that the switch value is produced indirectly, so we mark these INDIRECT
/// operations as \e not \e collapsible, to guarantee that the indirect value is not lost during analysis.
/// \param op is the given BRANCHIND op
void ActionRestructureVarnode::protectSwitchPathIndirects(PcodeOp *op)
{
vector<PcodeOp *> indirects;
Varnode *curVn = op->getIn(0);
while(curVn->isWritten()) {
PcodeOp *curOp = curVn->getDef();
uint4 evalType = curOp->getEvalType();
if ((evalType & (PcodeOp::binary | PcodeOp::ternary)) != 0) {
if (curOp->numInput() > 1) {
if (!curOp->getIn(1)->isConstant()) return; // Multiple paths
}
curVn = curOp->getIn(0);
}
else if ((evalType & PcodeOp::unary) != 0)
curVn = curOp->getIn(0);
else if (curOp->code() == CPUI_INDIRECT) {
indirects.push_back(curOp);
curVn = curOp->getIn(0);
}
else if (curOp->code() == CPUI_LOAD) {
curVn = curOp->getIn(1);
}
else
return;
}
if (!curVn->isConstant()) return;
// If we reach here, there is exactly one path, from a constant to a switch
for(int4 i=0;i<indirects.size();++i) {
indirects[i]->setNoIndirectCollapse();
}
}
/// Run through BRANCHIND ops, treat them as switches and protect the data-flow path to the destination variable
/// \param data is the function to examine
void ActionRestructureVarnode::protectSwitchPaths(Funcdata &data)
{
const BlockGraph &bblocks(data.getBasicBlocks());
for(int4 i=0;i<bblocks.getSize();++i) {
PcodeOp *op = bblocks.getBlock(i)->lastOp();
if (op == (PcodeOp *)0) continue;
if (op->code() != CPUI_BRANCHIND) continue;
protectSwitchPathIndirects(op);
}
}
int4 ActionRestructureVarnode::apply(Funcdata &data)
{
@ -2132,6 +2183,9 @@ int4 ActionRestructureVarnode::apply(Funcdata &data)
if (data.syncVarnodesWithSymbols(l1,false,aliasyes))
count += 1;
if (data.isJumptableRecoveryOn())
protectSwitchPaths(data);
numpass += 1;
#ifdef OPACTION_DEBUG
if ((flags&rule_debug)==0) return 0;

View file

@ -831,6 +831,8 @@ public:
/// This produces on intermediate view of symbols on the stack.
class ActionRestructureVarnode : public Action {
int4 numpass; ///< Number of passes performed for this function
static void protectSwitchPathIndirects(PcodeOp *op); ///< Protect path to the given switch from INDIRECT collapse
static void protectSwitchPaths(Funcdata &data); ///< Look for switches and protect path of switch variable
public:
ActionRestructureVarnode(const string &g) : Action(0,"restructure_varnode",g) {} ///< Constructor
virtual void reset(Funcdata &data) { numpass = 0; }

View file

@ -114,7 +114,8 @@ public:
is_cpool_transformed = 0x20, ///< Have we checked for cpool transforms
stop_type_propagation = 0x40, ///< Stop data-type propagation into output from descendants
hold_output = 0x80, ///< Output varnode (of call) should not be removed if it is unread
concat_root = 0x100 ///< Output of \b this is root of a CONCAT tree
concat_root = 0x100, ///< Output of \b this is root of a CONCAT tree
no_indirect_collapse = 0x200 ///< Do not collapse \b this INDIRECT (via RuleIndirectCollapse)
};
private:
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
@ -219,6 +220,8 @@ public:
void setPartialRoot(void) { addlflags |= concat_root; } ///< Mark \b this as root of CONCAT tree
bool stopsCopyPropagation(void) const { return ((flags&no_copy_propagation)!=0); } ///< Does \b this allow COPY propagation
void setStopCopyPropagation(void) { flags |= no_copy_propagation; } ///< Stop COPY propagation through inputs
bool noIndirectCollapse(void) const { return ((addlflags & no_indirect_collapse)!=0); } ///< Check if INDIRECT collapse is possible
void setNoIndirectCollapse(void) { addlflags |= no_indirect_collapse; } ///< Prevent collapse of INDIRECT
/// \brief Return \b true if this LOADs or STOREs from a dynamic \e spacebase pointer
bool usesSpacebasePtr(void) const { return ((flags&PcodeOp::spacebase_ptr)!=0); }
uintm getCseHash(void) const; ///< Return hash indicating possibility of common subexpression elimination

View file

@ -2926,7 +2926,7 @@ int4 RuleIndirectCollapse::applyOp(PcodeOp *op,Funcdata &data)
}
}
else if (indop->isCall()) {
if (op->isIndirectCreation())
if (op->isIndirectCreation() || op->noIndirectCollapse())
return 0;
// If there are no aliases to a local variable, collapse
if (!op->getOut()->hasNoLocalAlias())