#include "coreaction.hh"
#include "condexe.hh"
#include "double.hh"
#include "subflow.hh"
struct StackEqn {
int4 var1; int4 var2; int4 rhs; static bool compare(const StackEqn &a,const StackEqn &b); };
class StackSolver {
vector<StackEqn> eqs; vector<StackEqn> guess; vector<Varnode *> vnlist; vector<int4> companion; Address spacebase; vector<int4> soln; int4 missedvariables; void duplicate(void); void propagate(int4 varnum,int4 val); public:
void solve(void); void build(const Funcdata &data,AddrSpace *id,int4 spcbase); int4 getNumVariables(void) const { return vnlist.size(); } Varnode *getVariable(int4 i) const { return vnlist[i]; } int4 getCompanion(int4 i) const { return companion[i]; } int4 getSolution(int4 i) const { return soln[i]; } };
bool StackEqn::compare(const StackEqn &a,const StackEqn &b)
{
return (a.var1<b.var1);
}
void StackSolver::propagate(int4 varnum,int4 val)
{
if (soln[varnum] != 65535) return; soln[varnum] = val;
StackEqn eqn;
vector<int4> workstack;
workstack.reserve(soln.size());
workstack.push_back(varnum);
vector<StackEqn>::iterator top;
while(!workstack.empty()) {
varnum = workstack.back();
workstack.pop_back();
eqn.var1 = varnum;
top = lower_bound(eqs.begin(),eqs.end(),eqn,StackEqn::compare);
while((top!=eqs.end())&&((*top).var1 == varnum)) {
int4 var2 = (*top).var2;
if (soln[var2] == 65535) {
soln[var2] = soln[varnum]-(*top).rhs;
workstack.push_back(var2);
}
++top;
}
}
}
void StackSolver::duplicate(void)
{
int4 size,i;
StackEqn eqn;
size = eqs.size();
for(i=0;i<size;++i) {
eqn.var1 = eqs[i].var2;
eqn.var2 = eqs[i].var1;
eqn.rhs = -eqs[i].rhs;
eqs.push_back(eqn);
}
stable_sort(eqs.begin(),eqs.end(),StackEqn::compare);
}
void StackSolver::solve(void)
{
int4 i,size,var1,var2,count,lastcount;
soln.clear();
soln.resize(vnlist.size(),65535); duplicate();
propagate(0,0); size = guess.size();
lastcount = size+2;
do {
count = 0;
for(i=0;i<size;++i) {
var1 = guess[i].var1;
var2 = guess[i].var2;
if ((soln[var1]!=65535)&&(soln[var2]==65535))
propagate(var2,soln[var1]-guess[i].rhs);
else if ((soln[var1]==65535)&&(soln[var2]!=65535))
propagate(var1,soln[var2]+guess[i].rhs);
else if ((soln[var1]==65535)&&(soln[var2]==65535))
count += 1;
}
if (count == lastcount) break;
lastcount = count;
} while(count > 0);
}
void StackSolver::build(const Funcdata &data,AddrSpace *id,int4 spcbase)
{
const VarnodeData &spacebasedata(id->getSpacebase(spcbase));
spacebase = Address(spacebasedata.space,spacebasedata.offset);
VarnodeLocSet::const_iterator begiter,enditer;
begiter = data.beginLoc(spacebasedata.size,spacebase);
enditer = data.endLoc(spacebasedata.size,spacebase);
while(begiter != enditer) { if ((*begiter)->isFree()) break;
vnlist.push_back(*begiter);
companion.push_back(-1);
++begiter;
}
missedvariables = 0;
if (vnlist.empty()) return;
if (!vnlist[0]->isInput())
throw LowlevelError("Input value of stackpointer is not used");
vector<Varnode *>::iterator iter;
StackEqn eqn;
for(int4 i=1;i<vnlist.size();++i) {
Varnode *vn = vnlist[i];
Varnode *othervn,*constvn;
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_INT_ADD) {
othervn = op->getIn(0);
constvn = op->getIn(1);
if (othervn->isConstant()) {
constvn = othervn;
othervn = op->getIn(1);
}
if (!constvn->isConstant()) { missedvariables+=1; continue; }
if (othervn->getAddr() != spacebase) { missedvariables+=1; continue; }
iter = lower_bound(vnlist.begin(),vnlist.end(),othervn,Varnode::comparePointers);
eqn.var1 = i;
eqn.var2 = iter-vnlist.begin();
eqn.rhs = constvn->getOffset();
eqs.push_back(eqn);
}
else if (op->code() == CPUI_COPY) {
othervn = op->getIn(0);
if (othervn->getAddr() != spacebase) { missedvariables+=1; continue; }
iter = lower_bound(vnlist.begin(),vnlist.end(),othervn,Varnode::comparePointers);
eqn.var1 = i;
eqn.var2 = iter-vnlist.begin();
eqn.rhs = 0;
eqs.push_back(eqn);
}
else if (op->code() == CPUI_INDIRECT) {
othervn = op->getIn(0);
if (othervn->getAddr() != spacebase) { missedvariables += 1; continue; }
iter = lower_bound(vnlist.begin(),vnlist.end(),othervn,Varnode::comparePointers);
eqn.var1 = i;
eqn.var2 = iter-vnlist.begin();
companion[i] = eqn.var2;
Varnode *iopvn = op->getIn(1);
if (iopvn->getSpace()->getType()==IPTR_IOP) { PcodeOp *iop = PcodeOp::getOpFromConst(iopvn->getAddr());
FuncCallSpecs *fc = data.getCallSpecs(iop); if (fc != (FuncCallSpecs *)0) {
if (fc->getExtraPop() != ProtoModel::extrapop_unknown) { eqn.rhs = fc->getExtraPop(); eqs.push_back(eqn);
continue;
}
}
}
eqn.rhs = 4; guess.push_back(eqn);
}
else if (op->code() == CPUI_MULTIEQUAL) {
for(int4 j=0;j<op->numInput();++j) {
othervn = op->getIn(j);
if (othervn->getAddr() != spacebase) { missedvariables += 1; continue; }
iter = lower_bound(vnlist.begin(),vnlist.end(),othervn,Varnode::comparePointers);
eqn.var1 = i;
eqn.var2 = iter-vnlist.begin();
eqn.rhs = 0;
eqs.push_back(eqn);
}
}
else if (op->code() == CPUI_INT_AND) {
othervn = op->getIn(0);
constvn = op->getIn(1);
if (othervn->isConstant()) {
constvn = othervn;
othervn = op->getIn(1);
}
if (!constvn->isConstant()) { missedvariables+=1; continue; }
if (othervn->getAddr() != spacebase) { missedvariables+=1; continue; }
iter = lower_bound(vnlist.begin(),vnlist.end(),othervn,Varnode::comparePointers);
eqn.var1 = i;
eqn.var2 = iter-vnlist.begin();
eqn.rhs = 0; eqs.push_back(eqn);
}
else
missedvariables += 1;
}
}
void ActionStackPtrFlow::analyzeExtraPop(Funcdata &data,AddrSpace *stackspace,int4 spcbase)
{
ProtoModel *myfp = data.getArch()->evalfp_called;
if (myfp == (ProtoModel *)0)
myfp = data.getArch()->defaultfp;
if (myfp->getExtraPop()!=ProtoModel::extrapop_unknown) return;
StackSolver solver;
try {
solver.build(data,stackspace,spcbase);
} catch(LowlevelError &err) {
ostringstream s;
s << "Stack frame is not setup normally: " << err.explain;
data.warningHeader(s.str());
return;
}
if (solver.getNumVariables() == 0) return;
solver.solve();
Varnode *invn = solver.getVariable(0);
bool warningprinted = false;
for(int4 i=1;i<solver.getNumVariables();++i) {
Varnode *vn = solver.getVariable(i);
int4 soln = solver.getSolution(i);
if (soln == 65535) {
if (!warningprinted) {
data.warningHeader("Unable to track spacebase fully for "+stackspace->getName());
warningprinted = true;
}
continue;
}
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_INDIRECT) {
Varnode *iopvn = op->getIn(1);
if (iopvn->getSpace()->getType()==IPTR_IOP) {
PcodeOp *iop = PcodeOp::getOpFromConst(iopvn->getAddr());
FuncCallSpecs *fc = data.getCallSpecs(iop);
if (fc != (FuncCallSpecs *)0) {
int4 soln2 = 0;
int4 comp = solver.getCompanion(i);
if (comp >= 0)
soln2 = solver.getSolution(comp);
fc->setEffectiveExtraPop(soln-soln2);
}
}
}
vector<Varnode *> paramlist;
paramlist.push_back(invn);
int4 sz = invn->getSize();
paramlist.push_back(data.newConstant(sz,soln&calc_mask(sz)));
data.opSetOpcode(op,CPUI_INT_ADD);
data.opSetAllInput(op,paramlist);
}
return;
}
bool ActionStackPtrFlow::isStackRelative(Varnode *spcbasein,Varnode *vn,uintb &constval)
{
if (spcbasein == vn) {
constval = 0;
return true;
}
if (!vn->isWritten()) return false;
PcodeOp *addop = vn->getDef();
if (addop->code() != CPUI_INT_ADD) return false;
if (addop->getIn(0) != spcbasein) return false;
Varnode *constvn = addop->getIn(1);
if (!constvn->isConstant()) return false;
constval = constvn->getOffset();
return true;
}
bool ActionStackPtrFlow::adjustLoad(Funcdata &data,PcodeOp *loadop,PcodeOp *storeop)
{
Varnode *vn = storeop->getIn(2);
if (vn->isConstant())
vn = data.newConstant(vn->getSize(),vn->getOffset());
else if (vn->isFree())
return false;
data.opRemoveInput(loadop,1);
data.opSetOpcode(loadop,CPUI_COPY);
data.opSetInput(loadop,vn,0);
return true;
}
int4 ActionStackPtrFlow::repair(Funcdata &data,AddrSpace *id,Varnode *spcbasein,PcodeOp *loadop,uintb constz)
{
int4 loadsize = loadop->getOut()->getSize();
BlockBasic *curblock = loadop->getParent();
list<PcodeOp *>::iterator begiter = curblock->beginOp();
list<PcodeOp *>::iterator iter = loadop->getBasicIter();
for(;;) {
if (iter == begiter) {
if (curblock->sizeIn() != 1) return 0; curblock = (BlockBasic *)curblock->getIn(0);
begiter = curblock->beginOp();
iter = curblock->endOp();
continue;
}
else {
--iter;
}
PcodeOp *curop = *iter;
if (curop->isCall()) return 0; if (curop->code() == CPUI_STORE) {
Varnode *ptrvn = curop->getIn(1);
Varnode *datavn = curop->getIn(2);
uintb constnew;
if (isStackRelative(spcbasein,ptrvn,constnew)) {
if ((constnew == constz)&&(loadsize == datavn->getSize())) {
if (adjustLoad(data,loadop,curop))
return 1;
return 0;
}
else if ((constnew <= constz + (loadsize-1))&&(constnew+(datavn->getSize()-1)>=constz))
return 0;
}
else
return 0; }
else {
Varnode *outvn = curop->getOut();
if (outvn != (Varnode *)0) {
if (outvn->getSpace() == id) return 0; }
}
}
}
int4 ActionStackPtrFlow::checkClog(Funcdata &data,AddrSpace *id,int4 spcbase)
{
const VarnodeData &spacebasedata(id->getSpacebase(spcbase));
Address spacebase = Address(spacebasedata.space,spacebasedata.offset);
VarnodeLocSet::const_iterator begiter,enditer;
int4 clogcount = 0;
begiter = data.beginLoc(spacebasedata.size,spacebase);
enditer = data.endLoc(spacebasedata.size,spacebase);
Varnode *spcbasein;
if (begiter == enditer) return clogcount;
spcbasein = *begiter;
++begiter;
if (!spcbasein->isInput()) return clogcount;
while(begiter != enditer) {
Varnode *outvn = *begiter;
++begiter;
if (!outvn->isWritten()) continue;
PcodeOp *addop = outvn->getDef();
if (addop->code() != CPUI_INT_ADD) continue;
Varnode *y = addop->getIn(1);
if (!y->isWritten()) continue; Varnode *x = addop->getIn(0); uintb constx;
if (!isStackRelative(spcbasein,x,constx)) { x = y; y = addop->getIn(0);
if (!isStackRelative(spcbasein,x,constx)) continue; }
PcodeOp *loadop = y->getDef();
if (loadop->code() == CPUI_INT_MULT) { Varnode *constvn = loadop->getIn(1);
if (!constvn->isConstant()) continue;
if (constvn->getOffset() != calc_mask(constvn->getSize())) continue; y = loadop->getIn(0);
if (!y->isWritten()) continue;
loadop = y->getDef();
}
if (loadop->code() != CPUI_LOAD) continue;
Varnode *ptrvn = loadop->getIn(1);
uintb constz;
if (!isStackRelative(spcbasein,ptrvn,constz)) continue;
clogcount += repair(data,id,spcbasein,loadop,constz);
}
return clogcount;
}
int4 ActionStackPtrFlow::apply(Funcdata &data)
{
if (analysis_finished)
return 0;
if (stackspace == (AddrSpace *)0) {
analysis_finished = true; return 0;
}
int4 numchange = checkClog(data,stackspace,0);
if (numchange > 0) {
count += 1;
}
if (numchange == 0) {
analyzeExtraPop(data,stackspace,0);
analysis_finished = true;
}
return 0;
}
void ActionLaneDivide::collectLaneSizes(Varnode *vn,const LanedRegister &allowedLanes,LanedRegister &checkLanes)
{
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
int4 step = 0; if (iter == vn->endDescend()) {
step = 1;
}
while(step < 2) {
int4 curSize; if (step == 0) {
PcodeOp *op = *iter;
++iter;
if (iter == vn->endDescend())
step = 1;
if (op->code() != CPUI_SUBPIECE) continue; curSize = op->getOut()->getSize();
}
else {
step = 2;
if (!vn->isWritten()) continue;
PcodeOp *op = vn->getDef();
if (op->code() != CPUI_PIECE) continue; curSize = op->getIn(0)->getSize();
int4 tmpSize = op->getIn(1)->getSize();
if (tmpSize < curSize)
curSize = tmpSize;
}
if (allowedLanes.allowedLane(curSize))
checkLanes.addLaneSize(curSize); }
}
bool ActionLaneDivide::processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 mode)
{
LanedRegister checkLanes; bool allowDowncast = (mode > 0);
if (mode < 2)
collectLaneSizes(vn,lanedRegister,checkLanes);
else {
checkLanes.addLaneSize(4); }
LanedRegister::const_iterator enditer = checkLanes.end();
for(LanedRegister::const_iterator iter=checkLanes.begin();iter!=enditer;++iter) {
int4 curSize = *iter;
LaneDescription description(lanedRegister.getWholeSize(),curSize); LaneDivide laneDivide(&data,vn,description,allowDowncast);
if (laneDivide.doTrace()) {
laneDivide.apply();
count += 1; return true;
}
}
return false;
}
int4 ActionLaneDivide::apply(Funcdata &data)
{
map<VarnodeData,const LanedRegister *>::const_iterator iter;
for(int4 mode=0;mode<3;++mode) {
bool allStorageProcessed = true;
for(iter=data.beginLaneAccess();iter!=data.endLaneAccess();++iter) {
const LanedRegister *lanedReg = (*iter).second;
Address addr = (*iter).first.getAddr();
int4 sz = (*iter).first.size;
VarnodeLocSet::const_iterator viter = data.beginLoc(sz,addr);
VarnodeLocSet::const_iterator venditer = data.endLoc(sz,addr);
bool allVarnodesProcessed = true;
while(viter != venditer) {
Varnode *vn = *viter;
if (processVarnode(data, vn, *lanedReg, mode)) {
viter = data.beginLoc(sz,addr);
venditer = data.endLoc(sz, addr); allVarnodesProcessed = true;
}
else {
++viter;
allVarnodesProcessed = false;
}
}
if (!allVarnodesProcessed)
allStorageProcessed = false;
}
if (allStorageProcessed) break;
}
data.clearLanedAccessMap();
data.setLanedRegGenerated();
return 0;
}
int4 ActionSegmentize::apply(Funcdata &data)
{
int4 numops = data.getArch()->userops.numSegmentOps();
if (numops==0) return 0;
if (localcount>0) return 0; localcount = 1;
vector<Varnode *> bindlist;
bindlist.push_back((Varnode *)0);
bindlist.push_back((Varnode *)0);
for(int4 i=0;i<numops;++i) {
SegmentOp *segdef = data.getArch()->userops.getSegmentOp(i);
if (segdef == (SegmentOp *)0) continue;
AddrSpace *spc = segdef->getSpace();
list<PcodeOp *>::const_iterator iter,enditer;
iter = data.beginOp(CPUI_CALLOTHER);
enditer = data.endOp(CPUI_CALLOTHER);
int4 uindex = segdef->getIndex();
while(iter != enditer) {
PcodeOp *segroot = *iter++;
if (segroot->isDead()) continue;
if (segroot->getIn(0)->getOffset() != uindex) continue;
if (!segdef->unify(data,segroot,bindlist)) {
ostringstream err;
err << "Segment op in wrong form at ";
segroot->getAddr().printRaw(err);
throw LowlevelError(err.str());
}
if (segdef->getNumVariableTerms()==1)
bindlist[0] = data.newConstant(4,0);
data.opSetOpcode(segroot,CPUI_SEGMENTOP);
data.opSetInput(segroot,data.newVarnodeSpace(spc),0);
data.opSetInput(segroot,bindlist[0],1);
data.opSetInput(segroot,bindlist[1],2);
for(int4 j=segroot->numInput()-1;j>2;--j) data.opRemoveInput(segroot,j);
count += 1;
}
}
return 0;
}
int4 ActionForceGoto::apply(Funcdata &data)
{
data.getOverride().applyForceGoto(data);
return 0;
}
int4 ActionConstbase::apply(Funcdata &data)
{
if (data.getBasicBlocks().getSize()==0) return 0; BlockBasic *bb = (BlockBasic *)data.getBasicBlocks().getBlock(0);
int4 injectid = data.getFuncProto().getInjectUponEntry();
if (injectid >= 0) {
InjectPayload *payload = data.getArch()->pcodeinjectlib->getPayload(injectid);
data.doLiveInject(payload,bb->getStart(),bb,bb->beginOp());
}
const TrackedSet trackset( data.getArch()->context->getTrackedSet(data.getAddress()));
for(int4 i=0;i<trackset.size();++i) {
const TrackedContext &ctx(trackset[i]);
Address addr(ctx.loc.space,ctx.loc.offset);
PcodeOp *op = data.newOp(1,bb->getStart());
data.newVarnodeOut(ctx.loc.size,addr,op);
Varnode *vnin = data.newConstant(ctx.loc.size,ctx.val);
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,vnin,0);
data.opInsertBegin(op,bb);
}
return 0;
}
bool ActionMultiCse::preferredOutput(Varnode *out1,Varnode *out2)
{
list<PcodeOp *>::const_iterator iter,enditer;
enditer = out1->endDescend();
for(iter=out1->beginDescend();iter!=enditer;++iter) {
PcodeOp *op = *iter;
if (op->code() == CPUI_RETURN)
return false;
}
enditer = out2->endDescend();
for(iter=out2->beginDescend();iter!=enditer;++iter) {
PcodeOp *op = *iter;
if (op->code() == CPUI_RETURN)
return true;
}
if (!out1->isAddrTied()) {
if (out2->isAddrTied())
return true;
else {
if (out1->getSpace()->getType()==IPTR_INTERNAL) {
if (out2->getSpace()->getType()!=IPTR_INTERNAL)
return true;
}
}
}
return false;
}
PcodeOp *ActionMultiCse::findMatch(BlockBasic *bl,PcodeOp *target,Varnode *in)
{
list<PcodeOp *>::iterator iter = bl->beginOp();
for(;;) {
PcodeOp *op = *iter;
++iter;
if (op == target) break;
int4 i,numinput;
numinput = op->numInput();
for(i=0;i<numinput;++i) {
Varnode *vn = op->getIn(i);
if (vn->isWritten() && (vn->getDef()->code() == CPUI_COPY))
vn = vn->getDef()->getIn(0); if (vn == in) break;
}
if (i < numinput) {
int4 j;
Varnode *buf1[2];
Varnode *buf2[2];
for(j=0;j<numinput;++j) {
Varnode *in1 = op->getIn(j);
if (in1->isWritten() && (in1->getDef()->code() == CPUI_COPY))
in1 = in1->getDef()->getIn(0); Varnode *in2 = target->getIn(j);
if (in2->isWritten() && (in2->getDef()->code() == CPUI_COPY))
in2 = in2->getDef()->getIn(0);
if (in1 == in2) continue;
if (0!=functionalEqualityLevel(in1,in2,buf1,buf2))
break;
}
if (j==numinput) return op;
}
}
return (PcodeOp *)0;
}
bool ActionMultiCse::processBlock(Funcdata &data,BlockBasic *bl)
{
vector<Varnode *> vnlist;
PcodeOp *targetop = (PcodeOp *)0;
PcodeOp *pairop;
list<PcodeOp *>::iterator iter = bl->beginOp();
list<PcodeOp *>::iterator enditer = bl->endOp();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
OpCode opc = op->code();
if (opc == CPUI_COPY) continue;
if (opc != CPUI_MULTIEQUAL) break;
int4 vnpos = vnlist.size();
int4 i;
int4 numinput = op->numInput();
for(i=0;i<numinput;++i) {
Varnode *vn = op->getIn(i);
if (vn->isWritten() && (vn->getDef()->code() == CPUI_COPY)) vn = vn->getDef()->getIn(0); vnlist.push_back(vn);
if (vn->isMark()) { pairop = findMatch(bl,op,vn);
if (pairop != (PcodeOp *)0)
break;
}
}
if (i<numinput) {
targetop = op;
break;
}
for(i=vnpos;i<vnlist.size();++i)
vnlist[i]->setMark(); }
for(int4 i=0;i<vnlist.size();++i)
vnlist[i]->clearMark();
if (targetop != (PcodeOp *)0) {
Varnode *out1 = pairop->getOut();
Varnode *out2 = targetop->getOut();
if (preferredOutput(out1,out2)) {
data.totalReplace(out1,out2); data.opDestroy(pairop);
}
else {
data.totalReplace(out2,out1);
data.opDestroy(targetop);
}
count += 1; return true;
}
return false;
}
int4 ActionMultiCse::apply(Funcdata &data)
{
const BlockGraph &bblocks( data.getBasicBlocks() );
int4 sz = bblocks.getSize();
for(int4 i=0;i<sz;++i) {
BlockBasic *bl = (BlockBasic *)bblocks.getBlock(i);
while(processBlock(data,bl)) {
}
}
return 0;
}
int4 ActionShadowVar::apply(Funcdata &data)
{
const BlockGraph &bblocks(data.getBasicBlocks());
BlockBasic *bl;
PcodeOp *op;
Varnode *vn;
vector<Varnode *> vnlist;
list<PcodeOp *> oplist;
uintb startoffset;
for(int4 i=0;i<bblocks.getSize();++i) {
vnlist.clear();
bl = (BlockBasic *)bblocks.getBlock(i);
startoffset = bl->getStart().getOffset();
list<PcodeOp *>::iterator iter = bl->beginOp();
while(iter != bl->endOp()) {
op = *iter++;
if (op->getAddr().getOffset() != startoffset) break;
if (op->code() != CPUI_MULTIEQUAL) continue;
vn = op->getIn(0);
if (vn->isMark())
oplist.push_back(op);
else {
vn->setMark();
vnlist.push_back(vn);
}
}
for(int4 j=0;j<vnlist.size();++j)
vnlist[j]->clearMark();
}
list<PcodeOp *>::iterator oiter;
for(oiter=oplist.begin();oiter!=oplist.end();++oiter) {
op = *oiter;
PcodeOp *op2;
for(op2=op->previousOp();op2!=(PcodeOp *)0;op2=op2->previousOp()) {
if (op2->code() != CPUI_MULTIEQUAL) continue;
int4 i;
for(i=0;i<op->numInput();++i) if (op->getIn(i) != op2->getIn(i)) break;
if (i != op->numInput()) continue;
vector<Varnode *> plist;
plist.push_back(op2->getOut());
data.opSetOpcode(op,CPUI_COPY);
data.opSetAllInput(op,plist);
count += 1;
}
}
return 0;
}
AddrSpace *ActionConstantPtr::searchForLoadStore(Varnode *vn,PcodeOp *op)
{
for(int4 i=0;i<3;++i) {
switch(op->code()) {
case CPUI_INT_ADD:
case CPUI_COPY:
case CPUI_INDIRECT:
case CPUI_MULTIEQUAL:
vn = op->getOut();
op = vn->loneDescend();
break;
case CPUI_LOAD:
return Address::getSpaceFromConst(op->getIn(0)->getAddr());
case CPUI_STORE:
if (op->getIn(1) == vn)
return Address::getSpaceFromConst(op->getIn(0)->getAddr());
return (AddrSpace *)0;
default:
return (AddrSpace *)0;
}
if (op == (PcodeOp *)0) break;
}
for(list<PcodeOp *>::const_iterator iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
op = *iter;
OpCode opc = op->code();
if (opc == CPUI_LOAD)
return Address::getSpaceFromConst(op->getIn(0)->getAddr());
else if (opc == CPUI_STORE && op->getIn(1) == vn)
return Address::getSpaceFromConst(op->getIn(0)->getAddr());
}
return (AddrSpace *)0;
}
AddrSpace *ActionConstantPtr::selectInferSpace(Varnode *vn,PcodeOp *op,const vector<AddrSpace *> &spaceList)
{
AddrSpace *resSpace = (AddrSpace *)0;
for(int4 i=0;i<spaceList.size();++i) {
AddrSpace *spc = spaceList[i];
int4 minSize = spc->getMinimumPtrSize();
if (minSize == 0) {
if (vn->getSize() != spc->getAddrSize())
continue;
}
else if (vn->getSize() < minSize)
continue;
if (resSpace != (AddrSpace *)0) {
AddrSpace *searchSpc = searchForLoadStore(vn,op);
if (searchSpc != (AddrSpace *)0)
resSpace = searchSpc;
break;
}
resSpace = spc;
}
return resSpace;
}
SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot,
Address &rampoint,uintb &fullEncoding,Funcdata &data)
{
bool needexacthit;
Architecture *glb = data.getArch();
Varnode *outvn;
if (vn->getType()->getMetatype() == TYPE_PTR) { rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
needexacthit = false;
}
else {
if (vn->isTypeLock()) return (SymbolEntry *)0; needexacthit = true;
switch(op->code()) {
case CPUI_RETURN:
case CPUI_CALL:
case CPUI_CALLIND:
if (!glb->infer_pointers)
return (SymbolEntry *)0;
if (slot==0)
return (SymbolEntry *)0;
break;
case CPUI_COPY:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
break;
case CPUI_INT_ADD:
outvn = op->getOut();
if (outvn->getType()->getMetatype()==TYPE_PTR) {
if (op->getIn(1-slot)->getType()->getMetatype()==TYPE_PTR)
return (SymbolEntry *)0; needexacthit = false;
}
else if (!glb->infer_pointers)
return (SymbolEntry *)0;
break;
case CPUI_STORE:
if (slot != 2)
return (SymbolEntry *)0;
break;
default:
return (SymbolEntry *)0;
}
if (spc->getPointerLowerBound() > vn->getOffset())
return (SymbolEntry *)0;
if (spc->getPointerUpperBound() < vn->getOffset())
return (SymbolEntry *)0;
if (bit_transitions(vn->getOffset(),vn->getSize()) < 3)
return (SymbolEntry *)0;
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
}
if (rampoint.isInvalid()) return (SymbolEntry *)0;
SymbolEntry *entry = data.getScopeLocal()->getParent()->queryContainer(rampoint,1,Address());
if (entry != (SymbolEntry *)0) {
Datatype *ptrType = entry->getSymbol()->getType();
if (ptrType->getMetatype() == TYPE_ARRAY) {
Datatype *ct = ((TypeArray *)ptrType)->getBase();
if (ct->isCharPrint())
needexacthit = false;
}
if (needexacthit && entry->getAddr() != rampoint)
return (SymbolEntry *)0;
}
return entry;
}
int4 ActionConstantPtr::apply(Funcdata &data)
{
if (!data.isTypeRecoveryOn()) return 0;
if (localcount >= 4) return 0;
localcount += 1;
VarnodeLocSet::const_iterator begiter,enditer;
Architecture *glb = data.getArch();
AddrSpace *cspc = glb->getConstantSpace();
SymbolEntry *entry;
Varnode *vn;
begiter = data.beginLoc(cspc);
enditer = data.endLoc(cspc);
while(begiter!=enditer) {
vn = *begiter++;
if (!vn->isConstant()) break; if (vn->getOffset() == 0) continue; if (vn->isPtrCheck()) continue; if (vn->hasNoDescend()) continue;
if (vn->isSpacebase()) continue;
PcodeOp *op = vn->loneDescend();
if (op == (PcodeOp *)0) continue;
AddrSpace *rspc = selectInferSpace(vn, op, glb->inferPtrSpaces);
if (rspc == (AddrSpace *)0) continue;
int4 slot = op->getSlot(vn);
OpCode opc = op->code();
if (opc == CPUI_INT_ADD) {
if (op->getIn(1-slot)->isSpacebase()) continue; }
else if ((opc == CPUI_PTRSUB)||(opc==CPUI_PTRADD))
continue;
Address rampoint;
uintb fullEncoding;
entry = isPointer(rspc,vn,op,slot,rampoint,fullEncoding,data);
vn->setPtrCheck(); if (entry != (SymbolEntry *)0) {
data.spacebaseConstant(op,slot,entry,rampoint,fullEncoding,vn->getSize());
if ((opc == CPUI_INT_ADD)&&(slot==1))
data.opSwapInput(op,0,1);
count += 1;
}
}
return 0;
}
int4 ActionDeindirect::apply(Funcdata &data)
{
FuncCallSpecs *fc;
PcodeOp *op;
Varnode *vn;
for(int4 i=0;i<data.numCalls();++i) {
fc = data.getCallSpecs(i);
op = fc->getOp();
if (op->code() != CPUI_CALLIND) continue;
vn = op->getIn(0);
while(vn->isWritten()&&(vn->getDef()->code()==CPUI_COPY))
vn = vn->getDef()->getIn(0);
if (vn->isPersist() && vn->isExternalRef()) { Funcdata *newfd = data.getScopeLocal()->getParent()->queryExternalRefFunction(vn->getAddr());
if (newfd != (Funcdata *)0) {
fc->deindirect(data,newfd);
count += 1;
continue;
}
}
else if (vn->isConstant()) {
AddrSpace *sp = data.getAddress().getSpace(); uintb offset = AddrSpace::addressToByte(vn->getOffset(),sp->getWordSize());
int4 align = data.getArch()->funcptr_align;
if (align != 0) { offset >>= align; offset <<= align;
}
Address codeaddr(sp,offset);
Funcdata *newfd = data.getScopeLocal()->getParent()->queryFunction(codeaddr);
if (newfd != (Funcdata *)0) {
fc->deindirect(data,newfd);
count += 1;
continue;
}
}
if (data.isTypeRecoveryOn()) {
Datatype *ct = op->getIn(0)->getType();
if ((ct->getMetatype()==TYPE_PTR)&&
(((TypePointer *)ct)->getPtrTo()->getMetatype()==TYPE_CODE)) {
TypeCode *tc = (TypeCode *)((TypePointer *)ct)->getPtrTo();
const FuncProto *fp = tc->getPrototype();
if (fp!=(const FuncProto *)0) {
if (!fc->isInputLocked()) {
fc->forceSet(data,*fp);
count += 1;
}
}
}
}
}
return 0;
}
int4 ActionVarnodeProps::apply(Funcdata &data)
{
Architecture *glb = data.getArch();
bool cachereadonly = glb->readonlypropagate;
int4 pass = data.getHeritagePass();
VarnodeLocSet::const_iterator iter;
Varnode *vn;
iter = data.beginLoc();
while(iter != data.endLoc()) {
vn = *iter++; if (vn->isAnnotation()) continue;
int4 vnSize = vn->getSize();
if (vn->isAutoLiveHold()) {
if (pass > 0) {
if (vn->isWritten()) {
PcodeOp *loadOp = vn->getDef();
if (loadOp->code() == CPUI_LOAD) {
Varnode *ptr = loadOp->getIn(1);
if (ptr->isConstant() || ptr->isReadOnly())
continue;
if (ptr->isWritten()) {
PcodeOp *copyOp = ptr->getDef();
if (copyOp->code() == CPUI_COPY) {
ptr = copyOp->getIn(0);
if (ptr->isConstant() || ptr->isReadOnly())
continue;
}
}
}
}
vn->clearAutoLiveHold();
count += 1;
}
}
else if (vn->hasActionProperty()) {
if (cachereadonly&&vn->isReadOnly()) {
if (data.fillinReadOnly(vn)) count += 1;
}
else if (vn->isVolatile())
if (data.replaceVolatile(vn))
count += 1; }
else if (((vn->getNZMask() & vn->getConsume())==0)&&(vnSize<=sizeof(uintb))) {
if (vn->isConstant()) continue; if (vn->isWritten()) {
if (vn->getDef()->code() == CPUI_COPY) {
if (vn->getDef()->getIn(0)->isConstant()) {
if (vn->getDef()->getIn(0)->getOffset() == 0)
continue;
}
}
}
if (!vn->hasNoDescend()) {
data.totalReplaceConstant(vn,0);
count += 1;
}
}
}
data.setLanedRegGenerated();
return 0;
}
int4 ActionDirectWrite::apply(Funcdata &data)
{
VarnodeLocSet::const_iterator iter;
list<PcodeOp *>::const_iterator oiter;
Varnode *vn,*dvn;
PcodeOp *op;
vector<Varnode *> worklist;
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
vn = *iter;
vn->clearDirectWrite();
if (vn->isInput()) {
if (vn->isPersist()||vn->isSpacebase()) {
vn->setDirectWrite();
worklist.push_back(vn);
}
else if (data.getFuncProto().possibleInputParam(vn->getAddr(),vn->getSize())) {
vn->setDirectWrite();
worklist.push_back(vn);
}
}
else if (vn->isWritten()) {
op = vn->getDef();
if (!op->isMarker()) {
if (vn->isPersist()) {
vn->setDirectWrite();
worklist.push_back(vn);
}
else if (op->code() == CPUI_COPY) { if (vn->isStackStore()) { Varnode *invn = op->getIn(0); if (invn->isWritten()) { PcodeOp *curop = invn->getDef();
if (curop->code() == CPUI_COPY)
invn = curop->getIn(0);
}
if (invn->isWritten() && invn->getDef()->isMarker()) { vn->setDirectWrite(); worklist.push_back(vn);
}
}
}
else if ((op->code()!=CPUI_PIECE)&&(op->code()!=CPUI_SUBPIECE)) {
vn->setDirectWrite();
worklist.push_back(vn);
}
}
else if (!propagateIndirect && op->code() == CPUI_INDIRECT) {
Varnode *outvn = op->getOut();
if (op->getIn(0)->getAddr() != outvn->getAddr()) vn->setDirectWrite(); else if (outvn->isPersist()) vn->setDirectWrite(); }
}
else if (vn->isConstant()) {
if (!vn->isIndirectZero()) {
vn->setDirectWrite();
worklist.push_back(vn);
}
}
}
while(!worklist.empty()) {
vn = worklist.back();
worklist.pop_back();
for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter) {
op = *oiter;
if (!op->isAssignment()) continue;
dvn = op->getOut();
if (!dvn->isDirectWrite()) {
dvn->setDirectWrite();
if (propagateIndirect || op->code() != CPUI_INDIRECT || op->isIndirectStore())
worklist.push_back(dvn);
}
}
}
return 0;
}
int4 ActionExtraPopSetup::apply(Funcdata &data)
{
FuncCallSpecs *fc;
PcodeOp *op;
if (stackspace == (AddrSpace *)0) return 0; const VarnodeData &point(stackspace->getSpacebase(0));
Address sb_addr(point.space,point.offset);
int4 sb_size = point.size;
for(int4 i=0;i<data.numCalls();++i) {
fc = data.getCallSpecs(i);
if (fc->getExtraPop() == 0) continue; op = data.newOp(2,fc->getOp()->getAddr());
data.newVarnodeOut(sb_size,sb_addr,op);
data.opSetInput(op,data.newVarnode(sb_size,sb_addr),0);
if (fc->getExtraPop() != ProtoModel::extrapop_unknown) { fc->setEffectiveExtraPop(fc->getExtraPop());
data.opSetOpcode(op,CPUI_INT_ADD);
data.opSetInput(op,data.newConstant(sb_size,fc->getExtraPop()),1);
data.opInsertAfter(op,fc->getOp());
}
else { data.opSetOpcode(op,CPUI_INDIRECT);
data.opSetInput(op,data.newVarnodeIop(fc->getOp()),1);
data.opInsertBefore(op,fc->getOp());
}
}
return 0;
}
void ActionFuncLink::funcLinkInput(FuncCallSpecs *fc,Funcdata &data)
{
bool inputlocked = fc->isInputLocked();
bool varargs = fc->isDotdotdot();
AddrSpace *spacebase = fc->getSpacebase(); ParamActive *active = fc->getActiveInput();
if ((!inputlocked)||varargs)
fc->initActiveInput();
if (inputlocked) {
PcodeOp *op = fc->getOp();
int4 numparam = fc->numParams();
bool setplaceholder = varargs;
for(int4 i=0;i<numparam;++i) {
ProtoParameter *param = fc->getParam(i);
active->registerTrial(param->getAddress(),param->getSize());
active->getTrial(i).markActive(); AddrSpace *spc = param->getAddress().getSpace();
uintb off = param->getAddress().getOffset();
int4 sz = param->getSize();
if (spc->getType() == IPTR_SPACEBASE) { Varnode *loadval = data.opStackLoad(spc,off,sz,op,(Varnode *)0,false);
data.opInsertInput(op,loadval,op->numInput());
if (!setplaceholder) {
setplaceholder = true;
loadval->setSpacebasePlaceholder();
spacebase = (AddrSpace *)0; }
}
else
data.opInsertInput(op,data.newVarnode(param->getSize(),param->getAddress()),op->numInput());
}
}
if (spacebase != (AddrSpace *)0) { PcodeOp *op = fc->getOp();
int4 slot = op->numInput();
Varnode *loadval = data.opStackLoad(spacebase,0,1,op,(Varnode *)0,false);
data.opInsertInput(op,loadval,slot);
fc->setStackPlaceholderSlot(slot);
loadval->setSpacebasePlaceholder();
}
}
void ActionFuncLink::funcLinkOutput(FuncCallSpecs *fc,Funcdata &data)
{
if (fc->isOutputLocked()) {
ProtoParameter *outparam = fc->getOutput();
Datatype *outtype = outparam->getType();
if (outtype->getMetatype() != TYPE_VOID) {
int4 sz = outparam->getSize();
Address addr = outparam->getAddress();
data.newVarnodeOut(sz,addr,fc->getOp());
VarnodeData vdata;
OpCode res = fc->assumedOutputExtension(addr,sz,vdata);
if (res == CPUI_PIECE) { if (outtype->getMetatype() == TYPE_INT)
res = CPUI_INT_SEXT;
else
res = CPUI_INT_ZEXT;
}
if (res != CPUI_COPY) { PcodeOp *callop = fc->getOp();
PcodeOp *op = data.newOp(1,callop->getAddr());
data.newVarnodeOut(vdata.size,vdata.getAddr(),op);
Varnode *invn = data.newVarnode(sz,addr);
data.opSetInput(op,invn,0);
data.opSetOpcode(op,res);
data.opInsertAfter(op,callop); }
}
}
else
fc->initActiveOutput();
}
int4 ActionFuncLink::apply(Funcdata &data)
{
int4 i,size;
size = data.numCalls();
for(i=0;i<size;++i) {
funcLinkInput(data.getCallSpecs(i),data);
funcLinkOutput(data.getCallSpecs(i),data);
}
return 0;
}
int4 ActionFuncLinkOutOnly::apply(Funcdata &data)
{
int4 size = data.numCalls();
for(int4 i=0;i<size;++i)
ActionFuncLink::funcLinkOutput(data.getCallSpecs(i),data);
return 0;
}
int4 ActionParamDouble::apply(Funcdata &data)
{
for(int4 i=0;i<data.numCalls();++i) {
FuncCallSpecs *fc = data.getCallSpecs(i);
PcodeOp *op = fc->getOp();
if (fc->isInputActive()) {
ParamActive *active = fc->getActiveInput();
for(int4 j=0;j<active->getNumTrials();++j) {
const ParamTrial ¶mtrial( active->getTrial(j) );
if (paramtrial.isChecked()) continue;
if (paramtrial.isUnref()) continue;
AddrSpace *spc = paramtrial.getAddress().getSpace();
if (spc->getType() != IPTR_SPACEBASE) continue;
int4 slot = paramtrial.getSlot();
Varnode *vn = op->getIn(slot);
if (!vn->isWritten()) continue;
PcodeOp *concatop = vn->getDef();
if (concatop->code() != CPUI_PIECE) continue;
if (!fc->hasModel()) continue;
Varnode *mostvn = concatop->getIn(0);
Varnode *leastvn = concatop->getIn(1);
int4 splitsize = spc->isBigEndian() ? mostvn->getSize() : leastvn->getSize();
if (fc->checkInputSplit(paramtrial.getAddress(),paramtrial.getSize(),splitsize)) {
active->splitTrial(j,splitsize);
if (spc->isBigEndian()) {
data.opInsertInput(op,mostvn,slot);
data.opSetInput(op,leastvn,slot+1);
}
else {
data.opInsertInput(op,leastvn,slot);
data.opSetInput(op,mostvn,slot+1);
}
count += 1;
j -= 1; }
}
}
else if ((!fc->isInputLocked())&&(data.isDoublePrecisOn())) {
int4 max = op->numInput() - 1;
for(int4 j=1;j<max;++j) {
Varnode *vn1 = op->getIn(j);
Varnode *vn2 = op->getIn(j+1);
SplitVarnode whole;
bool isslothi;
if (whole.inHandHi(vn1)) {
if (whole.getLo() != vn2) continue;
isslothi = true;
}
else if (whole.inHandLo(vn1)) {
if (whole.getHi() != vn2) continue;
isslothi = false;
}
else
continue;
if (fc->checkInputJoin(j,isslothi,vn1,vn2)) {
data.opSetInput(op,whole.getWhole(),j);
data.opRemoveInput(op,j+1);
fc->doInputJoin(j,isslothi);
max = op->numInput() - 1;
count += 1;
}
}
}
}
const FuncProto &fp( data.getFuncProto() );
if (fp.isInputLocked() && data.isDoublePrecisOn()) {
vector<Varnode *> lovec;
vector<Varnode *> hivec;
int4 minDoubleSize = data.getArch()->getDefaultSize(); int4 numparams = fp.numParams();
for(int4 i=0;i<numparams;++i) {
ProtoParameter *param = fp.getParam(i);
Datatype *tp = param->getType();
type_metatype mt = tp->getMetatype();
if ((mt==TYPE_ARRAY)||(mt==TYPE_STRUCT)) continue; Varnode *vn = data.findVarnodeInput(tp->getSize(),param->getAddress());
if (vn == (Varnode *)0) continue;
if (vn->getSize() < minDoubleSize) continue;
int4 halfSize = vn->getSize() / 2;
lovec.clear();
hivec.clear();
bool otherUse = false; list<PcodeOp *>::const_iterator iter,enditer;
iter = vn->beginDescend();
enditer = vn->endDescend();
while(iter != enditer) {
PcodeOp *subop = *iter;
++iter;
if (subop->code() != CPUI_SUBPIECE) continue;
Varnode *outvn = subop->getOut();
if (outvn->getSize() != halfSize) continue;
if (subop->getIn(1)->getOffset() == 0) lovec.push_back(outvn);
else if (subop->getIn(1)->getOffset() == halfSize) hivec.push_back(outvn);
else {
otherUse = true;
break;
}
}
if ((!otherUse)&&(!lovec.empty())&&(!hivec.empty())) { for(int4 j=0;j<lovec.size();++j) {
Varnode *piecevn = lovec[j];
if (!piecevn->isPrecisLo()) {
piecevn->setPrecisLo();
count += 1; }
}
for(int4 j=0;j<hivec.size();++j) {
Varnode *piecevn = hivec[j];
if (!piecevn->isPrecisHi()) {
piecevn->setPrecisHi();
count += 1;
}
}
}
}
}
return 0;
}
int4 ActionActiveParam::apply(Funcdata &data)
{
int4 i;
FuncCallSpecs *fc;
AliasChecker aliascheck;
aliascheck.gather(&data,data.getArch()->getStackSpace(),true);
for(i=0;i<data.numCalls();++i) {
fc = data.getCallSpecs(i);
try {
if (fc->isInputActive()) {
ParamActive *activeinput = fc->getActiveInput();
bool trimmable = ((activeinput->getNumPasses()>0)||(fc->getOp()->code() != CPUI_CALLIND));
if (!activeinput->isFullyChecked())
fc->checkInputTrialUse(data,aliascheck);
activeinput->finishPass();
if (activeinput->getNumPasses() > activeinput->getMaxPass())
activeinput->markFullyChecked();
else
count += 1; if (trimmable && activeinput->isFullyChecked()) {
if (activeinput->needsFinalCheck())
fc->finalInputCheck();
fc->resolveModel(activeinput);
fc->deriveInputMap(activeinput);
fc->buildInputFromTrials(data);
fc->clearActiveInput();
count += 1;
}
}
}
catch(LowlevelError &err) {
ostringstream s;
s << "Error processing " << fc->getName();
PcodeOp *op = fc->getOp();
if (op != (PcodeOp *)0)
s << " called at " << op->getSeqNum();
s << ": " << err.explain;
throw LowlevelError(s.str());
}
}
return 0;
}
int4 ActionActiveReturn::apply(Funcdata &data)
{
int4 i;
FuncCallSpecs *fc;
for(i=0;i<data.numCalls();++i) {
fc = data.getCallSpecs(i);
if (fc->isOutputActive()) {
ParamActive *activeoutput = fc->getActiveOutput();
vector<Varnode *> trialvn;
fc->checkOutputTrialUse(data,trialvn);
fc->deriveOutputMap(activeoutput);
fc->buildOutputFromTrials(data,trialvn);
fc->clearActiveOutput();
count += 1;
}
}
return 0;
}
void ActionReturnRecovery::buildReturnOutput(ParamActive *active,PcodeOp *retop,Funcdata &data)
{
vector<Varnode *> newparam;
newparam.push_back(retop->getIn(0)); for(int4 i=0;i<active->getNumTrials();++i) { ParamTrial &curtrial(active->getTrial(i));
if (!curtrial.isUsed()) break;
if (curtrial.getSlot() >= retop->numInput()) break;
newparam.push_back(retop->getIn(curtrial.getSlot()));
}
if (newparam.size()<=2) data.opSetAllInput(retop,newparam);
else if (newparam.size()==3) { Varnode *lovn = newparam[1];
Varnode *hivn = newparam[2];
ParamTrial &triallo( active->getTrial(0) );
ParamTrial &trialhi( active->getTrial(1) );
Address joinaddr = data.getArch()->constructJoinAddress(data.getArch()->translate,
trialhi.getAddress(),trialhi.getSize(),
triallo.getAddress(),triallo.getSize());
PcodeOp *newop = data.newOp(2,retop->getAddr());
data.opSetOpcode(newop,CPUI_PIECE);
Varnode *newwhole = data.newVarnodeOut(trialhi.getSize()+triallo.getSize(),joinaddr,newop);
newwhole->setWriteMask(); data.opInsertBefore(newop,retop);
newparam.pop_back();
newparam.back() = newwhole;
data.opSetAllInput(retop,newparam);
data.opSetInput(newop,hivn,0);
data.opSetInput(newop,lovn,1);
}
else { newparam.clear();
newparam.push_back(retop->getIn(0));
int4 offmatch = 0;
Varnode *preexist = (Varnode *)0;
for(int4 i=0;i<active->getNumTrials();++i) {
ParamTrial &curtrial(active->getTrial(i));
if (!curtrial.isUsed()) break;
if (curtrial.getSlot() >= retop->numInput()) break;
if (preexist == (Varnode *)0) {
preexist = retop->getIn(curtrial.getSlot());
offmatch = curtrial.getOffset() + curtrial.getSize();
}
else if (offmatch == curtrial.getOffset()) {
offmatch += curtrial.getSize();
Varnode *vn = retop->getIn(curtrial.getSlot());
PcodeOp *newop = data.newOp(2,retop->getAddr());
data.opSetOpcode(newop,CPUI_PIECE);
Address addr = preexist->getAddr();
if (vn->getAddr() < addr)
addr = vn->getAddr();
Varnode *newout = data.newVarnodeOut(preexist->getSize()+vn->getSize(),addr,newop);
newout->setWriteMask(); data.opSetInput(newop,vn,0); data.opSetInput(newop,preexist,1);
data.opInsertBefore(newop,retop);
preexist = newout;
}
else
break;
}
if (preexist != (Varnode *)0)
newparam.push_back(preexist);
data.opSetAllInput(retop,newparam);
}
}
int4 ActionReturnRecovery::apply(Funcdata &data)
{
ParamActive *active = data.getActiveOutput();
if (active != (ParamActive *)0) {
PcodeOp *op;
Varnode *vn;
list<PcodeOp *>::const_iterator iter,iterend;
int4 i;
int4 maxancestor = data.getArch()->trim_recurse_max;
iterend = data.endOp(CPUI_RETURN);
AncestorRealistic ancestorReal;
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
op = *iter;
if (op->isDead()) continue;
if (op->getHaltType() != 0) continue; for(i=0;i<active->getNumTrials();++i) {
ParamTrial &trial(active->getTrial(i));
if (trial.isChecked()) continue; int4 slot = trial.getSlot();
vn = op->getIn(slot);
if (ancestorReal.execute(op,slot,&trial,false))
if (data.ancestorOpUse(maxancestor,vn,op,trial,0))
trial.markActive(); count += 1;
}
}
active->finishPass();
if (active->getNumPasses() > active->getMaxPass())
active->markFullyChecked();
if (active->isFullyChecked()) {
data.getFuncProto().deriveOutputMap(active);
iterend = data.endOp(CPUI_RETURN);
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
op = *iter;
if (op->isDead()) continue;
if (op->getHaltType() != 0) continue;
buildReturnOutput(active,op,data);
}
data.clearActiveOutput();
count += 1;
}
}
return 0;
}
int4 ActionRestrictLocal::apply(Funcdata &data)
{
FuncCallSpecs *fc;
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
Varnode *vn;
int4 i;
vector<EffectRecord>::const_iterator eiter,endeiter;
for(i=0;i<data.numCalls();++i) {
fc = data.getCallSpecs(i);
op = fc->getOp();
if (!fc->isInputLocked()) continue;
if (fc->getSpacebaseOffset() == FuncCallSpecs::offset_unknown) continue;
int4 numparam = fc->numParams();
for(int4 j=0;j<numparam;++j) {
ProtoParameter *param = fc->getParam(j);
Address addr = param->getAddress();
if (addr.getSpace()->getType() != IPTR_SPACEBASE) continue;
uintb off = addr.getSpace()->wrapOffset(fc->getSpacebaseOffset() + addr.getOffset());
data.getScopeLocal()->markNotMapped(addr.getSpace(),off,param->getSize(),true);
}
}
eiter = data.getFuncProto().effectBegin();
endeiter = data.getFuncProto().effectEnd();
for(;eiter!=endeiter;++eiter) { if ((*eiter).getType() == EffectRecord::killedbycall) continue; vn = data.findVarnodeInput((*eiter).getSize(),(*eiter).getAddress());
if ((vn != (Varnode *)0)&&(vn->isUnaffected())) {
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
op = *iter;
if (op->code() != CPUI_COPY) continue;
Varnode *outvn = op->getOut();
if (!data.getScopeLocal()->isUnaffectedStorage(outvn)) continue;
data.getScopeLocal()->markNotMapped(outvn->getSpace(),outvn->getOffset(),outvn->getSize(),false);
}
}
}
return 0;
}
uint4 ActionLikelyTrash::countMarks(PcodeOp *op)
{
uint4 res = 0;
for(int4 i=0;i<op->numInput();++i) {
Varnode *vn = op->getIn(i);
for(;;) {
if (vn->isMark()) {
res += 1;
break;
}
if (!vn->isWritten()) break;
PcodeOp *defOp = vn->getDef();
if (defOp == op) { res += 1;
break;
}
else if (defOp->code() != CPUI_INDIRECT) break;
vn = vn->getDef()->getIn(0);
}
}
return res;
}
bool ActionLikelyTrash::traceTrash(Varnode *vn,vector<PcodeOp *> &indlist)
{
vector<PcodeOp *> allroutes; vector<Varnode *> markedlist; list<PcodeOp *>::const_iterator iter,enditer;
Varnode *outvn;
uintb val;
uint4 traced = 0;
vn->setMark();
markedlist.push_back(vn);
bool istrash = true;
while(traced < markedlist.size()) {
Varnode *curvn = markedlist[traced++];
iter = curvn->beginDescend();
enditer = curvn->endDescend();
for(;iter!=enditer;++iter) {
PcodeOp *op = *iter;
outvn = op->getOut();
switch(op->code()) {
case CPUI_INDIRECT:
if (outvn->isPersist())
istrash = false;
else if (op->isIndirectStore()) {
if (!outvn->isMark()) {
outvn->setMark();
markedlist.push_back(outvn);
}
}
else
indlist.push_back(op);
break;
case CPUI_SUBPIECE:
if (outvn->isPersist())
istrash = false;
else {
if (!outvn->isMark()) {
outvn->setMark();
markedlist.push_back(outvn);
}
}
break;
case CPUI_MULTIEQUAL:
case CPUI_PIECE:
if (outvn->isPersist())
istrash = false;
else {
if (!op->isMark()) {
op->setMark();
allroutes.push_back(op);
}
uint4 nummark = countMarks(op);
if (nummark == op->numInput()) {
if (!outvn->isMark()) {
outvn->setMark();
markedlist.push_back(outvn);
}
}
}
break;
case CPUI_INT_AND:
if (op->getIn(1)->isConstant()) {
val = op->getIn(1)->getOffset();
uintb mask = calc_mask(op->getIn(1)->getSize());
if ((val == ((mask<<8)&mask))||(val == ((mask<<16)&mask))||(val==((mask<<32)&mask))) {
indlist.push_back(op);
break;
}
}
istrash = false;
break;
default:
istrash = false;
break;
}
if (!istrash) break;
}
if (!istrash) break;
}
for(uint4 i=0;i<allroutes.size();++i) {
if (!allroutes[i]->getOut()->isMark())
istrash = false; allroutes[i]->clearMark();
}
for(uint4 i=0;i<markedlist.size();++i)
markedlist[i]->clearMark();
return istrash;
}
int4 ActionLikelyTrash::apply(Funcdata &data)
{
vector<PcodeOp *> indlist;
vector<VarnodeData>::const_iterator iter,enditer;
iter = data.getFuncProto().trashBegin();
enditer = data.getFuncProto().trashEnd();
for(;iter!=enditer;++iter) {
const VarnodeData &vdata( *iter );
Varnode *vn = data.findCoveredInput(vdata.size,vdata.getAddr());
if (vn == (Varnode *)0) continue;
if (vn->isTypeLock()||vn->isNameLock()) continue;
indlist.clear();
if (!traceTrash(vn,indlist)) continue;
for(uint4 i=0;i<indlist.size();++i) {
PcodeOp *op = indlist[i];
if (op->code() == CPUI_INDIRECT) {
data.opSetInput(op,data.newConstant(op->getOut()->getSize(), 0),0);
data.markIndirectCreation(op,false);
}
else if (op->code() == CPUI_INT_AND) {
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),0),1);
}
count += 1; }
}
return 0;
}
int4 ActionRestructureVarnode::apply(Funcdata &data)
{
ScopeLocal *l1 = data.getScopeLocal();
bool aliasyes = data.isJumptableRecoveryOn() ? false : (numpass != 0);
l1->restructureVarnode(aliasyes);
if (data.syncVarnodesWithSymbols(l1,false))
count += 1;
numpass += 1;
#ifdef OPACTION_DEBUG
if ((flags&rule_debug)==0) return 0;
ostringstream s;
data.getScopeLocal()->printEntries(s);
data.getArch()->printDebug(s.str());
#endif
return 0;
}
int4 ActionRestructureHigh::apply(Funcdata &data)
{
if (!data.isHighOn()) return 0;
ScopeLocal *l1 = data.getScopeLocal();
#ifdef OPACTION_DEBUG
if ((flags&rule_debug)!=0)
l1->turnOnDebug();
#endif
l1->restructureHigh();
if (data.syncVarnodesWithSymbols(l1,true))
count += 1;
#ifdef OPACTION_DEBUG
if ((flags&rule_debug)==0) return 0;
l1->turnOffDebug();
ostringstream s;
data.getScopeLocal()->printEntries(s);
data.getArch()->printDebug(s.str());
#endif
return 0;
}
int4 ActionDefaultParams::apply(Funcdata &data)
{
int4 i,size;
FuncCallSpecs *fc;
ProtoModel *evalfp = data.getArch()->evalfp_called; if (evalfp == (ProtoModel *)0) evalfp = data.getArch()->defaultfp;
size = data.numCalls();
for(i=0;i<size;++i) {
fc = data.getCallSpecs(i);
if (!fc->hasModel()) {
Funcdata *otherfunc = fc->getFuncdata();
if (otherfunc != (Funcdata *)0) {
fc->copy(otherfunc->getFuncProto());
if ((!fc->isModelLocked())&&(!fc->hasMatchingModel(evalfp)))
fc->setModel(evalfp);
}
else
fc->setInternal(evalfp,data.getArch()->types->getTypeVoid());
}
fc->insertPcode(data); }
return 0; }
bool ActionSetCasts::testStructOffset0(Varnode *vn,Datatype *ct,CastStrategy *castStrategy)
{
if (ct->getMetatype() != TYPE_PTR) return false;
Datatype *highType = vn->getHigh()->getType();
if (highType->getMetatype() != TYPE_PTR) return false;
Datatype *highPtrTo = ((TypePointer *)highType)->getPtrTo();
if (highPtrTo->getMetatype() != TYPE_STRUCT) return false;
TypeStruct *highStruct = (TypeStruct *)highPtrTo;
if (highStruct->numDepend() == 0) return false;
vector<TypeField>::const_iterator iter = highStruct->beginField();
if ((*iter).offset != 0) return false;
Datatype *reqtype = ((TypePointer *)ct)->getPtrTo();
Datatype *curtype = (*iter).type;
if (reqtype->getMetatype() == TYPE_ARRAY)
reqtype = ((TypeArray *)reqtype)->getBase();
if (curtype->getMetatype() == TYPE_ARRAY)
curtype = ((TypeArray *)curtype)->getBase();
return (castStrategy->castStandard(reqtype, curtype, true, true) == (Datatype *)0);
}
bool ActionSetCasts::isOpIdentical(Datatype *ct1,Datatype *ct2)
{
while((ct1->getMetatype()==TYPE_PTR)&&(ct2->getMetatype()==TYPE_PTR)) {
ct1 = ((const TypePointer *)ct1)->getPtrTo();
ct2 = ((const TypePointer *)ct2)->getPtrTo();
}
while(ct1->getTypedef() != (Datatype *)0)
ct1 = ct1->getTypedef();
while(ct2->getTypedef() != (Datatype *)0)
ct2 = ct2->getTypedef();
return (ct1 == ct2);
}
int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy)
{
Datatype *outct,*ct,*tokenct;
Varnode *vn,*outvn;
PcodeOp *newop;
HighVariable *outHigh;
bool force=false;
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
outvn = op->getOut();
outHigh = outvn->getHigh();
if (outvn->isImplied()) {
if (outvn->isTypeLock()) {
PcodeOp *outOp = outvn->loneDescend();
if (outOp == (PcodeOp *)0 || outOp->code() != CPUI_RETURN) {
force = !isOpIdentical(outHigh->getType(), tokenct);
}
}
else if (outHigh->getType()->getMetatype() != TYPE_PTR) outvn->updateType(tokenct,false,false); else if (tokenct->getMetatype() == TYPE_PTR) { outct = ((TypePointer *)outHigh->getType())->getPtrTo();
type_metatype meta = outct->getMetatype();
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT))
outvn->updateType(tokenct,false,false); }
}
if (!force) {
outct = outHigh->getType(); ct = castStrategy->castStandard(outct,tokenct,false,true);
if (ct == (Datatype *)0) return 0;
}
vn = data.newUnique(op->getOut()->getSize());
vn->updateType(tokenct,false,false);
vn->setImplied();
newop = data.newOp(1,op->getAddr());
#ifdef CPUI_STATISTICS
data.getArch()->stats->countCast();
#endif
data.opSetOpcode(newop,CPUI_CAST);
data.opSetOutput(newop,op->getOut());
data.opSetInput(newop,vn,0);
data.opSetOutput(op,vn);
data.opInsertAfter(newop,op); return 1;
}
int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy)
{
Datatype *ct;
Varnode *vn,*vnout;
PcodeOp *newop;
ct = op->getOpcode()->getInputCast(op,slot,castStrategy); if (ct == (Datatype *)0) {
if (op->markExplicitUnsigned(slot)) return 1;
return 0;
}
vn = op->getIn(slot);
if (vn->isWritten() && (vn->getDef()->code() == CPUI_CAST)) {
if (vn->isImplied() && (vn->loneDescend() == op)) {
vn->updateType(ct,false,false);
if (vn->getType()==ct)
return 1;
}
}
else if (vn->isConstant()) {
vn->updateType(ct,false,false);
if (vn->getType() == ct)
return 1;
}
else if (testStructOffset0(vn, ct, castStrategy)) {
newop = data.newOp(2,op->getAddr());
vnout = data.newUniqueOut(vn->getSize(), newop);
vnout->updateType(ct,false,false);
vnout->setImplied();
data.opSetOpcode(newop, CPUI_PTRSUB);
data.opSetInput(newop,vn,0);
data.opSetInput(newop,data.newConstant(4, 0),1);
data.opSetInput(op,vnout,slot);
data.opInsertBefore(newop,op);
return 1;
}
newop = data.newOp(1,op->getAddr());
vnout = data.newUniqueOut(vn->getSize(),newop);
vnout->updateType(ct,false,false);
vnout->setImplied();
#ifdef CPUI_STATISTICS
data.getArch()->stats->countCast();
#endif
data.opSetOpcode(newop,CPUI_CAST);
data.opSetInput(newop,vn,0);
data.opSetInput(op,vnout,slot);
data.opInsertBefore(newop,op); return 1;
}
int4 ActionSetCasts::apply(Funcdata &data)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
data.startCastPhase();
CastStrategy *castStrategy = data.getArch()->print->getCastStrategy();
const BlockGraph &basicblocks( data.getBasicBlocks() );
for(int4 j=0;j<basicblocks.getSize();++j) {
BlockBasic *bb = (BlockBasic *)basicblocks.getBlock(j);
for(iter=bb->beginOp();iter!=bb->endOp();++iter) {
op = *iter;
if (op->notPrinted()) continue;
OpCode opc = op->code();
if (opc == CPUI_CAST) continue;
if (opc == CPUI_PTRADD) { int4 sz = (int4)op->getIn(2)->getOffset();
TypePointer *ct = (TypePointer *)op->getIn(0)->getHigh()->getType();
if ((ct->getMetatype() != TYPE_PTR)||(ct->getPtrTo()->getSize() != AddrSpace::addressToByteInt(sz, ct->getWordSize())))
data.opUndoPtradd(op,true);
}
else if (opc == CPUI_PTRSUB) { if (!op->getIn(0)->getHigh()->getType()->isPtrsubMatching(op->getIn(1)->getOffset())) {
if (op->getIn(1)->getOffset() == 0) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
}
else
data.opSetOpcode(op, CPUI_INT_ADD);
}
}
for(int4 i=0;i<op->numInput();++i) count += castInput(op,i,data,castStrategy);
if (opc == CPUI_LOAD) {
TypePointer *ptrtype = (TypePointer *)op->getIn(1)->getHigh()->getType();
int4 valsize = op->getOut()->getSize();
if ((ptrtype->getMetatype()!=TYPE_PTR)||
(ptrtype->getPtrTo()->getSize() != valsize))
data.warning("Load size is inaccurate",op->getAddr());
}
else if (opc == CPUI_STORE) {
TypePointer *ptrtype = (TypePointer *)op->getIn(1)->getHigh()->getType();
int4 valsize = op->getIn(2)->getSize();
if ((ptrtype->getMetatype()!=TYPE_PTR)||
(ptrtype->getPtrTo()->getSize() != valsize))
data.warning("Store size is inaccurate",op->getAddr());
}
Varnode *vn = op->getOut();
if (vn == (Varnode *)0) continue;
count += castOutput(op,data,castStrategy);
}
}
return 0; }
void ActionNameVars::lookForBadJumpTables(Funcdata &data)
{
int4 numfunc = data.numCalls();
ScopeLocal *localmap = data.getScopeLocal();
for(int4 i=0;i<numfunc;++i) {
FuncCallSpecs *fc = data.getCallSpecs(i);
if (fc->isBadJumpTable()) {
PcodeOp *op = fc->getOp();
Varnode *vn = op->getIn(0);
if (vn->isImplied()&&vn->isWritten()) { PcodeOp *castop = vn->getDef();
if (castop->code() == CPUI_CAST)
vn = castop->getIn(0);
}
if (vn->isFree()) continue;
Symbol *sym = vn->getHigh()->getSymbol();
if (sym == (Symbol *)0) continue;
if (sym->isNameLocked()) continue; if (sym->getScope() != localmap) continue; string newname = "UNRECOVERED_JUMPTABLE";
sym->getScope()->renameSymbol(sym,localmap->makeNameUnique(newname));
}
}
}
void ActionNameVars::makeRec(ProtoParameter *param,Varnode *vn,map<HighVariable *,OpRecommend> &recmap)
{
if (!param->isNameLocked()) return;
if (param->isNameUndefined()) return;
if (vn->getSize() != param->getSize()) return;
Datatype *ct = param->getType();
if (vn->isImplied()&&vn->isWritten()) { PcodeOp *castop = vn->getDef();
if (castop->code() == CPUI_CAST) {
vn = castop->getIn(0);
ct = (Datatype *)0; }
}
HighVariable *high = vn->getHigh();
if (high->isAddrTied()) return; if (param->getName().compare(0,6,"param_")==0) return;
map<HighVariable *,OpRecommend>::iterator iter = recmap.find(high);
if (iter != recmap.end()) { if (ct == (Datatype *)0) return; Datatype *oldtype = (*iter).second.ct;
if (oldtype != (Datatype *)0) {
if (oldtype->typeOrder(*ct) <= 0) return; }
(*iter).second.ct = ct;
(*iter).second.namerec = param->getName();
}
else {
OpRecommend oprec;
oprec.ct = ct;
oprec.namerec = param->getName();
recmap[high] = oprec;
}
}
void ActionNameVars::lookForFuncParamNames(Funcdata &data,const vector<Varnode *> &varlist)
{
int4 numfunc = data.numCalls();
if (numfunc == 0) return;
map<HighVariable *,OpRecommend> recmap;
ScopeLocal *localmap = data.getScopeLocal();
for(int4 i=0;i<numfunc;++i) { FuncCallSpecs *fc = data.getCallSpecs(i);
if (!fc->isInputLocked()) continue;
PcodeOp *op = fc->getOp();
int4 numparam = fc->numParams();
if (numparam >= op->numInput())
numparam = op->numInput()-1;
for(int4 j=0;j<numparam;++j) {
ProtoParameter *param = fc->getParam(j); Varnode *vn = op->getIn(j+1);
makeRec(param,vn,recmap);
}
}
if (recmap.empty()) return;
map<HighVariable *,OpRecommend>::iterator iter;
for(uint4 i=0;i<varlist.size();++i) { Varnode *vn = varlist[i];
if (vn->isFree()) continue;
if (vn->isInput()) continue; HighVariable *high = vn->getHigh();
if (high->getNumMergeClasses() > 1) continue; Symbol *sym = high->getSymbol();
if (sym == (Symbol *)0) continue;
if (!sym->isNameUndefined()) continue;
iter = recmap.find(high);
if (iter != recmap.end()) {
sym->getScope()->renameSymbol(sym,localmap->makeNameUnique((*iter).second.namerec));
}
}
}
void ActionNameVars::linkSpacebaseSymbol(Varnode *vn,Funcdata &data,vector<Varnode *> &namerec)
{
if (!vn->isConstant() && !vn->isInput()) return;
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->code() != CPUI_PTRSUB) continue;
Varnode *offVn = op->getIn(1);
Symbol *sym = data.linkSymbolReference(offVn);
if ((sym != (Symbol *)0) && sym->isNameUndefined())
namerec.push_back(offVn);
}
}
void ActionNameVars::linkSymbols(Funcdata &data,vector<Varnode *> &namerec)
{
const AddrSpaceManager *manage = data.getArch();
VarnodeLocSet::const_iterator iter,enditer;
AddrSpace *spc;
AddrSpace *constSpace = manage->getConstantSpace();
enditer = data.endLoc(constSpace);
for(iter=data.beginLoc(constSpace);iter!=enditer;++iter) {
Varnode *curvn = *iter;
if (curvn->getSymbolEntry() != (SymbolEntry *)0)
data.linkSymbol(curvn); else if (curvn->isSpacebase())
linkSpacebaseSymbol(curvn, data, namerec);
}
for(int4 i=0;i<manage->numSpaces();++i) { spc = manage->getSpace(i);
if (spc == (AddrSpace *)0) continue;
if (spc == constSpace) continue;
enditer = data.endLoc(spc);
for(iter=data.beginLoc(spc);iter!=enditer;++iter) {
Varnode *curvn = *iter;
if (curvn->isFree()) {
continue;
}
if (curvn->isSpacebase())
linkSpacebaseSymbol(curvn, data, namerec);
Varnode *vn = curvn->getHigh()->getNameRepresentative();
if (vn != curvn) continue; HighVariable *high = vn->getHigh();
if (!high->hasName()) continue;
Symbol *sym = data.linkSymbol(vn);
if (sym != (Symbol *)0) { if (sym->isNameUndefined() && high->getSymbolOffset() < 0)
namerec.push_back(vn); if (sym->isSizeTypeLocked()) {
if (vn->getSize() == sym->getType()->getSize())
sym->getScope()->overrideSizeLockType(sym,high->getType());
}
}
}
}
}
int4 ActionNameVars::apply(Funcdata &data)
{
vector<Varnode *> namerec;
linkSymbols(data, namerec);
data.getScopeLocal()->recoverNameRecommendationsForSymbols(); lookForBadJumpTables(data);
lookForFuncParamNames(data,namerec);
int4 base = 1;
for(uint4 i=0;i<namerec.size();++i) {
Varnode *vn = namerec[i];
Symbol *sym = vn->getHigh()->getSymbol();
if (sym->isNameUndefined()) {
Scope *scope = sym->getScope();
string newname = scope->buildDefaultName(sym, base, vn);
scope->renameSymbol(sym,newname);
}
}
data.getScopeLocal()->assignDefaultNames(base);
return 0;
}
int4 ActionMarkExplicit::baseExplicit(Varnode *vn,int4 maxref)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *def = vn->getDef();
if (def == (PcodeOp *)0) return -1;
if (def->isMarker()) return -1;
if (def->isCall()) {
if ((def->code() == CPUI_NEW)&&(def->numInput() == 1))
return -2; return -1;
}
HighVariable *high = vn->getHigh();
if ((high!=(HighVariable *)0)&&(high->numInstances()>1)) return -1; if (vn->isAddrTied()) { if (def->code() == CPUI_SUBPIECE) {
Varnode *vin = def->getIn(0);
if (vin->isAddrTied()) {
if (vn->overlap(*vin) == def->getIn(1)->getOffset())
return -1; }
}
bool shouldbeimplicit = true;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if ((op->code()!=CPUI_INT_ZEXT)&&(op->code()!=CPUI_PIECE)) {
shouldbeimplicit = false;
break;
}
Varnode *vnout = op->getOut();
if ((!vnout->isAddrTied())||(0!=vnout->contains(*vn))) {
shouldbeimplicit = false;
break;
}
}
if (!shouldbeimplicit) return -1;
}
else if (vn->isMapped()) {
return -1;
}
if (vn->hasNoDescend()) return -1;
if (def->code() == CPUI_PTRSUB) { Varnode *basevn = def->getIn(0);
if (basevn->isSpacebase()) { if (basevn->isConstant() || basevn->isInput())
maxref = 1000000; }
}
int4 desccount = 0;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->isMarker()) return -1;
desccount += 1;
if (desccount > maxref) return -1; }
return desccount;
}
int4 ActionMarkExplicit::multipleInteraction(vector<Varnode *> &multlist)
{
vector<Varnode *> purgelist;
for(int4 i=0;i<multlist.size();++i) {
Varnode *vn = multlist[i]; PcodeOp *op = vn->getDef();
OpCode opc = op->code();
if (op->isBoolOutput() || (opc == CPUI_INT_ZEXT) || (opc == CPUI_INT_SEXT) || (opc == CPUI_PTRADD)) {
int4 maxparam = 2;
if (op->numInput() < maxparam)
maxparam = op->numInput();
Varnode *topvn = (Varnode *)0;
for(int4 j=0;j<maxparam;++j) {
topvn = op->getIn(j);
if (topvn->isMark()) { OpCode topopc = CPUI_COPY;
if (topvn->isWritten()) {
if (topvn->getDef()->isBoolOutput())
continue; topopc = topvn->getDef()->code();
}
if (opc == CPUI_PTRADD) {
if (topopc == CPUI_PTRADD)
purgelist.push_back(topvn);
}
else
purgelist.push_back(topvn);
}
}
}
}
for(int4 i=0;i<purgelist.size();++i) {
Varnode *vn = purgelist[i];
vn->setExplicit();
vn->clearImplied();
vn->clearMark();
}
return purgelist.size();
}
ActionMarkExplicit::OpStackElement::OpStackElement(Varnode *v)
{
vn = v;
slot = 0;
slotback = 0;
if (v->isWritten()) {
OpCode opc = v->getDef()->code();
if (opc == CPUI_LOAD) {
slot = 1;
slotback = 2;
}
else if (opc == CPUI_PTRADD)
slotback = 1; else
slotback = v->getDef()->numInput();
}
}
void ActionMarkExplicit::processMultiplier(Varnode *vn,int4 max)
{
vector<OpStackElement> opstack;
Varnode *vncur;
int4 finalcount = 0;
opstack.push_back(vn);
do {
vncur = opstack.back().vn;
bool isaterm = vncur->isExplicit() || (!vncur->isWritten());
if (isaterm || (opstack.back().slotback<=opstack.back().slot)) { if (isaterm) {
if (!vncur->isSpacebase()) finalcount += 1;
}
if (finalcount > max) {
vn->setExplicit(); vn->clearImplied();
return;
}
opstack.pop_back();
}
else {
PcodeOp *op = vncur->getDef();
Varnode *newvn = op->getIn(opstack.back().slot++);
if (newvn->isMark()) { vn->setExplicit(); vn->clearImplied();
}
opstack.push_back(newvn);
}
} while(!opstack.empty());
}
void ActionMarkExplicit::checkNewToConstructor(Funcdata &data,Varnode *vn)
{ PcodeOp *op = vn->getDef();
BlockBasic *bb = op->getParent();
PcodeOp *firstuse = (PcodeOp *)0;
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *curop = *iter;
if (curop->getParent() != bb) continue;
if (firstuse == (PcodeOp *)0)
firstuse = curop;
else if (curop->getSeqNum().getOrder() < firstuse->getSeqNum().getOrder())
firstuse = curop;
else if (curop->code() == CPUI_CALLIND) {
Varnode *ptr = curop->getIn(0);
if (ptr->isWritten()) {
if (ptr->getDef() == firstuse)
firstuse = curop;
}
}
}
if (firstuse == (PcodeOp *)0) return;
if (!firstuse->isCall()) return;
if (firstuse->getOut() != (Varnode *)0) return;
if (firstuse->numInput() < 2) return; if (firstuse->getIn(1) != vn) return; data.opMarkSpecialPrint(firstuse); data.opMarkNonPrinting(op); }
int4 ActionMarkExplicit::apply(Funcdata &data)
{
VarnodeDefSet::const_iterator viter,enditer;
vector<Varnode *> multlist; int4 maxref;
maxref = data.getArch()->max_implied_ref;
enditer = data.beginDef(0); for(viter=data.beginDef();viter!=enditer;++viter) {
Varnode *vn = *viter;
int4 desccount = baseExplicit(vn,maxref);
if (desccount < 0) {
vn->setExplicit();
count += 1;
if (desccount < -1)
checkNewToConstructor(data,vn);
}
else if (desccount > 1) { vn->setMark();
multlist.push_back(vn);
}
}
count += multipleInteraction(multlist);
int4 maxdup = data.getArch()->max_term_duplication;
for(int4 i=0;i<multlist.size();++i) {
Varnode *vn = multlist[i];
if (vn->isMark()) processMultiplier(vn,maxdup);
}
for(int4 i=0;i<multlist.size();++i)
multlist[i]->clearMark();
return 0;
}
bool ActionMarkImplied::isPossibleAliasStep(Varnode *vn1,Varnode *vn2)
{
Varnode *var[2];
var[0] = vn1;
var[1] = vn2;
for(int4 i=0;i<2;++i) {
Varnode *vncur = var[i];
if (!vncur->isWritten()) continue;
PcodeOp *op = vncur->getDef();
OpCode opc = op->code();
if ((opc!=CPUI_INT_ADD)&&(opc!=CPUI_PTRSUB)&&(opc!=CPUI_PTRADD)&&(opc!=CPUI_INT_XOR)) continue;
if (var[1-i] != op->getIn(0)) continue;
if (op->getIn(1)->isConstant()) return false;
}
return true;
}
bool ActionMarkImplied::isPossibleAlias(Varnode *vn1,Varnode *vn2,int4 depth)
{
if (vn1 == vn2) return true; if ((!vn1->isWritten())||(!vn2->isWritten())) {
if (vn1->isConstant() && vn2->isConstant())
return (vn1->getOffset()==vn2->getOffset()); return isPossibleAliasStep(vn1,vn2);
}
if (!isPossibleAliasStep(vn1,vn2))
return false;
Varnode *cvn1,*cvn2;
PcodeOp *op1 = vn1->getDef();
PcodeOp *op2 = vn2->getDef();
OpCode opc1 = op1->code();
OpCode opc2 = op2->code();
int4 mult1 = 1;
int4 mult2 = 1;
if (opc1 == CPUI_PTRSUB)
opc1 = CPUI_INT_ADD;
else if (opc1 == CPUI_PTRADD) {
opc1 = CPUI_INT_ADD;
mult1 = (int4) op1->getIn(2)->getOffset();
}
if (opc2 == CPUI_PTRSUB)
opc2 = CPUI_INT_ADD;
else if (opc2 == CPUI_PTRADD) {
opc2 = CPUI_INT_ADD;
mult2 = (int4) op2->getIn(2)->getOffset();
}
if (opc1 != opc2) return true;
if (depth == 0) return true; depth -= 1;
switch(opc1) {
case CPUI_COPY:
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
case CPUI_INT_2COMP:
case CPUI_INT_NEGATE:
return isPossibleAlias(op1->getIn(0),op2->getIn(0),depth);
case CPUI_INT_ADD:
cvn1 = op1->getIn(1);
cvn2 = op2->getIn(1);
if (cvn1->isConstant() && cvn2->isConstant()) {
uintb val1 = mult1 * cvn1->getOffset();
uintb val2 = mult2 * cvn2->getOffset();
if (val1 == val2)
return isPossibleAlias(op1->getIn(0),op2->getIn(0),depth);
return !functionalEquality(op1->getIn(0),op2->getIn(0));
}
if (mult1 != mult2) return true;
if (functionalEquality(op1->getIn(0),op2->getIn(0)))
return isPossibleAlias(op1->getIn(1),op2->getIn(1),depth);
if (functionalEquality(op1->getIn(1),op2->getIn(1)))
return isPossibleAlias(op1->getIn(0),op2->getIn(0),depth);
if (functionalEquality(op1->getIn(0),op2->getIn(1)))
return isPossibleAlias(op1->getIn(1),op2->getIn(0),depth);
if (functionalEquality(op1->getIn(1),op2->getIn(0)))
return isPossibleAlias(op1->getIn(0),op2->getIn(1),depth);
break;
default:
break;
}
return true;
}
bool ActionMarkImplied::checkImpliedCover(Funcdata &data,Varnode *vn)
{
PcodeOp *op,*storeop,*callop;
Varnode *defvn;
int4 i;
op = vn->getDef();
if (op->code() == CPUI_LOAD) { list<PcodeOp *>::const_iterator oiter,iterend;
iterend = data.endOp(CPUI_STORE);
for(oiter=data.beginOp(CPUI_STORE);oiter!=iterend;++oiter) {
storeop = *oiter;
if (storeop->isDead()) continue;
if (vn->getCover()->contain(storeop,2)) {
if (storeop->getIn(0)->getOffset() == op->getIn(0)->getOffset()) {
if (isPossibleAlias(storeop->getIn(1),op->getIn(1),2)) return false;
}
}
}
}
if (op->isCall() || (op->code() == CPUI_LOAD)) { for(i=0;i<data.numCalls();++i) {
callop = data.getCallSpecs(i)->getOp();
if (vn->getCover()->contain(callop,2)) return false;
}
}
for(i=0;i<op->numInput();++i) {
defvn = op->getIn(i);
if (defvn->isConstant()) continue;
if (data.getMerge().inflateTest(defvn,vn->getHigh())) return false;
}
return true;
}
int4 ActionMarkImplied::apply(Funcdata &data)
{
VarnodeLocSet::const_iterator viter;
list<PcodeOp *>::const_iterator oiter;
Varnode *vn,*vncur,*defvn,*outvn;
PcodeOp *op;
vector<DescTreeElement> varstack;
for(viter=data.beginLoc();viter!=data.endLoc();++viter) {
vn = *viter;
if (vn->isFree()) continue;
if (vn->isExplicit()) continue;
if (vn->isImplied()) continue;
varstack.push_back(vn);
do {
vncur = varstack.back().vn;
if (varstack.back().desciter == vncur->endDescend()) {
count += 1; if (!checkImpliedCover(data,vncur)) vncur->setExplicit(); else {
vncur->setImplied(); op = vncur->getDef();
for(int4 i=0;i<op->numInput();++i) {
defvn = op->getIn(i);
if (!defvn->hasCover()) continue;
data.getMerge().inflate(defvn,vncur->getHigh());
}
}
varstack.pop_back();
}
else {
outvn = (*varstack.back().desciter++)->getOut();
if (outvn != (Varnode *)0) {
if ((!outvn->isExplicit())&&(!outvn->isImplied()))
varstack.push_back(outvn);
}
}
} while(!varstack.empty());
}
return 0;
}
int4 ActionUnreachable::apply(Funcdata &data)
{ if (data.removeUnreachableBlocks(true,false))
count += 1;
return 0;
}
int4 ActionDoNothing::apply(Funcdata &data)
{ int4 i;
const BlockGraph &graph(data.getBasicBlocks());
BlockBasic *bb;
for(i=0;i<graph.getSize();++i) {
bb = (BlockBasic *) graph.getBlock(i);
if (bb->isDoNothing()) {
if ((bb->sizeOut()==1)&&(bb->getOut(0)==bb)) { if (!bb->isDonothingLoop()) {
bb->setDonothingLoop();
data.warning("Do nothing block with infinite loop",bb->getStart());
}
}
else if (bb->unblockedMulti(0)) {
data.removeDoNothingBlock(bb);
count += 1;
return 0;
}
}
}
return 0;
}
int4 ActionRedundBranch::apply(Funcdata &data)
{
int4 i,j;
const BlockGraph &graph(data.getBasicBlocks());
BlockBasic *bb;
FlowBlock *bl;
for(i=0;i<graph.getSize();++i) {
bb = (BlockBasic *) graph.getBlock(i);
if (bb->sizeOut() == 0) continue;
bl = bb->getOut(0);
if (bb->sizeOut() == 1) {
if ((bl->sizeIn() == 1)&&(!bl->isEntryPoint())&&(!bb->isSwitchOut())) {
data.spliceBlockBasic(bb);
count += 1;
i = -1;
}
continue;
}
for(j=1;j<bb->sizeOut();++j) if (bb->getOut(j) != bl) break;
if (j!=bb->sizeOut()) continue;
data.removeBranch(bb,1); count += 1;
}
return 0; }
int4 ActionDeterminedBranch::apply(Funcdata &data)
{
int4 i;
const BlockGraph &graph(data.getBasicBlocks());
BlockBasic *bb;
PcodeOp *cbranch;
for(i=0;i<graph.getSize();++i) {
bb = (BlockBasic *) graph.getBlock(i);
cbranch = bb->lastOp();
if ((cbranch == (PcodeOp *)0)||(cbranch->code() != CPUI_CBRANCH)) continue;
if (!cbranch->getIn(1)->isConstant()) continue;
if (cbranch->isSplitting()) continue; uintb val = cbranch->getIn(1)->getOffset();
int4 num = ((val!=0)!=cbranch->isBooleanFlip()) ? 0 : 1;
data.removeBranch(bb,num);
count += 1;
}
return 0;
}
inline void ActionDeadCode::pushConsumed(uintb val,Varnode *vn,vector<Varnode *> &worklist)
{
uintb newval = (val | vn->getConsume())&calc_mask(vn->getSize());
if ((newval == vn->getConsume())&&vn->isConsumeVacuous()) return;
vn->setConsumeVacuous();
if (!vn->isConsumeList()) { vn->setConsumeList(); if (vn->isWritten())
worklist.push_back(vn); }
vn->setConsume(newval);
}
void ActionDeadCode::propagateConsumed(vector<Varnode *> &worklist)
{
Varnode *vn = worklist.back();
worklist.pop_back();
uintb outc = vn->getConsume();
vn->clearConsumeList();
PcodeOp *op = vn->getDef();
int4 sz;
uintb a,b;
switch(op->code()) {
case CPUI_INT_MULT:
b = coveringmask(outc);
if (op->getIn(1)->isConstant()) {
int4 leastSet = leastsigbit_set(op->getIn(1)->getOffset());
if (leastSet >= 0) {
a = calc_mask(vn->getSize()) >> leastSet;
a &= b;
}
else
a = 0;
}
else
a = b;
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(b,op->getIn(1),worklist);
break;
case CPUI_INT_ADD:
case CPUI_INT_SUB:
a = coveringmask(outc); pushConsumed(a,op->getIn(0),worklist);
pushConsumed(a,op->getIn(1),worklist);
break;
case CPUI_SUBPIECE:
sz = op->getIn(1)->getOffset();
if (sz >= sizeof(uintb)) a = 0; else
a = outc << (sz*8);
if ((a==0)&&(outc!=0)&&(op->getIn(0)->getSize() > sizeof(uintb))) {
a = ~((uintb)0);
a = a ^ (a >> 1); }
b = (outc == 0) ? 0 : ~((uintb)0);
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(b,op->getIn(1),worklist);
break;
case CPUI_PIECE:
sz = op->getIn(1)->getSize();
if (vn->getSize() > sizeof(uintb)) { if (sz >= sizeof(uintb)) {
a = ~((uintb)0); b = outc;
}
else {
a = (outc >> (sz*8)) ^ ( (~((uintb)0)) << 8*(sizeof(uintb)-sz));
b = outc ^ (a << (sz*8));
}
}
else {
a = outc >> (sz*8);
b = outc ^ (a << (sz*8));
}
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(b,op->getIn(1),worklist);
break;
case CPUI_INDIRECT:
pushConsumed(outc,op->getIn(0),worklist);
if (op->getIn(1)->getSpace()->getType()==IPTR_IOP) {
PcodeOp *indop = PcodeOp::getOpFromConst(op->getIn(1)->getAddr());
if (!indop->isDead()) {
if (indop->code() == CPUI_COPY) {
if (indop->getOut()->characterizeOverlap(*op->getOut())>0) {
pushConsumed(~((uintb)0),indop->getOut(),worklist); indop->setIndirectSource();
}
}
else
indop->setIndirectSource();
}
}
break;
case CPUI_COPY:
case CPUI_INT_NEGATE:
pushConsumed(outc,op->getIn(0),worklist);
break;
case CPUI_INT_XOR:
case CPUI_INT_OR:
pushConsumed(outc,op->getIn(0),worklist);
pushConsumed(outc,op->getIn(1),worklist);
break;
case CPUI_INT_AND:
if (op->getIn(1)->isConstant()) {
uintb val = op->getIn(1)->getOffset();
pushConsumed(outc&val,op->getIn(0),worklist);
pushConsumed(outc,op->getIn(1),worklist);
}
else {
pushConsumed(outc,op->getIn(0),worklist);
pushConsumed(outc,op->getIn(1),worklist);
}
break;
case CPUI_MULTIEQUAL:
for(int4 i=0;i<op->numInput();++i)
pushConsumed(outc,op->getIn(i),worklist);
break;
case CPUI_INT_ZEXT:
pushConsumed(outc,op->getIn(0),worklist);
break;
case CPUI_INT_SEXT:
b = calc_mask(op->getIn(0)->getSize());
a = outc & b;
if (outc > b)
a |= (b ^ (b>>1)); pushConsumed(a,op->getIn(0),worklist);
break;
case CPUI_INT_LEFT:
if (op->getIn(1)->isConstant()) {
sz = vn->getSize();
int4 sa = op->getIn(1)->getOffset();
if (sz > sizeof(uintb)) { if (sa >= 8*sizeof(uintb))
a = ~((uintb)0); else
a = (outc >> sa) ^ ( (~((uintb)0)) << (8*sizeof(uintb)-sa));
sz = 8*sz -sa;
if (sz < 8*sizeof(uintb)) {
uintb mask = ~((uintb)0);
mask <<= sz;
a = a & ~mask; }
}
else
a = outc >> sa; b = (outc == 0) ? 0 : ~((uintb)0);
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(b,op->getIn(1),worklist);
}
else {
a = (outc==0) ? 0 : ~((uintb)0);
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(a,op->getIn(1),worklist);
}
break;
case CPUI_INT_RIGHT:
if (op->getIn(1)->isConstant()) {
int4 sa = op->getIn(1)->getOffset();
if (sa >= 8*sizeof(uintb)) a = 0; else
a = outc << sa; b = (outc == 0) ? 0 : ~((uintb)0);
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(b,op->getIn(1),worklist);
}
else {
a = (outc==0) ? 0 : ~((uintb)0);
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(a,op->getIn(1),worklist);
}
break;
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if (outc==0)
a = 0;
else a = op->getIn(0)->getNZMask() | op->getIn(1)->getNZMask();
pushConsumed(a,op->getIn(0),worklist);
pushConsumed(a,op->getIn(1),worklist);
break;
case CPUI_INSERT:
a = 1;
a <<= (int4)op->getIn(3)->getOffset();
a -= 1; pushConsumed(a,op->getIn(1),worklist);
a <<= (int4)op->getIn(2)->getOffset();
pushConsumed(outc & ~a, op->getIn(0), worklist);
b = (outc == 0) ? 0 : ~((uintb)0);
pushConsumed(b,op->getIn(2), worklist);
pushConsumed(b,op->getIn(3), worklist);
break;
case CPUI_EXTRACT:
a = 1;
a <<= (int4)op->getIn(2)->getOffset();
a -= 1; a &= outc; a <<= (int4)op->getIn(1)->getOffset();
pushConsumed(a,op->getIn(0),worklist);
b = (outc == 0) ? 0 : ~((uintb)0);
pushConsumed(b,op->getIn(1), worklist);
pushConsumed(b,op->getIn(2), worklist);
break;
case CPUI_POPCOUNT:
a = 16 * op->getIn(0)->getSize() - 1; a &= outc; b = (a == 0) ? 0 : ~((uintb)0); pushConsumed(b,op->getIn(0), worklist);
break;
case CPUI_CALL:
case CPUI_CALLIND:
break; default:
a = (outc==0) ? 0 : ~((uintb)0); for(int4 i=0;i<op->numInput();++i)
pushConsumed(a,op->getIn(i),worklist);
break;
}
}
bool ActionDeadCode::neverConsumed(Varnode *vn,Funcdata &data)
{
if (vn->getSize() > sizeof(uintb)) return false; list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
iter = vn->beginDescend();
while(iter != vn->endDescend()) {
op = *iter++; int4 slot = op->getSlot(vn);
data.opSetInput(op,data.newConstant(vn->getSize(),0),slot);
}
op = vn->getDef();
if (op->isCall())
data.opUnsetOutput(op); else
data.opDestroy(op); return true;
}
void ActionDeadCode::markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist)
{
PcodeOp *callOp = fc->getOp();
pushConsumed(~((uintb)0),callOp->getIn(0),worklist); if (fc->isInputLocked() || fc->isInputActive()) { for(int4 i=1;i<callOp->numInput();++i)
pushConsumed(~((uintb)0),callOp->getIn(i),worklist); return;
}
for(int4 i=1;i<callOp->numInput();++i) {
Varnode *vn = callOp->getIn(i);
uintb consumeVal;
if (vn->isAutoLive())
consumeVal = ~((uintb)0);
else
consumeVal = minimalmask(vn->getNZMask());
int4 bytesConsumed = fc->getInputBytesConsumed(i);
if (bytesConsumed != 0)
consumeVal &= calc_mask(bytesConsumed);
pushConsumed(consumeVal,vn,worklist);
}
}
uintb ActionDeadCode::gatherConsumedReturn(Funcdata &data)
{
if (data.getFuncProto().isOutputLocked() || data.getActiveOutput() != (ParamActive *)0)
return ~((uintb)0);
list<PcodeOp *>::const_iterator iter,enditer;
enditer = data.endOp(CPUI_RETURN);
uintb consumeVal = 0;
for(iter=data.beginOp(CPUI_RETURN);iter!=enditer;++iter) {
PcodeOp *returnOp = *iter;
if (returnOp->isDead()) continue;
if (returnOp->numInput() > 1) {
Varnode *vn = returnOp->getIn(1);
consumeVal |= minimalmask(vn->getNZMask());
}
}
int4 val = data.getFuncProto().getReturnBytesConsumed();
if (val != 0) {
consumeVal &= calc_mask(val);
}
return consumeVal;
}
bool ActionDeadCode::isEventualConstant(Varnode *vn,int4 addCount,int4 loadCount)
{
if (vn->isConstant()) return true;
if (!vn->isWritten()) return false;
PcodeOp *op = vn->getDef();
while(op->code() == CPUI_COPY) {
vn = op->getIn(0);
if (vn->isConstant()) return true;
if (!vn->isWritten()) return false;
op = vn->getDef();
}
switch(op->code()) {
case CPUI_INT_ADD:
if (addCount > 0) return false;
if (!isEventualConstant(op->getIn(0),addCount+1,loadCount))
return false;
return isEventualConstant(op->getIn(1),addCount+1,loadCount);
case CPUI_LOAD:
if (loadCount > 0) return false;
return isEventualConstant(op->getIn(1),0,loadCount+1);
case CPUI_INT_LEFT:
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
case CPUI_INT_MULT:
if (!op->getIn(1)->isConstant())
return false;
return isEventualConstant(op->getIn(0),addCount,loadCount);
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
return isEventualConstant(op->getIn(0),addCount,loadCount);
default:
break;
}
return false;
}
bool ActionDeadCode::lastChanceLoad(Funcdata &data,vector<Varnode *> &worklist)
{
if (data.getHeritagePass() > 1) return false;
if (data.isJumptableRecoveryOn()) return false;
list<PcodeOp *>::const_iterator iter = data.beginOp(CPUI_LOAD);
list<PcodeOp *>::const_iterator enditer = data.endOp(CPUI_LOAD);
bool res = false;
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->isDead()) continue;
Varnode *vn = op->getOut();
if (vn->isConsumeVacuous()) continue;
if (isEventualConstant(op->getIn(1), 0, 0)) {
pushConsumed(~(uintb)0, vn, worklist);
vn->setAutoLiveHold();
res = true;
}
}
return res;
}
int4 ActionDeadCode::apply(Funcdata &data)
{
int4 i;
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
Varnode *vn;
uintb returnConsume;
vector<Varnode *> worklist;
VarnodeLocSet::const_iterator viter,endviter;
const AddrSpaceManager *manage = data.getArch();
AddrSpace *spc;
for(viter=data.beginLoc();viter!=data.endLoc();++viter) {
vn = *viter;
vn->clearConsumeList();
vn->clearConsumeVacuous();
vn->setConsume(0);
if (vn->isAddrForce()&&(!vn->isDirectWrite()))
vn->clearAddrForce();
}
for(i=0;i<manage->numSpaces();++i) {
spc = manage->getSpace(i);
if (spc == (AddrSpace *)0 || !spc->doesDeadcode()) continue;
if (data.deadRemovalAllowed(spc)) continue; viter = data.beginLoc(spc);
endviter = data.endLoc(spc);
while(viter != endviter) {
vn = *viter++;
pushConsumed(~((uintb)0),vn,worklist);
}
}
returnConsume = gatherConsumedReturn(data);
for(iter=data.beginOpAlive();iter!=data.endOpAlive();++iter) {
op = *iter;
op->clearIndirectSource();
if (op->isCall()) {
if (op->isCallWithoutSpec()) {
for(i=0;i<op->numInput();++i)
pushConsumed(~((uintb)0),op->getIn(i),worklist);
}
if (!op->isAssignment())
continue;
}
else if (!op->isAssignment()) {
OpCode opc = op->code();
if (opc == CPUI_RETURN) {
pushConsumed(~((uintb)0),op->getIn(0),worklist);
for(i=1;i<op->numInput();++i)
pushConsumed(returnConsume,op->getIn(i),worklist);
}
else if (opc == CPUI_BRANCHIND) {
JumpTable *jt = data.findJumpTable(op);
uintb mask;
if (jt != (JumpTable *)0)
mask = jt->getSwitchVarConsume();
else
mask = ~((uintb)0);
pushConsumed(mask,op->getIn(0),worklist);
}
else {
for(i=0;i<op->numInput();++i)
pushConsumed(~((uintb)0),op->getIn(i),worklist);
}
continue;
}
else {
for(i=0;i<op->numInput();++i) {
vn = op->getIn(i);
if (vn->isAutoLive())
pushConsumed(~((uintb)0),vn,worklist);
}
}
vn = op->getOut();
if (vn->isAutoLive())
pushConsumed(~((uintb)0),vn,worklist);
}
for(i=0;i<data.numCalls();++i)
markConsumedParameters(data.getCallSpecs(i),worklist);
while(!worklist.empty())
propagateConsumed(worklist);
if (lastChanceLoad(data, worklist)) {
while(!worklist.empty())
propagateConsumed(worklist);
}
for(i=0;i<manage->numSpaces();++i) {
spc = manage->getSpace(i);
if (spc == (AddrSpace *)0 || !spc->doesDeadcode()) continue;
if (!data.deadRemovalAllowed(spc)) continue; viter = data.beginLoc(spc);
endviter = data.endLoc(spc);
int4 changecount = 0;
while(viter != endviter) {
vn = *viter++; if (!vn->isWritten()) continue;
bool vacflag = vn->isConsumeVacuous();
vn->clearConsumeList();
vn->clearConsumeVacuous();
if (!vacflag) { op = vn->getDef();
changecount += 1;
if (op->isCall())
data.opUnsetOutput(op); else
data.opDestroy(op); }
else {
if (vn->getConsume()==0) {
if (neverConsumed(vn,data))
changecount += 1;
}
}
}
if (changecount != 0)
data.seenDeadcode(spc); }
#ifdef OPACTION_DEBUG
data.debugModPrint(getName()); #endif
data.clearDeadVarnodes();
data.clearDeadOps();
return 0;
}
void ActionConditionalConst::propagateConstant(Varnode *varVn,Varnode *constVn,FlowBlock *constBlock,Funcdata &data)
{
list<PcodeOp *>::const_iterator iter,enditer;
iter = varVn->beginDescend();
enditer = varVn->endDescend();
FlowBlock *rootBlock = (FlowBlock *)0;
if (varVn->isWritten())
rootBlock = varVn->getDef()->getParent();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter; if (op->isMarker()) continue; if (op->code() == CPUI_COPY) { PcodeOp *followOp = op->getOut()->loneDescend();
if (followOp == (PcodeOp *)0) continue;
if (followOp->isMarker()) continue;
if (followOp->code() == CPUI_COPY) continue;
}
FlowBlock *bl = op->getParent();
while(bl != (FlowBlock *)0) {
if (bl == rootBlock) break;
if (bl == constBlock) { int4 slot = op->getSlot(varVn);
data.opSetInput(op,data.newConstant(varVn->getSize(),constVn->getOffset()),slot); count += 1; break;
}
bl = bl->getImmedDom();
}
}
}
int4 ActionConditionalConst::apply(Funcdata &data)
{
const BlockGraph &blockGraph(data.getBasicBlocks());
for(int4 i=0;i<blockGraph.getSize();++i) {
FlowBlock *bl = blockGraph.getBlock(i);
PcodeOp *cBranch = bl->lastOp();
if (cBranch == (PcodeOp *)0 || cBranch->code() != CPUI_CBRANCH) continue;
Varnode *boolVn = cBranch->getIn(1);
if (!boolVn->isWritten()) continue;
PcodeOp *compOp = boolVn->getDef();
OpCode opc = compOp->code();
bool flipEdge = cBranch->isBooleanFlip();
if (opc == CPUI_BOOL_NEGATE) {
flipEdge = !flipEdge;
boolVn = compOp->getIn(0);
if (!boolVn->isWritten()) continue;
compOp = boolVn->getDef();
opc = compOp->code();
}
int4 constEdge; if (opc == CPUI_INT_EQUAL)
constEdge = 1;
else if (opc == CPUI_INT_NOTEQUAL)
constEdge = 0;
else
continue;
Varnode *varVn = compOp->getIn(0);
Varnode *constVn = compOp->getIn(1);
if (!constVn->isConstant()) {
if (!varVn->isConstant())
continue;
Varnode *tmp = constVn;
constVn = varVn;
varVn = tmp;
}
if (flipEdge)
constEdge = 1 - constEdge;
FlowBlock *constBlock = bl->getOut(constEdge);
if (!constBlock->restrictedByConditional(bl)) continue; propagateConstant(varVn,constVn,constBlock,data);
}
return 0;
}
int4 ActionSwitchNorm::apply(Funcdata &data)
{
for(int4 i=0;i<data.numJumpTables();++i) {
JumpTable *jt = data.getJumpTable(i);
if (!jt->isLabelled()) {
if (jt->recoverLabels(&data)) { data.getOverride().insertMultistageJump(jt->getOpAddress());
data.setRestartPending(true);
}
jt->foldInNormalization(&data);
count += 1;
}
if (jt->foldInGuards(&data)) {
data.getStructure().clear(); count += 1;
}
}
return 0;
}
int4 ActionNormalizeSetup::apply(Funcdata &data)
{
FuncProto &fp( data.getFuncProto() );
fp.clearInput();
fp.setModelLock(false); fp.setOutputLock(false);
return 0;
}
void ActionPrototypeTypes::extendInput(Funcdata &data,Varnode *invn,ProtoParameter *param,BlockBasic *topbl)
{
VarnodeData vdata;
OpCode res = data.getFuncProto().assumedInputExtension(invn->getAddr(),invn->getSize(),vdata);
if (res == CPUI_COPY) return; if (res == CPUI_PIECE) { if (param->getType()->getMetatype() == TYPE_INT)
res = CPUI_INT_SEXT;
else
res = CPUI_INT_ZEXT;
}
PcodeOp *op = data.newOp(1,topbl->getStart());
data.newVarnodeOut(vdata.size,vdata.getAddr(),op);
data.opSetOpcode(op,res);
data.opSetInput(op,invn,0);
data.opInsertBegin(op,topbl);
}
int4 ActionPrototypeTypes::apply(Funcdata &data)
{
list<PcodeOp *>::const_iterator iter,iterend;
ProtoModel *evalfp = data.getArch()->evalfp_current;
if (evalfp == (ProtoModel *)0)
evalfp = data.getArch()->defaultfp;
if ((!data.getFuncProto().isModelLocked())&&(!data.getFuncProto().hasMatchingModel(evalfp)))
data.getFuncProto().setModel(evalfp);
iterend = data.endOp(CPUI_RETURN);
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
PcodeOp *op = *iter;
if (op->isDead()) continue;
if (!op->getIn(0)->isConstant()) {
Varnode *vn = data.newConstant(op->getIn(0)->getSize(),0);
data.opSetInput(op,vn,0);
}
}
if (data.getFuncProto().isOutputLocked()) {
ProtoParameter *outparam = data.getFuncProto().getOutput();
if (outparam->getType()->getMetatype() != TYPE_VOID) {
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
PcodeOp *op = *iter;
if (op->isDead()) continue;
if (op->getHaltType() != 0) continue;
Varnode *vn = data.newVarnode(outparam->getSize(),outparam->getAddress());
data.opInsertInput(op,vn,op->numInput());
vn->updateType(outparam->getType(),true,true);
}
}
}
else
data.initActiveOutput();
AddrSpace *spc = data.getArch()->getDefaultCodeSpace();
if (spc->isTruncated()) {
AddrSpace *stackspc = data.getArch()->getStackSpace();
BlockBasic *topbl = (BlockBasic *)0;
if (data.getBasicBlocks().getSize() > 0)
topbl = (BlockBasic *)data.getBasicBlocks().getBlock(0);
if ((stackspc != (AddrSpace *)0)&&(topbl != (BlockBasic *)0)) {
for(int4 i=0;i<stackspc->numSpacebase();++i) {
const VarnodeData &fullReg( stackspc->getSpacebaseFull(i) );
const VarnodeData &truncReg( stackspc->getSpacebase(i) );
Varnode *invn = data.newVarnode( truncReg.size, truncReg.getAddr() );
invn = data.setInputVarnode(invn);
PcodeOp *extop = data.newOp(1,topbl->getStart());
data.newVarnodeOut(fullReg.size,fullReg.getAddr(),extop);
data.opSetOpcode(extop,CPUI_INT_ZEXT);
data.opSetInput(extop,invn,0);
data.opInsertBegin(extop,topbl);
}
}
}
if (data.getFuncProto().isInputLocked()) {
int4 ptr_size = spc->isTruncated() ? spc->getAddrSize() : 0; BlockBasic *topbl = (BlockBasic *)0;
if (data.getBasicBlocks().getSize() > 0)
topbl = (BlockBasic *)data.getBasicBlocks().getBlock(0);
int4 numparams = data.getFuncProto().numParams();
for(int4 i=0;i<numparams;++i) {
ProtoParameter *param = data.getFuncProto().getParam(i);
Varnode *vn = data.newVarnode( param->getSize(), param->getAddress());
vn = data.setInputVarnode(vn);
vn->setLockedInput();
if (topbl != (BlockBasic *)0)
extendInput(data,vn,param,topbl);
if (ptr_size > 0) {
Datatype *ct = param->getType();
if ((ct->getMetatype() == TYPE_PTR)&&(ct->getSize() == ptr_size))
vn->setPtrFlow();
}
}
}
return 0;
}
int4 ActionInputPrototype::apply(Funcdata &data)
{
vector<Varnode *> triallist;
ParamActive active(false);
Varnode *vn;
data.getScopeLocal()->clearUnlockedCategory(-1);
data.getFuncProto().clearUnlockedInput();
if (!data.getFuncProto().isInputLocked()) {
VarnodeDefSet::const_iterator iter,enditer;
iter = data.beginDef(Varnode::input);
enditer = data.endDef(Varnode::input);
while(iter != enditer) {
vn = *iter;
++iter;
if (data.getFuncProto().possibleInputParam(vn->getAddr(),vn->getSize())) {
int4 slot = active.getNumTrials();
active.registerTrial(vn->getAddr(),vn->getSize());
if (!vn->hasNoDescend())
active.getTrial(slot).markActive(); triallist.push_back(vn);
}
}
data.getFuncProto().resolveModel(&active);
data.getFuncProto().deriveInputMap(&active); for(int4 i=0;i<active.getNumTrials();++i) {
ParamTrial ¶mtrial(active.getTrial(i));
if (paramtrial.isUnref() && paramtrial.isUsed()) {
vn = data.newVarnode(paramtrial.getSize(),paramtrial.getAddress());
vn = data.setInputVarnode(vn);
int4 slot = triallist.size();
triallist.push_back(vn);
paramtrial.setSlot(slot + 1);
}
}
if (data.isHighOn())
data.getFuncProto().updateInputTypes(data,triallist,&active);
else
data.getFuncProto().updateInputNoTypes(data,triallist,&active);
}
data.clearDeadVarnodes();
#ifdef OPACTION_DEBUG
if ((flags&rule_debug)==0) return 0;
ostringstream s;
data.getScopeLocal()->printEntries(s);
data.getArch()->printDebug(s.str());
#endif
return 0;
}
int4 ActionOutputPrototype::apply(Funcdata &data)
{
ProtoParameter *outparam = data.getFuncProto().getOutput();
if ((!outparam->isTypeLocked())||outparam->isSizeTypeLocked()) {
PcodeOp *op = data.getFirstReturnOp();
vector<Varnode *> vnlist;
if (op != (PcodeOp *)0) {
for(int4 i=1;i<op->numInput();++i)
vnlist.push_back(op->getIn(i));
}
if (data.isHighOn())
data.getFuncProto().updateOutputTypes(vnlist);
else
data.getFuncProto().updateOutputNoTypes(vnlist,data.getArch()->types);
}
return 0;
}
int4 ActionUnjustifiedParams::apply(Funcdata &data)
{
VarnodeDefSet::const_iterator iter,enditer;
FuncProto &proto( data.getFuncProto() );
iter = data.beginDef(Varnode::input);
enditer = data.endDef(Varnode::input);
while(iter != enditer) {
Varnode *vn = *iter++;
VarnodeData vdata;
if (!proto.unjustifiedInputParam(vn->getAddr(),vn->getSize(),vdata)) continue;
bool newcontainer;
do {
newcontainer = false;
VarnodeDefSet::const_iterator begiter,iter2;
begiter = data.beginDef(Varnode::input);
iter2 = iter;
bool overlaps = false;
while(iter2 != begiter) {
--iter2;
vn = *iter2;
if (vn->getSpace() != vdata.space) continue;
uintb offset = vn->getOffset() + vn->getSize()-1; if ((offset >= vdata.offset)&&(vn->getOffset()<vdata.offset)) { overlaps = true;
uintb endpoint = vdata.offset + vdata.size;
vdata.offset = vn->getOffset();
vdata.size = endpoint - vdata.offset;
}
}
if (!overlaps) break; newcontainer = proto.unjustifiedInputParam(vdata.getAddr(),vdata.size,vdata);
} while(newcontainer);
data.adjustInputVarnodes(vdata.getAddr(),vdata.size);
iter = data.beginDef(Varnode::input,vdata.getAddr());
enditer = data.endDef(Varnode::input);
count += 1;
}
return 0;
}
int4 ActionHideShadow::apply(Funcdata &data)
{
VarnodeDefSet::const_iterator iter,enditer;
HighVariable *high;
enditer = data.endDef(Varnode::written);
for(iter=data.beginDef();iter!=enditer;++iter) {
high = (*iter)->getHigh();
if (high->isMark()) continue;
if (data.getMerge().hideShadows(high))
count += 1;
high->setMark();
}
for(iter=data.beginDef();iter!=enditer;++iter) {
high = (*iter)->getHigh();
high->clearMark();
}
return 0;
}
int4 ActionDynamicMapping::apply(Funcdata &data)
{
ScopeLocal *localmap = data.getScopeLocal();
list<SymbolEntry>::iterator iter,enditer;
iter = localmap->beginDynamic();
enditer = localmap->endDynamic();
DynamicHash dhash;
while(iter != enditer) {
SymbolEntry *entry = &(*iter);
++iter;
if (data.attemptDynamicMapping(entry,dhash))
count += 1;
}
return 0;
}
int4 ActionDynamicSymbols::apply(Funcdata &data)
{
ScopeLocal *localmap = data.getScopeLocal();
list<SymbolEntry>::iterator iter,enditer;
iter = localmap->beginDynamic();
enditer = localmap->endDynamic();
DynamicHash dhash;
while(iter != enditer) {
SymbolEntry *entry = &(*iter);
++iter;
if (data.attemptDynamicMappingLate(entry, dhash))
count += 1;
}
return 0;
}
int4 ActionPrototypeWarnings::apply(Funcdata &data)
{
vector<string> overridemessages;
data.getOverride().generateOverrideMessages(overridemessages,data.getArch());
for(int4 i=0;i<overridemessages.size();++i)
data.warningHeader(overridemessages[i]);
FuncProto &ourproto( data.getFuncProto() );
if (ourproto.hasInputErrors()) {
data.warningHeader("Cannot assign parameter locations for this function: Prototype may be inaccurate");
}
if (ourproto.hasOutputErrors()) {
data.warningHeader("Cannot assign location of return value for this function: Return value may be inaccurate");
}
if (ourproto.isUnknownModel() && (!ourproto.hasCustomStorage()) &&
(ourproto.isInputLocked() || ourproto.isOutputLocked())) {
data.warningHeader("Unknown calling convention yet parameter storage is locked");
}
int4 numcalls = data.numCalls();
for(int4 i=0;i<numcalls;++i) {
FuncCallSpecs *fc = data.getCallSpecs(i);
Funcdata *fd = fc->getFuncdata();
if (fc->hasInputErrors()) {
ostringstream s;
s << "Cannot assign parameter location for function ";
if (fd != (Funcdata *)0)
s << fd->getName();
else
s << "<indirect>";
s << ": Prototype may be inaccurate";
data.warning(s.str(),fc->getEntryAddress());
}
if (fc->hasOutputErrors()) {
ostringstream s;
s << "Cannot assign location of return value for function ";
if (fd != (Funcdata *)0)
s << fd->getName();
else
s << "<indirect>";
s << ": Return value may be inaccurate";
data.warning(s.str(),fc->getEntryAddress());
}
}
return 0;
}
#ifdef TYPEPROP_DEBUG
void ActionInferTypes::propagationDebug(Architecture *glb,Varnode *vn,const Datatype *newtype,PcodeOp *op,int4 slot,Varnode *ptralias)
{
ostringstream s;
vn->printRaw(s);
s << " : ";
newtype->printRaw(s);
if ((op == (PcodeOp *)0)&&(ptralias == (Varnode *)0)) {
s << " init";
}
else if (ptralias != (Varnode *)0) {
s << " alias ";
ptralias->printRaw(s);
}
else {
s << " from ";
op->printRaw(s);
s << " slot=" << dec << slot;
}
glb->printDebug(s.str());
}
#endif
void ActionInferTypes::buildLocaltypes(Funcdata &data)
{
Datatype *ct;
Varnode *vn;
VarnodeLocSet::const_iterator iter;
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
vn = *iter;
if (vn->isAnnotation()) continue;
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
bool needsBlock = false;
ct = vn->getLocalType(needsBlock);
if (needsBlock)
vn->setStopUpPropagation();
#ifdef TYPEPROP_DEBUG
propagationDebug(data.getArch(),vn,ct,(PcodeOp *)0,0,(Varnode *)0);
#endif
vn->setTempType(ct);
}
}
bool ActionInferTypes::writeBack(Funcdata &data)
{
bool change = false;
Datatype *ct;
Varnode *vn;
VarnodeLocSet::const_iterator iter;
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
vn = *iter;
if (vn->isAnnotation()) continue;
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
ct = vn->getTempType();
if (vn->updateType(ct,false,false))
change = true;
}
return change;
}
int4 ActionInferTypes::propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4 sz)
{
if (op->code() == CPUI_PTRADD) {
if (slot != 0) return 2;
Varnode *constvn = op->getIn(1);
uintb mult = op->getIn(2)->getOffset();
if (constvn->isConstant()) {
off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ;
return (off == 0) ? 0 : 1;
}
if (sz != 0 && (mult % sz) != 0)
return 2;
return 3;
}
if (op->code() == CPUI_PTRSUB) {
if (slot != 0) return 2;
off = op->getIn(1)->getOffset();
return (off == 0) ? 0 : 1;
}
if (op->code() == CPUI_INT_ADD) {
Varnode *othervn = op->getIn(1-slot);
if (!othervn->isConstant()) {
if (othervn->isWritten()) {
PcodeOp *multop = othervn->getDef();
if (multop->code() == CPUI_INT_MULT) {
Varnode *constvn = multop->getIn(1);
if (constvn->isConstant()) {
uintb mult = constvn->getOffset();
if (mult == calc_mask(constvn->getSize())) return 2; if (sz != 0 && (mult % sz) !=0)
return 2;
}
return 3;
}
}
if (sz == 1)
return 3;
return 2;
}
if (othervn->getTempType()->getMetatype() == TYPE_PTR) return 2;
off = othervn->getOffset();
return (off == 0) ? 0 : 1;
}
return 2;
}
Datatype *ActionInferTypes::propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,int4 inslot)
{
TypePointer *pointer = (TypePointer *)op->getIn(inslot)->getTempType(); uintb uoffset;
int4 command = propagateAddPointer(uoffset,op,inslot,pointer->getPtrTo()->getSize());
if (command == 2) return op->getOut()->getTempType(); TypePointer *parent = (TypePointer *)0;
uintb parentOff;
if (command != 3) {
uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize());
bool allowWrap = (op->code() != CPUI_PTRSUB);
do {
pointer = pointer->downChain(uoffset,parent,parentOff,allowWrap,*typegrp);
if (pointer == (TypePointer *)0)
break;
} while(uoffset != 0);
}
if (parent != (TypePointer *)0) {
Datatype *pt;
if (pointer == (TypePointer *)0)
pt = typegrp->getBase(1,TYPE_UNKNOWN); else
pt = pointer->getPtrTo(); pointer = typegrp->getTypePointerRel(parent, pt, parentOff);
}
if (pointer == (TypePointer *)0) {
if (command == 0)
return op->getIn(inslot)->getTempType();
return op->getOut()->getTempType();
}
if (op->getIn(inslot)->isSpacebase()) {
if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
pointer = typegrp->getTypePointer(pointer->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),pointer->getWordSize());
}
return pointer;
}
bool ActionInferTypes::propagateGoodEdge(PcodeOp *op,int4 inslot,int4 outslot,Varnode *invn)
{
if (inslot == outslot) return false; type_metatype metain = invn->getTempType()->getMetatype();
switch(op->code()) {
case CPUI_NEW:
if ((inslot != 0)||(outslot != -1)) return false;
break;
case CPUI_INDIRECT:
if (op->isIndirectCreation()) return false;
if ((inslot==1)||(outslot==1)) return false;
if ((inslot!=-1)&&(outslot!=-1)) return false; break;
case CPUI_COPY:
if ((inslot!=-1)&&(outslot!=-1)) return false; break;
case CPUI_MULTIEQUAL:
if ((inslot!=-1)&&(outslot!=-1)) return false; break;
case CPUI_INT_SLESS:
case CPUI_INT_SLESSEQUAL:
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
if ((inslot==-1)||(outslot==-1)) return false; break;
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if ((inslot==-1)||(outslot==-1)) return false; break;
case CPUI_LOAD:
case CPUI_STORE:
if ((inslot==0)||(outslot==0)) return false; if (invn->isSpacebase()) return false;
break;
case CPUI_PTRADD:
if ((inslot==2)||(outslot==2)) return false; case CPUI_PTRSUB:
if ((inslot!=-1)&&(outslot!=-1)) return false; if (metain != TYPE_PTR) return false;
break;
case CPUI_INT_ADD:
if (metain != TYPE_PTR) {
if ((metain == TYPE_INT)||(metain == TYPE_UINT)) {
if ((outslot==1) && (op->getIn(1)->isConstant()))
return true;
}
return false;
}
if ((inslot!=-1)&&(outslot!=-1)) return false; break;
case CPUI_SEGMENTOP:
if ((inslot==0)||(inslot==1)) return false;
if ((outslot==0)||(outslot==1)) return false;
if (invn->isSpacebase()) return false;
if (metain != TYPE_PTR) return false;
break;
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
if (!invn->getTempType()->isPowerOfTwo()) return false; break;
default:
return false;
}
return true;
}
bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 inslot,int4 outslot)
{
Varnode *invn,*outvn;
Datatype *newtype;
if (outslot < 0)
outvn = op->getOut();
else {
outvn = op->getIn(outslot);
if (outvn->stopsUpPropagation())
return false;
}
if (outvn->isAnnotation()) return false;
if (outvn->isTypeLock()) return false; invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
if (!propagateGoodEdge(op,inslot,outslot,invn))
return false;
Datatype *alttype = invn->getTempType();
if (alttype->getMetatype() == TYPE_BOOL) { if (outvn->getNZMask() > 1) return false;
}
switch(op->code()) {
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if (invn->isSpacebase()) {
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
newtype = typegrp->getTypePointer(alttype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else if (alttype->isPointerRel() && !outvn->isConstant()) {
TypePointerRel *relPtr = (TypePointerRel *)alttype;
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getPointerOffset() >= 0) {
newtype = typegrp->getTypePointer(relPtr->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),relPtr->getWordSize());
}
else
newtype = alttype;
}
else
newtype = alttype;
break;
case CPUI_INDIRECT:
case CPUI_COPY:
case CPUI_MULTIEQUAL:
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
if (invn->isSpacebase()) {
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
newtype = typegrp->getTypePointer(alttype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
break;
case CPUI_INT_SLESS:
case CPUI_INT_SLESSEQUAL:
if (alttype->getMetatype() != TYPE_INT) return false; newtype = alttype;
break;
case CPUI_NEW:
{
Varnode *vn0 = op->getIn(0);
if (!vn0->isWritten()) return false; if (vn0->getDef()->code() != CPUI_CPOOLREF) return false;
newtype = alttype; }
break;
case CPUI_SEGMENTOP:
{
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
Datatype *btype = ((TypePointer *)alttype)->getPtrTo();
newtype = typegrp->getTypePointer(outvn->getSize(),btype,spc->getWordSize());
}
break;
case CPUI_LOAD:
if (inslot == -1) { AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
newtype = typegrp->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength()) newtype = outvn->getTempType();
}
else
newtype = outvn->getTempType(); break;
case CPUI_STORE:
if (inslot==2) { AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
newtype = typegrp->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength())
newtype = outvn->getTempType();
}
else
newtype = outvn->getTempType(); break;
case CPUI_PTRADD:
case CPUI_PTRSUB:
if (inslot == -1) newtype = op->getIn(outslot)->getTempType(); else
newtype = propagateAddIn2Out(typegrp,op,inslot);
break;
case CPUI_INT_ADD:
if (outvn->isConstant() && (alttype->getMetatype() != TYPE_PTR))
newtype = alttype;
else if (inslot == -1) newtype = op->getIn(outslot)->getTempType(); else
newtype = propagateAddIn2Out(typegrp,op,inslot);
break;
default:
return false; }
if (0>newtype->typeOrder(*outvn->getTempType())) {
#ifdef TYPEPROP_DEBUG
propagationDebug(typegrp->getArch(),outvn,newtype,op,inslot,(Varnode *)0);
#endif
outvn->setTempType(newtype);
return !outvn->isMark();
}
return false;
}
PropagationState::PropagationState(Varnode *v)
{
vn = v;
iter = vn->beginDescend();
if (iter != vn->endDescend()) {
op = *iter++;
if (op->getOut() != (Varnode *)0)
slot = -1;
else
slot = 0;
inslot = op->getSlot(vn);
}
else {
op = vn->getDef();
inslot = -1;
slot = 0;
}
}
void PropagationState::step(void)
{
slot += 1;
if (slot < op->numInput())
return;
if (iter != vn->endDescend()) {
op = *iter++;
if (op->getOut() != (Varnode *)0)
slot = -1;
else
slot = 0;
inslot = op->getSlot(vn);
return;
}
if (inslot == -1)
op = (PcodeOp *)0;
else
op = vn->getDef();
inslot = -1;
slot = 0;
}
void ActionInferTypes::propagateOneType(TypeFactory *typegrp,Varnode *vn)
{
PropagationState *ptr;
vector<PropagationState> state;
state.emplace_back(vn);
vn->setMark();
while(!state.empty()) {
ptr = &state.back();
if (!ptr->valid()) { ptr->vn->clearMark();
state.pop_back();
}
else {
if (propagateTypeEdge(typegrp,ptr->op,ptr->inslot,ptr->slot)) {
vn = (ptr->slot==-1) ? ptr->op->getOut() : ptr->op->getIn(ptr->slot);
ptr->step(); state.emplace_back(vn);
vn->setMark();
}
else
ptr->step();
}
}
}
void ActionInferTypes::propagateRef(Funcdata &data,Varnode *vn,const Address &addr)
{
Datatype *ct = vn->getTempType();
if (ct->getMetatype() != TYPE_PTR) return;
ct = ((TypePointer *)ct)->getPtrTo();
if (ct->getMetatype() == TYPE_SPACEBASE) return;
if (ct->getMetatype() == TYPE_UNKNOWN) return; VarnodeLocSet::const_iterator iter,enditer;
uintb off = addr.getOffset();
TypeFactory *typegrp = data.getArch()->types;
Address endaddr = addr + ct->getSize();
if (endaddr.getOffset() < off) enditer = data.endLoc(addr.getSpace()); else
enditer = data.endLoc(endaddr);
iter = data.beginLoc(addr);
uintb lastoff = 0;
int4 lastsize = ct->getSize();
Datatype *lastct = ct;
while(iter != enditer) {
Varnode *curvn = *iter;
++iter;
if (curvn->isAnnotation()) continue;
if ((!curvn->isWritten())&&curvn->hasNoDescend()) continue;
uintb curoff = curvn->getOffset() - off;
int4 cursize = curvn->getSize();
if (curoff + cursize > ct->getSize()) continue;
if ((cursize!=lastsize)||(curoff!=lastoff)) {
lastoff = curoff;
lastsize = cursize;
Datatype *cur = ct;
do {
lastct = cur;
cur = cur->getSubType(curoff,&curoff);
} while(cur != (Datatype *)0);
}
if (lastct->getSize() != cursize) continue;
if (0>lastct->typeOrder(*curvn->getTempType())) {
#ifdef TYPEPROP_DEBUG
propagationDebug(data.getArch(),curvn,lastct,(PcodeOp *)0,0,vn);
#endif
curvn->setTempType(lastct);
propagateOneType(typegrp,curvn); }
}
}
void ActionInferTypes::propagateSpacebaseRef(Funcdata &data,Varnode *spcvn)
{
Datatype *spctype = spcvn->getType(); if (spctype->getMetatype() != TYPE_PTR) return;
spctype = ((TypePointer *)spctype)->getPtrTo();
if (spctype->getMetatype() != TYPE_SPACEBASE) return;
TypeSpacebase *sbtype = (TypeSpacebase *)spctype;
list<PcodeOp *>::const_iterator iter;
Address addr;
for(iter=spcvn->beginDescend();iter!=spcvn->endDescend();++iter) {
PcodeOp *op = *iter;
Varnode *vn;
switch(op->code()) {
case CPUI_COPY:
vn = op->getIn(0);
addr = sbtype->getAddress(0,vn->getSize(),op->getAddr());
propagateRef(data,op->getOut(),addr);
break;
case CPUI_INT_ADD:
case CPUI_PTRSUB:
vn = op->getIn(1);
if (vn->isConstant()) {
addr = sbtype->getAddress(vn->getOffset(),vn->getSize(),op->getAddr());
propagateRef(data,op->getOut(),addr);
}
break;
case CPUI_PTRADD:
vn = op->getIn(1);
if (vn->isConstant()) {
uintb off = vn->getOffset() * op->getIn(2)->getOffset();
addr = sbtype->getAddress(off,vn->getSize(),op->getAddr());
propagateRef(data,op->getOut(),addr);
}
break;
default:
break;
}
}
}
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;
}
void ActionInferTypes::propagateAcrossReturns(Funcdata &data)
{
if (data.getFuncProto().isOutputLocked()) return;
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; if (vn->getTempType() == ct) continue; vn->setTempType(ct);
#ifdef TYPEPROP_DEBUG
propagationDebug(typegrp->getArch(),vn,ct,op,1,(Varnode *)0);
#endif
propagateOneType(typegrp, vn);
}
}
}
int4 ActionInferTypes::apply(Funcdata &data)
{
if (!data.isTypeRecoveryOn()) return 0;
TypeFactory *typegrp = data.getArch()->types;
Varnode *vn;
VarnodeLocSet::const_iterator iter;
#ifdef TYPEPROP_DEBUG
ostringstream s;
s << "Type propagation pass - " << dec << localcount;
data.getArch()->printDebug(s.str());
#endif
if (localcount >= 7) { if (localcount == 7) {
data.warningHeader("Type propagation algorithm not settling");
localcount += 1;
}
return 0;
}
data.getScopeLocal()->applyTypeRecommendations();
buildLocaltypes(data); for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
vn = *iter;
if (vn->isAnnotation()) continue;
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)
propagateSpacebaseRef(data,spcvn);
if (writeBack(data)) {
localcount += 1;
}
return 0;
}
void TermOrder::collect(void)
{
Varnode *curvn;
PcodeOp *curop;
PcodeOp *subop,*multop;
vector<PcodeOp *> opstack; vector<PcodeOp *> multstack;
opstack.push_back(root);
multstack.push_back((PcodeOp *)0);
while(!opstack.empty()) {
curop = opstack.back();
multop = multstack.back();
opstack.pop_back();
multstack.pop_back();
for(int4 i=0;i<curop->numInput();++i) {
curvn = curop->getIn(i); if (!curvn->isWritten()) { terms.push_back(PcodeOpEdge(curop,i,multop));
continue;
}
if (curvn->loneDescend() == (PcodeOp *)0) { terms.push_back(PcodeOpEdge(curop,i,multop));
continue;
}
subop = curvn->getDef();
if (subop->code() != CPUI_INT_ADD) { if ((subop->code()==CPUI_INT_MULT)&&(subop->getIn(1)->isConstant())) {
PcodeOp *addop = subop->getIn(0)->getDef();
if ((addop!=(PcodeOp *)0)&&(addop->code()==CPUI_INT_ADD)) {
if (addop->getOut()->loneDescend()!=(PcodeOp *)0) {
opstack.push_back(addop);
multstack.push_back(subop);
continue;
}
}
}
terms.push_back(PcodeOpEdge(curop,i,multop));
continue;
}
opstack.push_back(subop);
multstack.push_back(multop);
}
}
}
void TermOrder::sortTerms(void)
{
for(vector<PcodeOpEdge>::iterator iter=terms.begin();iter!=terms.end();++iter)
sorter.push_back( &(*iter) );
sort(sorter.begin(),sorter.end(),additiveCompare);
}
void ActionDatabase::buildDefaultGroups(void)
{
if (isDefaultGroups) return;
groupmap.clear();
const char *members[] = { "base", "protorecovery", "protorecovery_a", "deindirect", "localrecovery",
"deadcode", "typerecovery", "stackptrflow",
"blockrecovery", "stackvars", "deadcontrolflow", "switchnorm",
"cleanup", "merge", "dynamic", "casts", "analysis",
"fixateglobals", "fixateproto",
"segment", "returnsplit", "nodejoin", "doubleload", "doubleprecis",
"unreachable", "subvar", "floatprecision",
"conditionalexe", "" };
setGroup("decompile",members);
const char *jumptab[] = { "base", "noproto", "localrecovery", "deadcode", "stackptrflow",
"stackvars", "analysis", "segment", "subvar", "conditionalexe", "" };
setGroup("jumptable",jumptab);
const char *normali[] = { "base", "protorecovery", "protorecovery_b", "deindirect", "localrecovery",
"deadcode", "stackptrflow", "normalanalysis",
"stackvars", "deadcontrolflow", "analysis", "fixateproto", "nodejoin",
"unreachable", "subvar", "floatprecision", "normalizebranches",
"conditionalexe", "" };
setGroup("normalize",normali);
const char *paramid[] = { "base", "protorecovery", "protorecovery_b", "deindirect", "localrecovery",
"deadcode", "typerecovery", "stackptrflow", "siganalysis",
"stackvars", "deadcontrolflow", "analysis", "fixateproto",
"unreachable", "subvar", "floatprecision",
"conditionalexe", "" };
setGroup("paramid",paramid);
const char *regmemb[] = { "base", "analysis", "subvar", "" };
setGroup("register",regmemb);
const char *firstmem[] = { "base", "" };
setGroup("firstpass",firstmem);
isDefaultGroups = true;
}
void ActionDatabase::universalAction(Architecture *conf)
{
vector<Rule *>::iterator iter;
ActionGroup *act;
ActionGroup *actmainloop;
ActionGroup *actfullloop;
ActionPool *actprop,*actprop2;
ActionPool *actcleanup;
ActionGroup *actstackstall;
AddrSpace *stackspace = conf->getStackSpace();
act = new ActionRestartGroup(Action::rule_onceperfunc,"universal",1);
registerAction(universalname,act);
act->addAction( new ActionStart("base"));
act->addAction( new ActionConstbase("base"));
act->addAction( new ActionNormalizeSetup("normalanalysis"));
act->addAction( new ActionDefaultParams("base"));
act->addAction( new ActionExtraPopSetup("base",stackspace) );
act->addAction( new ActionPrototypeTypes("protorecovery"));
act->addAction( new ActionFuncLink("protorecovery") );
act->addAction( new ActionFuncLinkOutOnly("noproto") );
{
actfullloop = new ActionGroup(Action::rule_repeatapply,"fullloop");
{
actmainloop = new ActionGroup(Action::rule_repeatapply,"mainloop");
actmainloop->addAction( new ActionUnreachable("base") );
actmainloop->addAction( new ActionVarnodeProps("base") );
actmainloop->addAction( new ActionHeritage("base") );
actmainloop->addAction( new ActionParamDouble("protorecovery") );
actmainloop->addAction( new ActionSegmentize("base"));
actmainloop->addAction( new ActionForceGoto("blockrecovery") );
actmainloop->addAction( new ActionDirectWrite("protorecovery_a", true) );
actmainloop->addAction( new ActionDirectWrite("protorecovery_b", false) );
actmainloop->addAction( new ActionActiveParam("protorecovery") );
actmainloop->addAction( new ActionReturnRecovery("protorecovery") );
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); actmainloop->addAction( new ActionDeadCode("deadcode") );
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
actmainloop->addAction( new ActionSpacebase("base") ); actmainloop->addAction( new ActionNonzeroMask("analysis") );
actmainloop->addAction( new ActionInferTypes("typerecovery") );
actstackstall = new ActionGroup(Action::rule_repeatapply,"stackstall");
{
actprop = new ActionPool(Action::rule_repeatapply,"oppool1");
actprop->addRule( new RuleEarlyRemoval("deadcode"));
actprop->addRule( new RuleTermOrder("analysis"));
actprop->addRule( new RuleSelectCse("analysis"));
actprop->addRule( new RuleCollectTerms("analysis"));
actprop->addRule( new RulePullsubMulti("analysis"));
actprop->addRule( new RulePullsubIndirect("analysis"));
actprop->addRule( new RulePushMulti("nodejoin"));
actprop->addRule( new RuleSborrow("analysis") );
actprop->addRule( new RuleIntLessEqual("analysis") );
actprop->addRule( new RuleTrivialArith("analysis") );
actprop->addRule( new RuleTrivialBool("analysis") );
actprop->addRule( new RuleTrivialShift("analysis") );
actprop->addRule( new RuleSignShift("analysis") );
actprop->addRule( new RuleTestSign("analysis") );
actprop->addRule( new RuleIdentityEl("analysis") );
actprop->addRule( new RuleOrMask("analysis") );
actprop->addRule( new RuleAndMask("analysis") );
actprop->addRule( new RuleOrConsume("analysis") );
actprop->addRule( new RuleOrCollapse("analysis") );
actprop->addRule( new RuleAndOrLump("analysis") );
actprop->addRule( new RuleShiftBitops("analysis") );
actprop->addRule( new RuleRightShiftAnd("analysis") );
actprop->addRule( new RuleNotDistribute("analysis") );
actprop->addRule( new RuleHighOrderAnd("analysis") );
actprop->addRule( new RuleAndDistribute("analysis") );
actprop->addRule( new RuleAndCommute("analysis") );
actprop->addRule( new RuleAndPiece("analysis") );
actprop->addRule( new RuleAndCompare("analysis") );
actprop->addRule( new RuleDoubleSub("analysis") );
actprop->addRule( new RuleDoubleShift("analysis") );
actprop->addRule( new RuleDoubleArithShift("analysis") );
actprop->addRule( new RuleConcatShift("analysis") );
actprop->addRule( new RuleLeftRight("analysis") );
actprop->addRule( new RuleShiftCompare("analysis") );
actprop->addRule( new RuleShift2Mult("analysis") );
actprop->addRule( new RuleShiftPiece("analysis") );
actprop->addRule( new RuleMultiCollapse("analysis") );
actprop->addRule( new RuleIndirectCollapse("analysis") );
actprop->addRule( new Rule2Comp2Mult("analysis") );
actprop->addRule( new RuleSub2Add("analysis") );
actprop->addRule( new RuleCarryElim("analysis") );
actprop->addRule( new RuleBxor2NotEqual("analysis") );
actprop->addRule( new RuleLess2Zero("analysis") );
actprop->addRule( new RuleLessEqual2Zero("analysis") );
actprop->addRule( new RuleSLess2Zero("analysis") );
actprop->addRule( new RuleEqual2Zero("analysis") );
actprop->addRule( new RuleEqual2Constant("analysis") );
actprop->addRule( new RuleThreeWayCompare("analysis") );
actprop->addRule( new RuleXorCollapse("analysis") );
actprop->addRule( new RuleAddMultCollapse("analysis") );
actprop->addRule( new RuleCollapseConstants("analysis") );
actprop->addRule( new RuleTransformCpool("analysis") );
actprop->addRule( new RulePropagateCopy("analysis") );
actprop->addRule( new RuleZextEliminate("analysis") );
actprop->addRule( new RuleSlessToLess("analysis") );
actprop->addRule( new RuleZextSless("analysis") );
actprop->addRule( new RuleBitUndistribute("analysis") );
actprop->addRule( new RuleBoolZext("analysis") );
actprop->addRule( new RuleBooleanNegate("analysis") );
actprop->addRule( new RuleLogic2Bool("analysis") );
actprop->addRule( new RuleSubExtComm("analysis") );
actprop->addRule( new RuleSubCommute("analysis") );
actprop->addRule( new RuleConcatCommute("analysis") );
actprop->addRule( new RuleConcatZext("analysis") );
actprop->addRule( new RuleZextCommute("analysis") );
actprop->addRule( new RuleZextShiftZext("analysis") );
actprop->addRule( new RuleShiftAnd("analysis") );
actprop->addRule( new RuleConcatZero("analysis") );
actprop->addRule( new RuleConcatLeftShift("analysis") );
actprop->addRule( new RuleEmbed("analysis") );
actprop->addRule( new RuleSubZext("analysis") );
actprop->addRule( new RuleSubCancel("analysis") );
actprop->addRule( new RuleShiftSub("analysis") );
actprop->addRule( new RuleHumptyDumpty("analysis") );
actprop->addRule( new RuleDumptyHump("analysis") );
actprop->addRule( new RuleHumptyOr("analysis") );
actprop->addRule( new RuleNegateIdentity("analysis") );
actprop->addRule( new RuleSubNormal("analysis") );
actprop->addRule( new RulePositiveDiv("analysis") );
actprop->addRule( new RuleDivTermAdd("analysis") );
actprop->addRule( new RuleDivTermAdd2("analysis") );
actprop->addRule( new RuleDivOpt("analysis") );
actprop->addRule( new RuleSignForm("analysis") );
actprop->addRule( new RuleSignDiv2("analysis") );
actprop->addRule( new RuleSignNearMult("analysis") );
actprop->addRule( new RuleModOpt("analysis") );
actprop->addRule( new RuleSwitchSingle("analysis") );
actprop->addRule( new RuleCondNegate("analysis") );
actprop->addRule( new RuleBoolNegate("analysis") );
actprop->addRule( new RuleLessEqual("analysis") );
actprop->addRule( new RuleLessNotEqual("analysis") );
actprop->addRule( new RuleLessOne("analysis") );
actprop->addRule( new RuleRangeMeld("analysis") );
actprop->addRule( new RuleFloatRange("analysis") );
actprop->addRule( new RulePiece2Zext("analysis") );
actprop->addRule( new RulePiece2Sext("analysis") );
actprop->addRule( new RulePopcountBoolXor("analysis") );
actprop->addRule( new RuleXorSwap("analysis") );
actprop->addRule( new RuleSubvarAnd("subvar") );
actprop->addRule( new RuleSubvarSubpiece("subvar") );
actprop->addRule( new RuleSplitFlow("subvar") );
actprop->addRule( new RulePtrFlow("subvar",conf) );
actprop->addRule( new RuleSubvarCompZero("subvar") );
actprop->addRule( new RuleSubvarShift("subvar") );
actprop->addRule( new RuleSubvarZext("subvar") );
actprop->addRule( new RuleSubvarSext("subvar") );
actprop->addRule( new RuleNegateNegate("analysis") );
actprop->addRule( new RuleConditionalMove("conditionalexe") );
actprop->addRule( new RuleOrPredicate("conditionalexe") );
actprop->addRule( new RuleFuncPtrEncoding("analysis") );
actprop->addRule( new RuleSubfloatConvert("floatprecision") );
actprop->addRule( new RuleFloatCast("floatprecision") );
actprop->addRule( new RuleIgnoreNan("floatprecision") );
actprop->addRule( new RulePtraddUndo("typerecovery") );
actprop->addRule( new RulePtrsubUndo("typerecovery") );
actprop->addRule( new RuleSegment("segment") );
actprop->addRule( new RulePiecePathology("protorecovery") );
actprop->addRule( new RuleDoubleLoad("doubleload") );
actprop->addRule( new RuleDoubleIn("doubleprecis") );
for(iter=conf->extra_pool_rules.begin();iter!=conf->extra_pool_rules.end();++iter)
actprop->addRule( *iter ); conf->extra_pool_rules.clear(); }
actstackstall->addAction( actprop );
actstackstall->addAction( new ActionLaneDivide("base") );
actstackstall->addAction( new ActionMultiCse("analysis") );
actstackstall->addAction( new ActionShadowVar("analysis") );
actstackstall->addAction( new ActionDeindirect("deindirect") );
actstackstall->addAction( new ActionStackPtrFlow("stackptrflow",stackspace));
actmainloop->addAction( actstackstall );
actmainloop->addAction( new ActionRedundBranch("deadcontrolflow") ); actmainloop->addAction( new ActionBlockStructure("blockrecovery"));
actmainloop->addAction( new ActionConstantPtr("typerecovery") );
{
actprop2 = new ActionPool(Action::rule_repeatapply,"oppool2");
actprop2->addRule( new RulePushPtr("typerecovery") );
actprop2->addRule( new RuleStructOffset0("typerecovery") );
actprop2->addRule( new RulePtrArith("typerecovery") );
actprop2->addRule( new RuleLoadVarnode("stackvars") );
actprop2->addRule( new RuleStoreVarnode("stackvars") );
}
actmainloop->addAction( actprop2 );
actmainloop->addAction( new ActionDeterminedBranch("unreachable") );
actmainloop->addAction( new ActionUnreachable("unreachable") );
actmainloop->addAction( new ActionNodeJoin("nodejoin") );
actmainloop->addAction( new ActionConditionalExe("conditionalexe") );
actmainloop->addAction( new ActionConditionalConst("analysis") );
}
actfullloop->addAction( actmainloop );
actfullloop->addAction( new ActionLikelyTrash("protorecovery") );
actfullloop->addAction( new ActionDirectWrite("protorecovery_a", true) );
actfullloop->addAction( new ActionDirectWrite("protorecovery_b", false) );
actfullloop->addAction( new ActionDeadCode("deadcode") );
actfullloop->addAction( new ActionDoNothing("deadcontrolflow") );
actfullloop->addAction( new ActionSwitchNorm("switchnorm") );
actfullloop->addAction( new ActionReturnSplit("returnsplit") );
actfullloop->addAction( new ActionUnjustifiedParams("protorecovery") );
actfullloop->addAction( new ActionStartTypes("typerecovery") );
actfullloop->addAction( new ActionActiveReturn("protorecovery") );
}
act->addAction( actfullloop );
act->addAction( new ActionStartCleanUp("cleanup") );
{
actcleanup = new ActionPool(Action::rule_repeatapply,"cleanup");
actcleanup->addRule( new RuleMultNegOne("cleanup") );
actcleanup->addRule( new RuleAddUnsigned("cleanup") );
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
actcleanup->addRule( new RuleSubRight("cleanup") );
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
actcleanup->addRule( new RuleExtensionPush("cleanup") );
}
act->addAction( actcleanup );
act->addAction( new ActionPreferComplement("blockrecovery") );
act->addAction( new ActionStructureTransform("blockrecovery") );
act->addAction( new ActionNormalizeBranches("normalizebranches") );
act->addAction( new ActionAssignHigh("merge") );
act->addAction( new ActionMergeRequired("merge") );
act->addAction( new ActionMarkExplicit("merge") );
act->addAction( new ActionMarkImplied("merge") ); act->addAction( new ActionMergeMultiEntry("merge") );
act->addAction( new ActionMergeCopy("merge") );
act->addAction( new ActionDominantCopy("merge") );
act->addAction( new ActionDynamicSymbols("dynamic") );
act->addAction( new ActionMarkIndirectOnly("merge") ); act->addAction( new ActionMergeAdjacent("merge") );
act->addAction( new ActionMergeType("merge") );
act->addAction( new ActionHideShadow("merge") );
act->addAction( new ActionCopyMarker("merge") );
act->addAction( new ActionOutputPrototype("localrecovery") );
act->addAction( new ActionInputPrototype("fixateproto") );
act->addAction( new ActionRestructureHigh("localrecovery") );
act->addAction( new ActionMapGlobals("fixateglobals") );
act->addAction( new ActionDynamicSymbols("dynamic") );
act->addAction( new ActionNameVars("merge") );
act->addAction( new ActionSetCasts("casts") );
act->addAction( new ActionFinalStructure("blockrecovery") );
act->addAction( new ActionPrototypeWarnings("protorecovery") );
act->addAction( new ActionStop("base") );
}