Data-type propagation across RETURN ops

This commit is contained in:
caheckman 2020-02-10 11:27:33 -05:00
parent 37cc39eaa3
commit 99367e1139
5 changed files with 81 additions and 26 deletions

View file

@ -3840,7 +3840,7 @@ int4 ActionOutputPrototype::apply(Funcdata &data)
{ {
ProtoParameter *outparam = data.getFuncProto().getOutput(); ProtoParameter *outparam = data.getFuncProto().getOutput();
if ((!outparam->isTypeLocked())||outparam->isSizeTypeLocked()) { if ((!outparam->isTypeLocked())||outparam->isSizeTypeLocked()) {
PcodeOp *op = data.canonicalReturnOp(); PcodeOp *op = data.getFirstReturnOp();
vector<Varnode *> vnlist; vector<Varnode *> vnlist;
if (op != (PcodeOp *)0) { if (op != (PcodeOp *)0) {
for(int4 i=1;i<op->numInput();++i) for(int4 i=1;i<op->numInput();++i)
@ -4548,6 +4548,72 @@ void ActionInferTypes::propagateSpacebaseRef(Funcdata &data,Varnode *spcvn)
} }
} }
/// Return the CPUI_RETURN op with the most specialized data-type, which is not
/// dead and is not a special halt.
/// \param data is the function
/// \return the representative CPUI_RETURN op or NULL
PcodeOp *ActionInferTypes::canonicalReturnOp(Funcdata &data)
{
PcodeOp *res = (PcodeOp *)0;
Datatype *bestdt = (Datatype *)0;
list<PcodeOp *>::const_iterator iter,iterend;
iterend = data.endOp(CPUI_RETURN);
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
PcodeOp *retop = *iter;
if (retop->isDead()) continue;
if (retop->getHaltType()!=0) continue;
if (retop->numInput() > 1) {
Varnode *vn = retop->getIn(1);
Datatype *ct = vn->getTempType();
if (bestdt == (Datatype *)0) {
res = retop;
bestdt = ct;
}
else if (ct->typeOrder(*bestdt) < 0) {
res = retop;
bestdt = ct;
}
}
}
return res;
}
/// \brief Give data-types a chance to propagate between CPUI_RETURN operations.
///
/// Since a function is intended to return a single data-type, data-types effectively
/// propagate between the input Varnodes to CPUI_RETURN ops, if there are more than one.
void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
{
PcodeOp *op = canonicalReturnOp(data);
if (op == (PcodeOp *)0) return;
TypeFactory *typegrp = data.getArch()->types;
Varnode *baseVn = op->getIn(1);
Datatype *ct = baseVn->getTempType();
int4 baseSize = baseVn->getSize();
bool isBool = ct->getMetatype() == TYPE_BOOL;
list<PcodeOp *>::const_iterator iter,iterend;
iterend = data.endOp(CPUI_RETURN);
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
PcodeOp *retop = *iter;
if (retop == op) continue;
if (retop->isDead()) continue;
if (retop->getHaltType()!=0) continue;
if (retop->numInput() > 1) {
Varnode *vn = retop->getIn(1);
if (vn->getSize() != baseSize) continue;
if (isBool && vn->getNZMask() > 1) continue; // Don't propagate bool if value is not necessarily 0 or 1
if (vn->getTempType() == ct) continue; // Already propagated
vn->setTempType(ct);
#ifdef TYPEPROP_DEBUG
propagationDebug(typegrp->getArch(),vn,ct,retop,1,(Varnode *)0);
#endif
propagateOneType(typegrp, vn);
}
}
}
int4 ActionInferTypes::apply(Funcdata &data) int4 ActionInferTypes::apply(Funcdata &data)
{ {
@ -4576,6 +4642,7 @@ int4 ActionInferTypes::apply(Funcdata &data)
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue; if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
propagateOneType(typegrp,vn); propagateOneType(typegrp,vn);
} }
propagateAcrossReturns(data);
AddrSpace *spcid = data.getScopeLocal()->getSpaceId(); AddrSpace *spcid = data.getScopeLocal()->getSpaceId();
Varnode *spcvn = data.findSpacebaseInput(spcid); Varnode *spcvn = data.findSpacebaseInput(spcid);
if (spcvn != (Varnode *)0) if (spcvn != (Varnode *)0)

View file

@ -932,6 +932,8 @@ class ActionInferTypes : public Action {
static void propagateOneType(TypeFactory *typegrp,Varnode *vn); static void propagateOneType(TypeFactory *typegrp,Varnode *vn);
static void propagateRef(Funcdata &data,Varnode *vn,const Address &addr); static void propagateRef(Funcdata &data,Varnode *vn,const Address &addr);
static void propagateSpacebaseRef(Funcdata &data,Varnode *spcvn); static void propagateSpacebaseRef(Funcdata &data,Varnode *spcvn);
static PcodeOp *canonicalReturnOp(Funcdata &data);
static void propagateAcrossReturns(Funcdata &data);
public: public:
ActionInferTypes(const string &g) : Action(0,"infertypes",g) {} ///< Constructor ActionInferTypes(const string &g) : Action(0,"infertypes",g) {} ///< Constructor
virtual void reset(Funcdata &data) { localcount = 0; } virtual void reset(Funcdata &data) { localcount = 0; }

View file

@ -399,7 +399,7 @@ public:
PcodeOp *newOp(int4 inputs,const SeqNum &sq); /// Allocate a new PcodeOp with sequence number PcodeOp *newOp(int4 inputs,const SeqNum &sq); /// Allocate a new PcodeOp with sequence number
PcodeOp *newOpBefore(PcodeOp *follow,OpCode opc,Varnode *in1,Varnode *in2,Varnode *in3=(Varnode *)0); PcodeOp *newOpBefore(PcodeOp *follow,OpCode opc,Varnode *in1,Varnode *in2,Varnode *in3=(Varnode *)0);
PcodeOp *cloneOp(const PcodeOp *op,const SeqNum &seq); /// Clone a PcodeOp into \b this function PcodeOp *cloneOp(const PcodeOp *op,const SeqNum &seq); /// Clone a PcodeOp into \b this function
PcodeOp *canonicalReturnOp(void) const; /// Find a representative CPUI_RETURN op for \b this function PcodeOp *getFirstReturnOp(void) const; /// Find a representative CPUI_RETURN op for \b this function
PcodeOp *newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 size,uint4 extraFlags); PcodeOp *newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 size,uint4 extraFlags);
PcodeOp *newIndirectCreation(PcodeOp *indeffect,const Address &addr,int4 size,bool possibleout); PcodeOp *newIndirectCreation(PcodeOp *indeffect,const Address &addr,int4 size,bool possibleout);
void markIndirectCreation(PcodeOp *indop,bool possibleOutput); ///< Convert CPUI_INDIRECT into an \e indirect \e creation void markIndirectCreation(PcodeOp *indop,bool possibleOutput); ///< Convert CPUI_INDIRECT into an \e indirect \e creation

View file

@ -577,37 +577,20 @@ PcodeOp *Funcdata::cloneOp(const PcodeOp *op,const SeqNum &seq)
return newop; return newop;
} }
/// Return the CPUI_RETURN op with the most specialized data-type, which is not /// Return the first CPUI_RETURN operation that is not dead or an artificial halt
/// dead and is not a special halt. If HighVariables are not available, just /// \return a representative CPUI_RETURN op or NULL if there are none
/// return the first CPUI_RETURN op. PcodeOp *Funcdata::getFirstReturnOp(void) const
/// \return the representative CPUI_RETURN op or NULL
PcodeOp *Funcdata::canonicalReturnOp(void) const
{ {
bool hasnohigh = !isHighOn();
PcodeOp *res = (PcodeOp *)0;
Datatype *bestdt = (Datatype *)0;
list<PcodeOp *>::const_iterator iter,iterend; list<PcodeOp *>::const_iterator iter,iterend;
iterend = endOp(CPUI_RETURN); iterend = endOp(CPUI_RETURN);
for(iter=beginOp(CPUI_RETURN);iter!=iterend;++iter) { for(iter=beginOp(CPUI_RETURN);iter!=iterend;++iter) {
PcodeOp *retop = *iter; PcodeOp *retop = *iter;
if (retop->isDead()) continue; if (retop->isDead()) continue;
if (retop->getHaltType()!=0) continue; if (retop->getHaltType()!=0) continue;
if (retop->numInput() > 1) { return retop;
if (hasnohigh) return retop;
Varnode *vn = retop->getIn(1);
Datatype *ct = vn->getHigh()->getType();
if (bestdt == (Datatype *)0) {
res = retop;
bestdt = ct;
} }
else if (ct->typeOrder(*bestdt) < 0) { return (PcodeOp *)0;
res = retop;
bestdt = ct;
}
}
}
return res;
} }
/// \brief Create new PcodeOp with 2 or 3 given operands /// \brief Create new PcodeOp with 2 or 3 given operands

View file

@ -1864,8 +1864,11 @@ void PrintC::emitPrototypeOutput(const FuncProto *proto,
PcodeOp *op; PcodeOp *op;
Varnode *vn; Varnode *vn;
if (fd != (const Funcdata *)0) if (fd != (const Funcdata *)0) {
op = fd->canonicalReturnOp(); op = fd->getFirstReturnOp();
if (op != (PcodeOp *)0 && op->numInput() < 2)
op = (PcodeOp *)0;
}
else else
op = (PcodeOp *)0; op = (PcodeOp *)0;