#include "funcdata.hh"
#include "flow.hh"
void Funcdata::opSetOpcode(PcodeOp *op,OpCode opc)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
obank.changeOpcode(op, glb->inst[opc] );
}
void Funcdata::opMarkHalt(PcodeOp *op,uint4 flag)
{
if (op->code() != CPUI_RETURN)
throw LowlevelError("Only RETURN pcode ops can be marked as halt");
flag &= (PcodeOp::halt|PcodeOp::badinstruction|
PcodeOp::unimplemented|PcodeOp::noreturn|
PcodeOp::missing);
if (flag == 0)
throw LowlevelError("Bad halt flag");
op->setFlag(flag);
}
void Funcdata::opUnsetOutput(PcodeOp *op)
{
Varnode *vn;
vn = op->getOut();
if (vn == (Varnode *)0) return; #ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
op->setOutput((Varnode *)0); vbank.makeFree(vn);
vn->clearCover();
}
void Funcdata::opSetOutput(PcodeOp *op,Varnode *vn)
{
if (vn == op->getOut()) return; #ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
if (op->getOut() != (Varnode *)0) {
opUnsetOutput(op);
}
if (vn->getDef() != (PcodeOp *)0) opUnsetOutput(vn->getDef());
vn = vbank.setDef(vn,op);
setVarnodeProperties(vn);
op->setOutput(vn);
}
void Funcdata::opUnsetInput(PcodeOp *op,int4 slot)
{
Varnode *vn = op->getIn(slot);
vn->eraseDescend(op);
op->clearInput(slot); }
void Funcdata::opSetInput(PcodeOp *op,Varnode *vn,int4 slot)
{
if (vn == op->getIn(slot)) return; if (vn->isConstant()) { if (!vn->hasNoDescend())
if (!vn->isSpacebase()) { Varnode *cvn = newConstant(vn->getSize(),vn->getOffset());
cvn->copySymbol(vn);
vn = cvn;
}
}
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
if (op->getIn(slot) != (Varnode *)0)
opUnsetInput(op,slot);
vn->addDescend(op); op->setInput(vn,slot); }
void Funcdata::opSwapInput(PcodeOp *op,int4 slot1,int4 slot2)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
Varnode *tmp = op->getIn(slot1);
op->setInput(op->getIn(slot2),slot1);
op->setInput(tmp,slot2);
}
void Funcdata::opInsert(PcodeOp *op,BlockBasic *bl,list<PcodeOp *>::iterator iter)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
obank.markAlive(op);
bl->insert(iter,op);
}
void Funcdata::opUninsert(PcodeOp *op)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
obank.markDead(op);
op->getParent()->removeOp(op);
}
void Funcdata::opUnlink(PcodeOp *op)
{
int4 i;
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
opUnsetOutput(op);
for(i=0;i<op->numInput();++i)
opUnsetInput(op,i);
if (op->getParent() != (BlockBasic *)0) opUninsert(op);
}
void Funcdata::opDestroy(PcodeOp *op)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
if (op->getOut() != (Varnode *)0)
destroyVarnode(op->getOut());
for(int4 i=0;i<op->numInput();++i) {
Varnode *vn = op->getIn(i);
if (vn != (Varnode *)0)
opUnsetInput(op,i);
}
if (op->getParent() != (BlockBasic *)0) {
obank.markDead(op);
op->getParent()->removeOp(op);
}
}
void Funcdata::opDestroyRaw(PcodeOp *op)
{
for(int4 i=0;i<op->numInput();++i)
destroyVarnode(op->getIn(i));
if (op->getOut() != (Varnode *)0)
destroyVarnode(op->getOut());
obank.destroy(op);
}
void Funcdata::opSetAllInput(PcodeOp *op,const vector<Varnode *> &vvec)
{
int4 i;
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
for(i=0;i<op->numInput();++i)
if (op->getIn(i) != (Varnode *)0)
opUnsetInput(op,i);
op->setNumInputs( vvec.size() );
for(i=0;i<op->numInput();++i)
opSetInput(op,vvec[i],i);
}
void Funcdata::opRemoveInput(PcodeOp *op,int4 slot)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
opUnsetInput(op,slot);
op->removeInput(slot);
}
void Funcdata::opInsertInput(PcodeOp *op,Varnode *vn,int4 slot)
{
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
op->insertInput(slot);
opSetInput(op,vn,slot);
}
PcodeOp *Funcdata::newOp(int4 inputs,const Address &pc)
{
return obank.create(inputs,pc);
}
PcodeOp *Funcdata::newOp(int4 inputs,const SeqNum &sq)
{
return obank.create(inputs,sq);
}
void Funcdata::opInsertBefore(PcodeOp *op,PcodeOp *follow)
{
list<PcodeOp *>::iterator iter = follow->getBasicIter();
BlockBasic *parent = follow->getParent();
if (op->code() != CPUI_INDIRECT) {
PcodeOp *previousop;
while(iter != parent->beginOp()) {
--iter;
previousop = *iter;
if (previousop->code() != CPUI_INDIRECT) {
++iter;
break;
}
}
}
opInsert(op,parent,iter);
}
void Funcdata::opInsertAfter(PcodeOp *op,PcodeOp *prev)
{
if (prev->isMarker()) {
if (prev->code() == CPUI_INDIRECT) {
Varnode *invn = prev->getIn(1);
if (invn->getSpace()->getType()==IPTR_IOP) {
PcodeOp *targOp = PcodeOp::getOpFromConst(invn->getAddr()); if (!targOp->isDead())
prev = targOp;
}
}
}
list<PcodeOp *>::iterator iter = prev->getBasicIter();
BlockBasic *parent = prev->getParent();
iter++;
if (op->code() != CPUI_MULTIEQUAL) {
PcodeOp *nextop;
while(iter != parent->endOp()) {
nextop = *iter;
++iter;
if (nextop->code() != CPUI_MULTIEQUAL) {
--iter;
break;
}
}
}
opInsert(op,prev->getParent(),iter);
}
void Funcdata::opInsertBegin(PcodeOp *op,BlockBasic *bl)
{
list<PcodeOp *>::iterator iter = bl->beginOp();
if (op->code()!=CPUI_MULTIEQUAL) {
while(iter != bl->endOp()) {
if ((*iter)->code() != CPUI_MULTIEQUAL)
break;
++iter;
}
}
opInsert(op,bl,iter);
}
void Funcdata::opInsertEnd(PcodeOp *op,BlockBasic *bl)
{
list<PcodeOp *>::iterator iter = bl->endOp();
if (iter != bl->beginOp()) {
--iter;
if (!(*iter)->isFlowBreak())
++iter;
}
opInsert(op,bl,iter);
}
Varnode *Funcdata::createStackRef(AddrSpace *spc,uintb off,PcodeOp *op,Varnode *stackptr,bool insertafter)
{
PcodeOp *addop;
Varnode *addout;
int4 addrsize;
if (stackptr == (Varnode *)0) stackptr = newSpacebasePtr(spc); addrsize = stackptr->getSize();
addop = newOp(2,op->getAddr());
opSetOpcode(addop,CPUI_INT_ADD);
addout = newUniqueOut(addrsize,addop);
opSetInput(addop,stackptr,0);
off = AddrSpace::byteToAddress(off,spc->getWordSize());
opSetInput(addop,newConstant(addrsize,off),1);
if (insertafter)
opInsertAfter(addop,op);
else
opInsertBefore(addop,op);
AddrSpace *containerid = spc->getContain();
SegmentOp *segdef = glb->userops.getSegmentOp(containerid->getIndex());
if (segdef != (SegmentOp *)0) {
PcodeOp *segop = newOp(3,op->getAddr());
opSetOpcode(segop,CPUI_SEGMENTOP);
Varnode *segout = newUniqueOut(containerid->getAddrSize(),segop);
opSetInput(segop,newVarnodeSpace(containerid),0);
opSetInput(segop,newConstant(segdef->getBaseSize(),0),1);
opSetInput(segop,addout,2);
opInsertAfter(segop,addop); addout = segout;
}
return addout;
}
PcodeOp *Funcdata::opStackStore(AddrSpace *spc,uintb off,PcodeOp *op,bool insertafter)
{ Varnode *addout;
PcodeOp *storeop;
addout = createStackRef(spc,off,op,(Varnode *)0,insertafter);
storeop = newOp(3,op->getAddr());
opSetOpcode(storeop,CPUI_STORE);
opSetInput(storeop,newVarnodeSpace(spc->getContain()),0);
opSetInput(storeop,addout,1);
opInsertAfter(storeop,addout->getDef()); return storeop;
}
Varnode *Funcdata::opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Varnode *stackref,bool insertafter)
{
Varnode *addout = createStackRef(spc,off,op,stackref,insertafter);
PcodeOp *loadop = newOp(2,op->getAddr());
opSetOpcode(loadop,CPUI_LOAD);
opSetInput(loadop,newVarnodeSpace(spc->getContain()),0);
opSetInput(loadop,addout,1);
Varnode *res = newUniqueOut(sz,loadop);
opInsertAfter(loadop,addout->getDef()); return res;
}
void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
{
Varnode *multVn = op->getIn(2);
int4 multSize = multVn->getOffset();
opRemoveInput(op,2);
opSetOpcode(op,CPUI_INT_ADD);
if (multSize == 1) return; Varnode *offVn = op->getIn(1);
if (offVn->isConstant()) {
uintb newVal = multSize * offVn->getOffset();
newVal &= calc_mask(offVn->getSize());
Varnode *newOffVn = newConstant(offVn->getSize(), newVal);
if (finalize)
newOffVn->updateType(offVn->getType(), false, false);
opSetInput(op,newOffVn,1);
return;
}
PcodeOp *multOp = newOp(2,op->getAddr());
opSetOpcode(multOp,CPUI_INT_MULT);
Varnode *addVn = newUniqueOut(offVn->getSize(),multOp);
if (finalize) {
addVn->updateType(multVn->getType(), false, false);
addVn->setImplied();
}
opSetInput(multOp,offVn,0);
opSetInput(multOp,multVn,1);
opSetInput(op,addVn,1);
opInsertBefore(multOp,op);
}
PcodeOp *Funcdata::cloneOp(const PcodeOp *op,const SeqNum &seq)
{
PcodeOp *newop = newOp(op->numInput(),seq);
opSetOpcode(newop,op->code());
uint4 fl = op->flags & (PcodeOp::startmark | PcodeOp::startbasic);
newop->setFlag(fl);
if (op->getOut() != (Varnode *)0)
opSetOutput(newop,cloneVarnode(op->getOut()));
for(int4 i=0;i<op->numInput();++i)
opSetInput(newop,cloneVarnode(op->getIn(i)),i);
return newop;
}
PcodeOp *Funcdata::getFirstReturnOp(void) const
{
list<PcodeOp *>::const_iterator iter,iterend;
iterend = endOp(CPUI_RETURN);
for(iter=beginOp(CPUI_RETURN);iter!=iterend;++iter) {
PcodeOp *retop = *iter;
if (retop->isDead()) continue;
if (retop->getHaltType()!=0) continue;
return retop;
}
return (PcodeOp *)0;
}
PcodeOp *Funcdata::newOpBefore(PcodeOp *follow,OpCode opc,Varnode *in1,Varnode *in2,Varnode *in3)
{
PcodeOp *newop;
int4 sz;
sz = (in3 == (Varnode *)0) ? 2 : 3;
newop = newOp(sz,follow->getAddr());
opSetOpcode(newop,opc);
newUniqueOut(in1->getSize(),newop);
opSetInput(newop,in1,0);
opSetInput(newop,in2,1);
if (sz==3)
opSetInput(newop,in3,2);
opInsertBefore(newop,follow);
return newop;
}
PcodeOp *Funcdata::newIndirectOp(PcodeOp *indeffect,const Address &addr,int4 sz,uint4 extraFlags)
{
Varnode *newin;
PcodeOp *newop;
newin = newVarnode(sz,addr);
newop = newOp(2,indeffect->getAddr());
newop->flags |= extraFlags;
newVarnodeOut(sz,addr,newop);
opSetOpcode(newop,CPUI_INDIRECT);
opSetInput(newop,newin,0);
opSetInput(newop,newVarnodeIop(indeffect),1);
opInsertBefore(newop,indeffect);
return newop;
}
PcodeOp *Funcdata::newIndirectCreation(PcodeOp *indeffect,const Address &addr,int4 sz,bool possibleout)
{
Varnode *newout,*newin;
PcodeOp *newop;
newin = newConstant(sz,0);
newop = newOp(2,indeffect->getAddr());
newop->flags |= PcodeOp::indirect_creation;
newout = newVarnodeOut(sz,addr,newop);
if (!possibleout)
newin->flags |= Varnode::indirect_creation;
newout->flags |= Varnode::indirect_creation;
opSetOpcode(newop,CPUI_INDIRECT);
opSetInput(newop,newin,0);
opSetInput(newop,newVarnodeIop(indeffect),1);
opInsertBefore(newop,indeffect);
return newop;
}
void Funcdata::markIndirectCreation(PcodeOp *indop,bool possibleOutput)
{
Varnode *outvn = indop->getOut();
Varnode *in0 = indop->getIn(0);
indop->flags |= PcodeOp::indirect_creation;
if (!in0->isConstant())
throw LowlevelError("Indirect creation not properly formed");
if (!possibleOutput)
in0->flags |= Varnode::indirect_creation;
outvn->flags |= Varnode::indirect_creation;
}
void Funcdata::followFlow(const Address &baddr,const Address &eaddr)
{
if (!obank.empty()) {
if ((flags & blocks_generated)==0)
throw LowlevelError("Function loaded for inlining");
return; }
uint4 fl = 0;
fl |= glb->flowoptions; FlowInfo flow(*this,obank,bblocks,qlst);
flow.setRange(baddr,eaddr);
flow.setFlags(fl);
flow.setMaximumInstructions(glb->max_instructions);
flow.generateOps();
size = flow.getSize();
flow.generateBlocks();
flags |= blocks_generated;
switchOverJumpTables(flow);
if (flow.hasUnimplemented())
flags |= unimplemented_present;
if (flow.hasBadData())
flags |= baddata_present;
}
void Funcdata::truncatedFlow(const Funcdata *fd,const FlowInfo *flow)
{
if (!obank.empty())
throw LowlevelError("Trying to do truncated flow on pre-existing pcode");
list<PcodeOp *>::const_iterator oiter; for(oiter=fd->obank.beginDead();oiter!=fd->obank.endDead();++oiter)
cloneOp(*oiter,(*oiter)->getSeqNum());
obank.setUniqId(fd->obank.getUniqId());
for(int4 i=0;i<fd->qlst.size();++i) {
FuncCallSpecs *oldspec = fd->qlst[i];
PcodeOp *newop = findOp(oldspec->getOp()->getSeqNum());
FuncCallSpecs *newspec = oldspec->clone(newop);
Varnode *invn0 = newop->getIn(0);
if (invn0->getSpace()->getType() == IPTR_FSPEC) { Varnode *newvn0 = newVarnodeCallSpecs(newspec);
opSetInput(newop,newvn0,0);
deleteVarnode(invn0);
}
qlst.push_back(newspec);
}
vector<JumpTable *>::const_iterator jiter; for(jiter=fd->jumpvec.begin();jiter!=fd->jumpvec.end();++jiter) {
PcodeOp *indop = (*jiter)->getIndirectOp();
if (indop == (PcodeOp *)0) continue; PcodeOp *newop = findOp(indop->getSeqNum());
if (newop == (PcodeOp *)0)
throw LowlevelError("Could not trace jumptable across partial clone");
JumpTable *jtclone = new JumpTable(*jiter);
jtclone->setIndirectOp(newop);
jumpvec.push_back(jtclone);
}
FlowInfo partialflow(*this,obank,bblocks,qlst,flow); if (partialflow.hasInject())
partialflow.injectPcode();
partialflow.clearFlags(~((uint4)FlowInfo::possible_unreachable));
partialflow.generateBlocks(); flags |= blocks_generated;
}
bool Funcdata::inlineFlow(Funcdata *inlinefd,FlowInfo &flow,PcodeOp *callop)
{
inlinefd->getArch()->clearAnalysis(inlinefd);
FlowInfo inlineflow(*inlinefd,inlinefd->obank,inlinefd->bblocks,inlinefd->qlst);
inlinefd->obank.setUniqId( obank.getUniqId() );
Address baddr(baseaddr.getSpace(),0);
Address eaddr(baseaddr.getSpace(),~((uintb)0));
inlineflow.setRange(baddr,eaddr);
inlineflow.setFlags(FlowInfo::error_outofbounds|FlowInfo::error_unimplemented|
FlowInfo::error_reinterpreted|FlowInfo::flow_forinline);
inlineflow.forwardRecursion(flow);
inlineflow.generateOps();
if (inlineflow.checkEZModel()) {
list<PcodeOp *>::const_iterator oiter = obank.endDead();
--oiter; flow.inlineEZClone(inlineflow,callop->getAddr());
++oiter;
if (oiter != obank.endDead()) { PcodeOp *firstop = *oiter;
oiter = obank.endDead();
--oiter;
PcodeOp *lastop = *oiter;
obank.moveSequenceDead(firstop,lastop,callop); if (callop->isBlockStart())
firstop->setFlag(PcodeOp::startbasic); else
firstop->clearFlag(PcodeOp::startbasic);
}
opDestroyRaw(callop);
}
else {
Address retaddr;
if (!flow.testHardInlineRestrictions(inlinefd,callop,retaddr))
return false;
vector<JumpTable *>::const_iterator jiter; for(jiter=inlinefd->jumpvec.begin();jiter!=inlinefd->jumpvec.end();++jiter) {
JumpTable *jtclone = new JumpTable(*jiter);
jumpvec.push_back(jtclone);
}
flow.inlineClone(inlineflow,retaddr);
while(callop->numInput()>1)
opRemoveInput(callop,callop->numInput()-1);
opSetOpcode(callop,CPUI_BRANCH);
Varnode *inlineaddr = newCodeRef( inlinefd->getAddress() );
opSetInput(callop,inlineaddr,0);
}
obank.setUniqId( inlinefd->obank.getUniqId() );
return true;
}
PcodeOp *Funcdata::findPrimaryBranch(PcodeOpTree::const_iterator iter,PcodeOpTree::const_iterator enditer,
bool findbranch,bool findcall,bool findreturn)
{
while(iter != enditer) {
PcodeOp *op = (*iter).second;
switch(op->code()) {
case CPUI_BRANCH:
case CPUI_CBRANCH:
if (findbranch) {
if (!op->getIn(0)->isConstant()) return op;
}
break;
case CPUI_BRANCHIND:
if (findbranch)
return op;
break;
case CPUI_CALL:
case CPUI_CALLIND:
if (findcall)
return op;
break;
case CPUI_RETURN:
if (findreturn)
return op;
break;
default:
break;
}
++iter;
}
return (PcodeOp *)0;
}
void Funcdata::overrideFlow(const Address &addr,uint4 type)
{
PcodeOpTree::const_iterator iter = beginOp(addr);
PcodeOpTree::const_iterator enditer = endOp(addr);
PcodeOp *op = (PcodeOp *)0;
if (type == Override::BRANCH)
op = findPrimaryBranch(iter,enditer,false,true,true);
else if (type == Override::CALL)
op = findPrimaryBranch(iter,enditer,true,false,true);
else if (type == Override::CALL_RETURN)
op = findPrimaryBranch(iter,enditer,true,true,true);
else if (type == Override::RETURN)
op = findPrimaryBranch(iter,enditer,true,true,false);
if ((op == (PcodeOp *)0)||(!op->isDead()))
throw LowlevelError("Could not apply flowoverride");
OpCode opc = op->code();
if (type == Override::BRANCH) {
if (opc == CPUI_CALL)
opSetOpcode(op,CPUI_BRANCH);
else if (opc == CPUI_CALLIND)
opSetOpcode(op,CPUI_BRANCHIND);
else if (opc == CPUI_RETURN)
opSetOpcode(op,CPUI_BRANCHIND);
}
else if ((type == Override::CALL)||(type == Override::CALL_RETURN)) {
if (opc == CPUI_BRANCH)
opSetOpcode(op,CPUI_CALL);
else if (opc == CPUI_BRANCHIND)
opSetOpcode(op,CPUI_CALLIND);
else if (opc == CPUI_CBRANCH)
throw LowlevelError("Do not currently support CBRANCH overrides");
else if (opc == CPUI_RETURN)
opSetOpcode(op,CPUI_CALLIND);
if (type == Override::CALL_RETURN) { PcodeOp *newReturn = newOp(1,addr);
opSetOpcode(newReturn,CPUI_RETURN);
opSetInput(newReturn,newConstant(1,0),0);
opDeadInsertAfter(newReturn,op);
}
}
else if (type == Override::RETURN) {
if ((opc == CPUI_BRANCH)||(opc == CPUI_CBRANCH)||(opc == CPUI_CALL))
throw LowlevelError("Do not currently support complex overrides");
else if (opc == CPUI_BRANCHIND)
opSetOpcode(op,CPUI_RETURN);
else if (opc == CPUI_CALLIND)
opSetOpcode(op,CPUI_RETURN);
}
}
bool Funcdata::replaceLessequal(PcodeOp *op)
{
Varnode *vn;
int4 i;
intb val,diff;
if ((vn=op->getIn(0))->isConstant()) {
diff = -1;
i = 0;
}
else if ((vn=op->getIn(1))->isConstant()) {
diff = 1;
i = 1;
}
else
return false;
val = vn->getOffset(); sign_extend(val,8*vn->getSize()-1);
if (op->code() == CPUI_INT_SLESSEQUAL) {
if ((val<0)&&(val+diff>0)) return false; if ((val>0)&&(val+diff<0)) return false;
opSetOpcode(op,CPUI_INT_SLESS);
}
else { if ((diff==-1)&&(val==0)) return false;
if ((diff==1)&&(val==-1)) return false;
opSetOpcode(op,CPUI_INT_LESS);
}
uintb res = (val+diff) & calc_mask(vn->getSize());
Varnode *newvn = newConstant(vn->getSize(),res);
newvn->copySymbol(vn); opSetInput(op,newvn,i);
return true;
}
bool Funcdata::distributeIntMultAdd(PcodeOp *op)
{
Varnode *newvn0,*newvn1;
PcodeOp *addop = op->getIn(0)->getDef();
Varnode *vn0 = addop->getIn(0);
Varnode *vn1 = addop->getIn(1);
if ((vn0->isFree())&&(!vn0->isConstant())) return false;
if ((vn1->isFree())&&(!vn1->isConstant())) return false;
uintb coeff = op->getIn(1)->getOffset();
int4 sz = op->getOut()->getSize();
if (vn0->isConstant()) {
uintb val = coeff * vn0->getOffset();
val &= calc_mask(sz);
newvn0 = newConstant(sz,val);
}
else {
PcodeOp *newop0 = newOp(2,op->getAddr());
opSetOpcode(newop0,CPUI_INT_MULT);
newvn0 = newUniqueOut(sz,newop0);
opSetInput(newop0, vn0, 0); Varnode *newcvn = newConstant(sz,coeff);
opSetInput(newop0, newcvn, 1);
opInsertBefore(newop0, op);
}
if (vn1->isConstant()) {
uintb val = coeff * vn1->getOffset();
val &= calc_mask(sz);
newvn1 = newConstant(sz,val);
}
else {
PcodeOp *newop1 = newOp(2,op->getAddr());
opSetOpcode(newop1,CPUI_INT_MULT);
newvn1 = newUniqueOut(sz,newop1);
opSetInput(newop1, vn1, 0); Varnode *newcvn = newConstant(sz,coeff);
opSetInput(newop1, newcvn, 1);
opInsertBefore(newop1, op);
}
opSetInput( op, newvn0, 0); opSetInput( op, newvn1, 1);
opSetOpcode(op, CPUI_INT_ADD);
return true;
}
bool Funcdata::collapseIntMultMult(Varnode *vn)
{
if (!vn->isWritten()) return false;
PcodeOp *op = vn->getDef();
if (op->code() != CPUI_INT_MULT) return false;
Varnode *constVnFirst = op->getIn(1);
if (!constVnFirst->isConstant()) return false;
if (!op->getIn(0)->isWritten()) return false;
PcodeOp *otherMultOp = op->getIn(0)->getDef();
if (otherMultOp->code() != CPUI_INT_MULT) return false;
Varnode *constVnSecond = otherMultOp->getIn(1);
if (!constVnSecond->isConstant()) return false;
Varnode *invn = otherMultOp->getIn(0);
if (invn->isFree()) return false;
int4 sz = invn->getSize();
uintb val = (constVnFirst->getOffset() * constVnSecond->getOffset()) & calc_mask(sz);
Varnode *newvn = newConstant(sz,val);
opSetInput(op,newvn,1);
opSetInput(op,invn,0);
return true;
}
int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
{
Varnode *vn;
int4 subtest1,subtest2;
switch(op->code()) {
case CPUI_CBRANCH:
vn = op->getIn(1);
if (vn->loneDescend() != op) return 2;
if (!vn->isWritten()) return 2;
return opFlipInPlaceTest(vn->getDef(),fliplist);
case CPUI_INT_EQUAL:
case CPUI_FLOAT_EQUAL:
fliplist.push_back(op);
return 1;
case CPUI_BOOL_NEGATE:
case CPUI_INT_NOTEQUAL:
case CPUI_FLOAT_NOTEQUAL:
fliplist.push_back(op);
return 0;
case CPUI_INT_SLESS:
case CPUI_INT_LESS:
vn = op->getIn(0);
fliplist.push_back(op);
if (!vn->isConstant()) return 1;
return 0;
case CPUI_INT_SLESSEQUAL:
case CPUI_INT_LESSEQUAL:
vn = op->getIn(1);
fliplist.push_back(op);
if (vn->isConstant()) return 1;
return 0;
case CPUI_BOOL_OR:
case CPUI_BOOL_AND:
vn = op->getIn(0);
if (vn->loneDescend() != op) return 2;
if (!vn->isWritten()) return 2;
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist);
if (subtest1 == 2)
return 2;
vn = op->getIn(1);
if (vn->loneDescend() != op) return 2;
if (!vn->isWritten()) return 2;
subtest2 = opFlipInPlaceTest(vn->getDef(),fliplist);
if (subtest2 == 2)
return 2;
fliplist.push_back(op);
return subtest1; default:
break;
}
return 2;
}
void opFlipInPlaceExecute(Funcdata &data,vector<PcodeOp *> &fliplist)
{
Varnode *vn;
for(int4 i=0;i<fliplist.size();++i) {
PcodeOp *op = fliplist[i];
bool flipyes;
OpCode opc = get_booleanflip(op->code(),flipyes);
if (opc == CPUI_COPY) { vn = op->getIn(0);
PcodeOp *otherop = op->getOut()->loneDescend(); int4 slot = otherop->getSlot(op->getOut());
data.opSetInput(otherop,vn,slot); data.opDestroy(op);
}
else if (opc == CPUI_MAX) {
if (op->code() == CPUI_BOOL_AND)
data.opSetOpcode(op,CPUI_BOOL_OR);
else if (op->code() == CPUI_BOOL_OR)
data.opSetOpcode(op,CPUI_BOOL_AND);
else
throw LowlevelError("Bad flipInPlace op");
}
else {
data.opSetOpcode(op,opc);
if (flipyes) {
data.opSwapInput(op,0,1);
if ((opc == CPUI_INT_LESSEQUAL)||(opc == CPUI_INT_SLESSEQUAL))
data.replaceLessequal(op);
}
}
}
}
PcodeOp *earliestUseInBlock(Varnode *vn,BlockBasic *bl)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *res = (PcodeOp *)0;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->getParent() != bl) continue;
if (res == (PcodeOp *)0)
res = op;
else {
if (op->getSeqNum().getOrder() < res->getSeqNum().getOrder())
res = op;
}
}
return res;
}
PcodeOp *cseFindInBlock(PcodeOp *op,Varnode *vn,BlockBasic *bl,PcodeOp *earliest)
{
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *res = *iter;
if (res == op) continue; if (res->getParent() != bl) continue; if (earliest != (PcodeOp *)0) {
if (earliest->getSeqNum().getOrder() < res->getSeqNum().getOrder()) continue; }
Varnode *outvn1 = op->getOut();
Varnode *outvn2 = res->getOut();
if (outvn2 == (Varnode *)0) continue;
Varnode *buf1[2];
Varnode *buf2[2];
if (functionalEqualityLevel(outvn1,outvn2,buf1,buf2) == 0)
return res;
}
return (PcodeOp *)0;
}
PcodeOp *cseElimination(Funcdata &data,PcodeOp *op1,PcodeOp *op2)
{
PcodeOp *replace;
if (op1->getParent() == op2->getParent()) {
if (op1->getSeqNum().getOrder() < op2->getSeqNum().getOrder())
replace = op1;
else
replace = op2;
}
else {
BlockBasic *common;
common = (BlockBasic *)FlowBlock::findCommonBlock(op1->getParent(),op2->getParent());
if (common == op1->getParent())
replace = op1;
else if (common == op2->getParent())
replace = op2;
else { replace = data.newOp(op1->numInput(),common->getStop());
data.opSetOpcode(replace,op1->code());
data.newVarnodeOut(op1->getOut()->getSize(),op1->getOut()->getAddr(),replace);
for(int4 i=0;i<op1->numInput();++i) {
if (op1->getIn(i)->isConstant())
data.opSetInput(replace,data.newConstant(op1->getIn(i)->getSize(),op1->getIn(i)->getOffset()),i);
else
data.opSetInput(replace,op1->getIn(i),i);
}
data.opInsertEnd(replace,common);
}
}
if (replace != op1) {
data.totalReplace(op1->getOut(),replace->getOut());
data.opDestroy(op1);
}
if (replace != op2) {
data.totalReplace(op2->getOut(),replace->getOut());
data.opDestroy(op2);
}
return replace;
}
static bool compareCseHash(const pair<uintm,PcodeOp *> &a,const pair<uintm,PcodeOp *> &b)
{
return (a.first < b.first);
}
void cseEliminateList(Funcdata &data,vector< pair<uintm,PcodeOp *> > &list,vector<Varnode *> &outlist)
{
PcodeOp *op1,*op2,*resop;
vector< pair<uintm,PcodeOp *> >::iterator liter1,liter2;
if (list.empty()) return;
stable_sort(list.begin(),list.end(),compareCseHash);
liter1 = list.begin();
liter2 = list.begin();
liter2++;
while(liter2 != list.end()) {
if ((*liter1).first == (*liter2).first) {
op1 = (*liter1).second;
op2 = (*liter2).second;
if ((!op1->isDead())&&(!op2->isDead())&&op1->isCseMatch(op2)) {
Varnode *outvn1 = op1->getOut();
Varnode *outvn2 = op2->getOut();
if ((outvn1 == (Varnode *)0)||data.isHeritaged(outvn1)) {
if ((outvn2 == (Varnode *)0)||data.isHeritaged(outvn2)) {
resop = cseElimination(data,op1,op2);
outlist.push_back(resop->getOut());
}
}
}
}
liter1++;
liter2++;
}
}
bool Funcdata::moveRespectingCover(PcodeOp *op,PcodeOp *lastOp)
{
if (op == lastOp) return true; if (op->isCall()) return false;
PcodeOp *prevOp = (PcodeOp *)0;
if (op->code() == CPUI_CAST) {
Varnode *vn = op->getIn(0);
if (!vn->isExplicit()) { if (!vn->isWritten()) return false;
prevOp = vn->getDef();
if (prevOp->isCall()) return false;
if (op->previousOp() != prevOp) return false; }
}
Varnode *rootvn = op->getOut();
vector<HighVariable *> highList;
int4 typeVal = HighVariable::markExpression(rootvn, highList);
PcodeOp *curOp = op;
do {
PcodeOp *nextOp = curOp->nextOp();
OpCode opc = nextOp->code();
if (opc != CPUI_COPY && opc != CPUI_CAST) break; if (rootvn == nextOp->getIn(0)) break; Varnode *copyVn = nextOp->getOut();
if (copyVn->getHigh()->isMark()) break; if (typeVal != 0 && copyVn->isAddrTied()) break; curOp = nextOp;
} while(curOp != lastOp);
for(int4 i=0;i<highList.size();++i) highList[i]->clearMark();
if (curOp == lastOp) { opUninsert(op); opInsertAfter(op, lastOp);
if (prevOp != (PcodeOp *)0) { opUninsert(prevOp);
opInsertAfter(prevOp, lastOp);
}
return true;
}
return false;
}