mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Data-type propagation across RETURN ops
This commit is contained in:
parent
37cc39eaa3
commit
99367e1139
5 changed files with 81 additions and 26 deletions
|
@ -3840,7 +3840,7 @@ int4 ActionOutputPrototype::apply(Funcdata &data)
|
|||
{
|
||||
ProtoParameter *outparam = data.getFuncProto().getOutput();
|
||||
if ((!outparam->isTypeLocked())||outparam->isSizeTypeLocked()) {
|
||||
PcodeOp *op = data.canonicalReturnOp();
|
||||
PcodeOp *op = data.getFirstReturnOp();
|
||||
vector<Varnode *> vnlist;
|
||||
if (op != (PcodeOp *)0) {
|
||||
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)
|
||||
|
||||
{
|
||||
|
@ -4576,6 +4642,7 @@ int4 ActionInferTypes::apply(Funcdata &data)
|
|||
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
|
||||
propagateOneType(typegrp,vn);
|
||||
}
|
||||
propagateAcrossReturns(data);
|
||||
AddrSpace *spcid = data.getScopeLocal()->getSpaceId();
|
||||
Varnode *spcvn = data.findSpacebaseInput(spcid);
|
||||
if (spcvn != (Varnode *)0)
|
||||
|
|
|
@ -932,6 +932,8 @@ class ActionInferTypes : public Action {
|
|||
static void propagateOneType(TypeFactory *typegrp,Varnode *vn);
|
||||
static void propagateRef(Funcdata &data,Varnode *vn,const Address &addr);
|
||||
static void propagateSpacebaseRef(Funcdata &data,Varnode *spcvn);
|
||||
static PcodeOp *canonicalReturnOp(Funcdata &data);
|
||||
static void propagateAcrossReturns(Funcdata &data);
|
||||
public:
|
||||
ActionInferTypes(const string &g) : Action(0,"infertypes",g) {} ///< Constructor
|
||||
virtual void reset(Funcdata &data) { localcount = 0; }
|
||||
|
|
|
@ -399,7 +399,7 @@ public:
|
|||
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 *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 *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
|
||||
|
|
|
@ -577,37 +577,20 @@ PcodeOp *Funcdata::cloneOp(const PcodeOp *op,const SeqNum &seq)
|
|||
return newop;
|
||||
}
|
||||
|
||||
/// Return the CPUI_RETURN op with the most specialized data-type, which is not
|
||||
/// dead and is not a special halt. If HighVariables are not available, just
|
||||
/// return the first CPUI_RETURN op.
|
||||
/// \return the representative CPUI_RETURN op or NULL
|
||||
PcodeOp *Funcdata::canonicalReturnOp(void) const
|
||||
/// Return the first CPUI_RETURN operation that is not dead or an artificial halt
|
||||
/// \return a representative CPUI_RETURN op or NULL if there are none
|
||||
PcodeOp *Funcdata::getFirstReturnOp(void) const
|
||||
|
||||
{
|
||||
bool hasnohigh = !isHighOn();
|
||||
PcodeOp *res = (PcodeOp *)0;
|
||||
Datatype *bestdt = (Datatype *)0;
|
||||
list<PcodeOp *>::const_iterator iter,iterend;
|
||||
iterend = endOp(CPUI_RETURN);
|
||||
for(iter=beginOp(CPUI_RETURN);iter!=iterend;++iter) {
|
||||
PcodeOp *retop = *iter;
|
||||
if (retop->isDead()) continue;
|
||||
if (retop->getHaltType()!=0) continue;
|
||||
if (retop->numInput() > 1) {
|
||||
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) {
|
||||
res = retop;
|
||||
bestdt = ct;
|
||||
}
|
||||
}
|
||||
return retop;
|
||||
}
|
||||
return res;
|
||||
return (PcodeOp *)0;
|
||||
}
|
||||
|
||||
/// \brief Create new PcodeOp with 2 or 3 given operands
|
||||
|
|
|
@ -1864,8 +1864,11 @@ void PrintC::emitPrototypeOutput(const FuncProto *proto,
|
|||
PcodeOp *op;
|
||||
Varnode *vn;
|
||||
|
||||
if (fd != (const Funcdata *)0)
|
||||
op = fd->canonicalReturnOp();
|
||||
if (fd != (const Funcdata *)0) {
|
||||
op = fd->getFirstReturnOp();
|
||||
if (op != (PcodeOp *)0 && op->numInput() < 2)
|
||||
op = (PcodeOp *)0;
|
||||
}
|
||||
else
|
||||
op = (PcodeOp *)0;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue