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();
|
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)
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue