#include "op.hh"
#include "funcdata.hh"
const string IopSpace::NAME = "iop";
IopSpace::IopSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
: AddrSpace(m,t,IPTR_IOP,NAME,sizeof(void *),1,ind,0,1)
{
clearFlags(heritaged|does_deadcode|big_endian);
if (HOST_ENDIAN==1) setFlags(big_endian);
}
void IopSpace::printRaw(ostream &s,uintb offset) const
{ BlockBasic *bs;
BlockBasic *bl;
PcodeOp *op = (PcodeOp *)(uintp)offset;
if (!op->isBranch()) { s << op->getSeqNum();
return;
}
bs = op->getParent();
if (bs->sizeOut()==2) bl = (BlockBasic *)(op->isFallthruTrue() ? bs->getOut(0) : bs->getOut(1));
else
bl = (BlockBasic *)bs->getOut(0);
s << "code_" << bl->getStart().getShortcut();
bl->getStart().printRaw(s);
}
void IopSpace::saveXml(ostream &s) const
{
throw LowlevelError("Should never save iop space to XML");
}
void IopSpace::restoreXml(const Element *el)
{
throw LowlevelError("Should never restore iop space from XML");
}
PcodeOp::PcodeOp(int4 s,const SeqNum &sq) : start(sq),inrefs(s)
{
flags = 0; addlflags = 0;
parent = (BlockBasic *)0;
output = (Varnode *) 0;
opcode = (TypeOp *)0;
for(int4 i=0;i<inrefs.size();++i)
inrefs[i] = (Varnode *)0;
}
int4 PcodeOp::getRepeatSlot(const Varnode *vn,int4 firstSlot,list<PcodeOp *>::const_iterator iter) const
{
int4 count = 1;
for(list<PcodeOp *>::const_iterator oiter=vn->beginDescend();oiter != iter;++oiter) {
if ((*oiter) == this)
count += 1;
}
if (count == 1) return firstSlot;
int4 recount = 1;
for(int4 i=firstSlot+1;i<inrefs.size();++i) {
if (inrefs[i] == vn) {
recount += 1;
if (recount == count)
return i;
}
}
return -1;
}
bool PcodeOp::isCollapsible(void) const
{
if (code() == CPUI_COPY) return false;
if ((flags & PcodeOp::nocollapse)!=0) return false;
if (!isAssignment()) return false;
if (inrefs.size()==0) return false;
for(int4 i=0;i<inrefs.size();++i)
if (!getIn(i)->isConstant()) return false;
if (getOut()->getSize() > sizeof(uintb)) return false;
return true;
}
uintm PcodeOp::getCseHash(void) const
{
uintm hash;
if ((getEvalType()&(PcodeOp::unary|PcodeOp::binary))==0) return ((uintm)0);
if (code()==CPUI_COPY) return ((uintm)0);
hash = (output->getSize()<<8) | (uintm)code();
for(int4 i=0;i<inrefs.size();++i) {
const Varnode *vn = getIn(i);
hash = (hash<<8) | (hash>>(sizeof(uintm)*8-8));
if (vn->isConstant())
hash ^= (uintm)vn->getOffset();
else
hash ^= (uintm)vn->getCreateIndex(); }
return hash;
}
bool PcodeOp::isCseMatch(const PcodeOp *op) const
{
if ((getEvalType()&(PcodeOp::unary|PcodeOp::binary))==0) return false;
if ((op->getEvalType()&(PcodeOp::unary|PcodeOp::binary))==0) return false;
if (output->getSize() != op->output->getSize()) return false;
if (code() != op->code()) return false;
if (code() == CPUI_COPY) return false; if (inrefs.size() != op->inrefs.size()) return false;
for(int4 i=0;i<inrefs.size();++i) {
const Varnode *vn1 = getIn(i);
const Varnode *vn2 = op->getIn(i);
if (vn1 == vn2) continue;
if (vn1->isConstant()&&vn2->isConstant()&&(vn1->getOffset()==vn2->getOffset()))
continue;
return false;
}
return true;
}
bool PcodeOp::isMoveable(const PcodeOp *point) const
{
if (this == point) return true; bool movingLoad = false;
if (getEvalType() == PcodeOp::special) {
if (code() == CPUI_LOAD)
movingLoad = true; else
return false; }
if (parent != point->parent) return false; if (output != (Varnode *)0) {
list<PcodeOp *>::const_iterator iter = output->beginDescend();
list<PcodeOp *>::const_iterator enditer = output->endDescend();
while(iter != enditer) {
PcodeOp *readOp = *iter;
++iter;
if (readOp->parent != parent) continue;
if (readOp->start.getOrder() <= point->start.getOrder())
return false; }
}
bool crossCalls = false;
if (getEvalType() != PcodeOp::special) {
if (output != (Varnode *)0 && !output->isAddrTied() && !output->isPersist()) {
int4 i;
for(i=0;i<numInput();++i) {
const Varnode *vn = getIn(i);
if (vn->isAddrTied() || vn->isPersist())
break;
}
if (i == numInput())
crossCalls = true;
}
}
vector<const Varnode *> tiedList;
for(int4 i=0;i<numInput();++i) {
const Varnode *vn = getIn(i);
if (vn->isAddrTied())
tiedList.push_back(vn);
}
list<PcodeOp *>::iterator biter = basiciter;
do {
++biter;
PcodeOp *op = *biter;
if (op->getEvalType() == PcodeOp::special) {
switch (op->code()) {
case CPUI_LOAD:
if (output != (Varnode *)0) {
if (output->isAddrTied()) return false;
}
break;
case CPUI_STORE:
if (movingLoad)
return false;
else {
if (!tiedList.empty()) return false;
if (output != (Varnode *)0) {
if (output->isAddrTied()) return false;
}
}
break;
case CPUI_INDIRECT: case CPUI_SEGMENTOP:
case CPUI_CPOOLREF:
break;
case CPUI_CALL:
case CPUI_CALLIND:
case CPUI_NEW:
if (!crossCalls) return false;
break;
default:
return false;
}
}
if (op->output != (Varnode *)0) {
if (movingLoad) {
if (op->output->isAddrTied()) return false;
}
for(int4 i=0;i<tiedList.size();++i) {
const Varnode *vn = tiedList[i];
if (vn->overlap(*op->output)>=0)
return false;
if (op->output->overlap(*vn)>=0)
return false;
}
}
} while(biter != point->basiciter);
return true;
}
void PcodeOp::setOpcode(TypeOp *t_op)
{
flags &= ~(PcodeOp::branch | PcodeOp::call | PcodeOp::coderef | PcodeOp::commutative |
PcodeOp::returns | PcodeOp::nocollapse | PcodeOp::marker | PcodeOp::booloutput |
PcodeOp::unary | PcodeOp::binary | PcodeOp::special);
opcode = t_op;
flags |= t_op->getFlags();
}
void PcodeOp::setNumInputs(int4 num)
{
inrefs.resize(num);
for(int4 i=0;i<num;++i)
inrefs[i] = (Varnode *)0;
}
void PcodeOp::removeInput(int4 slot)
{
for(int4 i=slot+1;i<inrefs.size();++i)
inrefs[i-1] = inrefs[i];
inrefs.pop_back();
}
void PcodeOp::insertInput(int4 slot)
{
inrefs.push_back((Varnode *)0);
for(int4 i=inrefs.size()-1;i>slot;--i)
inrefs[i] = inrefs[i-1];
inrefs[slot] = (Varnode *)0;
}
PcodeOp *PcodeOp::nextOp(void) const
{
list<PcodeOp *>::iterator iter;
BlockBasic *p;
p = parent; iter = basiciter;
iter ++;
while(iter == p->endOp()) {
if ((p->sizeOut() != 1)&&(p->sizeOut()!=2)) return (PcodeOp *)0;
p = (BlockBasic *) p->getOut(0);
iter = p->beginOp();
}
return *iter;
}
PcodeOp *PcodeOp::previousOp(void) const
{
list<PcodeOp *>::iterator iter;
if (basiciter == parent->beginOp()) return (PcodeOp *) 0;
iter = basiciter;
iter--;
return *iter;
}
PcodeOp *PcodeOp::target(void) const
{
PcodeOp *retop;
list<PcodeOp *>::iterator iter;
iter = isDead() ? insertiter : basiciter;
retop = *iter;
while((retop->flags&PcodeOp::startmark)==0) {
--iter;
retop = *iter;
}
return retop;
}
void PcodeOp::printDebug(ostream &s) const
{
s << start << ": ";
if (isDead()||(parent==(BlockBasic *)0))
s << "**";
else
printRaw(s);
}
void PcodeOp::saveXml(ostream &s) const
{
s << "<op";
a_v_i(s,"code",(int4)code());
s << ">\n";
start.saveXml(s);
s << '\n';
if (output==(Varnode *)0)
s << "<void/>\n";
else
s << "<addr ref=\"0x" << hex << output->getCreateIndex() << "\"/>\n";
for(int4 i=0;i<inrefs.size();++i) {
const Varnode *vn = getIn(i);
if (vn == (const Varnode *)0)
s << "<void/>\n";
else if (vn->getSpace()->getType()==IPTR_IOP) {
if ((i==1)&&(code()==CPUI_INDIRECT)) {
PcodeOp *indop = PcodeOp::getOpFromConst(vn->getAddr());
s << "<iop";
a_v_u(s,"value",indop->getSeqNum().getTime());
s << "/>\n";
}
else
s << "<void/>\n";
}
else if (vn->getSpace()->getType()==IPTR_CONSTANT) {
if ((i==0)&&((code()==CPUI_STORE)||(code()==CPUI_LOAD))) {
AddrSpace *spc = Address::getSpaceFromConst(vn->getAddr());
s << "<spaceid";
a_v(s,"name",spc->getName());
s << "/>\n";
}
else
s << "<addr ref=\"0x" << hex << vn->getCreateIndex() << "\"/>\n";
}
else {
s << "<addr ref=\"0x" << hex << vn->getCreateIndex() << "\"/>\n";
}
}
s << "</op>\n";
}
uintb PcodeOp::collapse(bool &markedInput) const {
const Varnode *vn0;
const Varnode *vn1;
vn0 = getIn(0);
if (vn0->getSymbolEntry() != (SymbolEntry *)0) {
markedInput = true;
}
switch(getEvalType()) {
case PcodeOp::unary:
return opcode->evaluateUnary(output->getSize(),vn0->getSize(),vn0->getOffset());
case PcodeOp::binary:
vn1 = getIn(1);
if (vn1->getSymbolEntry() != (SymbolEntry *)0) {
markedInput = true;
}
return opcode->evaluateBinary(output->getSize(),vn0->getSize(),
vn0->getOffset(),vn1->getOffset());
default:
break;
}
throw LowlevelError("Invalid constant collapse");
}
void PcodeOp::collapseConstantSymbol(Varnode *newConst) const
{
const Varnode *copyVn = (const Varnode *)0;
switch(code()) {
case CPUI_SUBPIECE:
if (getIn(1)->getOffset() != 0)
return; copyVn = getIn(0);
break;
case CPUI_COPY:
case CPUI_INT_ZEXT:
case CPUI_INT_NEGATE:
case CPUI_INT_2COMP:
copyVn = getIn(0);
break;
case CPUI_INT_LEFT:
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
copyVn = getIn(0); break;
case CPUI_INT_ADD:
case CPUI_INT_MULT:
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
copyVn = getIn(0);
if (copyVn->getSymbolEntry() == (SymbolEntry *)0) {
copyVn = getIn(1);
}
break;
default:
return;
}
if (copyVn->getSymbolEntry() == (SymbolEntry *)0)
return; newConst->copySymbolIfValid(copyVn);
}
uintb PcodeOp::getNZMaskLocal(bool cliploop) const
{
int4 sa,sz1,sz2,size;
uintb resmask,val;
size = output->getSize();
uintb fullmask = calc_mask( size );
switch(opcode->getOpcode()) {
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
case CPUI_INT_SLESS:
case CPUI_INT_SLESSEQUAL:
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
case CPUI_INT_CARRY:
case CPUI_INT_SCARRY:
case CPUI_INT_SBORROW:
case CPUI_BOOL_NEGATE:
case CPUI_BOOL_XOR:
case CPUI_BOOL_AND:
case CPUI_BOOL_OR:
case CPUI_FLOAT_EQUAL:
case CPUI_FLOAT_NOTEQUAL:
case CPUI_FLOAT_LESS:
case CPUI_FLOAT_LESSEQUAL:
case CPUI_FLOAT_NAN:
resmask=1; break;
case CPUI_COPY:
case CPUI_INT_ZEXT:
resmask = getIn(0)->getNZMask();
break;
case CPUI_INT_SEXT:
resmask = sign_extend( getIn(0)->getNZMask(), getIn(0)->getSize(), size);
break;
case CPUI_INT_XOR:
case CPUI_INT_OR:
resmask = getIn(0)->getNZMask();
if (resmask != fullmask)
resmask |= getIn(1)->getNZMask();
break;
case CPUI_INT_AND:
resmask = getIn(0)->getNZMask();
if (resmask != 0)
resmask &= getIn(1)->getNZMask();
break;
case CPUI_INT_LEFT:
if (!getIn(1)->isConstant())
resmask = fullmask;
else {
sa = getIn(1)->getOffset(); resmask = getIn(0)->getNZMask();
resmask = pcode_left(resmask,sa) & fullmask;
}
break;
case CPUI_INT_RIGHT:
if (!getIn(1)->isConstant())
resmask = fullmask;
else {
sz1 = getIn(0)->getSize();
sa = getIn(1)->getOffset(); resmask = getIn(0)->getNZMask();
resmask = pcode_right(resmask,sa);
if (sz1 > sizeof(uintb)) {
if (sa >= 8*sz1)
resmask = 0;
else if (sa >= 8*sizeof(uintb)) {
resmask = calc_mask( sz1-sizeof(uintb) );
resmask >>= (sa-8*sizeof(uintb));
}
else {
uintb tmp = 0;
tmp -= 1;
tmp <<= (8*sizeof(uintb)-sa);
resmask |= tmp;
}
}
}
break;
case CPUI_INT_SRIGHT:
if ((!getIn(1)->isConstant())||(size > sizeof(uintb)))
resmask = fullmask;
else {
sa = getIn(1)->getOffset(); resmask = getIn(0)->getNZMask();
if ((resmask & (fullmask ^ (fullmask>>1))) == 0) { resmask = pcode_right(resmask,sa); }
else {
resmask = pcode_right(resmask,sa);
resmask |= (fullmask >> sa) ^ fullmask; }
}
break;
case CPUI_INT_DIV:
val = getIn(0)->getNZMask();
resmask = coveringmask(val);
if (getIn(1)->isConstant()) {
sa = mostsigbit_set(getIn(1)->getNZMask());
if (sa != -1)
resmask >>= sa; }
break;
case CPUI_INT_REM:
val = (getIn(1)->getNZMask()-1); resmask = coveringmask(val);
break;
case CPUI_POPCOUNT:
sz1 = popcount(getIn(0)->getNZMask());
resmask = coveringmask((uintb)sz1);
resmask &= fullmask;
break;
case CPUI_SUBPIECE:
resmask = getIn(0)->getNZMask();
sz1 = (int4)getIn(1)->getOffset();
if ((int4)getIn(0)->getSize() <= sizeof(uintb)) {
if (sz1 < sizeof(uintb))
resmask >>= 8*sz1;
else
resmask = 0;
}
else { if (sz1 < sizeof(uintb)) {
resmask >>= 8*sz1;
if (sz1 > 0)
resmask |= fullmask << (8*(sizeof(uintb)-sz1));
}
else
resmask = fullmask;
}
resmask &= fullmask;
break;
case CPUI_PIECE:
resmask = getIn(0)->getNZMask();
resmask <<= 8*getIn(1)->getSize();
resmask |= getIn(1)->getNZMask();
break;
case CPUI_INT_MULT:
val = getIn(0)->getNZMask();
resmask = getIn(1)->getNZMask();
sz1 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(val);
if (sz1 == -1)
resmask = 0;
else {
sz2 = (size > sizeof(uintb)) ? 8*size-1 : mostsigbit_set(resmask);
if (sz2 == -1)
resmask = 0;
else {
if (sz1 + sz2 < 8*size-2)
fullmask >>= (8*size-2-sz1-sz2);
sz1 = leastsigbit_set(val);
sz2 = leastsigbit_set(resmask);
resmask = (~((uintb)0))<<(sz1+sz2);
resmask &= fullmask;
}
}
break;
case CPUI_INT_ADD:
resmask = getIn(0)->getNZMask();
if (resmask!=fullmask) {
resmask |= getIn(1)->getNZMask();
resmask |= (resmask<<1); resmask &= fullmask;
}
break;
case CPUI_MULTIEQUAL:
if (inrefs.size()==0)
resmask = fullmask;
else {
int4 i=0;
resmask = 0;
if (cliploop) {
for(;i<inrefs.size();++i) {
if (parent->isLoopIn(i)) continue;
resmask |= getIn(i)->getNZMask();
}
}
else {
for(;i<inrefs.size();++i)
resmask |= getIn(i)->getNZMask();
}
}
break;
case CPUI_CALL:
case CPUI_CALLIND:
case CPUI_CPOOLREF:
if (isCalculatedBool())
resmask = 1; else
resmask = fullmask;
break;
default:
resmask = fullmask;
break;
}
return resmask;
}
int4 PcodeOp::compareOrder(const PcodeOp *bop) const
{
if (parent == bop->parent)
return (start.getOrder() < bop->start.getOrder()) ? -1 : 1;
FlowBlock *common = FlowBlock::findCommonBlock(parent,bop->parent);
if (common == parent)
return -1;
if (common == bop->parent)
return 1;
return 0;
}
void PcodeOpBank::addToCodeList(PcodeOp *op)
{
switch(op->code()) {
case CPUI_STORE:
op->codeiter = storelist.insert(storelist.end(),op);
break;
case CPUI_LOAD:
op->codeiter = loadlist.insert(loadlist.end(), op);
break;
case CPUI_RETURN:
op->codeiter = returnlist.insert(returnlist.end(),op);
break;
case CPUI_CALLOTHER:
op->codeiter = useroplist.insert(useroplist.end(),op);
break;
default:
break;
}
}
void PcodeOpBank::removeFromCodeList(PcodeOp *op)
{
switch(op->code()) {
case CPUI_STORE:
storelist.erase(op->codeiter);
break;
case CPUI_LOAD:
loadlist.erase(op->codeiter);
break;
case CPUI_RETURN:
returnlist.erase(op->codeiter);
break;
case CPUI_CALLOTHER:
useroplist.erase(op->codeiter);
break;
default:
break;
}
}
void PcodeOpBank::clearCodeLists(void)
{
storelist.clear();
loadlist.clear();
returnlist.clear();
useroplist.clear();
}
PcodeOp *PcodeOpBank::create(int4 inputs,const Address &pc)
{
PcodeOp *op = new PcodeOp(inputs,SeqNum(pc,uniqid++));
optree[op->getSeqNum()] = op;
op->setFlag(PcodeOp::dead); op->insertiter = deadlist.insert(deadlist.end(),op);
return op;
}
PcodeOp *PcodeOpBank::create(int4 inputs,const SeqNum &sq)
{
PcodeOp *op;
op = new PcodeOp(inputs,sq);
if (sq.getTime() >= uniqid)
uniqid = sq.getTime() + 1;
optree[op->getSeqNum()] = op;
op->setFlag(PcodeOp::dead); op->insertiter = deadlist.insert(deadlist.end(),op);
return op;
}
void PcodeOpBank::destroyDead(void)
{
list<PcodeOp *>::iterator iter;
PcodeOp *op;
iter = deadlist.begin();
while(iter!=deadlist.end()) {
op = *iter++;
destroy(op);
}
}
void PcodeOpBank::destroy(PcodeOp *op)
{
if (!op->isDead())
throw LowlevelError("Deleting integrated op");
optree.erase(op->getSeqNum());
deadlist.erase(op->insertiter);
removeFromCodeList(op);
deadandgone.push_back(op);
}
void PcodeOpBank::changeOpcode(PcodeOp *op,TypeOp *newopc)
{
if (op->opcode != (TypeOp *)0)
removeFromCodeList(op);
op->setOpcode( newopc );
addToCodeList(op);
}
void PcodeOpBank::markAlive(PcodeOp *op)
{
deadlist.erase(op->insertiter);
op->clearFlag(PcodeOp::dead);
op->insertiter = alivelist.insert(alivelist.end(),op);
}
void PcodeOpBank::markDead(PcodeOp *op)
{
alivelist.erase(op->insertiter);
op->setFlag(PcodeOp::dead);
op->insertiter = deadlist.insert(deadlist.end(),op);
}
void PcodeOpBank::insertAfterDead(PcodeOp *op,PcodeOp *prev)
{
if ((!op->isDead())||(!prev->isDead()))
throw LowlevelError("Dead move called on ops which aren't dead");
deadlist.erase(op->insertiter);
list<PcodeOp *>::iterator iter = prev->insertiter;
++iter;
op->insertiter = deadlist.insert(iter,op);
}
void PcodeOpBank::moveSequenceDead(PcodeOp *firstop,PcodeOp *lastop,PcodeOp *prev)
{
list<PcodeOp *>::iterator enditer = lastop->insertiter;
++enditer;
list<PcodeOp *>::iterator previter = prev->insertiter;
++previter;
if (previter != firstop->insertiter) deadlist.splice(previter,deadlist,firstop->insertiter,enditer);
}
void PcodeOpBank::markIncidentalCopy(PcodeOp *firstop,PcodeOp *lastop)
{
list<PcodeOp *>::iterator iter = firstop->insertiter;
list<PcodeOp *>::iterator enditer = lastop->insertiter;
++enditer;
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->code() == CPUI_COPY)
op->setAdditionalFlag(PcodeOp::incidental_copy);
}
}
PcodeOp *PcodeOpBank::target(const Address &addr) const
{
PcodeOpTree::const_iterator iter = optree.lower_bound(SeqNum(addr,0));
if (iter == optree.end()) return (PcodeOp *)0;
return (*iter).second->target();
}
PcodeOp *PcodeOpBank::findOp(const SeqNum &num) const
{
PcodeOpTree::const_iterator iter = optree.find(num);
if (iter == optree.end()) return (PcodeOp *)0;
return (*iter).second;
}
PcodeOp *PcodeOpBank::fallthru(const PcodeOp *op) const
{
PcodeOp *retop;
if (op->isDead()) {
list<PcodeOp *>::const_iterator iter = op->insertiter;
++iter;
if (iter != deadlist.end()) {
retop = *iter;
if (!retop->isInstructionStart()) return retop; }
--iter;
SeqNum max = op->getSeqNum();
while(!(*iter)->isInstructionStart()) --iter;
while((iter!=deadlist.end())&&(*iter != op)) {
if (max < (*iter)->getSeqNum())
max = (*iter)->getSeqNum();
++iter;
}
PcodeOpTree::const_iterator nextiter = optree.upper_bound(max);
if (nextiter == optree.end()) return (PcodeOp *)0;
retop = (*nextiter).second;
return retop;
}
else
return op->nextOp();
}
PcodeOpTree::const_iterator PcodeOpBank::begin(const Address &addr) const
{
return optree.lower_bound(SeqNum(addr,0));
}
PcodeOpTree::const_iterator PcodeOpBank::end(const Address &addr) const
{
return optree.upper_bound(SeqNum(addr,~((uintm)0)));
}
list<PcodeOp *>::const_iterator PcodeOpBank::begin(OpCode opc) const
{
switch(opc) {
case CPUI_STORE:
return storelist.begin();
case CPUI_LOAD:
return loadlist.begin();
case CPUI_RETURN:
return returnlist.begin();
case CPUI_CALLOTHER:
return useroplist.begin();
default:
break;
}
return alivelist.end();
}
list<PcodeOp *>::const_iterator PcodeOpBank::end(OpCode opc) const
{
switch(opc) {
case CPUI_STORE:
return storelist.end();
case CPUI_LOAD:
return loadlist.end();
case CPUI_RETURN:
return returnlist.end();
case CPUI_CALLOTHER:
return useroplist.end();
default:
break;
}
return alivelist.end();
}
void PcodeOpBank::clear(void)
{
list<PcodeOp *>::iterator iter;
for(iter=alivelist.begin();iter!=alivelist.end();++iter)
delete *iter;
for(iter=deadlist.begin();iter!=deadlist.end();++iter)
delete *iter;
for(iter=deadandgone.begin();iter!=deadandgone.end();++iter)
delete *iter;
optree.clear();
alivelist.clear();
deadlist.clear();
clearCodeLists();
deadandgone.clear();
uniqid = 0;
}
static int4 functionalEqualityLevel0(Varnode *vn1,Varnode *vn2)
{ if (vn1==vn2) return 0;
if (vn1->getSize() != vn2->getSize()) return -1;
if (vn1->isConstant()) {
if (vn2->isConstant()) {
return (vn1->getOffset() == vn2->getOffset()) ? 0 : -1;
}
return -1;
}
if (vn2->isConstant()) return -1;
if (vn1->isWritten() && vn2->isWritten()) return 1;
return -1;
}
int4 functionalEqualityLevel(Varnode *vn1,Varnode *vn2,Varnode **res1,Varnode **res2)
{
int4 testval = functionalEqualityLevel0(vn1,vn2);
if (testval != 1) return testval;
PcodeOp *op1 = vn1->getDef();
PcodeOp *op2 = vn2->getDef();
OpCode opc = op1->code();
if (opc != op2->code()) return -1;
int4 num = op1->numInput();
if (num != op2->numInput()) return -1;
if (op1->isMarker()) return -1;
if (op2->isCall()) return -1;
if (opc == CPUI_LOAD) {
if (op1->getAddr() != op2->getAddr()) return -1;
}
if (num >= 3) {
if (opc != CPUI_PTRADD) return -1; if (op1->getIn(2)->getOffset() != op2->getIn(2)->getOffset()) return -1; num = 2; }
for(int4 i=0;i<num;++i) {
res1[i] = op1->getIn(i);
res2[i] = op2->getIn(i);
}
testval = functionalEqualityLevel0(res1[0],res2[0]);
if (testval == 0) { if (num==1) return 0;
testval = functionalEqualityLevel0(res1[1],res2[1]);
if (testval==0) return 0;
if (testval < 0) return -1;
res1[0] = res1[1]; res2[0] = res2[1];
return 1;
}
if (num == 1) return testval;
int4 testval2 = functionalEqualityLevel0(res1[1],res2[1]);
if (testval2 == 0) { return testval;
}
int4 unmatchsize;
if ((testval==1)&&(testval2==1))
unmatchsize = 2;
else
unmatchsize = -1;
if (!op1->isCommutative()) return unmatchsize;
int4 comm1 = functionalEqualityLevel0(res1[0],res2[1]);
int4 comm2 = functionalEqualityLevel0(res1[1],res2[0]);
if ((comm1==0) && (comm2==0))
return 0;
if ((comm1<0)||(comm2<0))
return unmatchsize;
if (comm1==0) { res1[0] = res1[1]; return 1;
}
if (comm2==0) { res2[0] = res2[1]; return 1;
}
if (unmatchsize == 2) return 2; Varnode *tmpvn = res2[0]; res2[0] = res2[1];
res2[1] = tmpvn;
return 2;
}
bool functionalEquality(Varnode *vn1,Varnode *vn2)
{
Varnode *buf1[2];
Varnode *buf2[2];
return (functionalEqualityLevel(vn1,vn2,buf1,buf2)==0);
}
bool functionalDifference(Varnode *vn1,Varnode *vn2,int4 depth)
{
PcodeOp *op1,*op2;
int4 i,num;
if (vn1 == vn2) return false;
if ((!vn1->isWritten())||(!vn2->isWritten())) {
if (vn1->isConstant() && vn2->isConstant())
return !(vn1->getAddr()==vn2->getAddr());
if (vn1->isInput()&&vn2->isInput()) return false; if (vn1->isFree()||vn2->isFree()) return false; return true;
}
op1 = vn1->getDef();
op2 = vn2->getDef();
if (op1->code() != op2->code()) return true;
num = op1->numInput();
if (num != op2->numInput()) return true;
if (depth==0) return true; depth -= 1;
for(i=0;i<num;++i)
if (functionalDifference(op1->getIn(i),op2->getIn(i),depth))
return true;
return false;
}