#include "ruleaction.hh"
#include "coreaction.hh"
#include "subflow.hh"
#include "rangeutil.hh"
int4 RuleEarlyRemoval::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn;
if (op->isCall()) return 0; if (op->isIndirectSource()) return 0;
vn = op->getOut();
if (vn == (Varnode *)0) return 0;
if (!vn->hasNoDescend()) return 0;
if (vn->isAutoLive()) return 0;
AddrSpace *spc = vn->getSpace();
if (spc->doesDeadcode())
if (!data.deadRemovalAllowedSeen(spc))
return 0;
data.opDestroy(op); return 1;
}
Varnode *RuleCollectTerms::getMultCoeff(Varnode *vn,uintb &coef)
{
PcodeOp *testop;
if (!vn->isWritten()) {
coef = 1;
return vn;
}
testop = vn->getDef();
if ((testop->code() != CPUI_INT_MULT)||(!testop->getIn(1)->isConstant())) {
coef = 1;
return vn;
}
coef = testop->getIn(1)->getOffset();
return testop->getIn(0);
}
void RuleCollectTerms::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ADD);
}
int4 RuleCollectTerms::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *nextop = op->getOut()->loneDescend();
if ((nextop!=(PcodeOp *)0)&&(nextop->code()==CPUI_INT_ADD)) return 0;
TermOrder termorder(op);
termorder.collect(); termorder.sortTerms(); Varnode *vn1,*vn2;
uintb coef1,coef2;
const vector<PcodeOpEdge *> &order( termorder.getSort() );
int4 i=0;
if (!order[0]->getVarnode()->isConstant()) {
for(i=1;i<order.size();++i) {
vn1 = order[i-1]->getVarnode();
vn2 = order[i]->getVarnode();
if (vn2->isConstant()) break;
vn1 = getMultCoeff(vn1,coef1);
vn2 = getMultCoeff(vn2,coef2);
if (vn1 == vn2) { if (order[i-1]->getMultiplier() != (PcodeOp *)0)
return data.distributeIntMultAdd(order[i-1]->getMultiplier()) ? 1 : 0;
if (order[i]->getMultiplier() != (PcodeOp *)0)
return data.distributeIntMultAdd(order[i]->getMultiplier()) ? 1 : 0;
coef1 = (coef1 + coef2) & calc_mask(vn1->getSize()); Varnode *newcoeff = data.newConstant(vn1->getSize(),coef1);
Varnode *zerocoeff = data.newConstant(vn1->getSize(),0);
data.opSetInput(order[i-1]->getOp(),zerocoeff,order[i-1]->getSlot());
if (coef1 == 0)
data.opSetInput(order[i]->getOp(),newcoeff,order[i]->getSlot());
else {
nextop = data.newOp(2,order[i]->getOp()->getAddr());
vn2 = data.newUniqueOut(vn1->getSize(),nextop);
data.opSetOpcode(nextop,CPUI_INT_MULT);
data.opSetInput(nextop,vn1,0);
data.opSetInput(nextop,newcoeff,1);
data.opInsertBefore(nextop,order[i]->getOp());
data.opSetInput(order[i]->getOp(),vn2,order[i]->getSlot());
}
return 1;
}
}
}
coef1 = 0;
int4 nonzerocount = 0; int4 lastconst=0;
for(int4 j=order.size()-1;j>=i;--j) {
if (order[j]->getMultiplier() != (PcodeOp *)0) continue;
vn1 = order[j]->getVarnode();
uintb val = vn1->getOffset();
if (val != 0) {
nonzerocount += 1;
coef1 += val; lastconst = j;
}
}
if (nonzerocount <= 1) return 0; vn1 = order[lastconst]->getVarnode();
coef1 &= calc_mask(vn1->getSize());
for(int4 j=lastconst+1;j<order.size();++j)
if (order[j]->getMultiplier() == (PcodeOp *)0)
data.opSetInput(order[j]->getOp(),data.newConstant(vn1->getSize(),0),order[j]->getSlot());
data.opSetInput(order[lastconst]->getOp(),data.newConstant(vn1->getSize(),coef1),order[lastconst]->getSlot());
return 1;
}
void RuleSelectCse::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
oplist.push_back(CPUI_INT_SRIGHT); }
int4 RuleSelectCse::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
list<PcodeOp *>::const_iterator iter;
OpCode opc = op->code();
PcodeOp *otherop;
uintm hash;
vector< pair<uintm,PcodeOp *> > list;
vector<Varnode *> vlist;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
otherop = *iter;
if (otherop->code() != opc) continue;
hash = otherop->getCseHash();
if (hash == 0) continue;
list.push_back(pair<uintm,PcodeOp *>(hash,otherop));
}
if (list.size()<=1) return 0;
cseEliminateList(data,list,vlist);
if (vlist.empty()) return 0;
return 1;
}
void RulePiece2Zext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RulePiece2Zext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constvn;
constvn = op->getIn(0); if (!constvn->isConstant()) return 0; if (constvn->getOffset() != 0) return 0; data.opRemoveInput(op,0); data.opSetOpcode(op,CPUI_INT_ZEXT);
return 1;
}
void RulePiece2Sext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RulePiece2Sext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *shiftout,*x;
PcodeOp *shiftop;
shiftout = op->getIn(0);
if (!shiftout->isWritten()) return 0;
shiftop = shiftout->getDef();
if (shiftop->code() != CPUI_INT_SRIGHT) return 0;
if (!shiftop->getIn(1)->isConstant()) return 0;
int4 n = shiftop->getIn(1)->getOffset();
x = shiftop->getIn(0);
if (x != op->getIn(1)) return 0;
if (n != 8*x->getSize() -1) return 0;
data.opRemoveInput(op,0);
data.opSetOpcode(op,CPUI_INT_SEXT);
return 1;
}
void RuleBxor2NotEqual::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_XOR);
}
int4 RuleBxor2NotEqual::applyOp(PcodeOp *op,Funcdata &data)
{
data.opSetOpcode(op,CPUI_INT_NOTEQUAL);
return 1;
}
void RuleOrMask::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_OR);
}
int4 RuleOrMask::applyOp(PcodeOp *op,Funcdata &data)
{
int4 size = op->getOut()->getSize();
if (size > sizeof(uintb)) return 0; Varnode *constvn;
constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
uintb val = constvn->getOffset();
uintb mask = calc_mask(size);
if ((val&mask) != mask) return 0;
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,constvn,0);
data.opRemoveInput(op,1);
return 1;
}
void RuleAndMask::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleAndMask::applyOp(PcodeOp *op,Funcdata &data)
{
uintb mask1,mask2,andmask;
int4 size = op->getOut()->getSize();
Varnode *vn;
if (size > sizeof(uintb)) return 0; mask1 = op->getIn(0)->getNZMask();
if (mask1 == 0)
andmask = 0;
else {
mask2 = op->getIn(1)->getNZMask();
andmask = mask1 & mask2;
}
if (andmask==0) vn = data.newConstant( size, 0);
else if ((andmask & op->getOut()->getConsume())==0)
vn = data.newConstant( size, 0);
else if (andmask == mask1) {
if (!op->getIn(1)->isConstant()) return 0;
vn = op->getIn(0); }
else
return 0;
if (!vn->isHeritageKnown()) return 0;
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
data.opSetInput(op,vn,0);
return 1;
}
void RuleOrConsume::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_OR);
oplist.push_back(CPUI_INT_XOR);
}
int4 RuleOrConsume::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *outvn = op->getOut();
int4 size = outvn->getSize();
if (size > sizeof(uintb)) return 0; uintb consume = outvn->getConsume();
if ((consume & op->getIn(0)->getNZMask()) == 0) {
data.opRemoveInput(op,0);
data.opSetOpcode(op, CPUI_COPY);
return 1;
}
else if ((consume & op->getIn(1)->getNZMask()) == 0) {
data.opRemoveInput(op,1);
data.opSetOpcode(op, CPUI_COPY);
return 1;
}
return 0;
}
void RuleOrCollapse::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_OR);
}
int4 RuleOrCollapse::applyOp(PcodeOp *op,Funcdata &data)
{
uintb val,mask;
int4 size = op->getOut()->getSize();
Varnode *vn;
vn = op->getIn(1);
if (!vn->isConstant()) return 0;
if (size > sizeof(uintb)) return 0; mask = op->getIn(0)->getNZMask();
val = vn->getOffset();
if ((mask | val)!=val) return 0;
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,0);
return 1;
}
void RuleAndOrLump::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
oplist.push_back(CPUI_INT_OR);
oplist.push_back(CPUI_INT_XOR);
}
int4 RuleAndOrLump::applyOp(PcodeOp *op,Funcdata &data)
{
OpCode opc;
Varnode *vn1,*basevn;
PcodeOp *op2;
opc = op->code();
if (!op->getIn(1)->isConstant()) return 0;
vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
op2 = vn1->getDef();
if (op2->code() != opc) return 0; if (!op2->getIn(1)->isConstant()) return 0;
basevn = op2->getIn(0);
if (basevn->isFree()) return 0;
uintb val = op->getIn(1)->getOffset();
uintb val2 = op2->getIn(1)->getOffset();
if (opc == CPUI_INT_AND)
val &= val2;
else if (opc == CPUI_INT_OR)
val |= val2;
else if (opc == CPUI_INT_XOR)
val ^= val2;
data.opSetInput(op,basevn,0);
data.opSetInput(op,data.newConstant(basevn->getSize(),val),1);
return 1;
}
void RuleNegateIdentity::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NEGATE);
}
int4 RuleNegateIdentity::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
PcodeOp *logicOp = *iter;
OpCode opc = logicOp->code();
if (opc != CPUI_INT_AND && opc != CPUI_INT_OR && opc != CPUI_INT_XOR)
continue;
int4 slot = logicOp->getSlot(outVn);
if (logicOp->getIn(1-slot) != vn) continue;
uintb value = 0;
if (opc != CPUI_INT_AND)
value = calc_mask(vn->getSize());
data.opSetInput(logicOp,data.newConstant(vn->getSize(),value),0);
data.opRemoveInput(logicOp,1);
data.opSetOpcode(logicOp,CPUI_COPY);
return 1;
}
return 0;
}
void RuleShiftBitops::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LEFT);
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_SUBPIECE);
oplist.push_back(CPUI_INT_MULT);
}
int4 RuleShiftBitops::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constvn = op->getIn(1);
if (!constvn->isConstant()) return 0; Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
if (vn->getSize() > sizeof(uintb)) return 0; int4 sa;
bool leftshift;
switch(op->code()) {
case CPUI_INT_LEFT:
sa = (int4) constvn->getOffset();
leftshift = true;
break;
case CPUI_INT_RIGHT:
sa = (int4) constvn->getOffset();
leftshift = false;
break;
case CPUI_SUBPIECE:
sa = (int4) constvn->getOffset();
sa = sa * 8;
leftshift = false;
break;
case CPUI_INT_MULT:
sa = leastsigbit_set(constvn->getOffset());
if (sa == -1) return 0;
leftshift = true;
break;
default:
return 0; }
PcodeOp *bitop = vn->getDef();
switch(bitop->code()) {
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
break;
case CPUI_INT_MULT:
case CPUI_INT_ADD:
if (!leftshift) return 0;
break;
default:
return 0;
}
int4 i;
for(i=0;i<bitop->numInput();++i) {
uintb nzm = bitop->getIn(i)->getNZMask();
uintb mask = calc_mask(op->getOut()->getSize());
if (leftshift)
nzm = pcode_left(nzm,sa);
else
nzm = pcode_right(nzm,sa);
if ((nzm&mask)==(uintb)0) break;
}
if (i==bitop->numInput()) return 0;
switch(bitop->code()) {
case CPUI_INT_MULT:
case CPUI_INT_AND:
vn = data.newConstant(vn->getSize(),0);
data.opSetInput(op,vn,0); break;
case CPUI_INT_ADD:
case CPUI_INT_XOR:
case CPUI_INT_OR:
vn = bitop->getIn(1-i);
if (!vn->isHeritageKnown()) return 0;
data.opSetInput(op,vn,0);
break;
default:
break;
}
return 1;
}
void RuleRightShiftAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleRightShiftAnd::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant()) return 0;
Varnode *inVn = op->getIn(0);
if (!inVn->isWritten()) return 0;
PcodeOp *andOp = inVn->getDef();
if (andOp->code() != CPUI_INT_AND) return 0;
Varnode *maskVn = andOp->getIn(1);
if (!maskVn->isConstant()) return 0;
int4 sa = (int4)constVn->getOffset();
uintb mask = maskVn->getOffset() >> sa;
Varnode *rootVn = andOp->getIn(0);
uintb full = calc_mask(rootVn->getSize()) >> sa;
if (full != mask) return 0;
if (rootVn->isFree()) return 0;
data.opSetInput(op, rootVn, 0); return 1;
}
void RuleIntLessEqual::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LESSEQUAL);
oplist.push_back(CPUI_INT_SLESSEQUAL);
}
int4 RuleIntLessEqual::applyOp(PcodeOp *op,Funcdata &data)
{
if (data.replaceLessequal(op))
return 1;
return 0;
}
void RuleEquality::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_EQUAL);
oplist.push_back(CPUI_INT_NOTEQUAL);
}
int4 RuleEquality::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn;
if (!functionalEquality(op->getIn(0),op->getIn(1)))
return 0;
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
vn = data.newConstant(1,(op->code()==CPUI_INT_EQUAL) ? 1: 0);
data.opSetInput(op,vn,0);
return 1;
}
void RuleTermOrder::getOpList(vector<uint4> &oplist) const
{
uint4 list[]={ CPUI_INT_EQUAL, CPUI_INT_NOTEQUAL, CPUI_INT_ADD, CPUI_INT_CARRY,
CPUI_INT_SCARRY, CPUI_INT_XOR, CPUI_INT_AND, CPUI_INT_OR,
CPUI_INT_MULT, CPUI_BOOL_XOR, CPUI_BOOL_AND, CPUI_BOOL_OR,
CPUI_FLOAT_EQUAL, CPUI_FLOAT_NOTEQUAL, CPUI_FLOAT_ADD,
CPUI_FLOAT_MULT };
oplist.insert(oplist.end(),list,list+16);
}
int4 RuleTermOrder::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn1 = op->getIn(0);
Varnode *vn2 = op->getIn(1);
if (vn1->isConstant() && (!vn2->isConstant())) {
data.opSwapInput(op,0,1); return 1;
}
return 0;
}
void RulePullsubMulti::minMaxUse(Varnode *vn,int4 &maxByte,int4 &minByte)
{
list<PcodeOp *>::const_iterator iter,enditer;
enditer = vn->endDescend();
int4 inSize = vn->getSize();
maxByte = -1;
minByte = inSize;
for(iter=vn->beginDescend();iter!=enditer;++iter) {
PcodeOp *op = *iter;
OpCode opc = op->code();
if (opc == CPUI_SUBPIECE) {
int4 min = (int4)op->getIn(1)->getOffset();
int4 max = min + op->getOut()->getSize() - 1;
if (min < minByte)
minByte = min;
if (max > maxByte)
maxByte = max;
}
else { maxByte = inSize - 1;
minByte = 0;
return;
}
}
}
void RulePullsubMulti::replaceDescendants(Varnode *origVn,Varnode *newVn,int4 maxByte,int4 minByte,Funcdata &data)
{
list<PcodeOp *>::const_iterator iter,enditer;
iter = origVn->beginDescend();
enditer = origVn->endDescend();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->code() == CPUI_SUBPIECE) {
int4 truncAmount = (int4)op->getIn(1)->getOffset();
int4 outSize = op->getOut()->getSize();
data.opSetInput(op,newVn,0);
if (newVn->getSize() == outSize) {
if (truncAmount != minByte)
throw LowlevelError("Could not perform -replaceDescendants-");
data.opSetOpcode(op, CPUI_COPY);
data.opRemoveInput(op, 1);
}
else if (newVn->getSize() > outSize) {
int4 newTrunc = truncAmount - minByte;
if (newTrunc < 0)
throw LowlevelError("Could not perform -replaceDescendants-");
if (newTrunc != truncAmount) {
data.opSetInput(op, data.newConstant(4, (uintb)newTrunc), 1);
}
}
else
throw LowlevelError("Could not perform -replaceDescendants-");
}
else
throw LowlevelError("Could not perform -replaceDescendants-");
}
}
bool RulePullsubMulti::acceptableSize(int4 size)
{
if (size == 0) return false;
if (size >= 8) return true;
if (size == 1 || size == 2 || size == 4 || size == 8)
return true;
return false;
}
Varnode *RulePullsubMulti::buildSubpiece(Varnode *basevn,uint4 outsize,uint4 shift,Funcdata &data)
{
Address newaddr;
PcodeOp *new_op;
Varnode *outvn;
if (basevn->isInput()) {
BlockBasic *bb = (BlockBasic *)data.getBasicBlocks().getBlock(0);
newaddr = bb->getStart();
}
else {
if (!basevn->isWritten()) throw LowlevelError("Undefined pullsub");
newaddr = basevn->getDef()->getAddr();
}
Address smalladdr1;
bool usetmp = false;
if (basevn->getAddr().isJoin()) {
usetmp = true;
JoinRecord *joinrec = data.getArch()->findJoin(basevn->getOffset());
if (joinrec->numPieces() > 1) { uint4 skipleft = shift;
for(int4 i=joinrec->numPieces()-1;i>=0;--i) { const VarnodeData &vdata(joinrec->getPiece(i));
if (skipleft >= vdata.size) {
skipleft -= vdata.size;
}
else {
if (skipleft + outsize > vdata.size)
break;
if (vdata.space->isBigEndian())
smalladdr1 = vdata.getAddr() + (vdata.size - (outsize + skipleft));
else
smalladdr1 = vdata.getAddr() + skipleft;
usetmp = false;
break;
}
}
}
}
else {
if (!basevn->getSpace()->isBigEndian())
smalladdr1 = basevn->getAddr()+shift;
else
smalladdr1 = basevn->getAddr()+(basevn->getSize()-(shift+outsize));
}
new_op = data.newOp(2,newaddr);
data.opSetOpcode(new_op,CPUI_SUBPIECE);
if (usetmp)
outvn = data.newUniqueOut(outsize,new_op);
else {
smalladdr1.renormalize(outsize);
outvn = data.newVarnodeOut(outsize,smalladdr1,new_op);
}
data.opSetInput(new_op,basevn,0);
data.opSetInput(new_op,data.newConstant(4,shift),1);
if (basevn->isInput())
data.opInsertBegin(new_op,(BlockBasic *)data.getBasicBlocks().getBlock(0));
else
data.opInsertAfter(new_op,basevn->getDef());
return outvn;
}
Varnode *RulePullsubMulti::findSubpiece(Varnode *basevn,uint4 outsize,uint4 shift)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *prevop;
for(iter=basevn->beginDescend();iter!=basevn->endDescend();++iter) {
prevop = *iter;
if (prevop->code() != CPUI_SUBPIECE) continue; if (basevn->isInput() && (prevop->getParent()->getIndex()!=0)) continue;
if (!basevn->isWritten()) continue;
if (basevn->getDef()->getParent() != prevop->getParent()) continue;
if ((prevop->getIn(0) == basevn)&&
(prevop->getOut()->getSize() == outsize)&&
(prevop->getIn(1)->getOffset()==shift)) {
return prevop->getOut();
}
}
return (Varnode *)0;
}
void RulePullsubMulti::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RulePullsubMulti::applyOp(PcodeOp *op,Funcdata &data)
{
int4 maxByte,minByte,newSize;
Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
PcodeOp *mult = vn->getDef();
if (mult->code()!=CPUI_MULTIEQUAL) return 0;
if (mult->getParent()->hasLoopIn()) return 0;
minMaxUse(vn, maxByte, minByte); newSize = maxByte - minByte + 1;
if (maxByte < minByte || (newSize >= vn->getSize()))
return 0; if (!acceptableSize(newSize)) return 0;
Varnode *outvn = op->getOut();
if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0;
int4 branches = mult->numInput();
uintb consume = calc_mask(newSize) << 8*minByte;
consume = ~consume; for(int4 i=0;i<branches;++i) {
Varnode *inVn = mult->getIn(i);
if ((consume & inVn->getConsume()) != 0) { if (minByte == 0 && inVn->isWritten()) {
PcodeOp *defOp = inVn->getDef();
OpCode opc = defOp->code();
if (opc == CPUI_INT_ZEXT || opc == CPUI_INT_SEXT) {
if (newSize == defOp->getIn(0)->getSize())
continue; }
}
return 0;
}
}
Address smalladdr2;
if (!vn->getSpace()->isBigEndian())
smalladdr2 = vn->getAddr()+minByte;
else
smalladdr2 = vn->getAddr()+(vn->getSize()-maxByte-1);
vector<Varnode *> params;
for(int4 i=0;i<branches;++i) {
Varnode *vn_piece = mult->getIn(i);
Varnode *vn_sub = findSubpiece(vn_piece,newSize,minByte);
if (vn_sub == (Varnode *)0) vn_sub = buildSubpiece(vn_piece,newSize,minByte,data);
params.push_back(vn_sub);
}
PcodeOp *new_multi = data.newOp(params.size(),mult->getAddr());
smalladdr2.renormalize(newSize);
Varnode *new_vn = data.newVarnodeOut(newSize,smalladdr2,new_multi);
data.opSetOpcode(new_multi,CPUI_MULTIEQUAL);
data.opSetAllInput(new_multi,params);
data.opInsertBegin(new_multi,mult->getParent());
replaceDescendants(vn, new_vn, maxByte, minByte, data);
return 1;
}
void RulePullsubIndirect::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RulePullsubIndirect::applyOp(PcodeOp *op,Funcdata &data)
{
int4 maxByte,minByte,newSize;
Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
PcodeOp *indir = vn->getDef();
if (indir->code()!=CPUI_INDIRECT) return 0;
if (indir->getIn(1)->getSpace()->getType()!=IPTR_IOP) return 0;
PcodeOp *targ_op = PcodeOp::getOpFromConst(indir->getIn(1)->getAddr());
if (targ_op->isDead()) return 0;
if (vn->isAddrForce()) return 0;
RulePullsubMulti::minMaxUse(vn, maxByte, minByte);
newSize = maxByte - minByte + 1;
if (maxByte < minByte || (newSize >= vn->getSize()))
return 0;
if (!RulePullsubMulti::acceptableSize(newSize)) return 0;
Varnode *outvn = op->getOut();
if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0;
uintb consume = calc_mask(newSize) << 8 * minByte;
consume = ~consume;
if ((consume & indir->getIn(0)->getConsume())!=0) return 0;
Varnode *small2;
Address smalladdr2;
PcodeOp *new_ind;
if (!vn->getSpace()->isBigEndian())
smalladdr2 = vn->getAddr()+minByte;
else
smalladdr2 = vn->getAddr()+(vn->getSize()-maxByte-1);
if (indir->isIndirectCreation()) {
bool possibleout = !indir->getIn(0)->isIndirectZero();
new_ind = data.newIndirectCreation(targ_op,smalladdr2,newSize,possibleout);
small2 = new_ind->getOut();
}
else {
Varnode *basevn = indir->getIn(0);
Varnode *small1 = RulePullsubMulti::findSubpiece(basevn,newSize,op->getIn(1)->getOffset());
if (small1 == (Varnode *)0)
small1 = RulePullsubMulti::buildSubpiece(basevn,newSize,op->getIn(1)->getOffset(),data);
new_ind = data.newOp(2,indir->getAddr());
data.opSetOpcode(new_ind,CPUI_INDIRECT);
small2 = data.newVarnodeOut(newSize,smalladdr2,new_ind);
data.opSetInput(new_ind,small1,0);
data.opSetInput(new_ind,data.newVarnodeIop(targ_op),1);
data.opInsertBefore(new_ind,indir);
}
RulePullsubMulti::replaceDescendants(vn, small2, maxByte, minByte, data);
return 1;
}
PcodeOp *RulePushMulti::findSubstitute(Varnode *in1,Varnode *in2,BlockBasic *bb,PcodeOp *earliest)
{
list<PcodeOp *>::const_iterator iter,enditer;
iter = in1->beginDescend();
enditer = in1->endDescend();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->getParent() != bb) continue;
if (op->code() != CPUI_MULTIEQUAL) continue;
if (op->getIn(0) != in1) continue;
if (op->getIn(1) != in2) continue;
return op;
}
if (in1 == in2) return (PcodeOp *)0;
Varnode *buf1[2];
Varnode *buf2[2];
if (0!=functionalEqualityLevel(in1,in2,buf1,buf2)) return (PcodeOp *)0;
PcodeOp *op1 = in1->getDef(); PcodeOp *op2 = in2->getDef();
for(int4 i=0;i<op1->numInput();++i) {
Varnode *vn = op1->getIn(i);
if (vn->isConstant()) continue;
if (vn == op2->getIn(i)) return cseFindInBlock(op1,vn,bb,earliest); }
return (PcodeOp *)0;
}
void RulePushMulti::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_MULTIEQUAL);
}
int4 RulePushMulti::applyOp(PcodeOp *op,Funcdata &data)
{
if (op->numInput() != 2) return 0;
Varnode *in1 = op->getIn(0);
Varnode *in2 = op->getIn(1);
if (!in1->isWritten()) return 0;
if (!in2->isWritten()) return 0;
if (in1->isSpacebase()) return 0;
if (in2->isSpacebase()) return 0;
Varnode *buf1[2];
Varnode *buf2[2];
int4 res = functionalEqualityLevel(in1,in2,buf1,buf2);
if (res < 0) return 0;
if (res > 1) return 0;
PcodeOp *op1 = in1->getDef();
if (op1->code() == CPUI_SUBPIECE) return 0;
BlockBasic *bl = op->getParent();
PcodeOp *earliest = earliestUseInBlock(op->getOut(),bl);
if (op1->code() == CPUI_COPY) { if (res==0) return 0;
PcodeOp *substitute = findSubstitute(buf1[0],buf2[0],bl,earliest);
if (substitute == (PcodeOp *)0) return 0;
data.totalReplace(op->getOut(),substitute->getOut());
data.opDestroy(op);
return 1;
}
PcodeOp *op2 = in2->getDef();
if (in1->loneDescend() != op) return 0;
if (in2->loneDescend() != op) return 0;
Varnode *outvn = op->getOut();
data.opSetOutput(op1,outvn); data.opUninsert(op1); if (res == 1) {
int4 slot1 = op1->getSlot(buf1[0]);
PcodeOp *substitute = findSubstitute(buf1[0],buf2[0],bl,earliest);
if (substitute == (PcodeOp *)0) {
substitute = data.newOp(2,op->getAddr());
data.opSetOpcode(substitute,CPUI_MULTIEQUAL);
if ((buf1[0]->getAddr() == buf2[0]->getAddr())&&(!buf1[0]->isAddrTied()))
data.newVarnodeOut(buf1[0]->getSize(),buf1[0]->getAddr(),substitute);
else
data.newUniqueOut(buf1[0]->getSize(),substitute);
data.opSetInput(substitute,buf1[0],0);
data.opSetInput(substitute,buf2[0],1);
data.opInsertBegin(substitute,bl);
}
data.opSetInput(op1,substitute->getOut(),slot1); data.opInsertAfter(op1,substitute); }
else
data.opInsertBegin(op1,bl); data.opDestroy(op); data.opDestroy(op2); return 1;
}
void RuleNotDistribute::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_NEGATE);
}
int4 RuleNotDistribute::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *compop = op->getIn(0)->getDef();
PcodeOp *newneg1,*newneg2;
Varnode *newout1,*newout2;
OpCode opc;
if (compop == (PcodeOp *)0) return 0;
switch(compop->code()) {
case CPUI_BOOL_AND:
opc = CPUI_BOOL_OR;
break;
case CPUI_BOOL_OR:
opc = CPUI_BOOL_AND;
break;
default:
return 0;
}
newneg1 = data.newOp(1,op->getAddr());
newout1 = data.newUniqueOut(1,newneg1);
data.opSetOpcode(newneg1,CPUI_BOOL_NEGATE);
data.opSetInput(newneg1,compop->getIn(0),0);
data.opInsertBefore(newneg1,op);
newneg2 = data.newOp(1,op->getAddr());
newout2 = data.newUniqueOut(1,newneg2);
data.opSetOpcode(newneg2,CPUI_BOOL_NEGATE);
data.opSetInput(newneg2,compop->getIn(1),0);
data.opInsertBefore(newneg2,op);
data.opSetOpcode(op,opc);
data.opSetInput(op,newout1,0);
data.opInsertInput(op,newout2,1);
return 1;
}
void RuleHighOrderAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleHighOrderAnd::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *xalign;
Varnode *cvn1 = op->getIn(1);
if (!cvn1->isConstant()) return 0;
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *addop = op->getIn(0)->getDef();
if (addop->code() != CPUI_INT_ADD) return 0;
uintb val = cvn1->getOffset();
int4 size = cvn1->getSize();
if (((val-1)|val) != calc_mask(size)) return 0;
Varnode *cvn2 = addop->getIn(1);
if (cvn2->isConstant()) {
xalign = addop->getIn(0);
if (xalign->isFree()) return 0;
uintb mask1 = xalign->getNZMask();
if ((mask1 & val)!=mask1) return 0;
data.opSetOpcode(op,CPUI_INT_ADD);
data.opSetInput(op,xalign,0);
val = val & cvn2->getOffset();
data.opSetInput(op,data.newConstant(size,val),1);
return 1;
}
else {
if (addop->getOut()->loneDescend() != op) return 0;
for(int4 i=0;i<2;++i) {
Varnode *zerovn = addop->getIn(i);
uintb mask2 = zerovn->getNZMask();
if ((mask2 & val)!=mask2) continue; Varnode *nonzerovn = addop->getIn(1-i);
if (!nonzerovn->isWritten()) continue;
PcodeOp *addop2 = nonzerovn->getDef();
if (addop2->code() != CPUI_INT_ADD) continue;
if (nonzerovn->loneDescend() != addop) continue;
cvn2 = addop2->getIn(1);
if (!cvn2->isConstant()) continue;
xalign = addop2->getIn(0);
mask2 = xalign->getNZMask();
if ((mask2 & val)!=mask2) continue;
val = val & cvn2->getOffset();
data.opSetInput(addop2,data.newConstant(size,val),1);
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
}
return 0;
}
void RuleAndDistribute::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleAndDistribute::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *orvn,*othervn,*newvn1,*newvn2;
PcodeOp *orop = (PcodeOp *)0;
PcodeOp *newop1,*newop2;
uintb ormask1,ormask2,othermask,fullmask;
int4 i,size;
size = op->getOut()->getSize();
if (size > sizeof(uintb)) return 0; fullmask = calc_mask(size);
for(i=0;i<2;++i) {
othervn = op->getIn(1-i);
if (!othervn->isHeritageKnown()) continue;
orvn = op->getIn(i);
orop = orvn->getDef();
if (orop == (PcodeOp *)0) continue;
if (orop->code() != CPUI_INT_OR) continue;
if (!orop->getIn(0)->isHeritageKnown()) continue;
if (!orop->getIn(1)->isHeritageKnown()) continue;
othermask = othervn->getNZMask();
if (othermask == 0) continue; if (othermask == fullmask) continue; ormask1 = orop->getIn(0)->getNZMask();
if ((ormask1 & othermask)==0) break; ormask2 = orop->getIn(1)->getNZMask();
if ((ormask2 & othermask)==0) break; if (othervn->isConstant()) {
if ((ormask1 & othermask) == ormask1) break; if ((ormask2 & othermask) == ormask2) break;
}
}
if (i==2) return 0;
newop1 = data.newOp(2,op->getAddr()); newvn1 = data.newUniqueOut(size,newop1);
data.opSetOpcode(newop1,CPUI_INT_AND);
data.opSetInput(newop1, orop->getIn(0), 0); data.opSetInput(newop1, othervn, 1);
data.opInsertBefore(newop1, op);
newop2 = data.newOp(2,op->getAddr()); newvn2 = data.newUniqueOut(size,newop2);
data.opSetOpcode(newop2,CPUI_INT_AND);
data.opSetInput(newop2, orop->getIn(1), 0); data.opSetInput(newop2, othervn, 1);
data.opInsertBefore(newop2, op);
data.opSetInput( op, newvn1, 0); data.opSetInput( op, newvn2, 1);
data.opSetOpcode(op, CPUI_INT_OR);
return 1;
}
void RuleLessOne::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LESS);
oplist.push_back(CPUI_INT_LESSEQUAL);
}
int4 RuleLessOne::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
uintb val = constvn->getOffset();
if ((op->code()==CPUI_INT_LESS)&&(val != 1)) return 0;
if ((op->code()==CPUI_INT_LESSEQUAL)&&(val != 0)) return 0;
data.opSetOpcode(op,CPUI_INT_EQUAL);
if (val != 0)
data.opSetInput(op,data.newConstant(constvn->getSize(),0),1);
return 1;
}
void RuleRangeMeld::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_OR);
oplist.push_back(CPUI_BOOL_AND);
}
int4 RuleRangeMeld::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *sub1,*sub2;
Varnode *vn1,*vn2;
Varnode *A1,*A2;
int4 restype;
vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
vn2 = op->getIn(1);
if (!vn2->isWritten()) return 0;
sub1 = vn1->getDef();
if (!sub1->isBoolOutput())
return 0;
sub2 = vn2->getDef();
if (!sub2->isBoolOutput())
return 0;
CircleRange range1(true);
Varnode *markup = (Varnode *)0;
A1 = range1.pullBack(sub1,&markup,false);
if (A1 == (Varnode *)0) return 0;
CircleRange range2(true);
A2 = range2.pullBack(sub2,&markup,false);
if (A2 == (Varnode *)0) return 0;
if (sub1->code() == CPUI_BOOL_NEGATE) { if (!A1->isWritten()) return 0;
A1 = range1.pullBack(A1->getDef(),&markup,false);
if (A1 == (Varnode *)0) return 0;
}
if (sub2->code() == CPUI_BOOL_NEGATE) { if (!A2->isWritten()) return 0;
A2 = range2.pullBack(A2->getDef(),&markup,false);
if (A2 == (Varnode *)0) return 0;
}
if (!functionalEquality(A1,A2)) {
if (A2->getSize() == A1->getSize()) return 0;
if ((A1->getSize() < A2->getSize())&&(A2->isWritten()))
A2 = range2.pullBack(A2->getDef(),&markup,false);
else if (A1->isWritten())
A1 = range1.pullBack(A1->getDef(),&markup,false);
if (A1 != A2) return 0;
}
if (!A1->isHeritageKnown()) return 0;
if (op->code() == CPUI_BOOL_AND)
restype = range1.intersect(range2);
else
restype = range1.circleUnion(range2);
if (restype == 0) {
OpCode opc;
uintb resc;
int4 resslot;
restype = range1.translate2Op(opc,resc,resslot);
if (restype == 0) {
Varnode *newConst = data.newConstant(A1->getSize(),resc);
if (markup != (Varnode *)0) { newConst->copySymbolIfValid(markup); }
data.opSetOpcode(op,opc);
data.opSetInput(op,A1,1-resslot);
data.opSetInput(op,newConst,resslot);
return 1;
}
}
if (restype == 2) return 0; if (restype == 1) { data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(1,1),0);
}
else if (restype == 3) { data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(1,0),0);
}
return 1;
}
void RuleFloatRange::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_OR);
oplist.push_back(CPUI_BOOL_AND);
}
int4 RuleFloatRange::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *cmp1,*cmp2;
Varnode *vn1,*vn2;
vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
vn2 = op->getIn(1);
if (!vn2->isWritten()) return 0;
cmp1 = vn1->getDef();
cmp2 = vn2->getDef();
OpCode opccmp1 = cmp1->code();
if ((opccmp1!=CPUI_FLOAT_LESS)&&(opccmp1!=CPUI_FLOAT_LESSEQUAL)) {
cmp1 = cmp2;
cmp2 = vn1->getDef();
opccmp1 = cmp1->code();
}
OpCode resultopc = CPUI_COPY;
if (opccmp1==CPUI_FLOAT_LESS) {
if ((cmp2->code() == CPUI_FLOAT_EQUAL)&&(op->code()==CPUI_BOOL_OR))
resultopc = CPUI_FLOAT_LESSEQUAL;
}
else if (opccmp1==CPUI_FLOAT_LESSEQUAL) {
if ((cmp2->code() == CPUI_FLOAT_NOTEQUAL)&&(op->code()==CPUI_BOOL_AND))
resultopc = CPUI_FLOAT_LESS;
}
if (resultopc == CPUI_COPY) return 0;
Varnode *nvn1,*cvn1;
int4 slot1 = 0;
nvn1 = cmp1->getIn(slot1); if (nvn1->isConstant()) {
slot1 = 1;
nvn1 = cmp1->getIn(slot1);
if (nvn1->isConstant()) return 0;
}
if (nvn1->isFree()) return 0;
cvn1 = cmp1->getIn(1-slot1); int4 slot2;
if (nvn1 != cmp2->getIn(0)) {
slot2 = 1;
if (nvn1 != cmp2->getIn(1))
return 0;
}
else
slot2 = 0;
Varnode *matchvn = cmp2->getIn(1-slot2);
if (cvn1->isConstant()) {
if (!matchvn->isConstant()) return 0;
if (matchvn->getOffset() != cvn1->getOffset()) return 0;
}
else if (cvn1 != matchvn)
return 0;
else if (cvn1->isFree())
return 0;
data.opSetOpcode(op,resultopc);
data.opSetInput(op,nvn1,slot1);
if (cvn1->isConstant())
data.opSetInput(op,data.newConstant(cvn1->getSize(),cvn1->getOffset()),1-slot1);
else
data.opSetInput(op,cvn1,1-slot1);
return 1;
}
void RuleAndCommute::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleAndCommute::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *orvn,*shiftvn,*othervn,*newvn1,*newvn2,*savn;
PcodeOp *orop,*shiftop,*newop1,*newop2;
uintb ormask1,ormask2,othermask,fullmask;
OpCode opc = CPUI_INT_OR; int4 sa,i,size;
orvn = othervn = savn = (Varnode *)0; size = op->getOut()->getSize();
if (size > sizeof(uintb)) return 0; fullmask = calc_mask(size);
for(i=0;i<2;++i) {
shiftvn = op->getIn(i);
shiftop = shiftvn->getDef();
if (shiftop == (PcodeOp *)0) continue;
opc = shiftop->code();
if ((opc != CPUI_INT_LEFT)&&(opc!=CPUI_INT_RIGHT)) continue;
savn = shiftop->getIn(1);
if (!savn->isConstant()) continue;
sa = (int4)savn->getOffset();
othervn = op->getIn(1-i);
if (!othervn->isHeritageKnown()) continue;
othermask = othervn->getNZMask();
if (opc==CPUI_INT_RIGHT) {
if ((fullmask>>sa)==othermask) continue;
othermask <<= sa; }
else {
if (((fullmask<<sa)&&fullmask)==othermask) continue;
othermask >>= sa; }
if (othermask == 0) continue; if (othermask == fullmask) continue;
orvn = shiftop->getIn(0);
if ((opc==CPUI_INT_LEFT)&&(othervn->isConstant())) {
if (shiftvn->loneDescend() == op) break; }
if (!orvn->isWritten()) continue;
orop = orvn->getDef();
if (orop->code() == CPUI_INT_OR) {
ormask1 = orop->getIn(0)->getNZMask();
if ((ormask1 & othermask)==0) break;
ormask2 = orop->getIn(1)->getNZMask();
if ((ormask2 & othermask)==0) break;
if (othervn->isConstant()) {
if ((ormask1 & othermask) == ormask1) break;
if ((ormask2 & othermask) == ormask2) break;
}
}
else if (orop->code() == CPUI_PIECE) {
ormask1 = orop->getIn(1)->getNZMask(); if ((ormask1 & othermask)==0) break;
ormask2 = orop->getIn(0)->getNZMask(); ormask2 <<= orop->getIn(1)->getSize() * 8;
if ((ormask2 & othermask)==0) break;
}
else
continue;
}
if (i==2) return 0;
newop1 = data.newOp(2,op->getAddr());
newvn1 = data.newUniqueOut(size,newop1);
data.opSetOpcode(newop1,(opc==CPUI_INT_LEFT)?CPUI_INT_RIGHT:CPUI_INT_LEFT);
data.opSetInput(newop1, othervn, 0);
data.opSetInput(newop1, savn, 1);
data.opInsertBefore(newop1, op);
newop2 = data.newOp(2,op->getAddr());
newvn2 = data.newUniqueOut(size,newop2);
data.opSetOpcode(newop2,CPUI_INT_AND);
data.opSetInput(newop2, orvn, 0);
data.opSetInput(newop2, newvn1, 1);
data.opInsertBefore(newop2, op);
data.opSetInput(op, newvn2, 0);
data.opSetInput(op, savn, 1);
data.opSetOpcode(op, opc);
return 1;
}
void RuleAndPiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleAndPiece::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *piecevn,*othervn,*highvn,*lowvn,*newvn,*newvn2;
PcodeOp *pieceop,*newop;
uintb othermask,maskhigh,masklow;
OpCode opc = CPUI_PIECE; int4 i,size;
size = op->getOut()->getSize();
highvn = lowvn = (Varnode *)0; for(i=0;i<2;++i) {
piecevn = op->getIn(i);
if (!piecevn->isWritten()) continue;
pieceop = piecevn->getDef();
if (pieceop->code() != CPUI_PIECE) continue;
othervn = op->getIn(1-i);
othermask = othervn->getNZMask();
if (othermask == calc_mask(size)) continue;
if (othermask == 0) continue; highvn = pieceop->getIn(0);
if (!highvn->isHeritageKnown()) continue;
lowvn = pieceop->getIn(1);
if (!lowvn->isHeritageKnown()) continue;
maskhigh = highvn->getNZMask();
masklow = lowvn->getNZMask();
if ((maskhigh & (othermask>>(lowvn->getSize()*8)))==0) {
if ((maskhigh==0)&&(highvn->isConstant())) continue; opc = CPUI_INT_ZEXT;
break;
}
else if ((masklow & othermask)==0) {
if (lowvn->isConstant()) continue; opc = CPUI_PIECE;
break;
}
}
if (i==2) return 0;
if (opc == CPUI_INT_ZEXT) { newop = data.newOp(1,op->getAddr());
data.opSetOpcode(newop,opc);
data.opSetInput(newop, lowvn, 0);
}
else { newvn2 = data.newConstant(lowvn->getSize(),0);
newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,opc);
data.opSetInput(newop, highvn, 0);
data.opSetInput(newop, newvn2, 1);
}
newvn = data.newUniqueOut(size,newop);
data.opInsertBefore(newop, op);
data.opSetInput(op,newvn,i);
return 1;
}
void RuleAndCompare::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_EQUAL);
oplist.push_back(CPUI_INT_NOTEQUAL);
}
int4 RuleAndCompare::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
if (op->getIn(1)->getOffset() != 0) return 0;
Varnode *andvn,*subvn,*basevn,*constvn;
PcodeOp *andop,*subop;
uintb andconst,baseconst;
andvn = op->getIn(0);
if (!andvn->isWritten()) return 0;
andop = andvn->getDef();
if (andop->code() != CPUI_INT_AND) return 0;
if (!andop->getIn(1)->isConstant()) return 0;
subvn = andop->getIn(0);
if (!subvn->isWritten()) return 0;
subop = subvn->getDef();
switch(subop->code()) {
case CPUI_SUBPIECE:
basevn = subop->getIn(0);
baseconst = andop->getIn(1)->getOffset();
andconst = baseconst << subop->getIn(1)->getOffset() * 8;
break;
case CPUI_INT_ZEXT:
basevn = subop->getIn(0);
baseconst = andop->getIn(1)->getOffset();
andconst = baseconst & calc_mask(basevn->getSize());
break;
default:
return 0;
}
if (baseconst == calc_mask(andvn->getSize())) return 0; if (basevn->isFree()) return 0;
constvn = data.newConstant(basevn->getSize(),andconst);
if (baseconst == andconst) constvn->copySymbol(andop->getIn(1)); PcodeOp *newop = data.newOp(2,andop->getAddr());
data.opSetOpcode(newop,CPUI_INT_AND);
Varnode *newout = data.newUniqueOut(basevn->getSize(),newop);
data.opSetInput(newop,basevn,0);
data.opSetInput(newop,constvn,1);
data.opInsertBefore(newop,andop);
data.opSetInput(op,newout,0);
data.opSetInput(op,data.newConstant(basevn->getSize(),0),1);
return 1;
}
void RuleDoubleSub::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleDoubleSub::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *op2;
Varnode *vn;
int4 offset1,offset2;
vn = op->getIn(0);
if (!vn->isWritten()) return 0;
op2 = vn->getDef();
if (op2->code() != CPUI_SUBPIECE) return 0;
offset1 = op->getIn(1)->getOffset();
offset2 = op2->getIn(1)->getOffset();
data.opSetInput(op,op2->getIn(0),0); data.opSetInput(op,data.newConstant(4,offset1+offset2), 1);
return 1;
}
void RuleDoubleShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LEFT);
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_INT_MULT);
}
int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *secvn,*newvn;
PcodeOp *secop;
OpCode opc1,opc2;
int4 sa1,sa2,size;
uintb mask;
if (!op->getIn(1)->isConstant()) return 0;
secvn = op->getIn(0);
if (!secvn->isWritten()) return 0;
secop = secvn->getDef();
opc2 = secop->code();
if ((opc2!=CPUI_INT_LEFT)&&(opc2!=CPUI_INT_RIGHT)&&(opc2!=CPUI_INT_MULT))
return 0;
if (!secop->getIn(1)->isConstant()) return 0;
opc1 = op->code();
size = secvn->getSize();
if (!secop->getIn(0)->isHeritageKnown()) return 0;
if (opc1 == CPUI_INT_MULT) {
uintb val = op->getIn(1)->getOffset();
sa1 = leastsigbit_set(val);
if ((val>>sa1) != (uintb)1) return 0; opc1 = CPUI_INT_LEFT;
}
else
sa1 = op->getIn(1)->getOffset();
if (opc2 == CPUI_INT_MULT) {
uintb val = secop->getIn(1)->getOffset();
sa2 = leastsigbit_set(val);
if ((val>>sa2) != (uintb)1) return 0; opc2 = CPUI_INT_LEFT;
}
else
sa2 = secop->getIn(1)->getOffset();
if (opc1 == opc2) {
if (sa1 + sa2 < 8*size) {
newvn = data.newConstant(size,sa1+sa2);
data.opSetOpcode(op,opc1);
data.opSetInput(op,secop->getIn(0),0);
data.opSetInput(op,newvn,1);
}
else {
newvn = data.newConstant(size,0);
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,newvn,0);
data.opRemoveInput(op,1);
}
}
else if (sa1 == sa2) {
mask = calc_mask(size);
if (opc1 == CPUI_INT_LEFT)
mask = (mask<<sa1) & mask;
else
mask = (mask>>sa1) & mask;
newvn = data.newConstant(size,mask);
data.opSetOpcode(op,CPUI_INT_AND);
data.opSetInput(op,secop->getIn(0),0);
data.opSetInput(op,newvn,1);
}
else
return 0;
return 1;
}
void RuleDoubleArithShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleDoubleArithShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constD = op->getIn(1);
if (!constD->isConstant()) return 0;
Varnode *shiftin = op->getIn(0);
if (!shiftin->isWritten()) return 0;
PcodeOp *shift2op = shiftin->getDef();
if (shift2op->code() != CPUI_INT_SRIGHT) return 0;
Varnode *constC = shift2op->getIn(1);
if (!constC->isConstant()) return 0;
Varnode *inVn = shift2op->getIn(0);
if (inVn->isFree()) return 0;
int4 max = op->getOut()->getSize() * 8 - 1; int4 sa = (int4)constC->getOffset() + (int4)constD->getOffset();
if (sa <= 0) return 0; if (sa > max)
sa = max; data.opSetInput(op, inVn, 0);
data.opSetInput(op, data.newConstant(4, sa),1);
return 1;
}
void RuleConcatShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleConcatShift::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *shiftin = op->getIn(0);
if (!shiftin->isWritten()) return 0;
PcodeOp *concat = shiftin->getDef();
if (concat->code() != CPUI_PIECE) return 0;
int4 sa = op->getIn(1)->getOffset();
int4 leastsize = concat->getIn(1)->getSize() * 8;
if (sa < leastsize) return 0; Varnode *mainin = concat->getIn(0);
if (mainin->isFree()) return 0;
sa -= leastsize;
OpCode extcode = (op->code() == CPUI_INT_RIGHT) ? CPUI_INT_ZEXT : CPUI_INT_SEXT;
if (sa == 0) { data.opRemoveInput(op,1); data.opSetOpcode(op,extcode); data.opSetInput(op,mainin,0);
}
else {
PcodeOp *extop = data.newOp(1,op->getAddr());
data.opSetOpcode(extop,extcode);
Varnode *newvn = data.newUniqueOut(shiftin->getSize(),extop);
data.opSetInput(extop,mainin,0);
data.opSetInput(op,newvn,0);
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),sa),1);
data.opInsertBefore(extop,op);
}
return 1;
}
void RuleLeftRight::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleLeftRight::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *shiftin = op->getIn(0);
if (!shiftin->isWritten()) return 0;
PcodeOp *leftshift = shiftin->getDef();
if (leftshift->code() != CPUI_INT_LEFT) return 0;
if (!leftshift->getIn(1)->isConstant()) return 0;
uintb sa = op->getIn(1)->getOffset();
if (leftshift->getIn(1)->getOffset() != sa) return 0;
if ((sa & 7) != 0) return 0; int4 isa = (int4)(sa>>3);
int4 tsz = shiftin->getSize() - isa;
if ((tsz!=1)&&(tsz!=2)&&(tsz!=4)&&(tsz!=8)) return 0;
if (shiftin->loneDescend() != op) return 0;
Address addr = shiftin->getAddr();
if (addr.isBigEndian())
addr = addr + isa;
data.opUnsetInput(op,0);
data.opUnsetOutput(leftshift);
addr.renormalize(tsz);
Varnode *newvn = data.newVarnodeOut(tsz,addr,leftshift);
data.opSetOpcode(leftshift,CPUI_SUBPIECE);
data.opSetInput(leftshift, data.newConstant( leftshift->getIn(1)->getSize(), 0), 1);
data.opSetInput(op, newvn, 0);
data.opRemoveInput(op,1); data.opSetOpcode( op, (op->code() == CPUI_INT_SRIGHT) ? CPUI_INT_SEXT : CPUI_INT_ZEXT);
return 1;
}
void RuleShiftCompare::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_EQUAL);
oplist.push_back(CPUI_INT_NOTEQUAL);
}
int4 RuleShiftCompare::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *shiftvn,*constvn,*savn,*mainvn;
PcodeOp *shiftop;
int4 sa;
uintb constval,nzmask,newconst;
OpCode opc;
bool isleft;
shiftvn = op->getIn(0);
constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
if (!shiftvn->isWritten()) return 0;
shiftop = shiftvn->getDef();
opc = shiftop->code();
if (opc==CPUI_INT_LEFT) {
isleft = true;
savn = shiftop->getIn(1);
if (!savn->isConstant()) return 0;
sa = savn->getOffset();
}
else if (opc == CPUI_INT_RIGHT) {
isleft = false;
savn = shiftop->getIn(1);
if (!savn->isConstant()) return 0;
sa = savn->getOffset();
if (shiftvn->loneDescend() != op) return 0;
}
else if (opc == CPUI_INT_MULT) {
isleft = true;
savn = shiftop->getIn(1);
if (!savn->isConstant()) return 0;
uintb val = savn->getOffset();
sa = leastsigbit_set(val);
if ((val>>sa) != (uintb)1) return 0; }
else if (opc == CPUI_INT_DIV) {
isleft = false;
savn = shiftop->getIn(1);
if (!savn->isConstant()) return 0;
uintb val = savn->getOffset();
sa = leastsigbit_set(val);
if ((val>>sa) != (uintb)1) return 0; if (shiftvn->loneDescend() != op) return 0;
}
else
return 0;
if (sa==0) return 0;
mainvn = shiftop->getIn(0);
if (mainvn->isFree()) return 0;
if (mainvn->getSize() > sizeof(uintb)) return 0;
constval = constvn->getOffset();
nzmask = mainvn->getNZMask();
if (isleft) {
newconst = constval >> sa;
if ((newconst << sa) != constval) return 0; uintb tmp = (nzmask << sa) & calc_mask(shiftvn->getSize());
if ((tmp>>sa)!=nzmask) { if (shiftvn->loneDescend() != op) return 0;
sa = 8*shiftvn->getSize() - sa;
tmp = (((uintb)1) << sa)-1;
Varnode *newmask = data.newConstant(constvn->getSize(),tmp);
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_INT_AND);
Varnode *newtmpvn = data.newUniqueOut(constvn->getSize(),newop);
data.opSetInput(newop, mainvn, 0);
data.opSetInput(newop, newmask, 1);
data.opInsertBefore(newop,shiftop);
data.opSetInput(op,newtmpvn,0);
data.opSetInput(op,data.newConstant(constvn->getSize(),newconst),1);
return 1;
}
}
else {
if (((nzmask >> sa)<<sa)!=nzmask) return 0; newconst = (constval << sa) & calc_mask(shiftvn->getSize());
if ((newconst>>sa)!=constval) return 0; }
Varnode *newconstvn = data.newConstant(constvn->getSize(),newconst);
data.opSetInput(op,mainvn,0);
data.opSetInput(op,newconstvn,1);
return 1;
}
void RuleLessEqual::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_OR);
}
int4 RuleLessEqual::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *compvn1,*compvn2,*vnout1,*vnout2;
PcodeOp *op_less,*op_equal;
OpCode opc,equalopc;
vnout1 = op->getIn(0);
if (!vnout1->isWritten()) return 0;
vnout2 = op->getIn(1);
if (!vnout2->isWritten()) return 0;
op_less = vnout1->getDef();
opc = op_less->code();
if ((opc != CPUI_INT_LESS)&&(opc!=CPUI_INT_SLESS)) {
op_equal = op_less;
op_less = vnout2->getDef();
opc = op_less->code();
if ((opc != CPUI_INT_LESS)&&(opc!=CPUI_INT_SLESS))
return 0;
}
else
op_equal = vnout2->getDef();
equalopc = op_equal->code();
if ((equalopc != CPUI_INT_EQUAL)&&( equalopc != CPUI_INT_NOTEQUAL))
return 0;
compvn1 = op_less->getIn(0);
compvn2 = op_less->getIn(1);
if (!compvn1->isHeritageKnown()) return 0;
if (!compvn2->isHeritageKnown()) return 0;
if (((*compvn1 != *op_equal->getIn(0))||(*compvn2 != *op_equal->getIn(1)))&&
((*compvn1 != *op_equal->getIn(1))||(*compvn2 != *op_equal->getIn(0))))
return 0;
if (equalopc == CPUI_INT_NOTEQUAL) { data.opSetOpcode(op, CPUI_COPY); data.opRemoveInput(op,1);
data.opSetInput(op,op_equal->getOut(),0); }
else {
data.opSetInput(op,compvn1,0);
data.opSetInput(op,compvn2,1);
data.opSetOpcode(op, (opc==CPUI_INT_SLESS) ? CPUI_INT_SLESSEQUAL : CPUI_INT_LESSEQUAL);
}
return 1;
}
void RuleLessNotEqual::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_AND);
}
int4 RuleLessNotEqual::applyOp(PcodeOp *op,Funcdata &data)
{ Varnode *compvn1,*compvn2,*vnout1,*vnout2;
PcodeOp *op_less,*op_equal;
OpCode opc;
vnout1 = op->getIn(0);
if (!vnout1->isWritten()) return 0;
vnout2 = op->getIn(1);
if (!vnout2->isWritten()) return 0;
op_less = vnout1->getDef();
opc = op_less->code();
if ((opc != CPUI_INT_LESSEQUAL)&&(opc!=CPUI_INT_SLESSEQUAL)) {
op_equal = op_less;
op_less = vnout2->getDef();
opc = op_less->code();
if ((opc != CPUI_INT_LESSEQUAL)&&(opc!=CPUI_INT_SLESSEQUAL))
return 0;
}
else
op_equal = vnout2->getDef();
if (op_equal->code() != CPUI_INT_NOTEQUAL) return 0;
compvn1 = op_less->getIn(0);
compvn2 = op_less->getIn(1);
if (!compvn1->isHeritageKnown()) return 0;
if (!compvn2->isHeritageKnown()) return 0;
if (((*compvn1 != *op_equal->getIn(0))||(*compvn2 != *op_equal->getIn(1)))&&
((*compvn1 != *op_equal->getIn(1))||(*compvn2 != *op_equal->getIn(0))))
return 0;
data.opSetInput(op,compvn1,0);
data.opSetInput(op,compvn2,1);
data.opSetOpcode(op, (opc==CPUI_INT_SLESSEQUAL) ? CPUI_INT_SLESS : CPUI_INT_LESS);
return 1;
}
void RuleTrivialArith::getOpList(vector<uint4> &oplist) const
{
uint4 list[]={ CPUI_INT_NOTEQUAL, CPUI_INT_SLESS, CPUI_INT_LESS, CPUI_BOOL_XOR, CPUI_BOOL_AND, CPUI_BOOL_OR,
CPUI_INT_EQUAL, CPUI_INT_SLESSEQUAL, CPUI_INT_LESSEQUAL,
CPUI_INT_XOR, CPUI_INT_AND, CPUI_INT_OR,
CPUI_FLOAT_EQUAL, CPUI_FLOAT_NOTEQUAL, CPUI_FLOAT_LESS, CPUI_FLOAT_LESSEQUAL };
oplist.insert(oplist.end(),list,list+16);
}
int4 RuleTrivialArith::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn;
Varnode *in0,*in1;
if (op->numInput() != 2) return 0;
in0 = op->getIn(0);
in1 = op->getIn(1);
if (in0 != in1) { if (!in0->isWritten()) return 0;
if (!in1->isWritten()) return 0;
if (!in0->getDef()->isCseMatch(in1->getDef())) return 0; }
switch(op->code()) {
case CPUI_INT_NOTEQUAL: case CPUI_INT_SLESS:
case CPUI_INT_LESS:
case CPUI_BOOL_XOR:
case CPUI_FLOAT_NOTEQUAL:
case CPUI_FLOAT_LESS:
vn = data.newConstant(1,0);
break;
case CPUI_INT_EQUAL: case CPUI_INT_SLESSEQUAL:
case CPUI_INT_LESSEQUAL:
case CPUI_FLOAT_EQUAL:
case CPUI_FLOAT_LESSEQUAL:
vn = data.newConstant(1,1);
break;
case CPUI_INT_XOR: vn = data.newConstant(op->getOut()->getSize(),0);
break;
case CPUI_BOOL_AND: case CPUI_BOOL_OR:
case CPUI_INT_AND:
case CPUI_INT_OR:
vn = (Varnode *)0;
break;
default:
return 0;
}
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
if (vn != (Varnode *)0)
data.opSetInput(op,vn,0);
return 1;
}
void RuleTrivialBool::getOpList(vector<uint4> &oplist) const
{
uint4 list[] = { CPUI_BOOL_AND, CPUI_BOOL_OR, CPUI_BOOL_XOR };
oplist.insert(oplist.end(),list,list+3);
}
int4 RuleTrivialBool::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vnconst = op->getIn(1);
Varnode *vn;
uintb val;
OpCode opc;
if (!vnconst->isConstant()) return 0;
val = vnconst->getOffset();
switch(op->code()) {
case CPUI_BOOL_XOR:
vn = op->getIn(0);
opc = (val==1) ? CPUI_BOOL_NEGATE : CPUI_COPY;
break;
case CPUI_BOOL_AND:
opc = CPUI_COPY;
if (val==1)
vn = op->getIn(0);
else
vn = data.newConstant(1,0); break;
case CPUI_BOOL_OR:
opc = CPUI_COPY;
if (val==1)
vn = data.newConstant(1,1);
else
vn = op->getIn(0);
break;
default:
return 0;
}
data.opRemoveInput(op,1);
data.opSetOpcode(op,opc);
data.opSetInput(op,vn,0);
return 1;
}
void RuleZextEliminate::getOpList(vector<uint4> &oplist) const
{
uint4 list[] = {CPUI_INT_EQUAL, CPUI_INT_NOTEQUAL,
CPUI_INT_LESS,CPUI_INT_LESSEQUAL };
oplist.insert(oplist.end(),list,list+4);
}
int4 RuleZextEliminate::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *zext;
Varnode *vn1,*vn2,*newvn;
uintb val;
int4 smallsize,zextslot,otherslot;
vn1 = op->getIn(0);
vn2 = op->getIn(1);
zextslot = 0;
otherslot = 1;
if ((vn2->isWritten())&&(vn2->getDef()->code()==CPUI_INT_ZEXT)) {
vn1 = vn2;
vn2 = op->getIn(0);
zextslot = 1;
otherslot = 0;
}
else if ((!vn1->isWritten())||(vn1->getDef()->code()!=CPUI_INT_ZEXT))
return 0;
if (!vn2->isConstant()) return 0;
zext = vn1->getDef();
if (!zext->getIn(0)->isHeritageKnown()) return 0;
if (vn1->loneDescend() != op) return 0; smallsize = zext->getIn(0)->getSize();
val = vn2->getOffset();
if ((val>>(8*smallsize))==0) { newvn = data.newConstant(smallsize,val);
newvn->copySymbolIfValid(vn2);
data.opSetInput(op,zext->getIn(0),zextslot);
data.opSetInput(op,newvn,otherslot);
return 1;
}
return 0;
}
void RuleSlessToLess::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SLESS);
oplist.push_back(CPUI_INT_SLESSEQUAL);
}
int4 RuleSlessToLess::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
int4 sz = vn->getSize();
if (signbit_negative(vn->getNZMask(),sz)) return 0;
if (signbit_negative(op->getIn(1)->getNZMask(),sz)) return 0;
if (op->code() == CPUI_INT_SLESS)
data.opSetOpcode(op,CPUI_INT_LESS);
else
data.opSetOpcode(op,CPUI_INT_LESSEQUAL);
return 1;
}
void RuleZextSless::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SLESS);
oplist.push_back(CPUI_INT_SLESSEQUAL);
}
int4 RuleZextSless::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *zext;
Varnode *vn1,*vn2;
int4 smallsize,zextslot,otherslot;
uintb val;
vn1 = op->getIn(0);
vn2 = op->getIn(1);
zextslot = 0;
otherslot = 1;
if ((vn2->isWritten())&&(vn2->getDef()->code()==CPUI_INT_ZEXT)) {
vn1 = vn2;
vn2 = op->getIn(0);
zextslot = 1;
otherslot = 0;
}
else if ((!vn1->isWritten())||(vn1->getDef()->code()!=CPUI_INT_ZEXT))
return 0;
if (!vn2->isConstant()) return 0;
zext = vn1->getDef();
if (!zext->getIn(0)->isHeritageKnown()) return 0;
smallsize = zext->getIn(0)->getSize();
val = vn2->getOffset();
if ((val>>(8*smallsize-1))!=0) return 0;
Varnode *newvn = data.newConstant(smallsize,val);
data.opSetInput(op,zext->getIn(0),zextslot);
data.opSetInput(op,newvn,otherslot);;
data.opSetOpcode(op,(op->code()==CPUI_INT_SLESS)? CPUI_INT_LESS : CPUI_INT_LESSEQUAL);
return 1;
}
void RuleBitUndistribute::getOpList(vector<uint4> &oplist) const
{
uint4 list[]= { CPUI_INT_AND, CPUI_INT_OR, CPUI_INT_XOR };
oplist.insert(oplist.end(),list,list+3);
}
int4 RuleBitUndistribute::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn1 = op->getIn(0);
Varnode *vn2 = op->getIn(1);
Varnode *in1,*in2,*vnextra;
OpCode opc;
if (!vn1->isWritten()) return 0;
if (!vn2->isWritten()) return 0;
opc = vn1->getDef()->code();
if (vn2->getDef()->code() != opc) return 0;
switch(opc) {
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
in1 = vn1->getDef()->getIn(0);
if (in1->isFree()) return 0;
in2 = vn2->getDef()->getIn(0);
if (in2->isFree()) return 0;
if (in1->getSize() != in2->getSize()) return 0;
data.opRemoveInput(op,1);
break;
case CPUI_INT_LEFT:
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
in1 = vn1->getDef()->getIn(1);
in2 = vn2->getDef()->getIn(1);
if (in1->isConstant() && in2->isConstant()) {
if (in1->getOffset() != in2->getOffset())
return 0;
vnextra = data.newConstant(in1->getSize(),in1->getOffset());
}
else if (in1 != in2)
return 0;
else {
if (in1->isFree()) return 0;
vnextra = in1;
}
in1 = vn1->getDef()->getIn(0);
if (in1->isFree()) return 0;
in2 = vn2->getDef()->getIn(0);
if (in2->isFree()) return 0;
data.opSetInput(op,vnextra,1);
break;
default:
return 0;
}
PcodeOp *newext = data.newOp(2,op->getAddr());
Varnode *smalllogic = data.newUniqueOut(in1->getSize(),newext);
data.opSetInput(newext,in1,0);
data.opSetInput(newext,in2,1);
data.opSetOpcode(newext,op->code());
data.opSetOpcode(op,opc);
data.opSetInput(op,smalllogic,0);
data.opInsertBefore(newext,op);
return 1;
}
void RuleBooleanNegate::getOpList(vector<uint4> &oplist) const
{
uint4 list[]= { CPUI_INT_NOTEQUAL, CPUI_INT_EQUAL };
oplist.insert(oplist.end(),list,list+2);
}
int4 RuleBooleanNegate::applyOp(PcodeOp *op,Funcdata &data)
{
OpCode opc;
Varnode *constvn;
Varnode *subbool;
PcodeOp *subop;
bool negate;
uintb val;
opc = op->code();
constvn = op->getIn(1);
subbool = op->getIn(0);
if (!constvn->isConstant()) return 0;
val = constvn->getOffset();
if ((val!=0)&&(val!=1))
return 0;
negate = (opc==CPUI_INT_NOTEQUAL);
if (val==0)
negate = !negate;
if (!subbool->isWritten()) return 0;
subop = subbool->getDef();
if (!subop->isCalculatedBool()) return 0;
data.opRemoveInput(op,1); data.opSetInput(op,subbool,0); if (negate)
data.opSetOpcode(op,CPUI_BOOL_NEGATE);
else
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
void RuleBoolZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleBoolZext::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *boolop1,*multop1,*actionop;
PcodeOp *boolop2,*zextop2,*multop2;
uintb coeff,val;
OpCode opc;
int4 size;
if (!op->getIn(0)->isWritten()) return 0;
boolop1 = op->getIn(0)->getDef();
if (!boolop1->isCalculatedBool()) return 0;
multop1 = op->getOut()->loneDescend();
if (multop1 == (PcodeOp *)0) return 0;
if (multop1->code() != CPUI_INT_MULT) return 0;
if (!multop1->getIn(1)->isConstant()) return 0;
coeff = multop1->getIn(1)->getOffset();
if (coeff != calc_mask(multop1->getIn(1)->getSize()))
return 0;
size = multop1->getOut()->getSize();
actionop = multop1->getOut()->loneDescend();
if (actionop == (PcodeOp *)0) return 0;
switch(actionop->code()) {
case CPUI_INT_ADD:
if (!actionop->getIn(1)->isConstant()) return 0;
if (actionop->getIn(1)->getOffset() == 1) {
Varnode *vn;
PcodeOp *newop = data.newOp(1,op->getAddr());
data.opSetOpcode(newop,CPUI_BOOL_NEGATE); vn = data.newUniqueOut(1,newop);
data.opSetInput(newop,boolop1->getOut(),0);
data.opInsertBefore(newop,op);
data.opSetInput(op,vn,0);
data.opRemoveInput(actionop,1); data.opSetOpcode(actionop,CPUI_COPY);
data.opSetInput(actionop,op->getOut(),0); return 1;
}
return 0;
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if (actionop->getIn(1)->isConstant()) {
val = actionop->getIn(1)->getOffset();
}
else
return 0;
if (val==coeff)
val = 1;
else if (val != 0)
return 0;
data.opSetInput(actionop,boolop1->getOut(),0);
data.opSetInput(actionop,data.newConstant(1,val),1);
return 1;
case CPUI_INT_AND:
opc = CPUI_BOOL_AND;
break;
case CPUI_INT_OR:
opc = CPUI_BOOL_OR;
break;
case CPUI_INT_XOR:
opc = CPUI_BOOL_XOR;
break;
default:
return 0;
}
multop2 = (multop1 == actionop->getIn(0)->getDef()) ? actionop->getIn(1)->getDef():actionop->getIn(0)->getDef();
if (multop2==(PcodeOp *)0) return 0;
if (multop2->code() != CPUI_INT_MULT) return 0;
if (!multop2->getIn(1)->isConstant()) return 0;
coeff = multop2->getIn(1)->getOffset();
if (coeff != calc_mask(size))
return 0;
zextop2 = multop2->getIn(0)->getDef();
if (zextop2 == (PcodeOp *)0) return 0;
if (zextop2->code() != CPUI_INT_ZEXT) return 0;
boolop2 = zextop2->getIn(0)->getDef();
if (boolop2 == (PcodeOp *)0) return 0;
if (!boolop2->isCalculatedBool()) return 0;
PcodeOp *newop = data.newOp(2,actionop->getAddr());
Varnode *newres = data.newUniqueOut(1,newop);
data.opSetOpcode(newop,opc);
data.opSetInput(newop, boolop1->getOut(), 0);
data.opSetInput(newop, boolop2->getOut(), 1);
data.opInsertBefore(newop,actionop);
PcodeOp *newzext = data.newOp(1,actionop->getAddr());
Varnode *newzout = data.newUniqueOut(size,newzext);
data.opSetOpcode(newzext,CPUI_INT_ZEXT);
data.opSetInput(newzext,newres,0);
data.opInsertBefore(newzext,actionop);
data.opSetOpcode(actionop,CPUI_INT_MULT);
data.opSetInput(actionop,newzout,0);
data.opSetInput(actionop,data.newConstant(size,coeff),1);
return 1;
}
void RuleLogic2Bool::getOpList(vector<uint4> &oplist) const
{
uint4 list[]= { CPUI_INT_AND, CPUI_INT_OR, CPUI_INT_XOR };
oplist.insert(oplist.end(),list,list+3);
}
int4 RuleLogic2Bool::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *boolop;
if (!op->getIn(0)->isWritten()) return 0;
boolop = op->getIn(0)->getDef();
if (!boolop->isCalculatedBool()) return 0;
Varnode *in1 = op->getIn(1);
if (!in1->isWritten()) {
if ((!in1->isConstant())||(in1->getOffset()>(uintb)1)) return 0;
}
else {
boolop = op->getIn(1)->getDef();
if (!boolop->isCalculatedBool()) return 0;
}
switch(op->code()) {
case CPUI_INT_AND:
data.opSetOpcode(op,CPUI_BOOL_AND);
break;
case CPUI_INT_OR:
data.opSetOpcode(op,CPUI_BOOL_OR);
break;
case CPUI_INT_XOR:
data.opSetOpcode(op,CPUI_BOOL_XOR);
break;
default:
return 0;
}
return 1;
}
void RuleIndirectCollapse::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INDIRECT);
}
int4 RuleIndirectCollapse::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *indop;
if (op->getIn(1)->getSpace()->getType()!=IPTR_IOP) return 0;
indop = PcodeOp::getOpFromConst(op->getIn(1)->getAddr());
if (!indop->isDead()) {
if (indop->code() == CPUI_COPY) { Varnode *vn1 = indop->getOut();
Varnode *vn2 = op->getOut();
int4 res = vn1->characterizeOverlap(*vn2);
if (res > 0) { if (res == 2) { data.opSetInput(op,vn1,0);
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
data.warning("Ignoring partial resolution of indirect",indop->getAddr());
return 0; }
}
else if (indop->isCall()) {
if (op->isIndirectCreation())
return 0;
if (!op->getOut()->hasNoLocalAlias())
return 0;
}
else if (indop->usesSpacebasePtr()) {
if (indop->code() == CPUI_STORE) {
const LoadGuard *guard = data.getStoreGuard(indop);
if (guard != (const LoadGuard *)0) {
if (guard->isGuarded(op->getOut()->getAddr()))
return 0;
}
else {
return 0;
}
}
}
else
return 0;
}
data.totalReplace(op->getOut(),op->getIn(0));
data.opDestroy(op); return 1;
}
void RuleMultiCollapse::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_MULTIEQUAL);
}
int4 RuleMultiCollapse::applyOp(PcodeOp *op,Funcdata &data)
{
vector<Varnode *> skiplist,matchlist;
Varnode *defcopyr,*copyr;
bool func_eq,nofunc;
PcodeOp *newop;
int4 j;
for(int4 i=0;i<op->numInput();++i) if (!op->getIn(i)->isHeritageKnown()) return 0;
func_eq = false; nofunc = false; defcopyr = (Varnode *)0;
j = 0;
for(int4 i=0;i<op->numInput();++i)
matchlist.push_back(op->getIn(i));
for(int4 i=0;i<op->numInput();++i) { copyr = matchlist[i];
if ((!copyr->isWritten())||(copyr->getDef()->code()!=CPUI_MULTIEQUAL)) {
defcopyr = copyr;
break;
}
}
bool success = true;
op->getOut()->setMark();
skiplist.push_back(op->getOut());
while( j < matchlist.size() ) {
copyr = matchlist[j++];
if (copyr->isMark()) continue; if (defcopyr == (Varnode *)0) { defcopyr = copyr; if (defcopyr->isWritten()) {
if (defcopyr->getDef()->code()==CPUI_MULTIEQUAL)
nofunc = true; }
else
nofunc = true; }
else if (*defcopyr == *copyr) continue; else if ((defcopyr!=copyr)&&(!nofunc)&&functionalEquality(defcopyr,copyr)) {
func_eq = true; continue;
}
else if ((copyr->isWritten())&&(copyr->getDef()->code()==CPUI_MULTIEQUAL)) {
newop = copyr->getDef();
skiplist.push_back(copyr); copyr->setMark();
for(int4 i=0;i<newop->numInput();++i) matchlist.push_back(newop->getIn(i));
}
else { success = false;
break;
}
}
if (success) {
for(j=0;j<skiplist.size();++j) { copyr = skiplist[j];
copyr->clearMark();
op = copyr->getDef();
if (func_eq) { PcodeOp *earliest = earliestUseInBlock(op->getOut(),op->getParent());
newop = defcopyr->getDef(); PcodeOp *substitute = (PcodeOp *)0;
for(int4 i=0;i<newop->numInput();++i) {
Varnode *invn = newop->getIn(i);
if (!invn->isConstant()) {
substitute = cseFindInBlock(newop,invn,op->getParent(),earliest); break;
}
}
if (substitute != (PcodeOp *)0) { data.totalReplace(copyr,substitute->getOut()); data.opDestroy(op);
}
else { bool needsreinsert = (op->code() == CPUI_MULTIEQUAL);
vector<Varnode *> parms;
for(int4 i=0;i<newop->numInput();++i)
parms.push_back(newop->getIn(i)); data.opSetAllInput(op,parms);
data.opSetOpcode(op,newop->code()); if (needsreinsert) { BlockBasic *bl = op->getParent();
data.opUninsert(op);
data.opInsertBegin(op,bl); }
}
}
else { data.totalReplace(copyr,defcopyr); data.opDestroy(op); }
}
return 1;
}
for(j=0;j<skiplist.size();++j)
skiplist[j]->clearMark();
return 0;
}
void RuleSborrow::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SBORROW);
}
int4 RuleSborrow::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *svn = op->getOut();
Varnode *cvn,*avn,*bvn;
list<PcodeOp *>::const_iterator iter;
PcodeOp *compop,*signop,*addop;
int4 zside;
if ((op->getIn(1)->isConstant()&&op->getIn(1)->getOffset()==0)||
(op->getIn(0)->isConstant()&&op->getIn(0)->getOffset()==0)) {
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,data.newConstant(1,0),0);
data.opRemoveInput(op,1);
return 1;
}
for(iter=svn->beginDescend();iter!=svn->endDescend();++iter) {
compop = *iter;
if ((compop->code()!=CPUI_INT_EQUAL)&&(compop->code()!=CPUI_INT_NOTEQUAL))
continue;
cvn = (compop->getIn(0)==svn) ? compop->getIn(1) : compop->getIn(0);
if (!cvn->isWritten()) continue;
signop = cvn->getDef();
if (signop->code() != CPUI_INT_SLESS) continue;
if (!signop->getIn(0)->constantMatch(0)) {
if (!signop->getIn(1)->constantMatch(0)) continue;
zside = 1;
}
else
zside = 0;
if (!signop->getIn(1-zside)->isWritten()) continue;
addop = signop->getIn(1-zside)->getDef();
if (addop->code() == CPUI_INT_ADD) {
avn = op->getIn(0);
if (functionalEquality(avn,addop->getIn(0)))
bvn = addop->getIn(1);
else if (functionalEquality(avn,addop->getIn(1)))
bvn = addop->getIn(0);
else
continue;
}
else
continue;
if (bvn->isConstant()) {
Address flip(bvn->getSpace(),uintb_negate(bvn->getOffset()-1,bvn->getSize()));
bvn = op->getIn(1);
if (flip != bvn->getAddr()) continue;
}
else if (bvn->isWritten()) {
PcodeOp *otherop = bvn->getDef();
if (otherop->code() == CPUI_INT_MULT) {
if (!otherop->getIn(1)->isConstant()) continue;
if (otherop->getIn(1)->getOffset() != calc_mask(otherop->getIn(1)->getSize())) continue;
bvn = otherop->getIn(0);
}
else if (otherop->code()==CPUI_INT_2COMP)
bvn = otherop->getIn(0);
if (!functionalEquality(bvn,op->getIn(1))) continue;
}
else
continue;
if (compop->code() == CPUI_INT_NOTEQUAL) {
data.opSetOpcode(compop,CPUI_INT_SLESS); data.opSetInput(compop,avn,1-zside);
data.opSetInput(compop,bvn,zside);
}
else {
data.opSetOpcode(compop,CPUI_INT_SLESSEQUAL);
data.opSetInput(compop,avn,zside);
data.opSetInput(compop,bvn,1-zside);
}
return 1;
}
return 0;
}
void RuleTrivialShift::getOpList(vector<uint4> &oplist) const
{
uint4 list[] = { CPUI_INT_LEFT, CPUI_INT_RIGHT, CPUI_INT_SRIGHT };
oplist.insert(oplist.end(),list,list+3);
}
int4 RuleTrivialShift::applyOp(PcodeOp *op,Funcdata &data)
{
uintb val;
Varnode *constvn = op->getIn(1);
if (!constvn->isConstant()) return 0; val = constvn->getOffset();
if (val!=0) {
Varnode *replace;
if (val < 8*op->getIn(0)->getSize()) return 0; if (op->code() == CPUI_INT_SRIGHT) return 0; replace = data.newConstant(op->getIn(0)->getSize(),0);
data.opSetInput(op,replace,0);
}
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
void RuleSignShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSignShift::applyOp(PcodeOp *op,Funcdata &data)
{
uintb val;
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant()) return 0;
val = constVn->getOffset();
Varnode *inVn = op->getIn(0);
if (val != 8*inVn->getSize() -1) return 0;
if (inVn->isFree()) return 0;
bool doConversion = false;
Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter = outVn->beginDescend();
while(iter != outVn->endDescend()) {
PcodeOp *arithOp = *iter;
++iter;
switch(arithOp->code()) {
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if (arithOp->getIn(1)->isConstant())
doConversion = true;
break;
case CPUI_INT_ADD:
case CPUI_INT_MULT:
doConversion = true;
break;
default:
break;
}
if (doConversion)
break;
}
if (!doConversion)
return 0;
PcodeOp *shiftOp = data.newOp(2,op->getAddr());
data.opSetOpcode(shiftOp, CPUI_INT_SRIGHT);
Varnode *uniqueVn = data.newUniqueOut(inVn->getSize(), shiftOp);
data.opSetInput(op,uniqueVn,0);
data.opSetInput(op,data.newConstant(inVn->getSize(),calc_mask(inVn->getSize())),1);
data.opSetOpcode(op, CPUI_INT_MULT);
data.opSetInput(shiftOp,inVn,0);
data.opSetInput(shiftOp,constVn,1);
data.opInsertBefore(shiftOp, op);
return 1;
}
void RuleTestSign::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SRIGHT);
}
void RuleTestSign::findComparisons(Varnode *vn,vector<PcodeOp *> &res)
{
list<PcodeOp *>::const_iterator iter1;
iter1 = vn->beginDescend();
while(iter1 != vn->endDescend()) {
PcodeOp *op = *iter1;
++iter1;
OpCode opc = op->code();
if (opc == CPUI_INT_EQUAL || opc == CPUI_INT_NOTEQUAL) {
if (op->getIn(1)->isConstant())
res.push_back(op);
}
}
}
int4 RuleTestSign::applyOp(PcodeOp *op,Funcdata &data)
{
uintb val;
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant()) return 0;
val = constVn->getOffset();
Varnode *inVn = op->getIn(0);
if (val != 8*inVn->getSize() -1) return 0;
Varnode *outVn = op->getOut();
if (inVn->isFree()) return 0;
vector<PcodeOp *> compareOps;
findComparisons(outVn, compareOps);
int4 resultCode = 0;
for(int4 i=0;i<compareOps.size();++i) {
PcodeOp *compareOp = compareOps[i];
Varnode *compVn = compareOp->getIn(0);
int4 compSize = compVn->getSize();
uintb offset = compareOp->getIn(1)->getOffset();
int4 sgn;
if (offset == 0)
sgn = 1;
else if (offset == calc_mask(compSize))
sgn = -1;
else
continue;
if (compareOp->code() == CPUI_INT_NOTEQUAL)
sgn = -sgn;
Varnode *zeroVn = data.newConstant(inVn->getSize(), 0);
if (sgn == 1) {
data.opSetInput(compareOp, inVn, 1);
data.opSetInput(compareOp, zeroVn, 0);
data.opSetOpcode(compareOp, CPUI_INT_SLESSEQUAL);
}
else {
data.opSetInput(compareOp, inVn, 0);
data.opSetInput(compareOp, zeroVn, 1);
data.opSetOpcode(compareOp, CPUI_INT_SLESS);
}
resultCode = 1;
}
return resultCode;
}
void RuleIdentityEl::getOpList(vector<uint4> &oplist) const
{
uint4 list[]= { CPUI_INT_ADD, CPUI_INT_XOR, CPUI_INT_OR,
CPUI_BOOL_XOR, CPUI_BOOL_OR, CPUI_INT_MULT };
oplist.insert(oplist.end(),list,list+6);
}
int4 RuleIdentityEl::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constvn;
uintb val;
constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
val = constvn->getOffset();
if ((val == 0)&&(op->code() != CPUI_INT_MULT)) {
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1); return 1;
}
if (op->code() != CPUI_INT_MULT) return 0;
if (val == 1) {
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
return 1;
}
if (val == 0) { data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,0);
return 1;
}
return 0;
}
void RuleShift2Mult::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LEFT);
}
int4 RuleShift2Mult::applyOp(PcodeOp *op,Funcdata &data)
{
int4 flag;
list<PcodeOp *>::const_iterator desc;
Varnode *vn,*constvn;
PcodeOp *arithop;
OpCode opc;
int4 val;
flag = 0;
vn = op->getOut();
constvn = op->getIn(1);
if (!constvn->isConstant()) return 0; val = constvn->getOffset();
if (val >= 32) return 0;
arithop = op->getIn(0)->getDef();
desc = vn->beginDescend();
for(;;) {
if (arithop != (PcodeOp *)0) {
opc = arithop->code();
if ((opc==CPUI_INT_ADD)||(opc==CPUI_INT_SUB)||(opc==CPUI_INT_MULT)) {
flag = 1;
break;
}
}
if (desc == vn->endDescend()) break;
arithop = *desc++;
}
if (flag==0) return 0;
constvn = data.newConstant(vn->getSize(),((uintb)1)<<val);
data.opSetInput(op,constvn,1);
data.opSetOpcode(op,CPUI_INT_MULT);
return 1;
}
void RuleShiftPiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_OR);
oplist.push_back(CPUI_INT_XOR);
oplist.push_back(CPUI_INT_ADD);
}
int4 RuleShiftPiece::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *shiftop,*zextloop,*zexthiop;
Varnode *vn1,*vn2;
vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
vn2 = op->getIn(1);
if (!vn2->isWritten()) return 0;
shiftop = vn1->getDef();
zextloop = vn2->getDef();
if (shiftop->code() != CPUI_INT_LEFT) {
if (zextloop->code() != CPUI_INT_LEFT) return 0;
PcodeOp *tmpop = zextloop;
zextloop = shiftop;
shiftop = tmpop;
}
if (!shiftop->getIn(1)->isConstant()) return 0;
vn1 = shiftop->getIn(0);
if (!vn1->isWritten()) return 0;
zexthiop = vn1->getDef();
if ((zexthiop->code() != CPUI_INT_ZEXT)&&
(zexthiop->code()!= CPUI_INT_SEXT))
return 0;
vn1 = zexthiop->getIn(0);
if (vn1->isConstant()) {
if (vn1->getSize() < sizeof(uintb))
return 0; }
else if (vn1->isFree())
return 0;
int4 sa = shiftop->getIn(1)->getOffset();
int4 concatsize = sa + 8*vn1->getSize();
if (op->getOut()->getSize() * 8 < concatsize) return 0;
if (zextloop->code() != CPUI_INT_ZEXT) {
if (!vn1->isWritten()) return 0;
PcodeOp *rShiftOp = vn1->getDef(); if (rShiftOp->code() != CPUI_INT_SRIGHT) return 0;
if (!rShiftOp->getIn(1)->isConstant()) return 0;
vn2 = rShiftOp->getIn(0);
if (!vn2->isWritten()) return 0;
PcodeOp *subop = vn2->getDef();
if (subop->code() != CPUI_SUBPIECE) return 0; if (subop->getIn(1)->getOffset() != 0) return 0; Varnode *bigVn = zextloop->getOut();
if (subop->getIn(0) != bigVn) return 0; int4 rsa = (int4)rShiftOp->getIn(1)->getOffset();
if (rsa != vn2->getSize() * 8 -1) return 0; if ((bigVn->getNZMask() >> sa) != 0) return 0; if (sa != 8*(vn2->getSize())) return 0;
data.opSetOpcode(op,CPUI_INT_SEXT); data.opSetInput(op,vn2,0);
data.opRemoveInput(op,1);
return 1;
}
vn2 = zextloop->getIn(0);
if (vn2->isFree()) return 0;
if (sa != 8*(vn2->getSize())) return 0;
if (concatsize == op->getOut()->getSize() * 8) {
data.opSetOpcode(op,CPUI_PIECE);
data.opSetInput(op,vn1,0);
data.opSetInput(op,vn2,1);
}
else {
PcodeOp *newop = data.newOp(2,op->getAddr());
data.newUniqueOut(concatsize/8,newop);
data.opSetOpcode(newop,CPUI_PIECE);
data.opSetInput(newop,vn1,0);
data.opSetInput(newop,vn2,1);
data.opInsertBefore(newop,op);
data.opSetOpcode(op,zexthiop->code());
data.opRemoveInput(op,1);
data.opSetInput(op,newop->getOut(),0);
}
return 1;
}
int4 RuleCollapseConstants::applyOp(PcodeOp *op,Funcdata &data)
{
int4 i;
Varnode *vn;
if (!op->isCollapsible()) return 0;
Address newval;
bool markedInput = false;
try {
newval = data.getArch()->getConstant(op->collapse(markedInput));
}
catch(LowlevelError &err) {
data.opMarkNoCollapse(op); return 0;
}
vn = data.newVarnode(op->getOut()->getSize(),newval); if (markedInput) {
op->collapseConstantSymbol(vn);
}
for(i=op->numInput()-1;i>0;--i)
data.opRemoveInput(op,i); data.opSetInput(op,vn,0); data.opSetOpcode(op,CPUI_COPY);
return 1;
}
void RuleTransformCpool::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_CPOOLREF);
}
int4 RuleTransformCpool::applyOp(PcodeOp *op,Funcdata &data)
{
if (op->isCpoolTransformed()) return 0; data.opMarkCpoolTransformed(op); vector<uintb> refs;
for(int4 i=1;i<op->numInput();++i)
refs.push_back(op->getIn(i)->getOffset());
const CPoolRecord *rec = data.getArch()->cpool->getRecord(refs); if (rec != (const CPoolRecord *)0) {
if (rec->getTag() == CPoolRecord::instance_of) {
data.opMarkCalculatedBool(op);
}
else if (rec->getTag() == CPoolRecord::primitive) {
int4 sz = op->getOut()->getSize();
Varnode *cvn = data.newConstant(sz,rec->getValue() & calc_mask(sz));
cvn->updateType(rec->getType(),true,true);
while(op->numInput() > 1) {
data.opRemoveInput(op,op->numInput()-1);
}
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,cvn,0);
return 1;
}
data.opInsertInput(op,data.newConstant(4,rec->getTag()),op->numInput());
}
return 1;
}
int4 RulePropagateCopy::applyOp(PcodeOp *op,Funcdata &data)
{
int4 i;
PcodeOp *copyop;
Varnode *vn,*invn;
OpCode opc;
opc = op->code();
if (opc==CPUI_RETURN) return 0; for(i=0;i<op->numInput();++i) {
vn = op->getIn(i);
if (!vn->isWritten()) continue;
copyop = vn->getDef();
if (copyop->code()!=CPUI_COPY)
continue;
invn = copyop->getIn(0);
if (!invn->isHeritageKnown()) continue; if (invn == vn)
throw LowlevelError("Self-defined varnode");
if (op->isMarker()) {
if (invn->isConstant()) continue; if (vn->isAddrForce()) continue; if (invn->isAddrTied() && op->getOut()->isAddrTied() &&
(op->getOut()->getAddr() != invn->getAddr()))
continue; }
data.opSetInput(op,invn,i); return 1;
}
return 0;
}
void Rule2Comp2Mult::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_2COMP);
}
int4 Rule2Comp2Mult::applyOp(PcodeOp *op,Funcdata &data)
{
data.opSetOpcode(op,CPUI_INT_MULT);
int4 size = op->getIn(0)->getSize();
Varnode *negone = data.newConstant(size,calc_mask(size));
data.opInsertInput(op,negone,1);
return 1;
}
void RuleCarryElim::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_CARRY);
}
int4 RuleCarryElim::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn1,*vn2;
vn2 = op->getIn(1);
if (!vn2->isConstant()) return 0;
vn1 = op->getIn(0);
if (vn1->isFree()) return 0;
uintb off = vn2->getOffset();
if (off == 0) { data.opRemoveInput(op,1); data.opSetInput(op,data.newConstant(1,0),0); data.opSetOpcode(op,CPUI_COPY);
return 1;
}
off = (-off) & calc_mask(vn2->getSize());
data.opSetOpcode(op,CPUI_INT_LESSEQUAL);
data.opSetInput(op,vn1,1); data.opSetInput(op,data.newConstant(vn1->getSize(),off),0); return 1;
}
void RuleSub2Add::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SUB);
}
int4 RuleSub2Add::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *newop;
Varnode *vn,*newvn;
vn = op->getIn(1); newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_INT_MULT);
newvn = data.newUniqueOut(vn->getSize(),newop);
data.opSetInput( op, newvn, 1); data.opSetInput(newop, vn, 0);
data.opSetInput(newop, data.newConstant(vn->getSize(),calc_mask(vn->getSize())),1);
data.opSetOpcode(op, CPUI_INT_ADD );
data.opInsertBefore( newop, op);
return 1;
}
void RuleXorCollapse::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_EQUAL);
oplist.push_back(CPUI_INT_NOTEQUAL);
}
int4 RuleXorCollapse::applyOp(PcodeOp *op,Funcdata &data)
{
uintb coeff1,coeff2;
if (!op->getIn(1)->isConstant()) return 0;
PcodeOp *xorop = op->getIn(0)->getDef();
if (xorop == (PcodeOp *)0) return 0;
if (xorop->code() != CPUI_INT_XOR) return 0;
if (op->getIn(0)->loneDescend() == (PcodeOp *)0) return 0;
coeff1 = op->getIn(1)->getOffset();
Varnode *xorvn = xorop->getIn(1);
if (xorop->getIn(0)->isFree()) return 0; if (!xorvn->isConstant()) {
if (coeff1 != 0) return 0;
if (xorvn->isFree()) return 0;
data.opSetInput(op,xorvn,1); data.opSetInput(op,xorop->getIn(0),0);
return 1;
}
coeff2 = xorvn->getOffset();
if (coeff2 == 0) return 0;
Varnode *constvn = data.newConstant(op->getIn(1)->getSize(),coeff1^coeff2);
constvn->copySymbolIfValid(xorvn);
data.opSetInput(op,constvn,1);
data.opSetInput(op,xorop->getIn(0),0);
return 1;
}
void RuleAddMultCollapse::getOpList(vector<uint4> &oplist) const
{
uint4 list[]= { CPUI_INT_ADD, CPUI_INT_MULT };
oplist.insert(oplist.end(),list,list+2);
}
int4 RuleAddMultCollapse::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *c[2]; Varnode *sub,*sub2,*newvn;
PcodeOp *subop;
OpCode opc;
opc = op->code();
c[0] = op->getIn(1);
if (!c[0]->isConstant()) return 0; sub = op->getIn(0);
if (!sub->isWritten()) return 0;
subop = sub->getDef();
if (subop->code() != opc) return 0; c[1] = subop->getIn(1);
if (!c[1]->isConstant()) {
if (opc != CPUI_INT_ADD) return 0;
Varnode *othervn,*basevn;
PcodeOp *baseop;
for(int4 i=0;i<2;++i) {
othervn = subop->getIn(i);
if (othervn->isConstant()) continue;
if (othervn->isFree()) continue;
sub2 = subop->getIn(1-i);
if (!sub2->isWritten()) continue;
baseop = sub2->getDef();
if (baseop->code() != CPUI_INT_ADD) continue;
c[1] = baseop->getIn(1);
if (!c[1]->isConstant()) continue;
basevn = baseop->getIn(0);
if (!basevn->isSpacebase()) continue; if (!basevn->isInput()) continue;
uintb val = op->getOpcode()->evaluateBinary(c[0]->getSize(),c[0]->getSize(),c[0]->getOffset(),c[1]->getOffset());
newvn = data.newConstant(c[0]->getSize(),val);
if (c[0]->getSymbolEntry() != (SymbolEntry *)0)
newvn->copySymbolIfValid(c[0]);
else if (c[1]->getSymbolEntry() != (SymbolEntry *)0)
newvn->copySymbolIfValid(c[1]);
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_INT_ADD);
Varnode *newout = data.newUniqueOut(c[0]->getSize(),newop);
data.opSetInput(newop,basevn,0);
data.opSetInput(newop,newvn,1);
data.opInsertBefore(newop,op);
data.opSetInput(op,newout,0);
data.opSetInput(op,othervn,1);
return 1;
}
return 0;
}
sub2 = subop->getIn(0);
if (sub2->isFree()) return 0;
uintb val = op->getOpcode()->evaluateBinary(c[0]->getSize(),c[0]->getSize(),c[0]->getOffset(),c[1]->getOffset());
newvn = data.newConstant(c[0]->getSize(),val);
if (c[0]->getSymbolEntry() != (SymbolEntry *)0)
newvn->copySymbolIfValid(c[0]);
else if (c[1]->getSymbolEntry() != (SymbolEntry *)0)
newvn->copySymbolIfValid(c[1]);
data.opSetInput(op,newvn,1); data.opSetInput(op,sub2,0); return 1;
}
AddrSpace *RuleLoadVarnode::correctSpacebase(Architecture *glb,Varnode *vn,AddrSpace *spc)
{
if (!vn->isSpacebase()) return (AddrSpace *)0;
if (vn->isConstant()) return spc; if (!vn->isInput()) return (AddrSpace *)0;
AddrSpace *assoc = glb->getSpaceBySpacebase(vn->getAddr(),vn->getSize());
if (assoc->getContain() != spc) return (AddrSpace *)0;
return assoc;
}
AddrSpace *RuleLoadVarnode::vnSpacebase(Architecture *glb,Varnode *vn,uintb &val,AddrSpace *spc)
{
PcodeOp *op;
Varnode *vn1,*vn2;
AddrSpace *retspace;
retspace = correctSpacebase(glb,vn,spc);
if (retspace != (AddrSpace *)0) {
val = 0;
return retspace;
}
if (!vn->isWritten()) return (AddrSpace *)0;
op = vn->getDef();
if (op->code() != CPUI_INT_ADD) return (AddrSpace *)0;
vn1 = op->getIn(0);
vn2 = op->getIn(1);
retspace = correctSpacebase(glb,vn1,spc);
if (retspace != (AddrSpace *)0) {
if (vn2->isConstant()) {
val = vn2->getOffset();
return retspace;
}
return (AddrSpace *)0;
}
retspace = correctSpacebase(glb,vn2,spc);
if (retspace != (AddrSpace *)0) {
if (vn1->isConstant()) {
val = vn1->getOffset();
return retspace;
}
}
return (AddrSpace *)0;
}
AddrSpace *RuleLoadVarnode::checkSpacebase(Architecture *glb,PcodeOp *op,uintb &offoff)
{
Varnode *offvn;
AddrSpace *loadspace;
offvn = op->getIn(1); loadspace = Address::getSpaceFromConst(op->getIn(0)->getAddr()); if (offvn->isWritten()&&(offvn->getDef()->code()==CPUI_SEGMENTOP)) {
offvn = offvn->getDef()->getIn(2);
if (offvn->isConstant())
return (AddrSpace *)0;
}
else if (offvn->isConstant()) { offoff = offvn->getOffset();
return loadspace;
}
return vnSpacebase(glb,offvn,offoff,loadspace);
}
void RuleLoadVarnode::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleLoadVarnode::applyOp(PcodeOp *op,Funcdata &data)
{
int4 size;
Varnode *newvn;
AddrSpace *baseoff;
uintb offoff;
baseoff = checkSpacebase(data.getArch(),op,offoff);
if (baseoff == (AddrSpace *)0) return 0;
size = op->getOut()->getSize();
offoff = AddrSpace::addressToByte(offoff,baseoff->getWordSize());
newvn = data.newVarnode(size,baseoff,offoff);
data.opSetInput(op,newvn,0);
data.opRemoveInput(op,1);
data.opSetOpcode(op, CPUI_COPY );
Varnode *refvn = op->getOut();
if (refvn->isSpacebasePlaceholder()) {
refvn->clearSpacebasePlaceholder(); PcodeOp *placeOp = refvn->loneDescend();
if (placeOp != (PcodeOp *)0) {
FuncCallSpecs *fc = data.getCallSpecs(placeOp);
if (fc != (FuncCallSpecs *)0)
fc->resolveSpacebaseRelative(data,refvn);
}
}
return 1;
}
void RuleStoreVarnode::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_STORE);
}
int4 RuleStoreVarnode::applyOp(PcodeOp *op,Funcdata &data)
{
int4 size;
AddrSpace *baseoff;
uintb offoff;
baseoff = RuleLoadVarnode::checkSpacebase(data.getArch(),op,offoff);
if (baseoff == (AddrSpace *)0) return 0;
size = op->getIn(2)->getSize();
offoff = AddrSpace::addressToByte(offoff,baseoff->getWordSize());
Address addr(baseoff,offoff);
data.newVarnodeOut(size, addr,op);
op->getOut()->setStackStore(); data.opRemoveInput(op,1);
data.opRemoveInput(op,0);
data.opSetOpcode(op, CPUI_COPY );
return 1;
}
void RuleSubExtComm::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubExtComm::applyOp(PcodeOp *op,Funcdata &data)
{
int4 subcut = (int4)op->getIn(1)->getOffset();
Varnode *base = op->getIn(0);
if (op->getOut()->getSize()+subcut != base->getSize()) return 0;
if (!base->isWritten()) return 0;
PcodeOp *extop = base->getDef();
if ((extop->code()!=CPUI_INT_ZEXT)&&(extop->code()!=CPUI_INT_SEXT))
return 0;
Varnode *invn = extop->getIn(0);
if (invn->isFree()) return 0;
if (subcut >= invn->getSize()) return 0;
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_SUBPIECE);
Varnode *newvn = data.newUniqueOut(invn->getSize()-subcut,newop);
data.opSetInput(newop,data.newConstant(op->getIn(1)->getSize(),(uintb)subcut),1);
data.opSetInput(newop,invn,0);
data.opInsertBefore(newop,op);
data.opRemoveInput(op,1);
data.opSetOpcode(op,extop->code());
data.opSetInput(op,newvn,0);
return 1;
}
void RuleSubCommute::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
bool RuleSubCommute::cancelExtensions(PcodeOp *longform,PcodeOp *subOp,Varnode *ext0In,Varnode *ext1In,Funcdata &data)
{
if (ext0In->getSize() != ext1In->getSize()) return false; if (ext0In->isFree()) return false; if (ext1In->isFree()) return false;
Varnode *outvn = longform->getOut();
if (outvn->loneDescend() != subOp) return false; data.opUnsetOutput(longform);
outvn = data.newUniqueOut(ext0In->getSize(),longform); data.opSetInput(longform,ext0In,0);
data.opSetInput(longform,ext1In,1);
data.opSetInput(subOp,outvn,0);
return true;
}
int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *base,*vn,*newvn,*outvn;
PcodeOp *longform,*newsub,*prevop;
int4 i,j,offset,insize;
base = op->getIn(0);
if (!base->isWritten()) return 0;
offset = op->getIn(1)->getOffset();
outvn = op->getOut();
if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0;
insize = base->getSize();
longform = base->getDef();
j = -1;
switch( longform->code() ) { case CPUI_INT_LEFT:
j = 1; if (offset != 0) return 0;
if (!longform->getIn(0)->isWritten()) return 0;
prevop = longform->getIn(0)->getDef();
if (prevop->code()==CPUI_INT_ZEXT) {
}
else if (prevop->code()==CPUI_PIECE) {
}
else
return 0;
break;
case CPUI_INT_REM:
case CPUI_INT_DIV:
{
if (offset != 0) return 0;
if (!longform->getIn(0)->isWritten()) return 0;
PcodeOp *zext0 = longform->getIn(0)->getDef();
if (zext0->code() != CPUI_INT_ZEXT) return 0;
Varnode *zext0In = zext0->getIn(0);
if (longform->getIn(1)->isWritten()) {
PcodeOp *zext1 = longform->getIn(1)->getDef();
if (zext1->code() != CPUI_INT_ZEXT) return 0;
Varnode *zext1In = zext1->getIn(0);
if (zext1In->getSize() > outvn->getSize() || zext0In->getSize() > outvn->getSize()) {
if (cancelExtensions(longform,op,zext0In,zext1In,data)) return 1; return 0;
}
}
else if (longform->getIn(1)->isConstant() && (zext0In->getSize() <= outvn->getSize())) {
uintb val = longform->getIn(1)->getOffset();
uintb smallval = val & calc_mask(outvn->getSize());
if (val != smallval)
return 0;
}
else
return 0;
break;
}
case CPUI_INT_SREM:
case CPUI_INT_SDIV:
{
if (offset != 0) return 0;
if (!longform->getIn(0)->isWritten()) return 0;
PcodeOp *sext0 = longform->getIn(0)->getDef();
if (sext0->code() != CPUI_INT_SEXT) return 0;
Varnode *sext0In = sext0->getIn(0);
if (longform->getIn(1)->isWritten()) {
PcodeOp *sext1 = longform->getIn(1)->getDef();
if (sext1->code() != CPUI_INT_SEXT) return 0;
Varnode *sext1In = sext1->getIn(0);
if (sext1In->getSize() > outvn->getSize() || sext0In->getSize() > outvn->getSize()) {
if (cancelExtensions(longform,op,sext0In,sext1In,data)) return 1; return 0;
}
}
else if (longform->getIn(1)->isConstant() && (sext0In->getSize() <= outvn->getSize())) {
uintb val = longform->getIn(1)->getOffset();
uintb smallval = val & calc_mask(outvn->getSize());
smallval = sign_extend(smallval,outvn->getSize(),insize);
if (val != smallval)
return 0;
}
else
return 0;
break;
}
case CPUI_INT_ADD:
case CPUI_INT_MULT:
if (offset != 0) return 0;
break;
case CPUI_INT_NEGATE:
case CPUI_INT_XOR:
case CPUI_INT_AND:
case CPUI_INT_OR:
break;
default: return 0;
}
if (base->loneDescend() != op) return 0;
if (offset == 0) { PcodeOp *nextop = outvn->loneDescend();
if ((nextop != (PcodeOp *)0)&&(nextop->code() == CPUI_INT_ZEXT)) {
if (nextop->getOut()->getSize() == insize)
return 0;
}
}
for(i=0;i<longform->numInput();++i) {
vn = longform->getIn(i);
if (i!=j) {
newsub = data.newOp(2,op->getAddr()); data.opSetOpcode(newsub,CPUI_SUBPIECE);
newvn = data.newUniqueOut(outvn->getSize(),newsub); data.opSetInput(longform,newvn,i);
data.opSetInput(newsub,vn,0); data.opSetInput(newsub,data.newConstant(4,offset),1);
data.opInsertBefore(newsub,longform);
}
}
data.opSetOutput(longform,outvn);
data.opDestroy(op); return 1;
}
void RuleConcatCommute::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RuleConcatCommute::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn;
Varnode *hi,*lo,*newvn;
PcodeOp *logicop,*newconcat;
OpCode opc;
uintb val;
for(int4 i=0;i<2;++i) {
vn = op->getIn(i);
if (!vn->isWritten()) continue;
logicop = vn->getDef();
opc = logicop->code();
if ((opc == CPUI_INT_OR)||(opc == CPUI_INT_XOR)) {
if (!logicop->getIn(1)->isConstant()) continue;
val = logicop->getIn(1)->getOffset();
if (i==0) {
hi = logicop->getIn(0);
lo = op->getIn(1);
val <<= 8*lo->getSize();
}
else {
hi = op->getIn(0);
lo = logicop->getIn(0);
}
}
else if (opc == CPUI_INT_AND) {
if (!logicop->getIn(1)->isConstant()) continue;
val = logicop->getIn(1)->getOffset();
if (i==0) {
hi = logicop->getIn(0);
lo = op->getIn(1);
val <<= 8*lo->getSize();
val |= calc_mask(lo->getSize());
}
else {
hi = op->getIn(0);
lo = logicop->getIn(0);
val |= (calc_mask(hi->getSize()) << 8*lo->getSize());
}
}
else
continue;
if (hi->isFree()) continue;
if (lo->isFree()) continue;
newconcat = data.newOp(2,op->getAddr());
data.opSetOpcode(newconcat,CPUI_PIECE);
newvn = data.newUniqueOut(op->getOut()->getSize(),newconcat);
data.opSetInput(newconcat,hi,0);
data.opSetInput(newconcat,lo,1);
data.opInsertBefore(newconcat,op);
data.opSetOpcode(op,opc);
data.opSetInput(op,newvn,0);
data.opSetInput(op,data.newConstant(newvn->getSize(),val),1);
return 1;
}
return 0;
}
void RuleConcatZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RuleConcatZext::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *zextop;
Varnode *hi,*lo;
hi = op->getIn(0);
if (!hi->isWritten()) return 0;
zextop = hi->getDef();
if (zextop->code() != CPUI_INT_ZEXT) return 0;
hi = zextop->getIn(0);
lo = op->getIn(1);
if (hi->isFree()) return 0;
if (lo->isFree()) return 0;
PcodeOp *newconcat = data.newOp(2,op->getAddr());
data.opSetOpcode(newconcat,CPUI_PIECE);
Varnode *newvn = data.newUniqueOut(hi->getSize()+lo->getSize(),newconcat);
data.opSetInput(newconcat,hi,0);
data.opSetInput(newconcat,lo,1);
data.opInsertBefore(newconcat,op);
data.opRemoveInput(op,1);
data.opSetInput(op,newvn,0);
data.opSetOpcode(op,CPUI_INT_ZEXT);
return 1;
}
void RuleZextCommute::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleZextCommute::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *zextvn = op->getIn(0);
if (!zextvn->isWritten()) return 0;
PcodeOp *zextop = zextvn->getDef();
if (zextop->code() != CPUI_INT_ZEXT) return 0;
Varnode *zextin = zextop->getIn(0);
if (zextin->isFree()) return 0;
Varnode *savn = op->getIn(1);
if ((!savn->isConstant())&&(savn->isFree()))
return 0;
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_INT_RIGHT);
Varnode *newout = data.newUniqueOut(zextin->getSize(),newop);
data.opRemoveInput(op,1);
data.opSetInput(op,newout,0);
data.opSetOpcode(op,CPUI_INT_ZEXT);
data.opSetInput(newop,zextin,0);
data.opSetInput(newop,savn,1);
data.opInsertBefore(newop,op);
return 1;
}
void RuleZextShiftZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleZextShiftZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
if (!invn->isWritten()) return 0;
PcodeOp *shiftop = invn->getDef();
if (shiftop->code() == CPUI_INT_ZEXT) { Varnode *vn = shiftop->getIn(0);
if (vn->isFree()) return 0;
if (invn->loneDescend() != op) return 0;
data.opSetInput(op,vn,0);
return 1;
}
if (shiftop->code() != CPUI_INT_LEFT) return 0;
if (!shiftop->getIn(1)->isConstant()) return 0;
if (!shiftop->getIn(0)->isWritten()) return 0;
PcodeOp *zext2op = shiftop->getIn(0)->getDef();
if (zext2op->code() != CPUI_INT_ZEXT) return 0;
Varnode *rootvn = zext2op->getIn(0);
if (rootvn->isFree()) return 0;
uintb sa = shiftop->getIn(1)->getOffset();
if (sa > 8* (uintb)(zext2op->getOut()->getSize() - rootvn->getSize()))
return 0; PcodeOp *newop = data.newOp(1,op->getAddr());
data.opSetOpcode(newop,CPUI_INT_ZEXT);
Varnode *outvn = data.newUniqueOut(op->getOut()->getSize(),newop);
data.opSetInput(newop,rootvn,0);
data.opSetOpcode(op,CPUI_INT_LEFT);
data.opSetInput(op,outvn,0);
data.opInsertInput(op,data.newConstant(4,sa),1);
data.opInsertBefore(newop,op);
return 1;
}
void RuleShiftAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_INT_LEFT);
oplist.push_back(CPUI_INT_MULT);
}
int4 RuleShiftAnd::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *cvn = op->getIn(1);
if (!cvn->isConstant()) return 0;
Varnode *shiftin = op->getIn(0);
if (!shiftin->isWritten()) return 0;
PcodeOp *andop = shiftin->getDef();
if (andop->code() != CPUI_INT_AND) return 0;
if (shiftin->loneDescend() != op) return 0;
Varnode *maskvn = andop->getIn(1);
if (!maskvn->isConstant()) return 0;
uintb mask = maskvn->getOffset();
Varnode *invn = andop->getIn(0);
if (invn->isFree()) return 0;
OpCode opc = op->code();
int4 sa;
if ((opc == CPUI_INT_RIGHT)||(opc == CPUI_INT_LEFT))
sa = (int4)cvn->getOffset();
else {
sa = leastsigbit_set(cvn->getOffset()); if (sa <= 0) return 0;
uintb testval = 1;
testval <<= sa;
if (testval != cvn->getOffset()) return 0;
opc = CPUI_INT_LEFT; }
uintb nzm = invn->getNZMask();
uintb fullmask = calc_mask(invn->getSize());
if (opc == CPUI_INT_RIGHT) {
nzm >>= sa;
mask >>= sa;
}
else {
nzm <<= sa;
mask <<= sa;
nzm &= fullmask;
mask &= fullmask;
}
if ((mask & nzm) != nzm) return 0;
data.opSetOpcode(andop,CPUI_COPY); data.opRemoveInput(andop,1);
return 1;
}
void RuleConcatZero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RuleConcatZero::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
if (op->getIn(1)->getOffset() != 0) return 0;
int4 sa = 8*op->getIn(1)->getSize();
Varnode *highvn = op->getIn(0);
PcodeOp *newop = data.newOp(1,op->getAddr());
Varnode *outvn = data.newUniqueOut(op->getOut()->getSize(),newop);
data.opSetOpcode(newop,CPUI_INT_ZEXT);
data.opSetOpcode(op,CPUI_INT_LEFT);
data.opSetInput(op,outvn,0);
data.opSetInput(op,data.newConstant(4,sa),1);
data.opSetInput(newop,highvn,0);
data.opInsertBefore(newop,op);
return 1;
}
void RuleConcatLeftShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RuleConcatLeftShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn2 = op->getIn(1);
if (!vn2->isWritten()) return 0;
PcodeOp *shiftop = vn2->getDef();
if (shiftop->code() != CPUI_INT_LEFT) return 0;
if (!shiftop->getIn(1)->isConstant()) return 0; int4 sa = shiftop->getIn(1)->getOffset();
if ((sa&7)!=0) return 0; Varnode *tmpvn = shiftop->getIn(0);
if (!tmpvn->isWritten()) return 0;
PcodeOp *zextop = tmpvn->getDef();
if (zextop->code() != CPUI_INT_ZEXT) return 0;
Varnode *b = zextop->getIn(0);
if (b->isFree()) return 0;
Varnode *vn1 = op->getIn(0);
if (vn1->isFree()) return 0;
sa /= 8; if (sa + b->getSize() != tmpvn->getSize()) return 0;
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_PIECE);
Varnode *newout = data.newUniqueOut(vn1->getSize() + b->getSize(),newop);
data.opSetInput(newop,vn1,0);
data.opSetInput(newop,b,1);
data.opInsertBefore(newop,op);
data.opSetInput(op,newout,0);
data.opSetInput(op,data.newConstant(op->getOut()->getSize()-newout->getSize() ,0),1);
return 1;
}
void RuleSubZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleSubZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *subvn,*basevn,*constvn;
PcodeOp *subop;
uintb val;
subvn = op->getIn(0);
if (!subvn->isWritten()) return 0;
subop = subvn->getDef();
if (subop->code() == CPUI_SUBPIECE) {
basevn = subop->getIn(0);
if (basevn->isFree()) return 0;
if (basevn->getSize() != op->getOut()->getSize()) return 0; if (subop->getIn(1)->getOffset() != 0) { if (subvn->loneDescend() != op) return 0; Varnode *newvn = data.newUnique(basevn->getSize(),(Datatype *)0);
constvn = subop->getIn(1);
uintb rightVal = constvn->getOffset() * 8;
data.opSetInput(op,newvn,0);
data.opSetOpcode(subop,CPUI_INT_RIGHT); data.opSetInput(subop,data.newConstant(constvn->getSize(),rightVal),1);
data.opSetOutput(subop,newvn);
}
else
data.opSetInput(op,basevn,0); val = calc_mask(subvn->getSize());
constvn = data.newConstant(basevn->getSize(),val);
data.opSetOpcode(op,CPUI_INT_AND);
data.opInsertInput(op,constvn,1);
return 1;
}
else if (subop->code() == CPUI_INT_RIGHT) {
PcodeOp *shiftop = subop;
if (!shiftop->getIn(1)->isConstant()) return 0;
Varnode *midvn = shiftop->getIn(0);
if (!midvn->isWritten()) return 0;
subop = midvn->getDef();
if (subop->code() != CPUI_SUBPIECE) return 0;
basevn = subop->getIn(0);
if (basevn->isFree()) return 0;
if (basevn->getSize() != op->getOut()->getSize()) return 0; if (midvn->loneDescend() != shiftop) return 0;
if (subvn->loneDescend() != op) return 0;
val = calc_mask(midvn->getSize()); uintb sa = shiftop->getIn(1)->getOffset(); val >>= sa;
sa += subop->getIn(1)->getOffset() * 8; Varnode *newvn = data.newUnique(basevn->getSize(),(Datatype *)0);
data.opSetInput(op,newvn,0);
data.opSetInput(shiftop,basevn,0); data.opSetInput(shiftop,data.newConstant(shiftop->getIn(1)->getSize(),sa),1); data.opSetOutput(shiftop,newvn);
constvn = data.newConstant(basevn->getSize(),val);
data.opSetOpcode(op,CPUI_INT_AND); data.opInsertInput(op,constvn,1); return 1;
}
return 0;
}
void RuleSubCancel::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubCancel::applyOp(PcodeOp *op,Funcdata &data)
{ Varnode *base,*thruvn;
int4 offset,outsize,insize,farinsize;
PcodeOp *extop;
OpCode opc;
base = op->getIn(0);
if (!base->isWritten()) return 0;
extop = base->getDef();
opc = extop->code();
if ((opc != CPUI_INT_ZEXT)&&(opc != CPUI_INT_SEXT))
return 0;
offset = op->getIn(1)->getOffset();
outsize = op->getOut()->getSize();
insize = base->getSize();
farinsize = extop->getIn(0)->getSize();
if (offset == 0) { thruvn = extop->getIn(0); if (thruvn->isFree()) {
if (thruvn->isConstant() && (insize > sizeof(uintb)) && (outsize == farinsize)) {
opc = CPUI_COPY; thruvn = data.newConstant(thruvn->getSize(),thruvn->getOffset()); }
else
return 0; }
else if (outsize == farinsize)
opc = CPUI_COPY; else if (outsize < farinsize)
opc = CPUI_SUBPIECE;
}
else {
if ((opc==CPUI_INT_ZEXT)&&(farinsize<=offset)) { opc = CPUI_COPY; thruvn = data.newConstant(outsize,0);
}
else return 0;
}
data.opSetOpcode(op,opc); data.opSetInput(op,thruvn,0);
if (opc == CPUI_SUBPIECE)
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),offset),1);
else
data.opRemoveInput(op,1); return 1;
}
void RuleShiftSub::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleShiftSub::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *shiftop = op->getIn(0)->getDef();
if (shiftop->code() != CPUI_INT_LEFT) return 0;
if (!shiftop->getIn(1)->isConstant()) return 0;
if (8*op->getIn(1)->getOffset() != shiftop->getIn(1)->getOffset())
return 0;
Varnode *vn = shiftop->getIn(0);
if (vn->isFree()) return 0;
data.opSetInput(op,vn,0);
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),0),1);
return 1;
}
void RuleHumptyDumpty::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RuleHumptyDumpty::applyOp(PcodeOp *op,Funcdata &data)
{
uintb pos1,pos2;
int4 size1,size2;
Varnode *vn1,*vn2,*root;
PcodeOp *sub1,*sub2;
vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
sub1 = vn1->getDef();
if (sub1->code() != CPUI_SUBPIECE) return 0; vn2 = op->getIn(1);
if (!vn2->isWritten()) return 0;
sub2 = vn2->getDef();
if (sub2->code() != CPUI_SUBPIECE) return 0;
root = sub1->getIn(0);
if (root != sub2->getIn(0)) return 0;
pos1 = sub1->getIn(1)->getOffset();
pos2 = sub2->getIn(1)->getOffset();
size1 = vn1->getSize();
size2 = vn2->getSize();
if (pos1 != pos2 + size2) return 0;
if ((pos2==0)&&(size1+size2==root->getSize())) { data.opRemoveInput(op,1);
data.opSetInput(op,root,0);
data.opSetOpcode(op,CPUI_COPY);
}
else { data.opSetInput(op,root,0);
data.opSetInput(op,data.newConstant(sub2->getIn(1)->getSize(),pos2),1);
data.opSetOpcode(op,CPUI_SUBPIECE);
}
return 1;
}
void RuleDumptyHump::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleDumptyHump::applyOp(PcodeOp *op,Funcdata &data)
{ Varnode *base,*vn,*vn1,*vn2;
PcodeOp *pieceop;
int4 offset,outsize;
base = op->getIn(0);
if (!base->isWritten()) return 0;
pieceop = base->getDef();
if (pieceop->code() != CPUI_PIECE) return 0;
offset = op->getIn(1)->getOffset();
outsize = op->getOut()->getSize();
vn1 = pieceop->getIn(0);
vn2 = pieceop->getIn(1);
if (offset < vn2->getSize()) { if (offset+outsize > vn2->getSize()) return 0; vn = vn2;
}
else { vn = vn1;
offset -= vn2->getSize(); }
if (vn->isFree() && (!vn->isConstant())) return 0;
if ((offset==0)&&(outsize==vn->getSize())) {
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
data.opSetInput(op,vn,0); }
else {
data.opSetInput(op,vn,0); data.opSetInput(op,data.newConstant(4,offset),1);
}
return 1;
}
void RuleHumptyOr::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_OR);
}
int4 RuleHumptyOr::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn1,*vn2;
Varnode *a, *b, *c, *d;
PcodeOp *and1,*and2;
vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
vn2 = op->getIn(1);
if (!vn2->isWritten()) return 0;
and1 = vn1->getDef();
if (and1->code() != CPUI_INT_AND) return 0;
and2 = vn2->getDef();
if (and2->code() != CPUI_INT_AND) return 0;
a = and1->getIn(0);
b = and1->getIn(1);
c = and2->getIn(0);
d = and2->getIn(1);
if (a == c) {
c = d; }
else if (a == d) { }
else if (b == c) { b = a;
a = c;
c = d;
}
else if (b == d) { b = a;
a = d;
}
else
return 0;
if (b->isConstant() && c->isConstant()) {
uintb totalbits = b->getOffset() | c->getOffset();
if (totalbits == calc_mask(a->getSize())) {
data.opSetOpcode(op,CPUI_COPY);
data.opRemoveInput(op,1);
data.opSetInput(op,a,0);
}
else {
data.opSetOpcode(op,CPUI_INT_AND);
data.opSetInput(op,a,0);
Varnode *newconst = data.newConstant(a->getSize(),totalbits);
data.opSetInput(op,newconst,1);
}
}
else {
if (!b->isHeritageKnown()) return 0;
if (!c->isHeritageKnown()) return 0;
uintb aMask = a->getNZMask();
if ((b->getNZMask() & aMask)==0) return 0; if ((c->getNZMask() & aMask)==0) return 0; PcodeOp *newOrOp = data.newOp(2,op->getAddr());
data.opSetOpcode(newOrOp,CPUI_INT_OR);
Varnode *orVn = data.newUniqueOut(a->getSize(),newOrOp);
data.opSetInput(newOrOp,b,0);
data.opSetInput(newOrOp,c,1);
data.opInsertBefore(newOrOp,op);
data.opSetInput(op,a,0);
data.opSetInput(op,orVn,1);
data.opSetOpcode(op,CPUI_INT_AND);
}
return 1;
}
void RuleEmbed::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RuleEmbed::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *a,*subout,*x;
PcodeOp *subop;
int4 i;
if (op->getOut()->getSize() > sizeof(uintb)) return 0; for(i=0;i<2;++i) {
subout = op->getIn(i);
if (!subout->isWritten()) continue;
subop = subout->getDef();
if (subop->code() != CPUI_SUBPIECE) continue;
int4 c = subop->getIn(1)->getOffset();
a = subop->getIn(0);
if (a->isFree()) continue;
if (a->getSize() != op->getOut()->getSize()) continue;
x = op->getIn(1-i);
if (x->isFree()) continue;
if (i==0) {
if (subout->getSize()+c != a->getSize()) continue; }
else {
if (c != 0) continue; }
if (x->isWritten()) { PcodeOp *othersub = x->getDef();
if (othersub->code() == CPUI_SUBPIECE) {
if (othersub->getIn(0)==a) {
int4 d = othersub->getIn(1)->getOffset();
if ((i==0)&&(d==0)) continue;
if ((i==1)&&(d==subout->getSize())) continue;
}
}
}
uintb mask = calc_mask(subout->getSize());
mask <<= 8*c;
PcodeOp *andop = data.newOp(2,op->getAddr());
data.opSetOpcode(andop,CPUI_INT_AND);
data.newUniqueOut(a->getSize(),andop);
data.opSetInput(andop,a,0);
data.opSetInput(andop,data.newConstant(a->getSize(),mask),1);
data.opInsertBefore(andop,op);
PcodeOp *extop = data.newOp(1,op->getAddr());
data.opSetOpcode(extop,CPUI_INT_ZEXT);
data.newUniqueOut(a->getSize(),extop);
data.opSetInput(extop,x,0);
data.opInsertBefore(extop,op);
x = extop->getOut();
if (i==1) { PcodeOp *shiftop = data.newOp(2,op->getAddr());
data.opSetOpcode(shiftop,CPUI_INT_LEFT);
data.newUniqueOut(a->getSize(),shiftop);
data.opSetInput(shiftop,x,0);
data.opSetInput(shiftop,data.newConstant(4,8*subout->getSize()),1);
data.opInsertBefore(shiftop,op);
x = shiftop->getOut();
}
data.opSetOpcode(op,CPUI_INT_OR);
data.opSetInput(op,andop->getOut(),0);
data.opSetInput(op,x,1);
return 1;
}
return 0;
}
void RuleSwitchSingle::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BRANCHIND);
}
int4 RuleSwitchSingle::applyOp(PcodeOp *op,Funcdata &data)
{
BlockBasic *bb = op->getParent();
if (bb->sizeOut() != 1) return 0;
JumpTable *jt = data.findJumpTable(op);
if (jt == (JumpTable *)0) return 0;
if (jt->numEntries() == 0) return 0;
if (!jt->isLabelled()) return 0; Address addr = jt->getAddressByIndex(0);
bool needwarning = false;
bool allcasesmatch = false;
if (jt->numEntries() != 1) {
needwarning = true;
allcasesmatch = true;
for(int4 i=1;i<jt->numEntries();++i) {
if (jt->getAddressByIndex(i) != addr) {
allcasesmatch = false;
break;
}
}
}
if (!op->getIn(0)->isConstant())
needwarning = true;
if (needwarning) {
ostringstream s;
s << "Switch with 1 destination removed at ";
op->getAddr().printRaw(s);
if (allcasesmatch) {
s << " : " << dec << jt->numEntries() << " cases all go to same destination";
}
data.warningHeader(s.str());
}
data.opSetOpcode(op,CPUI_BRANCH);
data.opSetInput(op,data.newCodeRef(addr),0);
data.removeJumpTable(jt);
data.getStructure().clear(); return 1;
}
void RuleCondNegate::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_CBRANCH);
}
int4 RuleCondNegate::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *newop;
Varnode *vn,*outvn;
if (!op->isBooleanFlip()) return 0;
vn = op->getIn(1);
newop = data.newOp(1,op->getAddr());
data.opSetOpcode(newop,CPUI_BOOL_NEGATE);
outvn = data.newUniqueOut(1,newop); data.opSetInput(newop,vn,0);
data.opSetInput(op,outvn,1);
data.opInsertBefore(newop,op);
data.opFlipCondition(op); return 1;
}
void RuleBoolNegate::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_BOOL_NEGATE);
}
int4 RuleBoolNegate::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn;
PcodeOp *flip_op;
OpCode opc;
bool flipyes;
vn = op->getIn(0);
if (!vn->isWritten()) return 0;
flip_op = vn->getDef();
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter)
if ((*iter)->code() != CPUI_BOOL_NEGATE) return 0;
opc = get_booleanflip(flip_op->code(),flipyes);
if (opc == CPUI_MAX) return 0;
data.opSetOpcode(flip_op,opc); if (flipyes) data.opSwapInput(flip_op,0,1);
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter)
data.opSetOpcode(*iter,CPUI_COPY); return 1;
}
void RuleLess2Zero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LESS);
}
int4 RuleLess2Zero::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *lvn,*rvn;
lvn = op->getIn(0);
rvn = op->getIn(1);
if (lvn->isConstant()) {
if (lvn->getOffset() == 0) {
data.opSetOpcode(op,CPUI_INT_NOTEQUAL); return 1;
}
else if (lvn->getOffset() == calc_mask(lvn->getSize())) {
data.opSetOpcode(op,CPUI_COPY); data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(1,0),0);
return 1;
}
}
else if (rvn->isConstant()) {
if (rvn->getOffset() == 0) {
data.opSetOpcode(op,CPUI_COPY); data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(1,0),0);
return 1;
}
else if (rvn->getOffset() == calc_mask(rvn->getSize())) { data.opSetOpcode(op,CPUI_INT_NOTEQUAL);
return 1;
}
}
return 0;
}
void RuleLessEqual2Zero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_LESSEQUAL);
}
int4 RuleLessEqual2Zero::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *lvn,*rvn;
lvn = op->getIn(0);
rvn = op->getIn(1);
if (lvn->isConstant()) {
if (lvn->getOffset() == 0) {
data.opSetOpcode(op,CPUI_COPY); data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(1,1),0);
return 1;
}
else if (lvn->getOffset() == calc_mask(lvn->getSize())) {
data.opSetOpcode(op,CPUI_INT_EQUAL); return 1;
}
}
else if (rvn->isConstant()) {
if (rvn->getOffset() == 0) {
data.opSetOpcode(op,CPUI_INT_EQUAL); return 1;
}
else if (rvn->getOffset() == calc_mask(rvn->getSize())) {
data.opSetOpcode(op,CPUI_COPY); data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(1,1),0);
return 1;
}
}
return 0;
}
Varnode *RuleSLess2Zero::getHiBit(PcodeOp *op)
{
OpCode opc = op->code();
if ((opc != CPUI_INT_ADD)&&(opc != CPUI_INT_OR)&&(opc != CPUI_INT_XOR))
return (Varnode *)0;
Varnode *vn1 = op->getIn(0);
Varnode *vn2 = op->getIn(1);
uintb mask = calc_mask(vn1->getSize());
mask = (mask ^ (mask>>1)); uintb nzmask1 = vn1->getNZMask();
if ((nzmask1!=mask)&&((nzmask1 & mask)!=0)) return (Varnode *)0;
uintb nzmask2 = vn2->getNZMask();
if ((nzmask2!=mask)&&((nzmask2 & mask)!=0))
return (Varnode *)0;
if (nzmask1 == mask)
return vn1;
if (nzmask2 == mask)
return vn2;
return (Varnode *)0;
}
void RuleSLess2Zero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SLESS);
}
int4 RuleSLess2Zero::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *lvn,*rvn,*coeff,*avn;
PcodeOp *feedOp;
OpCode feedOpCode;
lvn = op->getIn(0);
rvn = op->getIn(1);
if (lvn->isConstant()) {
if (!rvn->isWritten()) return 0;
if (lvn->getOffset() == 0) {
feedOp = rvn->getDef();
feedOpCode = feedOp->code();
if (feedOpCode == CPUI_INT_MULT) {
coeff = feedOp->getIn(1);
if (!coeff->isConstant()) return 0;
if (coeff->getOffset() != calc_mask(coeff->getSize())) return 0;
avn = feedOp->getIn(0);
if (avn->isFree()) return 0;
data.opSetInput(op,avn,0);
data.opSetInput(op,lvn,1);
return 1;
}
}
else if (lvn->getOffset() == calc_mask(lvn->getSize())) {
feedOp = rvn->getDef();
feedOpCode = feedOp->code();
Varnode *hibit = getHiBit(feedOp);
if (hibit != (Varnode *) 0) { if (hibit->isConstant())
data.opSetInput(op, data.newConstant(hibit->getSize(), hibit->getOffset()), 1);
else
data.opSetInput(op, hibit, 1);
data.opSetOpcode(op, CPUI_INT_EQUAL);
data.opSetInput(op, data.newConstant(hibit->getSize(), 0), 0);
return 1;
}
else if (feedOpCode == CPUI_SUBPIECE) {
avn = feedOp->getIn(0);
if (avn->isFree())
return 0;
if (rvn->getSize() + (int4) feedOp->getIn(1)->getOffset() == avn->getSize()) {
data.opSetInput(op, avn, 1);
data.opSetInput(op, data.newConstant(avn->getSize(), calc_mask(avn->getSize())), 0);
return 1;
}
}
else if (feedOpCode == CPUI_INT_NEGATE) {
avn = feedOp->getIn(0);
if (avn->isFree())
return 0;
data.opSetInput(op, avn, 0);
data.opSetInput(op, data.newConstant(avn->getSize(), 0), 1);
return 1;
}
else if (feedOpCode == CPUI_INT_AND) {
avn = feedOp->getIn(0);
if (avn->isFree() || rvn->loneDescend() == (PcodeOp *)0)
return 0;
Varnode *maskVn = feedOp->getIn(1);
if (maskVn->isConstant()) {
uintb mask = maskVn->getOffset();
mask >>= (8 * avn->getSize() - 1); if ((mask & 1) != 0) {
data.opSetInput(op, avn, 1);
return 1;
}
}
}
else if (feedOpCode == CPUI_PIECE) {
avn = feedOp->getIn(0); if (avn->isFree())
return 0;
data.opSetInput(op, avn, 1);
data.opSetInput(op, data.newConstant(avn->getSize(),calc_mask(avn->getSize())), 0);
return 1;
}
}
}
else if (rvn->isConstant()) {
if (!lvn->isWritten()) return 0;
if (rvn->getOffset() == 0) {
feedOp = lvn->getDef();
feedOpCode = feedOp->code();
if (feedOpCode == CPUI_INT_MULT) {
coeff = feedOp->getIn(1);
if (!coeff->isConstant()) return 0;
if (coeff->getOffset() != calc_mask(coeff->getSize())) return 0;
avn = feedOp->getIn(0);
if (avn->isFree()) return 0;
data.opSetInput(op,avn,1);
data.opSetInput(op,rvn,0);
return 1;
}
else {
Varnode *hibit = getHiBit(feedOp);
if (hibit != (Varnode *)0) { if (hibit->isConstant())
data.opSetInput(op,data.newConstant(hibit->getSize(),hibit->getOffset()),0);
else
data.opSetInput(op,hibit,0);
data.opSetOpcode(op,CPUI_INT_NOTEQUAL);
return 1;
}
else if (feedOpCode == CPUI_SUBPIECE) {
avn = feedOp->getIn(0);
if (avn->isFree()) return 0;
if (lvn->getSize() + (int4)feedOp->getIn(1)->getOffset() == avn->getSize()) {
data.opSetInput(op,avn,0);
data.opSetInput(op,data.newConstant(avn->getSize(),0),1);
return 1;
}
}
else if (feedOpCode == CPUI_INT_NEGATE) {
avn = feedOp->getIn(0);
if (avn->isFree()) return 0;
data.opSetInput(op,avn,1);
data.opSetInput(op,data.newConstant(avn->getSize(),calc_mask(avn->getSize())),0);
return 1;
}
else if (feedOpCode == CPUI_INT_AND) {
avn = feedOp->getIn(0);
if (avn->isFree() || lvn->loneDescend() == (PcodeOp *)0)
return 0;
Varnode *maskVn = feedOp->getIn(1);
if (maskVn->isConstant()) {
uintb mask = maskVn->getOffset();
mask >>= (8 * avn->getSize() - 1); if ((mask & 1) != 0) {
data.opSetInput(op, avn, 0);
return 1;
}
}
}
else if (feedOpCode == CPUI_PIECE) {
avn = feedOp->getIn(0); if (avn->isFree())
return 0;
data.opSetInput(op, avn, 0);
data.opSetInput(op, data.newConstant(avn->getSize(), 0), 1);
return 1;
}
}
}
}
return 0;
}
void RuleEqual2Zero::getOpList(vector<uint4> &oplist) const
{
uint4 list[] = { CPUI_INT_EQUAL, CPUI_INT_NOTEQUAL };
oplist.insert(oplist.end(),list,list+2);
}
int4 RuleEqual2Zero::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn,*vn2,*addvn;
Varnode *posvn,*negvn,*unnegvn;
PcodeOp *addop;
vn = op->getIn(0);
if ((vn->isConstant())&&(vn->getOffset() == 0))
addvn = op->getIn(1);
else {
addvn = vn;
vn = op->getIn(1);
if ((!vn->isConstant())||(vn->getOffset() != 0))
return 0;
}
for(list<PcodeOp *>::const_iterator iter=addvn->beginDescend();iter!=addvn->endDescend();++iter) {
PcodeOp *boolop = *iter;
if (!boolop->isBoolOutput()) return 0;
}
addop = addvn->getDef();
if (addop==(PcodeOp *)0) return 0;
if (addop->code() != CPUI_INT_ADD) return 0;
vn = addop->getIn(0);
vn2 = addop->getIn(1);
if (vn2->isConstant()) {
Address val(vn2->getSpace(),uintb_negate(vn2->getOffset()-1,vn2->getSize()));
unnegvn = data.newVarnode(vn2->getSize(),val);
unnegvn->copySymbolIfValid(vn2); posvn = vn;
}
else {
if ((vn->isWritten())&&(vn->getDef()->code()==CPUI_INT_MULT)) {
negvn = vn;
posvn = vn2;
}
else if ((vn2->isWritten())&&(vn2->getDef()->code()==CPUI_INT_MULT)) {
negvn = vn2;
posvn = vn;
}
else
return 0;
uintb multiplier;
if (!negvn->getDef()->getIn(1)->isConstant()) return 0;
unnegvn = negvn->getDef()->getIn(0);
multiplier = negvn->getDef()->getIn(1)->getOffset();
if (multiplier != calc_mask(unnegvn->getSize())) return 0;
}
if (!posvn->isHeritageKnown()) return 0;
if (!unnegvn->isHeritageKnown()) return 0;
data.opSetInput(op,posvn,0);
data.opSetInput(op,unnegvn,1);
return 1;
}
void RuleEqual2Constant::getOpList(vector<uint4> &oplist) const
{
uint4 list[] = { CPUI_INT_EQUAL, CPUI_INT_NOTEQUAL };
oplist.insert(oplist.end(),list,list+2);
}
int4 RuleEqual2Constant::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *cvn = op->getIn(1);
if (!cvn->isConstant()) return 0;
Varnode *lhs = op->getIn(0);
if (!lhs->isWritten()) return 0;
PcodeOp *leftop = lhs->getDef();
Varnode *a;
uintb newconst;
OpCode opc = leftop->code();
if (opc == CPUI_INT_ADD) {
Varnode *otherconst = leftop->getIn(1);
if (!otherconst->isConstant()) return 0;
newconst = cvn->getOffset() - otherconst->getOffset();
newconst &= calc_mask(cvn->getSize());
}
else if (opc == CPUI_INT_MULT) {
Varnode *otherconst = leftop->getIn(1);
if (!otherconst->isConstant()) return 0;
if (otherconst->getOffset() != calc_mask(otherconst->getSize())) return 0;
newconst = cvn->getOffset();
newconst = (-newconst) & calc_mask(otherconst->getSize());
}
else if (opc == CPUI_INT_NEGATE) {
newconst = cvn->getOffset();
newconst = (~newconst) & calc_mask(lhs->getSize());
}
else
return 0;
a = leftop->getIn(0);
if (a->isFree()) return 0;
list<PcodeOp *>::const_iterator iter;
for(iter=lhs->beginDescend();iter!=lhs->endDescend();++iter) {
PcodeOp *dop = *iter;
if (dop == op) continue;
if ((dop->code()!=CPUI_INT_EQUAL)&&(dop->code()!=CPUI_INT_NOTEQUAL))
return 0;
if (!dop->getIn(1)->isConstant()) return 0;
}
data.opSetInput(op,a,0);
data.opSetInput(op,data.newConstant(a->getSize(),newconst),1);
return 1;
}
void AddTreeState::clear(void)
{
multsum = 0;
nonmultsum = 0;
if (pRelType != (const TypePointerRel *)0) {
nonmultsum = ((TypePointerRel *)ct)->getPointerOffset();
nonmultsum &= ptrmask;
}
multiple.clear();
coeff.clear();
nonmult.clear();
correct = 0;
offset = 0;
valid = true;
isDistributeUsed = false;
isSubtype = false;
distributeOp = (PcodeOp *)0;
}
bool AddTreeState::initAlternateForm(void)
{
if (pRelType == (const TypePointerRel *)0)
return false;
pRelType = (const TypePointerRel *)0;
baseType = ct->getPtrTo();
if (baseType->isVariableLength())
size = 0; else
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
int4 unitsize = AddrSpace::addressToByteInt(1,ct->getWordSize());
isDegenerate = (baseType->getSize() <= unitsize && baseType->getSize() > 0);
preventDistribution = false;
clear();
return true;
}
AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
: data(d)
{
baseOp = op;
ptr = op->getIn(slot);
ct = (const TypePointer *)ptr->getType();
ptrsize = ptr->getSize();
ptrmask = calc_mask(ptrsize);
baseType = ct->getPtrTo();
multsum = 0; nonmultsum = 0;
pRelType = (const TypePointerRel *)0;
if (ct->isFormalPointerRel()) {
pRelType = (const TypePointerRel *)ct;
baseType = pRelType->getParent();
nonmultsum = pRelType->getPointerOffset();
nonmultsum &= ptrmask;
}
if (baseType->isVariableLength())
size = 0; else
size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize());
correct = 0;
offset = 0;
valid = true; preventDistribution = false;
isDistributeUsed = false;
isSubtype = false;
distributeOp = (PcodeOp *)0;
int4 unitsize = AddrSpace::addressToByteInt(1,ct->getWordSize());
isDegenerate = (baseType->getSize() <= unitsize && baseType->getSize() > 0);
}
uint4 AddTreeState::findArrayHint(void) const
{
uint4 res = 0;
for(int4 i=0;i<nonmult.size();++i) {
Varnode *vn = nonmult[i];
if (vn->isConstant()) continue;
uint4 vncoeff = 1;
if (vn->isWritten()) {
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_INT_MULT) {
Varnode *vnconst = op->getIn(1);
if (vnconst->isConstant()) {
intb sval = vnconst->getOffset();
sign_extend(sval,vnconst->getSize()*8-1);
vncoeff = (sval < 0) ? (uint4)-sval : (uint4)sval;
}
}
}
if (vncoeff > res)
res = vncoeff;
}
return res;
}
bool AddTreeState::hasMatchingSubType(uintb off,uint4 arrayHint,uintb *newoff) const
{
if (arrayHint == 0)
return (baseType->getSubType(off,newoff) != (Datatype *)0);
int4 elSizeBefore;
uintb offBefore;
Datatype *typeBefore = baseType->nearestArrayedComponentBackward(off, &offBefore, &elSizeBefore);
if (typeBefore != (Datatype *)0) {
if (arrayHint == 1 || elSizeBefore == arrayHint) {
int4 sizeAddr = AddrSpace::byteToAddressInt(typeBefore->getSize(),ct->getWordSize());
if (offBefore < sizeAddr) {
*newoff = offBefore;
return true;
}
}
}
int4 elSizeAfter;
uintb offAfter;
Datatype *typeAfter = baseType->nearestArrayedComponentForward(off, &offAfter, &elSizeAfter);
if (typeBefore == (Datatype *)0 && typeAfter == (Datatype *)0)
return (baseType->getSubType(off,newoff) != (Datatype *)0);
if (typeBefore == (Datatype *)0) {
*newoff = offAfter;
return true;
}
if (typeAfter == (Datatype *)0) {
*newoff = offBefore;
return true;
}
uintb distBefore = offBefore;
uintb distAfter = -offAfter;
if (arrayHint != 1) {
if (elSizeBefore != arrayHint)
distBefore += 0x1000;
if (elSizeAfter != arrayHint)
distAfter += 0x1000;
}
*newoff = (distAfter < distBefore) ? offAfter : offBefore;
return true;
}
bool AddTreeState::checkMultTerm(Varnode *vn,PcodeOp *op,uintb treeCoeff)
{
Varnode *vnconst = op->getIn(1);
Varnode *vnterm = op->getIn(0);
uintb val;
if (vnterm->isFree()) {
valid = false;
return false;
}
if (vnconst->isConstant()) {
val = (vnconst->getOffset() * treeCoeff) & ptrmask;
intb sval = (intb) val;
sign_extend(sval, vn->getSize() * 8 - 1);
intb rem = (size == 0) ? sval : sval % size;
if (rem != 0) {
if ((val > size) && (size != 0)) {
valid = false; return false;
}
if (!preventDistribution) {
if (vnterm->isWritten() && vnterm->getDef()->code() == CPUI_INT_ADD) {
if (distributeOp == (PcodeOp *)0)
distributeOp = op;
return spanAddTree(vnterm->getDef(), val);
}
}
return true;
}
else {
if (treeCoeff != 1)
isDistributeUsed = true;
multiple.push_back(vnterm);
coeff.push_back(sval);
return false;
}
}
return true;
}
bool AddTreeState::checkTerm(Varnode *vn,uintb treeCoeff)
{
uintb val;
PcodeOp *def;
if (vn == ptr) return false;
if (vn->isConstant()) {
val = vn->getOffset() * treeCoeff;
intb sval = (intb)val;
sign_extend(sval,vn->getSize()*8-1);
intb rem = (size == 0) ? sval : (sval % size);
if (rem!=0) { if (treeCoeff != 1) {
if (baseType->getMetatype() == TYPE_ARRAY || baseType->getMetatype() == TYPE_STRUCT)
isDistributeUsed = true;
}
nonmultsum += val;
nonmultsum &= ptrmask;
return true;
}
if (treeCoeff != 1)
isDistributeUsed = true;
multsum += val; multsum &= ptrmask;
return false;
}
if (vn->isWritten()) {
def = vn->getDef();
if (def->code() == CPUI_INT_ADD) return spanAddTree(def, treeCoeff);
if (def->code() == CPUI_COPY) { valid = false;
return false;
}
if (def->code() == CPUI_INT_MULT) return checkMultTerm(vn, def, treeCoeff);
}
else if (vn->isFree()) {
valid = false;
return false;
}
return true;
}
bool AddTreeState::spanAddTree(PcodeOp *op,uintb treeCoeff)
{
bool one_is_non,two_is_non;
one_is_non = checkTerm(op->getIn(0),treeCoeff);
if (!valid) return false;
two_is_non = checkTerm(op->getIn(1),treeCoeff);
if (!valid) return false;
if (pRelType != (const TypePointerRel *)0) {
if (multsum != 0 || nonmultsum >= size || !multiple.empty()) {
valid = false;
return false;
}
}
if (one_is_non&&two_is_non) return true;
if (one_is_non)
nonmult.push_back(op->getIn(0));
if (two_is_non)
nonmult.push_back(op->getIn(1));
return false; }
void AddTreeState::calcSubtype(void)
{
if (size == 0 || nonmultsum < size)
offset = nonmultsum;
else {
intb snonmult = (intb)nonmultsum;
sign_extend(snonmult,ptrsize*8-1);
snonmult = snonmult % size;
if (snonmult >= 0)
offset = (uintb)snonmult;
else {
if (baseType->getMetatype() == TYPE_STRUCT && findArrayHint() != 0)
offset = nonmultsum;
else
offset = (uintb)(snonmult + size);
}
}
correct = nonmultsum - offset;
nonmultsum = offset;
multsum = (multsum + correct) & ptrmask; if (nonmult.empty()) {
if ((multsum == 0) && multiple.empty()) { valid = false;
return;
}
isSubtype = false; }
else if (baseType->getMetatype() == TYPE_SPACEBASE) {
uintb nonmultbytes = AddrSpace::addressToByte(nonmultsum,ct->getWordSize()); uintb extra;
uint4 arrayHint = findArrayHint();
if (!hasMatchingSubType(nonmultbytes, arrayHint, &extra)) {
valid = false; return;
}
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); offset = (nonmultsum - extra) & ptrmask;
isSubtype = true;
}
else if (baseType->getMetatype() == TYPE_STRUCT) {
uintb nonmultbytes = AddrSpace::addressToByte(nonmultsum,ct->getWordSize()); uintb extra;
uint4 arrayHint = findArrayHint();
if (!hasMatchingSubType(nonmultbytes, arrayHint, &extra)) {
if (nonmultbytes >= baseType->getSize()) { valid = false; return;
}
extra = 0; }
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); offset = (nonmultsum - extra) & ptrmask;
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) {
if (!pRelType->evaluateThruParent(0)) { valid = false; return;
}
}
isSubtype = true;
}
else if (baseType->getMetatype() == TYPE_ARRAY) {
isSubtype = true;
offset = 0;
}
else {
valid = false; }
}
Varnode *AddTreeState::buildMultiples(void)
{
Varnode *resNode;
intb smultsum = (intb)multsum;
sign_extend(smultsum,ptrsize*8-1);
uintb constCoeff = (size==0) ? (uintb)0 : (smultsum / size) & ptrmask;
if (constCoeff == 0)
resNode = (Varnode *)0;
else
resNode= data.newConstant(ptrsize,constCoeff);
for(int4 i=0;i<multiple.size();++i) {
uintb finalCoeff = (size==0) ? (uintb)0 : (coeff[i] / size) & ptrmask;
Varnode *vn = multiple[i];
if (finalCoeff != 1) {
PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_MULT,vn,data.newConstant(ptrsize,finalCoeff));
vn = op->getOut();
}
if (resNode == (Varnode *)0)
resNode = vn;
else {
PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_ADD, vn, resNode);
resNode = op->getOut();
}
}
return resNode;
}
Varnode *AddTreeState::buildExtra(void)
{
correct = (correct+offset) & ptrmask; bool offset_corrected= (correct==0);
Varnode *resNode = (Varnode *)0;
for(int4 i=0;i<nonmult.size();++i) {
Varnode *vn = nonmult[i];
if ((!offset_corrected)&&(vn->isConstant()))
if (vn->getOffset() == correct) {
offset_corrected = true;
continue;
}
if (resNode == (Varnode *)0)
resNode = vn;
else {
PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_ADD,vn,resNode);
resNode = op->getOut();
}
}
if (!offset_corrected) {
Varnode *vn = data.newConstant(ptrsize,uintb_negate(correct-1,ptrsize));
if (resNode == (Varnode *)0)
resNode = vn;
else {
PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_ADD,vn,resNode);
resNode = op->getOut();
}
}
return resNode;
}
bool AddTreeState::buildDegenerate(void)
{
if (baseType->getSize() < ct->getWordSize())
return false; if (baseOp->getOut()->getType()->getMetatype() != TYPE_PTR) return false;
vector<Varnode *> newparams;
int4 slot = baseOp->getSlot(ptr);
newparams.push_back( ptr );
newparams.push_back( baseOp->getIn(1-slot) );
newparams.push_back( data.newConstant(ct->getSize(),1));
data.opSetAllInput(baseOp,newparams);
data.opSetOpcode(baseOp,CPUI_PTRADD);
return true;
}
bool AddTreeState::apply(void)
{
if (isDegenerate)
return buildDegenerate();
spanAddTree(baseOp,1);
if (!valid) return false; if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {
clear();
preventDistribution = true;
spanAddTree(baseOp,1);
}
calcSubtype();
if (!valid) return false;
while(valid && distributeOp != (PcodeOp *)0) {
if (!data.distributeIntMultAdd(distributeOp)) {
valid = false;
break;
}
data.collapseIntMultMult(distributeOp->getIn(0));
data.collapseIntMultMult(distributeOp->getIn(1));
clear();
spanAddTree(baseOp,1);
if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {
clear();
preventDistribution = true;
spanAddTree(baseOp,1);
}
calcSubtype();
}
if (!valid) {
ostringstream s;
s << "Problems distributing in pointer arithmetic at ";
baseOp->getAddr().printRaw(s);
data.warningHeader(s.str());
return true;
}
buildTree();
return true;
}
void AddTreeState::buildTree(void)
{
if (pRelType != (const TypePointerRel *)0) {
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
offset -= ptrOff;
offset &= ptrmask;
}
Varnode *multNode = buildMultiples();
Varnode *extraNode = buildExtra();
PcodeOp *newop = (PcodeOp *)0;
if (multNode != (Varnode *)0) {
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
multNode = newop->getOut();
}
else
multNode = ptr;
if (isSubtype) {
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
if (size != 0)
newop->setStopPropagation();
multNode = newop->getOut();
}
if (extraNode != (Varnode *)0)
newop = data.newOpBefore(baseOp,CPUI_INT_ADD,multNode,extraNode);
if (newop == (PcodeOp *)0) {
data.warning("ptrarith problems",baseOp->getAddr());
return;
}
data.opSetOutput(newop,baseOp->getOut());
data.opDestroy(baseOp);
}
bool RulePtrArith::verifyPreferredPointer(PcodeOp *op,int4 slot)
{
Varnode *vn = op->getIn(slot);
if (!vn->isWritten()) return true;
PcodeOp *preOp = vn->getDef();
if (preOp->code() != CPUI_INT_ADD) return true;
int preslot = 0;
if (preOp->getIn(preslot)->getType()->getMetatype() != TYPE_PTR) {
preslot = 1;
if (preOp->getIn(preslot)->getType()->getMetatype() != TYPE_PTR)
return true;
}
return (1 != evaluatePointerExpression(preOp, preslot)); }
int4 RulePtrArith::evaluatePointerExpression(PcodeOp *op,int4 slot)
{
int4 res = 1; int4 count = 0; Varnode *ptrBase = op->getIn(slot);
if (ptrBase->isFree() && !ptrBase->isConstant())
return 0;
if (op->getIn(1 - slot)->getType()->getMetatype() == TYPE_PTR)
res = 2;
Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
PcodeOp *decOp = *iter;
count += 1;
OpCode opc = decOp->code();
if (opc == CPUI_INT_ADD) {
Varnode *otherVn = decOp->getIn(1 - decOp->getSlot(outVn));
if (otherVn->isFree() && !otherVn->isConstant())
return 0; if (otherVn->getType()->getMetatype() == TYPE_PTR)
res = 2; }
else if ((opc == CPUI_LOAD || opc == CPUI_STORE) && decOp->getIn(1) == outVn) { if (ptrBase->isSpacebase() && (ptrBase->isInput()||(ptrBase->isConstant())) &&
(op->getIn(1-slot)->isConstant()))
return 0;
res = 2;
}
else { res = 2;
}
}
if (count == 0)
return 0;
if (count > 1) {
if (outVn->isSpacebase())
return 0; }
return res;
}
void RulePtrArith::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ADD);
}
int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
{
int4 slot;
const Datatype *ct = (const Datatype *)0;
if (!data.isTypeRecoveryOn()) return 0;
for(slot=0;slot<op->numInput();++slot) { ct = op->getIn(slot)->getType();
if (ct->getMetatype() == TYPE_PTR) break;
}
if (slot == op->numInput()) return 0;
if (evaluatePointerExpression(op, slot) != 2) return 0;
if (!verifyPreferredPointer(op, slot)) return 0;
AddTreeState state(data,op,slot);
if (state.apply()) return 1;
if (state.initAlternateForm()) {
if (state.apply()) return 1;
}
return 0;
}
void RuleStructOffset0::getOpList(vector<uint4> &oplist) const
{
uint4 list[]={ CPUI_LOAD, CPUI_STORE };
oplist.insert(oplist.end(),list,list+2);
}
int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
{
int4 movesize;
if (!data.isTypeRecoveryOn()) return 0;
if (op->code()==CPUI_LOAD) {
movesize = op->getOut()->getSize();
}
else if (op->code()==CPUI_STORE) {
movesize = op->getIn(2)->getSize();
}
else
return 0;
Datatype *ct = op->getIn(1)->getType();
if (ct->getMetatype() != TYPE_PTR) return 0;
Datatype *baseType = ((TypePointer *)ct)->getPtrTo();
uintb offset = 0;
if (ct->isFormalPointerRel() && ((TypePointerRel *)ct)->evaluateThruParent(0)) {
TypePointerRel *ptRel = (TypePointerRel *)ct;
baseType = ptRel->getParent();
if (baseType->getMetatype() != TYPE_STRUCT)
return 0;
int4 iOff = ptRel->getPointerOffset();
iOff = AddrSpace::addressToByteInt(iOff, ptRel->getWordSize());
if (iOff >= baseType->getSize())
return 0;
offset = iOff;
}
if (baseType->getMetatype() == TYPE_STRUCT) {
if (baseType->getSize() < movesize)
return 0; Datatype *subType = baseType->getSubType(offset,&offset); if (subType==(Datatype *)0) return 0;
if (subType->getSize() < movesize) return 0; }
else if (baseType->getMetatype() == TYPE_ARRAY) {
if (baseType->getSize() < movesize)
return 0; if (baseType->getSize() == movesize) { if (((TypeArray *)baseType)->numElements() != 1)
return 0;
}
}
else
return 0;
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,op->getIn(1),data.newConstant(op->getIn(1)->getSize(),0));
newop->setStopPropagation();
data.opSetInput(op,newop->getOut(),1);
return 1;
}
Varnode *RulePushPtr::buildVarnodeOut(Varnode *vn,PcodeOp *op,Funcdata &data)
{
if (vn->isAddrTied() || vn->getSpace()->getType() == IPTR_INTERNAL)
return data.newUniqueOut(vn->getSize(), op);
return data.newVarnodeOut(vn->getSize(), vn->getAddr(), op);
}
void RulePushPtr::collectDuplicateNeeds(vector<PcodeOp *> &reslist,Varnode *vn)
{
for(;;) {
if (!vn->isWritten()) return;
if (vn->isAutoLive()) return;
if (vn->loneDescend() == (PcodeOp *)0) return; PcodeOp *op = vn->getDef();
OpCode opc = op->code();
if (opc == CPUI_INT_ZEXT || opc == CPUI_INT_SEXT || opc == CPUI_INT_2COMP)
reslist.push_back(op);
else if (opc == CPUI_INT_MULT) {
if (op->getIn(1)->isConstant())
reslist.push_back(op);
}
else
return;
vn = op->getIn(0);
}
}
void RulePushPtr::duplicateNeed(PcodeOp *op,Funcdata &data)
{
Varnode *outVn = op->getOut();
Varnode *inVn = op->getIn(0);
int num = op->numInput();
OpCode opc = op->code();
list<PcodeOp *>::const_iterator iter = outVn->beginDescend();
do {
PcodeOp *decOp = *iter;
int4 slot = decOp->getSlot(outVn);
PcodeOp *newOp = data.newOp(num, op->getAddr()); Varnode *newOut = buildVarnodeOut(outVn, newOp, data); newOut->updateType(outVn->getType(),false,false);
data.opSetOpcode(newOp, opc);
data.opSetInput(newOp, inVn, 0);
if (num > 1)
data.opSetInput(newOp, op->getIn(1), 1);
data.opSetInput(decOp, newOut, slot);
data.opInsertBefore(newOp, decOp);
iter = outVn->beginDescend();
} while(iter != outVn->endDescend());
data.opDestroy(op);
}
void RulePushPtr::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ADD);
}
int4 RulePushPtr::applyOp(PcodeOp *op,Funcdata &data)
{
int4 slot;
Varnode *vni = (Varnode *)0;
if (!data.isTypeRecoveryOn()) return 0;
for(slot=0;slot<op->numInput();++slot) { vni = op->getIn(slot);
if (vni->getType()->getMetatype() == TYPE_PTR) break;
}
if (slot == op->numInput()) return 0;
if (RulePtrArith::evaluatePointerExpression(op, slot) != 1) return 0;
Varnode *vn = op->getOut();
Varnode *vnadd2 = op->getIn(1-slot);
vector<PcodeOp *> duplicateList;
if (vn->loneDescend() == (PcodeOp *)0)
collectDuplicateNeeds(duplicateList, vnadd2);
for(;;) {
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
if (iter == vn->endDescend()) break;
PcodeOp *decop = *iter;
int4 j = decop->getSlot(vn);
Varnode *vnadd1 = decop->getIn(1-j);
Varnode *newout;
PcodeOp *newop = data.newOp(2,decop->getAddr()); data.opSetOpcode(newop,CPUI_INT_ADD);
newout = data.newUniqueOut(vnadd1->getSize(),newop);
data.opSetInput(decop,vni,0);
data.opSetInput(decop,newout,1);
data.opSetInput(newop,vnadd1,0);
data.opSetInput(newop,vnadd2,1);
data.opInsertBefore(newop,decop);
}
if (!vn->isAutoLive())
data.opDestroy(op);
for(int4 i=0;i<duplicateList.size();++i)
duplicateNeed(duplicateList[i], data);
return 1;
}
void RulePtraddUndo::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PTRADD);
}
int4 RulePtraddUndo::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *basevn;
TypePointer *tp;
if (!data.isTypeRecoveryOn()) return 0;
int4 size = (int4)op->getIn(2)->getOffset(); basevn = op->getIn(0);
tp = (TypePointer *)basevn->getType();
if (tp->getMetatype() == TYPE_PTR) if (tp->getPtrTo()->getSize()==AddrSpace::addressToByteInt(size,tp->getWordSize())) { Varnode *indVn = op->getIn(1);
if ((!indVn->isConstant()) || (indVn->getOffset() != 0)) return 0;
}
data.opUndoPtradd(op,false);
return 1;
}
void RulePtrsubUndo::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PTRSUB);
}
int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
{
if (!data.isTypeRecoveryOn()) return 0;
Varnode *basevn = op->getIn(0);
if (basevn->getType()->isPtrsubMatching(op->getIn(1)->getOffset()))
return 0;
data.opSetOpcode(op,CPUI_INT_ADD);
op->clearStopPropagation();
return 1;
}
void RuleMultNegOne::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_MULT);
}
int4 RuleMultNegOne::applyOp(PcodeOp *op,Funcdata &data)
{ Varnode *constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
if (constvn->getOffset() != calc_mask(constvn->getSize())) return 0;
data.opSetOpcode(op,CPUI_INT_2COMP);
data.opRemoveInput(op,1);
return 1;
}
void RuleAddUnsigned::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ADD);
}
int4 RuleAddUnsigned::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
Datatype *dt = constvn->getType();
if (dt->getMetatype() != TYPE_UINT) return 0;
if (dt->isCharPrint()) return 0; if (dt->isEnumType()) return 0;
uintb val = constvn->getOffset();
uintb mask = calc_mask(constvn->getSize());
int4 sa = constvn->getSize() * 6; uintb quarter = (mask>>sa) << sa;
if ((val & quarter) != quarter) return 0; if (constvn->getSymbolEntry() != (SymbolEntry *)0) {
EquateSymbol *sym = dynamic_cast<EquateSymbol *>(constvn->getSymbolEntry()->getSymbol());
if (sym != (EquateSymbol *)0) {
if (sym->isNameLocked())
return 0; }
}
data.opSetOpcode(op,CPUI_INT_SUB);
Varnode *cvn = data.newConstant(constvn->getSize(), (-val) & mask);
cvn->copySymbol(constvn);
data.opSetInput(op,cvn,1);
return 1;
}
void Rule2Comp2Sub::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_2COMP);
}
int4 Rule2Comp2Sub::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *addop = op->getOut()->loneDescend();
if (addop == (PcodeOp *)0) return 0;
if (addop->code() != CPUI_INT_ADD) return 0;
if (addop->getIn(0) == op->getOut())
data.opSetInput(addop,addop->getIn(1),0);
data.opSetInput(addop,op->getIn(0),1);
data.opSetOpcode(addop,CPUI_INT_SUB);
data.opDestroy(op); return 1;
}
void RuleSubRight::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubRight::applyOp(PcodeOp *op,Funcdata &data)
{
int4 c = op->getIn(1)->getOffset();
if (c==0) return 0; Varnode *a = op->getIn(0);
Varnode *outvn = op->getOut();
if (outvn->isAddrTied() && a->isAddrTied()) {
if (outvn->overlap(*a) == c) return 0; }
OpCode opc = CPUI_INT_RIGHT; int4 d = c*8; PcodeOp *lone = outvn->loneDescend();
if (lone!=(PcodeOp *)0) {
OpCode opc2 = lone->code();
if ((opc2==CPUI_INT_RIGHT)||(opc2==CPUI_INT_SRIGHT)) {
if (lone->getIn(1)->isConstant()) { if (outvn->getSize() + c == a->getSize()) {
d += lone->getIn(1)->getOffset();
data.opUnlink(op);
op = lone;
data.opSetOpcode(op,CPUI_SUBPIECE);
opc = opc2;
}
}
}
}
Datatype *ct;
if (opc == CPUI_INT_RIGHT)
ct = data.getArch()->types->getBase(a->getSize(),TYPE_UINT);
else
ct = data.getArch()->types->getBase(a->getSize(),TYPE_INT);
PcodeOp *shiftop = data.newOp(2,op->getAddr());
data.opSetOpcode(shiftop,opc);
Varnode *newout = data.newUnique(a->getSize(),ct);
data.opSetOutput(shiftop,newout);
data.opSetInput(shiftop,a,0);
data.opSetInput(shiftop,data.newConstant(4,d),1);
data.opInsertBefore(shiftop,op);
data.opSetInput(op,newout,0);
data.opSetInput(op,data.newConstant(4,0),1);
return 1;
}
bool RulePtrsubCharConstant::pushConstFurther(Funcdata &data,TypePointer *outtype,PcodeOp *op,int4 slot,uintb val)
{
if (op->code() != CPUI_PTRADD) return false; if (slot != 0) return false;
Varnode *vn = op->getIn(1);
if (!vn->isConstant()) return false; uintb addval = vn->getOffset();
addval *= op->getIn(2)->getOffset();
val += addval;
Varnode *newconst = data.newConstant(vn->getSize(),val);
newconst->updateType(outtype,false,false); data.opRemoveInput(op,2);
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,newconst,0);
return true;
}
void RulePtrsubCharConstant::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PTRSUB);
}
int4 RulePtrsubCharConstant::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *sb = op->getIn(0);
if (sb->getType()->getMetatype() != TYPE_PTR) return 0;
TypeSpacebase *sbtype = (TypeSpacebase *)((TypePointer *)sb->getType())->getPtrTo();
if (sbtype->getMetatype() != TYPE_SPACEBASE) return 0;
Varnode *vn1 = op->getIn(1);
if (!vn1->isConstant()) return 0;
Varnode *outvn = op->getOut();
TypePointer *outtype = (TypePointer *)outvn->getType();
if (outtype->getMetatype() != TYPE_PTR) return 0;
Datatype *basetype = outtype->getPtrTo();
if (!basetype->isCharPrint()) return 0;
Address symaddr = sbtype->getAddress(vn1->getOffset(),vn1->getSize(),op->getAddr());
Scope *scope = sbtype->getMap();
if (!scope->isReadOnly(symaddr,1,op->getAddr()))
return 0;
if (!data.getArch()->stringManager->isString(symaddr, basetype))
return 0;
bool removeCopy = false;
if (!outvn->isAddrForce()) {
removeCopy = true; list<PcodeOp *>::const_iterator iter,enditer;
iter = outvn->beginDescend();
enditer = outvn->endDescend();
while(iter != enditer) {
PcodeOp *subop = *iter; ++iter;
if (!pushConstFurther(data,outtype,subop,subop->getSlot(outvn),vn1->getOffset()))
removeCopy = false; }
}
if (removeCopy) {
data.opDestroy(op);
}
else { Varnode *newvn = data.newConstant(outvn->getSize(),vn1->getOffset());
newvn->updateType(outtype,false,false);
data.opRemoveInput(op,1);
data.opSetInput(op,newvn,0);
data.opSetOpcode(op,CPUI_COPY);
}
return 1;
}
void RuleExtensionPush::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
oplist.push_back(CPUI_INT_SEXT);
}
int4 RuleExtensionPush::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *inVn = op->getIn(0);
if (inVn->isConstant()) return 0;
if (inVn->isAddrForce()) return 0;
if (inVn->isAddrTied()) return 0;
Varnode *outVn = op->getOut();
if (outVn->isTypeLock() || outVn->isNameLock()) return 0;
if (outVn->isAddrForce() || outVn->isAddrTied()) return 0;
list<PcodeOp *>::const_iterator iter;
int4 addcount = 0; int4 ptrcount = 0; for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
PcodeOp *decOp = *iter;
OpCode opc = decOp->code();
if (opc == CPUI_PTRADD) {
ptrcount += 1;
}
else if (opc == CPUI_INT_ADD) {
PcodeOp *subOp = decOp->getOut()->loneDescend();
if (subOp == (PcodeOp *)0 || subOp->code() != CPUI_PTRADD)
return 0;
addcount += 1;
}
else {
return 0;
}
}
if ((addcount + ptrcount) <= 1) return 0;
if (addcount > 0) {
if (op->getIn(0)->loneDescend() != (PcodeOp *)0) return 0;
}
RulePushPtr::duplicateNeed(op, data); return 1;
}
void RuleSubNormal::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *shiftout = op->getIn(0);
if (!shiftout->isWritten()) return 0;
PcodeOp *shiftop = shiftout->getDef();
OpCode opc = shiftop->code();
if ((opc!=CPUI_INT_RIGHT)&&(opc!=CPUI_INT_SRIGHT))
return 0;
if (!shiftop->getIn(1)->isConstant()) return 0;
Varnode *a = shiftop->getIn(0);
if (a->isFree()) return 0;
int4 n = shiftop->getIn(1)->getOffset();
int4 c = op->getIn(1)->getOffset();
int4 k = (n/8);
int4 outsize = op->getOut()->getSize();
if (k+c+outsize > shiftout->getSize())
k = shiftout->getSize()-c-outsize;
if ((n+8*c+8*outsize < 8*a->getSize())&&(n != k*8)) return 0;
c += k;
n -= k*8;
if (n==0) { data.opSetInput(op,a,0);
data.opSetInput(op,data.newConstant(4,c),1);
return 1;
}
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_SUBPIECE);
data.newUniqueOut(op->getOut()->getSize(),newop);
data.opSetInput(newop,a,0);
data.opSetInput(newop,data.newConstant(4,c),1);
data.opInsertBefore(newop,op);
data.opSetInput(op,newop->getOut(),0);
data.opSetInput(op,data.newConstant(4,n),1);
data.opSetOpcode(op,opc);
return 1;
}
void RulePositiveDiv::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SDIV);
oplist.push_back(CPUI_INT_SREM);
}
int4 RulePositiveDiv::applyOp(PcodeOp *op,Funcdata &data)
{
int4 sa = op->getOut()->getSize();
if (sa > sizeof(uintb)) return 0;
sa = sa * 8 - 1;
if (((op->getIn(0)->getNZMask() >> sa) & 1) != 0)
return 0; if (((op->getIn(1)->getNZMask() >> sa) & 1) != 0)
return 0; OpCode opc = (op->code() == CPUI_INT_SDIV) ? CPUI_INT_DIV : CPUI_INT_REM;
data.opSetOpcode(op, opc);
return 1;
}
void RuleDivTermAdd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
oplist.push_back(CPUI_INT_RIGHT); oplist.push_back(CPUI_INT_SRIGHT); }
int4 RuleDivTermAdd::applyOp(PcodeOp *op,Funcdata &data)
{
int4 n;
OpCode shiftopc;
PcodeOp *subop = findSubshift(op,n,shiftopc);
if (subop == (PcodeOp *)0) return 0;
if (n > 64) return 0;
Varnode *multvn = subop->getIn(0);
if (!multvn->isWritten()) return 0;
PcodeOp *multop = multvn->getDef();
if (multop->code() != CPUI_INT_MULT) return 0;
uintb multConst;
int4 constExtType = multop->getIn(1)->isConstantExtended(multConst);
if (constExtType < 0) return 0;
Varnode *extvn = multop->getIn(0);
if (!extvn->isWritten()) return 0;
PcodeOp *extop = extvn->getDef();
OpCode opc = extop->code();
if (opc == CPUI_INT_ZEXT) {
if (op->code()==CPUI_INT_SRIGHT) return 0;
}
else if (opc == CPUI_INT_SEXT) {
if (op->code()==CPUI_INT_RIGHT) return 0;
}
uintb newc;
if (n < 64 || (extvn->getSize() <= 8)) {
uintb pow = 1;
pow <<= n; newc = multConst + pow;
}
else {
if (constExtType != 2) return 0; if (!signbit_negative(multConst,8)) return 0;
constExtType = 1; }
Varnode *x = extop->getIn(0);
list<PcodeOp *>::const_iterator iter;
for(iter=op->getOut()->beginDescend();iter!=op->getOut()->endDescend();++iter) {
PcodeOp *addop = *iter;
if (addop->code() != CPUI_INT_ADD) continue;
if ((addop->getIn(0)!=x)&&(addop->getIn(1)!=x))
continue;
Varnode *newConstVn;
if (constExtType == 0)
newConstVn = data.newConstant(extvn->getSize(),newc);
else {
PcodeOp *newExtOp = data.newOp(1,op->getAddr());
data.opSetOpcode(newExtOp,(constExtType==1) ? CPUI_INT_ZEXT : CPUI_INT_SEXT);
newConstVn = data.newUniqueOut(extvn->getSize(),newExtOp);
data.opSetInput(newExtOp,data.newConstant(8,multConst),0);
data.opInsertBefore(newExtOp,op);
}
PcodeOp *newmultop = data.newOp(2,op->getAddr());
data.opSetOpcode(newmultop,CPUI_INT_MULT);
Varnode *newmultvn = data.newUniqueOut(extvn->getSize(),newmultop);
data.opSetInput(newmultop,extvn,0);
data.opSetInput(newmultop,newConstVn,1);
data.opInsertBefore(newmultop,op);
PcodeOp *newshiftop = data.newOp(2,op->getAddr());
if (shiftopc == CPUI_MAX)
shiftopc = CPUI_INT_RIGHT;
data.opSetOpcode(newshiftop,shiftopc);
Varnode *newshiftvn = data.newUniqueOut(extvn->getSize(),newshiftop);
data.opSetInput(newshiftop,newmultvn,0);
data.opSetInput(newshiftop,data.newConstant(4,n),1);
data.opInsertBefore(newshiftop,op);
data.opSetOpcode(addop,CPUI_SUBPIECE);
data.opSetInput(addop,newshiftvn,0);
data.opSetInput(addop,data.newConstant(4,0),1);
return 1;
}
return 0;
}
PcodeOp *RuleDivTermAdd::findSubshift(PcodeOp *op,int4 &n,OpCode &shiftopc)
{ PcodeOp *subop;
shiftopc = op->code();
if (shiftopc != CPUI_SUBPIECE) { Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return (PcodeOp *)0;
subop = vn->getDef();
if (subop->code() != CPUI_SUBPIECE) return (PcodeOp *)0;
if (!op->getIn(1)->isConstant()) return (PcodeOp *)0;
n = op->getIn(1)->getOffset();
}
else {
shiftopc = CPUI_MAX; subop = op;
n = 0;
}
int4 c = subop->getIn(1)->getOffset();
if (subop->getOut()->getSize() + c != subop->getIn(0)->getSize())
return (PcodeOp *)0; n += 8*c;
return subop;
}
void RuleDivTermAdd2::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleDivTermAdd2::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
if (op->getIn(1)->getOffset() != 1) return 0;
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *subop = op->getIn(0)->getDef();
if (subop->code() != CPUI_INT_ADD) return 0;
Varnode *x = (Varnode *)0;
Varnode *compvn;
PcodeOp *compop;
int4 i;
for(i=0;i<2;++i) {
compvn = subop->getIn(i);
if (compvn->isWritten()) {
compop = compvn->getDef();
if (compop->code() == CPUI_INT_MULT) {
Varnode *invn = compop->getIn(1);
if (invn->isConstant()) {
if (invn->getOffset() == calc_mask(invn->getSize())) {
x = subop->getIn(1-i);
break;
}
}
}
}
}
if (i==2) return 0;
Varnode *z = compvn->getDef()->getIn(0);
if (!z->isWritten()) return 0;
PcodeOp *subpieceop = z->getDef();
if (subpieceop->code() != CPUI_SUBPIECE) return 0;
int4 n = subpieceop->getIn(1)->getOffset() *8;
if (n!= 8*(subpieceop->getIn(0)->getSize() - z->getSize())) return 0;
Varnode *multvn = subpieceop->getIn(0);
if (!multvn->isWritten()) return 0;
PcodeOp *multop = multvn->getDef();
if (multop->code() != CPUI_INT_MULT) return 0;
if (!multop->getIn(1)->isConstant()) return 0;
Varnode *zextvn = multop->getIn(0);
if (!zextvn->isWritten()) return 0;
PcodeOp *zextop = zextvn->getDef();
if (zextop->code() != CPUI_INT_ZEXT) return 0;
if (zextop->getIn(0) != x) return 0;
list<PcodeOp *>::const_iterator iter;
for(iter=op->getOut()->beginDescend();iter!=op->getOut()->endDescend();++iter) {
PcodeOp *addop = *iter;
if (addop->code() != CPUI_INT_ADD) continue;
if ((addop->getIn(0)!=z)&&(addop->getIn(1)!=z)) continue;
uintb pow = 1;
pow <<= n; uintb newc = multop->getIn(1)->getOffset() + pow;
PcodeOp *newmultop = data.newOp(2,op->getAddr());
data.opSetOpcode(newmultop,CPUI_INT_MULT);
Varnode *newmultvn = data.newUniqueOut(zextvn->getSize(),newmultop);
data.opSetInput(newmultop,zextvn,0);
data.opSetInput(newmultop,data.newConstant(zextvn->getSize(),newc),1);
data.opInsertBefore(newmultop,op);
PcodeOp *newshiftop = data.newOp(2,op->getAddr());
data.opSetOpcode(newshiftop,CPUI_INT_RIGHT);
Varnode *newshiftvn = data.newUniqueOut(zextvn->getSize(),newshiftop);
data.opSetInput(newshiftop,newmultvn,0);
data.opSetInput(newshiftop,data.newConstant(4,n+1),1);
data.opInsertBefore(newshiftop,op);
data.opSetOpcode(addop,CPUI_SUBPIECE);
data.opSetInput(addop,newshiftvn,0);
data.opSetInput(addop,data.newConstant(4,0),1);
return 1;
}
return 0;
}
Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &extopc)
{
PcodeOp *curOp = op;
OpCode shiftopc = curOp->code();
if (shiftopc == CPUI_INT_RIGHT || shiftopc == CPUI_INT_SRIGHT) {
Varnode *vn = curOp->getIn(0);
if (!vn->isWritten()) return (Varnode *)0;
Varnode *cvn = curOp->getIn(1);
if (!cvn->isConstant()) return (Varnode *)0;
n = cvn->getOffset();
curOp = vn->getDef();
}
else {
n = 0; if (shiftopc != CPUI_SUBPIECE) return (Varnode *)0; shiftopc = CPUI_MAX;
}
if (curOp->code() == CPUI_SUBPIECE) { int4 c = curOp->getIn(1)->getOffset();
Varnode *inVn = curOp->getIn(0);
if (!inVn->isWritten()) return (Varnode *)0;
if (curOp->getOut()->getSize() + c != inVn->getSize())
return (Varnode *)0; n += 8*c;
curOp = inVn->getDef();
}
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; Varnode *inVn = curOp->getIn(0);
if (!inVn->isWritten()) return (Varnode *)0;
if (inVn->isConstantExtended(y) >= 0) {
inVn = curOp->getIn(1);
if (!inVn->isWritten()) return (Varnode *)0;
}
else if (curOp->getIn(1)->isConstantExtended(y) < 0)
return (Varnode *)0;
Varnode *resVn;
PcodeOp *extOp = inVn->getDef();
extopc = extOp->code();
if (extopc != CPUI_INT_SEXT) {
uintb nzMask = inVn->getNZMask();
xsize = 8*sizeof(uintb) - count_leading_zeros(nzMask);
if (xsize == 0) return (Varnode *)0;
if (xsize > 4*inVn->getSize()) return (Varnode *)0;
}
else
xsize = extOp->getIn(0)->getSize() * 8;
if (extopc == CPUI_INT_ZEXT || extopc == CPUI_INT_SEXT) {
Varnode *extVn = extOp->getIn(0);
if (extVn->isFree()) return (Varnode *)0;
if (inVn->getSize() == op->getOut()->getSize())
resVn = inVn;
else
resVn = extVn;
}
else {
extopc = CPUI_INT_ZEXT; resVn = inVn;
}
if (((extopc == CPUI_INT_ZEXT)&&(shiftopc==CPUI_INT_SRIGHT))||
((extopc == CPUI_INT_SEXT)&&(shiftopc==CPUI_INT_RIGHT))) {
if (8*op->getOut()->getSize() - n != xsize)
return (Varnode *)0;
}
return resVn;
}
uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
{
if (n > 127) return 0; if (y <= 1) return 0;
uint8 d,r;
uint8 power;
if (n < 64) {
power = ((uint8)1) << n;
d = power / (y-1);
r = power % (y-1);
}
else {
if (0 != power2Divide(n,y-1,d,r))
return 0; }
if (d>=y) return 0;
if (r >= d) return 0;
uint8 maxx = 1;
maxx <<= xsize;
maxx -= 1; uint8 tmp;
if (n < 64)
tmp = power / (d-r); else {
uint8 unused;
if (0 != power2Divide(n,d-r,tmp,unused))
return (uintb)d; }
if (tmp<=maxx) return 0;
return (uintb)d;
}
void RuleDivOpt::moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data)
{
vector<Varnode *> testList;
testList.push_back(firstVn);
if (firstVn->isWritten()) {
PcodeOp *op = firstVn->getDef();
if (op->code() == CPUI_INT_SRIGHT) {
testList.push_back(op->getIn(0));
}
}
for(int4 i=0;i<testList.size();++i) {
Varnode *vn = testList[i];
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while(iter!=vn->endDescend()) {
PcodeOp *op = *iter;
++iter; OpCode opc = op->code();
if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) {
Varnode *constVn = op->getIn(1);
if (constVn->isWritten()) {
PcodeOp *constOp = constVn->getDef();
if (constOp->code() == CPUI_COPY)
constVn = constOp->getIn(0);
else if (constOp->code() == CPUI_INT_AND) {
constVn = constOp->getIn(0);
Varnode *otherVn = constOp->getIn(1);
if (!otherVn->isConstant()) continue;
if (constVn->getOffset() != (constVn->getOffset() & otherVn->getOffset())) continue;
}
}
if (constVn->isConstant()) {
int4 sa = firstVn->getSize() * 8 - 1;
if (sa == (int4)constVn->getOffset()) {
data.opSetInput(op,replaceVn,0);
}
}
}
else if (opc == CPUI_COPY) {
testList.push_back(op->getOut());
}
}
}
}
bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
{
if (op->code() != CPUI_SUBPIECE) return false;
Varnode *vn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *superOp = *iter;
OpCode opc = superOp->code();
if (opc != CPUI_INT_RIGHT && opc != CPUI_INT_SRIGHT) continue;
Varnode *cvn = superOp->getIn(1);
if (!cvn->isConstant()) return true; int4 n,xsize;
uintb y;
OpCode extopc;
Varnode *inVn = findForm(superOp, n, y, xsize, extopc);
if (inVn != (Varnode *)0) return true;
}
return false;
}
void RuleDivOpt::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
oplist.push_back(CPUI_INT_RIGHT);
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data)
{
int4 n,xsize;
uintb y;
OpCode extOpc;
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
if (inVn == (Varnode *)0) return 0;
if (checkFormOverlap(op)) return 0;
if (extOpc == CPUI_INT_SEXT)
xsize -= 1; uintb divisor = calcDivisor(n,y,xsize);
if (divisor == 0) return 0;
int4 outSize = op->getOut()->getSize();
if (inVn->getSize() < outSize) { PcodeOp *inExt = data.newOp(1,op->getAddr());
data.opSetOpcode(inExt,extOpc);
Varnode *extOut = data.newUniqueOut(outSize,inExt);
data.opSetInput(inExt,inVn,0);
inVn = extOut;
data.opInsertBefore(inExt,op);
}
else if (inVn->getSize() > outSize) { PcodeOp *newop = data.newOp(2,op->getAddr()); data.opSetOpcode(newop, CPUI_INT_ADD); Varnode *resVn = data.newUniqueOut(inVn->getSize(), newop);
data.opInsertBefore(newop, op);
data.opSetOpcode(op, CPUI_SUBPIECE); data.opSetInput(op,resVn,0);
data.opSetInput(op,data.newConstant(4, 0),1);
op = newop; outSize = inVn->getSize();
}
if (extOpc == CPUI_INT_ZEXT) { data.opSetInput(op,inVn,0);
data.opSetInput(op,data.newConstant(outSize,divisor),1);
data.opSetOpcode(op,CPUI_INT_DIV);
}
else { moveSignBitExtraction(op->getOut(), inVn, data);
PcodeOp *divop = data.newOp(2,op->getAddr());
data.opSetOpcode(divop,CPUI_INT_SDIV);
Varnode *newout = data.newUniqueOut(outSize,divop);
data.opSetInput(divop,inVn,0);
data.opSetInput(divop,data.newConstant(outSize,divisor),1);
data.opInsertBefore(divop,op);
PcodeOp *sgnop = data.newOp(2,op->getAddr());
data.opSetOpcode(sgnop,CPUI_INT_SRIGHT);
Varnode *sgnvn = data.newUniqueOut(outSize,sgnop);
data.opSetInput(sgnop,inVn,0);
data.opSetInput(sgnop,data.newConstant(outSize,outSize*8-1),1);
data.opInsertBefore(sgnop,op);
data.opSetInput(op,newout,0);
data.opSetInput(op,sgnvn,1);
data.opSetOpcode(op,CPUI_INT_ADD);
}
return 1;
}
void RuleSignDiv2::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SRIGHT);
}
int4 RuleSignDiv2::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *addout,*multout,*shiftout,*a;
PcodeOp *addop,*multop,*shiftop;
if (!op->getIn(1)->isConstant()) return 0;
if (op->getIn(1)->getOffset() != 1) return 0;
addout = op->getIn(0);
if (!addout->isWritten()) return 0;
addop = addout->getDef();
if (addop->code() != CPUI_INT_ADD) return 0;
int4 i;
a = (Varnode *)0;
for(i=0;i<2;++i) {
multout = addop->getIn(i);
if (!multout->isWritten()) continue;
multop = multout->getDef();
if (multop->code() != CPUI_INT_MULT)
continue;
if (!multop->getIn(1)->isConstant()) continue;
if (multop->getIn(1)->getOffset() !=
calc_mask(multop->getIn(1)->getSize()))
continue;
shiftout = multop->getIn(0);
if (!shiftout->isWritten()) continue;
shiftop = shiftout->getDef();
if (shiftop->code() != CPUI_INT_SRIGHT)
continue;
if (!shiftop->getIn(1)->isConstant()) continue;
int4 n = shiftop->getIn(1)->getOffset();
a = shiftop->getIn(0);
if (a != addop->getIn(1-i)) continue;
if (n != 8*a->getSize() - 1) continue;
if (a->isFree()) continue;
break;
}
if (i==2) return 0;
data.opSetInput(op,a,0);
data.opSetInput(op,data.newConstant(a->getSize(),2),1);
data.opSetOpcode(op,CPUI_INT_SDIV);
return 1;
}
void RuleSignForm::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSignForm::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *sextout,*a;
PcodeOp *sextop;
sextout = op->getIn(0);
if (!sextout->isWritten()) return 0;
sextop = sextout->getDef();
if (sextop->code() != CPUI_INT_SEXT)
return 0;
a = sextop->getIn(0);
int4 c = op->getIn(1)->getOffset();
if (c < a->getSize()) return 0;
if (a->isFree()) return 0;
data.opSetInput(op,a,0);
int4 n = 8*a->getSize()-1;
data.opSetInput(op,data.newConstant(4,n),1);
data.opSetOpcode(op,CPUI_INT_SRIGHT);
return 1;
}
void RuleSignNearMult::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSignNearMult::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *addop = op->getIn(0)->getDef();
if (addop->code() != CPUI_INT_ADD) return 0;
Varnode *shiftvn;
PcodeOp *unshiftop = (PcodeOp *)0;
int4 i;
for(i=0;i<2;++i) {
shiftvn = addop->getIn(i);
if (!shiftvn->isWritten()) continue;
unshiftop = shiftvn->getDef();
if (unshiftop->code() == CPUI_INT_RIGHT) {
if (!unshiftop->getIn(1)->isConstant()) continue;
break;
}
}
if (i==2) return 0;
Varnode *x = addop->getIn(1-i);
if (x->isFree()) return 0;
int4 n = unshiftop->getIn(1)->getOffset();
if (n<=0) return 0;
n = shiftvn->getSize()*8 - n;
if (n<=0) return 0;
uintb mask = calc_mask(shiftvn->getSize());
mask = (mask<<n)&mask;
if (mask != op->getIn(1)->getOffset()) return 0;
Varnode *sgnvn = unshiftop->getIn(0);
if (!sgnvn->isWritten()) return 0;
PcodeOp *sshiftop = sgnvn->getDef();
if (sshiftop->code() != CPUI_INT_SRIGHT) return 0;
if (!sshiftop->getIn(1)->isConstant()) return 0;
if (sshiftop->getIn(0) != x) return 0;
int4 val = sshiftop->getIn(1)->getOffset();
if (val != 8*x->getSize()-1) return 0;
uintb pow = 1;
pow <<= n;
PcodeOp *newdiv = data.newOp(2,op->getAddr());
data.opSetOpcode(newdiv,CPUI_INT_SDIV);
Varnode *divvn = data.newUniqueOut(x->getSize(),newdiv);
data.opSetInput(newdiv,x,0);
data.opSetInput(newdiv,data.newConstant(x->getSize(),pow),1);
data.opInsertBefore(newdiv,op);
data.opSetOpcode(op,CPUI_INT_MULT);
data.opSetInput(op,divvn,0);
data.opSetInput(op,data.newConstant(x->getSize(),pow),1);
return 1;
}
void RuleModOpt::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_DIV);
oplist.push_back(CPUI_INT_SDIV);
}
int4 RuleModOpt::applyOp(PcodeOp *op,Funcdata &data)
{
PcodeOp *multop,*addop;
Varnode *div,*x,*outvn,*outvn2,*div2;
list<PcodeOp *>::const_iterator iter1,iter2;
x = op->getIn(0);
div = op->getIn(1);
outvn = op->getOut();
for(iter1=outvn->beginDescend();iter1!=outvn->endDescend();++iter1) {
multop = *iter1;
if (multop->code() != CPUI_INT_MULT) continue;
div2 = multop->getIn(1);
if (div2 == outvn)
div2 = multop->getIn(0);
if (div2->isConstant()) {
if (!div->isConstant()) continue;
uintb mask = calc_mask(div2->getSize());
if ((((div2->getOffset() ^ mask)+1)&mask) != div->getOffset())
continue;
}
else {
if (!div2->isWritten()) continue;
if (div2->getDef()->code() != CPUI_INT_2COMP) continue;
if (div2->getDef()->getIn(0) != div) continue;
}
outvn2 = multop->getOut();
for(iter2=outvn2->beginDescend();iter2!=outvn2->endDescend();++iter2) {
addop = *iter2;
if (addop->code() != CPUI_INT_ADD) continue;
Varnode *lvn;
lvn = addop->getIn(0);
if (lvn == outvn2)
lvn = addop->getIn(1);
if (lvn != x) continue;
data.opSetInput(addop,x,0);
if (div->isConstant())
data.opSetInput(addop,data.newConstant(div->getSize(),div->getOffset()),1);
else
data.opSetInput(addop,div,1);
if (op->code() == CPUI_INT_DIV) data.opSetOpcode(addop,CPUI_INT_REM);
else
data.opSetOpcode(addop,CPUI_INT_SREM);
return 1;
}
}
return 0;
}
void RuleSegment::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SEGMENTOP);
}
int4 RuleSegment::applyOp(PcodeOp *op,Funcdata &data)
{
SegmentOp *segdef = data.getArch()->userops.getSegmentOp(Address::getSpaceFromConst(op->getIn(0)->getAddr())->getIndex());
if (segdef == (SegmentOp *)0)
throw LowlevelError("Segment operand missing definition");
Varnode *vn1 = op->getIn(1);
Varnode *vn2 = op->getIn(2);
if (vn1->isConstant() && vn2->isConstant()) {
vector<uintb> bindlist;
bindlist.push_back(vn1->getOffset());
bindlist.push_back(vn2->getOffset());
uintb val = segdef->execute(bindlist);
data.opRemoveInput(op,2);
data.opRemoveInput(op,1);
data.opSetInput(op,data.newConstant(op->getOut()->getSize(),val),0);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
else if (segdef->hasFarPointerSupport()) {
if (!contiguous_test(vn1,vn2)) return 0;
Varnode *whole = findContiguousWhole(data,vn1,vn2);
if (whole == (Varnode *)0) return 0;
if (whole->isFree()) return 0;
data.opRemoveInput(op,2);
data.opRemoveInput(op,1);
data.opSetInput(op,whole,0);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
return 0;
}
void RuleSubvarAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSubvarAnd::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
if (outvn->getConsume() != op->getIn(1)->getOffset()) return 0;
if ((outvn->getConsume() & 1)==0) return 0;
uintb cmask;
if (outvn->getConsume() == (uintb)1)
cmask = (uintb)1;
else {
cmask = calc_mask(vn->getSize());
cmask >>=8;
while(cmask != 0) {
if (cmask == outvn->getConsume()) break;
cmask >>=8;
}
}
if (cmask == 0) return 0;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,cmask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSubpiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubvarSubpiece::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 flowsize = outvn->getSize();
uintb mask = calc_mask( flowsize );
mask <<= 8*((int4)op->getIn(1)->getOffset());
bool aggressive = outvn->isPtrFlow();
if (!aggressive) {
if ((vn->getConsume() & mask) != vn->getConsume()) return 0;
if (op->getOut()->hasNoDescend()) return 0;
}
bool big = false;
if (flowsize >= 8 && vn->isInput()) {
if (vn->loneDescend() == op)
big = true;
}
SubvariableFlow subflow(&data,vn,mask,aggressive,false,big);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSplitFlow::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSplitFlow::applyOp(PcodeOp *op,Funcdata &data)
{
int4 loSize = (int4)op->getIn(1)->getOffset();
if (loSize == 0) return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten())
return 0;
if (vn->isPrecisLo() || vn->isPrecisHi())
return 0;
if (op->getOut()->getSize() + loSize != vn->getSize())
return 0; PcodeOp *concatOp = (PcodeOp *)0;
PcodeOp *multiOp = vn->getDef();
while(multiOp->code() == CPUI_INDIRECT) { Varnode *tmpvn = multiOp->getIn(0);
if (!tmpvn->isWritten()) return 0;
multiOp = tmpvn->getDef();
}
if (multiOp->code() == CPUI_PIECE) {
if (vn->getDef() != multiOp)
concatOp = multiOp;
}
else if (multiOp->code() == CPUI_MULTIEQUAL) { for(int4 i=0;i<multiOp->numInput();++i) {
Varnode *invn = multiOp->getIn(i);
if (!invn->isWritten()) continue;
PcodeOp *tmpOp = invn->getDef();
if (tmpOp->code() == CPUI_PIECE) {
concatOp = tmpOp;
break;
}
}
}
if (concatOp == (PcodeOp *)0) return 0;
if (concatOp->getIn(1)->getSize() != loSize)
return 0;
SplitFlow splitFlow(&data,vn,loSize);
if (!splitFlow.doTrace()) return 0;
splitFlow.apply();
return 1;
}
RulePtrFlow::RulePtrFlow(const string &g,Architecture *conf)
: Rule( g, 0, "ptrflow")
{
glb = conf;
hasTruncations = glb->getDefaultDataSpace()->isTruncated();
}
void RulePtrFlow::getOpList(vector<uint4> &oplist) const
{
if (!hasTruncations) return; oplist.push_back(CPUI_STORE);
oplist.push_back(CPUI_LOAD);
oplist.push_back(CPUI_COPY);
oplist.push_back(CPUI_MULTIEQUAL);
oplist.push_back(CPUI_INDIRECT);
oplist.push_back(CPUI_INT_ADD);
oplist.push_back(CPUI_CALLIND);
oplist.push_back(CPUI_BRANCHIND);
oplist.push_back(CPUI_PTRSUB);
oplist.push_back(CPUI_PTRADD);
}
bool RulePtrFlow::trialSetPtrFlow(PcodeOp *op)
{
switch(op->code()) {
case CPUI_COPY:
case CPUI_MULTIEQUAL:
case CPUI_INT_ADD:
case CPUI_INDIRECT:
case CPUI_PTRSUB:
case CPUI_PTRADD:
if (!op->isPtrFlow()) {
op->setPtrFlow();
return true;
}
break;
default:
break;
}
return false;
}
bool RulePtrFlow::propagateFlowToDef(Varnode *vn)
{
bool madeChange = false;
if (!vn->isPtrFlow()) {
vn->setPtrFlow();
madeChange = true;
}
if (!vn->isWritten()) return madeChange;
PcodeOp *op = vn->getDef();
if (trialSetPtrFlow(op))
madeChange = true;
return madeChange;
}
bool RulePtrFlow::propagateFlowToReads(Varnode *vn)
{
list<PcodeOp *>::const_iterator iter;
bool madeChange = false;
if (!vn->isPtrFlow()) {
vn->setPtrFlow();
madeChange = true;
}
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (trialSetPtrFlow(op))
madeChange = true;
}
return madeChange;
}
Varnode *RulePtrFlow::truncatePointer(AddrSpace *spc,PcodeOp *op,Varnode *vn,int4 slot,Funcdata &data)
{
Varnode *newvn;
PcodeOp *truncop = data.newOp(2,op->getAddr());
data.opSetOpcode(truncop,CPUI_SUBPIECE);
data.opSetInput(truncop,data.newConstant(vn->getSize(),0),1);
if (vn->getSpace()->getType() == IPTR_INTERNAL) {
newvn = data.newUniqueOut(spc->getAddrSize(),truncop);
}
else {
Address addr = vn->getAddr();
if (addr.isBigEndian())
addr = addr + (vn->getSize() - spc->getAddrSize());
addr.renormalize(spc->getAddrSize());
newvn = data.newVarnodeOut(spc->getAddrSize(),addr,truncop);
}
data.opSetInput(op,newvn,slot);
data.opSetInput(truncop,vn,0);
data.opInsertBefore(truncop,op);
return newvn;
}
int4 RulePtrFlow::applyOp(PcodeOp *op,Funcdata &data)
{ Varnode *vn;
AddrSpace *spc;
int4 madeChange = 0;
switch(op->code()) {
case CPUI_LOAD:
case CPUI_STORE:
vn = op->getIn(1);
spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
if (vn->getSize() > spc->getAddrSize()) {
vn = truncatePointer(spc,op,vn,1,data);
madeChange = 1;
}
if (propagateFlowToDef(vn))
madeChange = 1;
break;
case CPUI_CALLIND:
case CPUI_BRANCHIND:
vn = op->getIn(0);
spc = data.getArch()->getDefaultCodeSpace();
if (vn->getSize() > spc->getAddrSize()) {
vn = truncatePointer(spc,op,vn,0,data);
madeChange = 1;
}
if (propagateFlowToDef(vn))
madeChange = 1;
break;
case CPUI_NEW:
vn = op->getOut();
if (propagateFlowToReads(vn))
madeChange = 1;
break;
case CPUI_INDIRECT:
if (!op->isPtrFlow()) return 0;
vn = op->getOut();
if (propagateFlowToReads(vn))
madeChange = 1;
vn = op->getIn(0);
if (propagateFlowToDef(vn))
madeChange = 1;
break;
case CPUI_COPY:
case CPUI_PTRSUB:
case CPUI_PTRADD:
if (!op->isPtrFlow()) return 0;
vn = op->getOut();
if (propagateFlowToReads(vn))
madeChange = 1;
vn = op->getIn(0);
if (propagateFlowToDef(vn))
madeChange = 1;
break;
case CPUI_MULTIEQUAL:
case CPUI_INT_ADD:
if (!op->isPtrFlow()) return 0;
vn = op->getOut();
if (propagateFlowToReads(vn))
madeChange = 1;
for(int4 i=0;i<op->numInput();++i) {
vn = op->getIn(i);
if (propagateFlowToDef(vn))
madeChange = 1;
}
break;
default:
break;
}
return madeChange;
}
void RuleSubvarCompZero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NOTEQUAL);
oplist.push_back(CPUI_INT_EQUAL);
}
int4 RuleSubvarCompZero::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
uintb mask = vn->getNZMask();
int4 bitnum = leastsigbit_set(mask);
if (bitnum == -1) return 0;
if ((mask >> bitnum) != 1) return 0;
if ((op->getIn(1)->getOffset()!=mask)&&
(op->getIn(1)->getOffset()!=0))
return 0;
if (op->getOut()->hasNoDescend()) return 0;
if (vn->isWritten()) {
PcodeOp *andop = vn->getDef();
if (andop->numInput()==0) return 0;
Varnode *vn0 = andop->getIn(0);
switch(andop->code()) {
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_RIGHT:
{
if (vn0->isConstant()) return 0;
uintb mask0 = vn0->getConsume() & vn0->getNZMask();
uintb wholemask = calc_mask(vn0->getSize()) & mask0;
if ((wholemask & 0xff)==0xff) return 0;
if ((wholemask & 0xff00)==0xff00) return 0;
}
break;
default:
break;
}
}
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) {
return 0;
}
subflow.doReplacement();
return 1;
}
void RuleSubvarShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSubvarShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
if (vn->getSize() != 1) return 0;
if (!op->getIn(1)->isConstant()) return 0;
int4 sa = (int4)op->getIn(1)->getOffset();
uintb mask = vn->getNZMask();
if ((mask >> sa) != (uintb)1) return 0; mask = (mask >> sa) << sa;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleSubvarZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,invn->isPtrFlow(),false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SEXT);
}
int4 RuleSubvarSext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,isaggressive,true,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::reset(Funcdata &data)
{
isaggressive = data.getArch()->aggressive_ext_trim;
}
void RuleSubfloatConvert::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_FLOAT2FLOAT);
}
int4 RuleSubfloatConvert::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 insize = invn->getSize();
int4 outsize = outvn->getSize();
if (outsize > insize) {
SubfloatFlow subflow(&data,outvn,insize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
else {
SubfloatFlow subflow(&data,invn,outsize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
return 1;
}
void RuleNegateNegate::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NEGATE);
}
int4 RuleNegateNegate::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
PcodeOp *neg2 = vn1->getDef();
if (neg2->code() != CPUI_INT_NEGATE)
return 0;
Varnode *vn2 = neg2->getIn(0);
if (vn2->isFree()) return 0;
data.opSetInput(op,vn2,0);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}
bool RuleConditionalMove::BoolExpress::initialize(Varnode *vn)
{
if (!vn->isWritten()) return false;
op = vn->getDef();
opc = op->code();
switch(opc) {
case CPUI_COPY:
in0 = op->getIn(0);
if (in0->isConstant()) {
optype = 0;
val = in0->getOffset();
return ((val & ~((uintb)1)) == 0);
}
return false;
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_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:
in0 = op->getIn(0);
in1 = op->getIn(1);
optype = 2;
break;
case CPUI_BOOL_NEGATE:
in0 = op->getIn(0);
optype = 1;
break;
default:
return false;
}
return true;
}
bool RuleConditionalMove::BoolExpress::evaluatePropagation(FlowBlock *root,FlowBlock *branch)
{
mustreconstruct = false;
if (optype==0) return true; if (root == branch) return true; if (op->getParent() != branch) return true; mustreconstruct = true; if (in0->isFree() && !in0->isConstant()) return false;
if (in0->isWritten() && (in0->getDef()->getParent()==branch)) return false;
if (optype == 2) {
if (in1->isFree() && !in1->isConstant()) return false;
if (in1->isWritten() && (in1->getDef()->getParent()==branch)) return false;
}
return true;
}
Varnode *RuleConditionalMove::BoolExpress::constructBool(PcodeOp *insertop,Funcdata &data)
{
Varnode *resvn;
if (mustreconstruct) {
PcodeOp *newop = data.newOp(optype,op->getAddr()); data.opSetOpcode(newop, opc );
resvn = data.newUniqueOut(1,newop);
if (in0->isConstant())
in0 = data.newConstant(in0->getSize(),in0->getOffset());
data.opSetInput(newop,in0,0);
if (optype == 2) { if (in1->isConstant())
in1 = data.newConstant(in1->getSize(),in1->getOffset());
data.opSetInput(newop,in1,1);
}
data.opInsertBefore(newop,insertop);
}
else {
if (optype == 0)
resvn = data.newConstant(1,val);
else
resvn = op->getOut();
}
return resvn;
}
Varnode *RuleConditionalMove::constructNegate(Varnode *vn,PcodeOp *op,Funcdata &data)
{
PcodeOp *negateop = data.newOp(1,op->getAddr());
data.opSetOpcode(negateop,CPUI_BOOL_NEGATE);
Varnode *resvn = data.newUniqueOut(1,negateop);
data.opSetInput(negateop,vn,0);
data.opInsertBefore(negateop,op);
return resvn;
}
void RuleConditionalMove::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_MULTIEQUAL);
}
int4 RuleConditionalMove::applyOp(PcodeOp *op,Funcdata &data)
{
BoolExpress bool0;
BoolExpress bool1;
BlockBasic *bb;
FlowBlock *inblock0,*inblock1;
FlowBlock *rootblock0,*rootblock1;
if (op->numInput() != 2) return 0;
if (!bool0.initialize(op->getIn(0))) return 0;
if (!bool1.initialize(op->getIn(1))) return 0;
bb = op->getParent();
inblock0 = bb->getIn(0);
if (inblock0->sizeOut() == 1) {
if (inblock0->sizeIn() != 1) return 0;
rootblock0 = inblock0->getIn(0);
}
else
rootblock0 = inblock0;
inblock1 = bb->getIn(1);
if (inblock1->sizeOut() == 1) {
if (inblock1->sizeIn() != 1) return 0;
rootblock1 = inblock1->getIn(0);
}
else
rootblock1 = inblock1;
if (rootblock0 != rootblock1) return 0;
PcodeOp *cbranch = rootblock0->lastOp();
if (cbranch == (PcodeOp *)0) return 0;
if (cbranch->code() != CPUI_CBRANCH) return 0;
if (!bool0.evaluatePropagation(rootblock0,inblock0)) return 0;
if (!bool1.evaluatePropagation(rootblock0,inblock1)) return 0;
bool path0istrue;
if (rootblock0 != inblock0)
path0istrue = (rootblock0->getTrueOut() == inblock0);
else
path0istrue = (rootblock0->getTrueOut() != inblock1);
if (cbranch->isBooleanFlip())
path0istrue = !path0istrue;
if (!bool0.isConstant() && !bool1.isConstant()) {
if (inblock0 == rootblock0) {
Varnode *boolvn = cbranch->getIn(1);
bool andorselect = path0istrue;
if (boolvn != op->getIn(0)) {
if (!boolvn->isWritten()) return 0;
PcodeOp *negop = boolvn->getDef();
if (negop->code() != CPUI_BOOL_NEGATE) return 0;
if (negop->getIn(0) != op->getIn(0)) return 0;
andorselect = !andorselect;
}
OpCode opc = andorselect ? CPUI_BOOL_OR : CPUI_BOOL_AND;
data.opUninsert( op );
data.opSetOpcode(op, opc);
data.opInsertBegin(op, bb);
Varnode *firstvn = bool0.constructBool(op,data);
Varnode *secondvn = bool1.constructBool(op,data);
data.opSetInput(op,firstvn,0);
data.opSetInput(op,secondvn,1);
return 1;
}
else if (inblock1 == rootblock0) {
Varnode *boolvn = cbranch->getIn(1);
bool andorselect = !path0istrue;
if (boolvn != op->getIn(1)) {
if (!boolvn->isWritten()) return 0;
PcodeOp *negop = boolvn->getDef();
if (negop->code() != CPUI_BOOL_NEGATE) return 0;
if (negop->getIn(0) != op->getIn(1)) return 0;
andorselect = !andorselect;
}
data.opUninsert( op );
OpCode opc = andorselect ? CPUI_BOOL_OR : CPUI_BOOL_AND;
data.opSetOpcode(op, opc);
data.opInsertBegin(op, bb);
Varnode *firstvn = bool1.constructBool(op,data);
Varnode *secondvn = bool0.constructBool(op,data);
data.opSetInput(op,firstvn,0);
data.opSetInput(op,secondvn,1);
return 1;
}
return 0;
}
data.opUninsert( op ); int4 sz = op->getOut()->getSize();
if (bool0.isConstant() && bool1.isConstant()) {
if (bool0.getVal() == bool1.getVal()) {
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op, data.newConstant( sz, bool0.getVal() ), 0 );
data.opInsertBegin(op,bb);
}
else {
data.opRemoveInput(op,1);
Varnode *boolvn = cbranch->getIn(1);
bool needcomplement = ( (bool0.getVal()==0) == path0istrue );
if (sz == 1) {
if (needcomplement)
data.opSetOpcode(op,CPUI_BOOL_NEGATE);
else
data.opSetOpcode(op,CPUI_COPY);
data.opInsertBegin(op,bb);
data.opSetInput(op, boolvn, 0);
}
else {
data.opSetOpcode(op,CPUI_INT_ZEXT);
data.opInsertBegin(op,bb);
if (needcomplement)
boolvn = constructNegate(boolvn,op,data);
data.opSetInput(op,boolvn,0);
}
}
}
else if (bool0.isConstant()) {
bool needcomplement = (path0istrue != (bool0.getVal()!=0));
OpCode opc = (bool0.getVal()!=0) ? CPUI_BOOL_OR : CPUI_BOOL_AND;
data.opSetOpcode(op,opc);
data.opInsertBegin(op,bb);
Varnode *boolvn = cbranch->getIn(1);
if (needcomplement)
boolvn = constructNegate(boolvn,op,data);
Varnode *body1 = bool1.constructBool(op,data);
data.opSetInput(op,boolvn,0);
data.opSetInput(op,body1,1);
}
else { bool needcomplement = (path0istrue == (bool1.getVal()!=0));
OpCode opc = (bool1.getVal()!=0) ? CPUI_BOOL_OR : CPUI_BOOL_AND;
data.opSetOpcode(op,opc);
data.opInsertBegin(op,bb);
Varnode *boolvn = cbranch->getIn(1);
if (needcomplement)
boolvn = constructNegate(boolvn,op,data);
Varnode *body0 = bool0.constructBool(op,data);
data.opSetInput(op,boolvn,0);
data.opSetInput(op,body0,1);
}
return 1;
}
void RuleFloatCast::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_FLOAT2FLOAT);
oplist.push_back(CPUI_FLOAT_TRUNC);
}
int4 RuleFloatCast::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn1 = op->getIn(0);
if (!vn1->isWritten()) return 0;
PcodeOp *castop = vn1->getDef();
OpCode opc2 = castop->code();
if ((opc2 != CPUI_FLOAT_FLOAT2FLOAT)&&(opc2 != CPUI_FLOAT_INT2FLOAT))
return 0;
OpCode opc1 = op->code();
Varnode *vn2 = castop->getIn(0);
int4 insize1 = vn1->getSize();
int4 insize2 = vn2->getSize();
int4 outsize = op->getOut()->getSize();
if (vn2->isFree()) return 0;
if ((opc2 == CPUI_FLOAT_FLOAT2FLOAT)&&(opc1 == CPUI_FLOAT_FLOAT2FLOAT)) {
if (insize1 > outsize) { data.opSetInput(op,vn2,0);
if (outsize == insize2)
data.opSetOpcode(op,CPUI_COPY); return 1;
}
else if (insize2 < insize1) { data.opSetInput(op,vn2,0);
return 1;
}
}
else if ((opc2 == CPUI_FLOAT_INT2FLOAT)&&(opc1 == CPUI_FLOAT_FLOAT2FLOAT)) {
data.opSetInput(op,vn2,0);
data.opSetOpcode(op,CPUI_FLOAT_INT2FLOAT);
return 1;
}
else if ((opc2 == CPUI_FLOAT_FLOAT2FLOAT)&&(opc1 == CPUI_FLOAT_TRUNC)) {
data.opSetInput(op,vn2,0);
return 1;
}
return 0;
}
void RuleIgnoreNan::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_NAN);
}
int4 RuleIgnoreNan::applyOp(PcodeOp *op,Funcdata &data)
{
if (op->numInput()==2)
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,data.newConstant(1,0),0);
return 1;
}
void RuleFuncPtrEncoding::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_CALLIND);
}
int4 RuleFuncPtrEncoding::applyOp(PcodeOp *op,Funcdata &data)
{
int4 align = data.getArch()->funcptr_align;
if (align == 0) return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
PcodeOp *andop = vn->getDef();
if (andop->code() != CPUI_INT_AND) return 0;
Varnode *maskvn = andop->getIn(1);
if (!maskvn->isConstant()) return 0;
uintb val = maskvn->getOffset();
uintb testmask = calc_mask(maskvn->getSize());
uintb slide = ~((uintb)0);
slide <<= align;
if ((testmask & slide)==val) { data.opRemoveInput(andop,1); data.opSetOpcode(andop,CPUI_COPY);
return 1;
}
return 0;
}
int4 RuleThreeWayCompare::testCompareEquivalence(PcodeOp *lessop,PcodeOp *lessequalop)
{
bool twoLessThan;
if (lessop->code() == CPUI_INT_LESS) { if (lessequalop->code() == CPUI_INT_LESSEQUAL)
twoLessThan = false;
else if (lessequalop->code() == CPUI_INT_LESS)
twoLessThan = true;
else
return -1;
}
else if (lessop->code() == CPUI_INT_SLESS) {
if (lessequalop->code() == CPUI_INT_SLESSEQUAL)
twoLessThan = false;
else if (lessequalop->code() == CPUI_INT_SLESS)
twoLessThan = true;
else
return -1;
}
else if (lessop->code() == CPUI_FLOAT_LESS) {
if (lessequalop->code() == CPUI_FLOAT_LESSEQUAL)
twoLessThan = false;
else
return -1; }
else
return -1;
Varnode *a1 = lessop->getIn(0);
Varnode *a2 = lessequalop->getIn(0);
Varnode *b1 = lessop->getIn(1);
Varnode *b2 = lessequalop->getIn(1);
int4 res = 0;
if (a1 != a2) { if ((!a1->isConstant())||(!a2->isConstant())) return -1;
if ((a1->getOffset() != a2->getOffset())&&twoLessThan) {
if (a2->getOffset() + 1 == a1->getOffset()) {
twoLessThan = false; }
else if (a1->getOffset() + 1 == a2->getOffset()) {
twoLessThan = false; res = 1; }
else
return -1;
}
}
if (b1 != b2) { if ((!b1->isConstant())||(!b2->isConstant())) return -1;
if ((b1->getOffset() != b2->getOffset())&&twoLessThan) {
if (b1->getOffset() + 1 == b2->getOffset()) {
twoLessThan = false;
}
else if (b2->getOffset() + 1 == b1->getOffset()) {
twoLessThan = false;
res = 1; }
}
else
return -1;
}
if (twoLessThan)
return -1; return res;
}
PcodeOp *RuleThreeWayCompare::detectThreeWay(PcodeOp *op,bool &isPartial)
{
Varnode *vn1, *vn2, *tmpvn;
PcodeOp *zext1, *zext2;
PcodeOp *addop, *lessop, *lessequalop;
uintb mask;
vn2 = op->getIn(1);
if (vn2->isConstant()) { mask = calc_mask(vn2->getSize());
if (mask != vn2->getOffset()) return (PcodeOp *)0; vn1 = op->getIn(0);
if (!vn1->isWritten()) return (PcodeOp *)0;
addop = vn1->getDef();
if (addop->code() != CPUI_INT_ADD) return (PcodeOp *)0; tmpvn = addop->getIn(0);
if (!tmpvn->isWritten()) return (PcodeOp *)0;
zext1 = tmpvn->getDef();
if (zext1->code() != CPUI_INT_ZEXT) return (PcodeOp *)0; tmpvn = addop->getIn(1);
if (!tmpvn->isWritten()) return (PcodeOp *)0;
zext2 = tmpvn->getDef();
if (zext2->code() != CPUI_INT_ZEXT) return (PcodeOp *)0; }
else if (vn2->isWritten()) {
PcodeOp *tmpop = vn2->getDef();
if (tmpop->code() == CPUI_INT_ZEXT) { zext2 = tmpop; vn1 = op->getIn(0);
if (!vn1->isWritten()) return (PcodeOp *)0;
addop = vn1->getDef();
if (addop->code() != CPUI_INT_ADD) { zext1 = addop;
if (zext1->code() != CPUI_INT_ZEXT)
return (PcodeOp *)0; isPartial = true;
}
else {
tmpvn = addop->getIn(1);
if (!tmpvn->isConstant()) return (PcodeOp *)0;
mask = calc_mask(tmpvn->getSize());
if (mask != tmpvn->getOffset()) return (PcodeOp *)0; tmpvn = addop->getIn(0);
if (!tmpvn->isWritten()) return (PcodeOp *)0;
zext1 = tmpvn->getDef();
if (zext1->code() != CPUI_INT_ZEXT) return (PcodeOp *)0; }
}
else if (tmpop->code() == CPUI_INT_ADD) { addop = tmpop; vn1 = op->getIn(0);
if (!vn1->isWritten()) return (PcodeOp *)0;
zext1 = vn1->getDef();
if (zext1->code() != CPUI_INT_ZEXT) return (PcodeOp *)0; tmpvn = addop->getIn(1);
if (!tmpvn->isConstant()) return (PcodeOp *)0;
mask = calc_mask(tmpvn->getSize());
if (mask != tmpvn->getOffset()) return (PcodeOp *)0; tmpvn = addop->getIn(0);
if (!tmpvn->isWritten()) return (PcodeOp *)0;
zext2 = tmpvn->getDef();
if (zext2->code() != CPUI_INT_ZEXT) return (PcodeOp *)0; }
else
return (PcodeOp *)0;
}
else
return (PcodeOp *)0;
vn1 = zext1->getIn(0);
if (!vn1->isWritten()) return (PcodeOp *)0;
vn2 = zext2->getIn(0);
if (!vn2->isWritten()) return (PcodeOp *)0;
lessop = vn1->getDef();
lessequalop = vn2->getDef();
OpCode opc = lessop->code();
if ((opc != CPUI_INT_LESS)&&(opc != CPUI_INT_SLESS)&&(opc != CPUI_FLOAT_LESS)) { PcodeOp *tmpop = lessop;
lessop = lessequalop;
lessequalop = tmpop;
}
int4 form = testCompareEquivalence(lessop,lessequalop);
if (form < 0)
return (PcodeOp *)0;
if (form == 1) {
PcodeOp *tmpop = lessop;
lessop = lessequalop;
lessequalop = tmpop;
}
return lessop;
}
void RuleThreeWayCompare::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SLESS);
oplist.push_back(CPUI_INT_SLESSEQUAL);
oplist.push_back(CPUI_INT_EQUAL);
oplist.push_back(CPUI_INT_NOTEQUAL);
}
int4 RuleThreeWayCompare::applyOp(PcodeOp *op,Funcdata &data)
{
int4 constSlot=0;
int4 form;
Varnode *tmpvn = op->getIn(constSlot);
if (!tmpvn->isConstant()) { constSlot = 1;
tmpvn = op->getIn(constSlot);
if (!tmpvn->isConstant()) return 0;
}
uintb val = tmpvn->getOffset(); if (val <= 2)
form = (int)val + 1;
else if (val == calc_mask(tmpvn->getSize()))
form = 0;
else
return 0;
tmpvn = op->getIn(1-constSlot);
if (!tmpvn->isWritten()) return 0;
if (tmpvn->getDef()->code() != CPUI_INT_ADD) return 0;
bool isPartial = false;
PcodeOp *lessop = detectThreeWay(tmpvn->getDef(),isPartial);
if (lessop == (PcodeOp *)0)
return 0;
if (isPartial) { if (form == 0)
return 0; form -= 1; }
form <<= 1;
if (constSlot == 1) form += 1;
OpCode lessform = lessop->code(); form <<= 2;
if (op->code() == CPUI_INT_SLESSEQUAL)
form += 1;
else if (op->code() == CPUI_INT_EQUAL)
form += 2;
else if (op->code() == CPUI_INT_NOTEQUAL)
form += 3;
Varnode *bvn = lessop->getIn(0); Varnode *avn = lessop->getIn(1); if ((!avn->isConstant())&&(avn->isFree())) return 0;
if ((!bvn->isConstant())&&(bvn->isFree())) return 0;
switch(form) {
case 1: case 21: data.opSetOpcode(op,CPUI_INT_EQUAL);
data.opSetInput(op,data.newConstant(1,0),0);
data.opSetInput(op,data.newConstant(1,0),1);
break;
case 4: case 16: data.opSetOpcode(op,CPUI_INT_NOTEQUAL);
data.opSetInput(op,data.newConstant(1,0),0);
data.opSetInput(op,data.newConstant(1,0),1);
break;
case 2: case 5: case 6: case 12: data.opSetOpcode(op,lessform);
data.opSetInput(op,avn,0);
data.opSetInput(op,bvn,1);
break;
case 13: case 19: case 20: case 23: data.opSetOpcode(op,(OpCode)(lessform+1)); data.opSetInput(op,avn,0);
data.opSetInput(op,bvn,1);
break;
case 8: case 17: case 18: case 22: data.opSetOpcode(op,lessform);
data.opSetInput(op,bvn,0);
data.opSetInput(op,avn,1);
break;
case 0: case 3: case 7: case 9: data.opSetOpcode(op,(OpCode)(lessform+1)); data.opSetInput(op,bvn,0);
data.opSetInput(op,avn,1);
break;
case 10: case 14: if (lessform == CPUI_FLOAT_LESS) lessform = CPUI_FLOAT_EQUAL; else
lessform = CPUI_INT_EQUAL; data.opSetOpcode(op,lessform);
data.opSetInput(op,avn,0);
data.opSetInput(op,bvn,1);
break;
case 11: case 15: if (lessform == CPUI_FLOAT_LESS) lessform = CPUI_FLOAT_NOTEQUAL; else
lessform = CPUI_INT_NOTEQUAL; data.opSetOpcode(op,lessform);
data.opSetInput(op,avn,0);
data.opSetInput(op,bvn,1);
break;
default:
return 0;
}
return 1;
}
void RulePopcountBoolXor::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_POPCOUNT);
}
int4 RulePopcountBoolXor::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
PcodeOp *baseOp = *iter;
if (baseOp->code() != CPUI_INT_AND) continue;
Varnode *tmpVn = baseOp->getIn(1);
if (!tmpVn->isConstant()) continue;
if (tmpVn->getOffset() != 1) continue; if (tmpVn->getSize() != 1) continue; Varnode *inVn = op->getIn(0);
if (!inVn->isWritten()) return 0;
int4 count = popcount(inVn->getNZMask());
if (count == 1) {
int4 leastPos = leastsigbit_set(inVn->getNZMask());
int4 constRes;
Varnode *b1 = getBooleanResult(inVn, leastPos, constRes);
if (b1 == (Varnode *)0) continue;
data.opSetOpcode(baseOp, CPUI_COPY); data.opRemoveInput(baseOp, 1); data.opSetInput(baseOp, b1, 0);
return 1;
}
if (count == 2) {
int4 pos0 = leastsigbit_set(inVn->getNZMask());
int4 pos1 = mostsigbit_set(inVn->getNZMask());
int4 constRes0,constRes1;
Varnode *b1 = getBooleanResult(inVn, pos0, constRes0);
if (b1 == (Varnode *)0 && constRes0 != 1) continue;
Varnode *b2 = getBooleanResult(inVn, pos1, constRes1);
if (b2 == (Varnode *)0 && constRes1 != 1) continue;
if (b1 == (Varnode *)0 && b2 == (Varnode *)0) continue;
if (b1 == (Varnode *)0)
b1 = data.newConstant(1, 1);
if (b2 == (Varnode *)0)
b2 = data.newConstant(1, 1);
data.opSetOpcode(baseOp, CPUI_INT_XOR); data.opSetInput(baseOp, b1, 0);
data.opSetInput(baseOp, b2, 1);
return 1;
}
}
return 0;
}
Varnode *RulePopcountBoolXor::getBooleanResult(Varnode *vn,int4 bitPos,int4 &constRes)
{
constRes = -1;
uintb mask = 1;
mask <<= bitPos;
Varnode *vn0;
Varnode *vn1;
int4 sa;
for(;;) {
if (vn->isConstant()) {
constRes = (vn->getOffset() >> bitPos) & 1;
return (Varnode *)0;
}
if (!vn->isWritten()) return (Varnode *)0;
if (bitPos == 0 && vn->getSize() == 1 && vn->getNZMask() == mask)
return vn;
PcodeOp *op = vn->getDef();
switch(op->code()) {
case CPUI_INT_AND:
if (!op->getIn(1)->isConstant()) return (Varnode *)0;
vn = op->getIn(0);
break;
case CPUI_INT_XOR:
case CPUI_INT_OR:
vn0 = op->getIn(0);
vn1 = op->getIn(1);
if ((vn0->getNZMask() & mask) != 0) {
if ((vn1->getNZMask() & mask) != 0)
return (Varnode *)0; vn = vn0;
}
else if ((vn1->getNZMask() & mask) != 0) {
vn = vn1;
}
else
return (Varnode *)0;
break;
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
vn = op->getIn(0);
if (bitPos >= vn->getSize() * 8) return (Varnode *)0;
break;
case CPUI_SUBPIECE:
sa = (int4)op->getIn(1)->getOffset() * 8;
bitPos += sa;
mask <<= sa;
vn = op->getIn(0);
break;
case CPUI_PIECE:
vn0 = op->getIn(0);
vn1 = op->getIn(1);
sa = (int4)vn1->getSize() * 8;
if (bitPos >= sa) {
vn = vn0;
bitPos -= sa;
mask >>= sa;
}
else {
vn = vn1;
}
break;
case CPUI_INT_LEFT:
vn1 = op->getIn(1);
if (!vn1->isConstant()) return (Varnode *)0;
sa = (int4) vn1->getOffset();
if (sa > bitPos) return (Varnode *)0;
bitPos -= sa;
mask >>= sa;
vn = op->getIn(0);
break;
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
vn1 = op->getIn(1);
if (!vn1->isConstant()) return (Varnode *)0;
sa = (int4) vn1->getOffset();
vn = op->getIn(0);
bitPos += sa;
if (bitPos >= vn->getSize() * 8) return (Varnode *)0;
mask <<= sa;
break;
default:
return (Varnode *)0;
}
}
}
bool RulePiecePathology::isPathology(Varnode *vn,Funcdata &data)
{
vector<PcodeOp *> worklist;
int4 pos = 0;
int4 slot = 0;
bool res = false;
for(;;) {
if (vn->isInput() && !vn->isPersist()) {
res = true;
break;
}
PcodeOp *op = vn->getDef();
while(!res && op != (PcodeOp *)0) {
switch(op->code()) {
case CPUI_COPY:
vn = op->getIn(0);
op = vn->getDef();
break;
case CPUI_MULTIEQUAL:
if (!op->isMark()) {
op->setMark();
worklist.push_back(op);
}
op = (PcodeOp *)0;
break;
case CPUI_INDIRECT:
if (op->getIn(1)->getSpace()->getType() == IPTR_IOP) {
PcodeOp *callOp = PcodeOp::getOpFromConst(op->getIn(1)->getAddr());
if (callOp->isCall()) {
FuncCallSpecs *fspec = data.getCallSpecs(callOp);
if (fspec != (FuncCallSpecs *) 0 && !fspec->isOutputActive()) {
res = true;
}
}
}
op = (PcodeOp *)0;
break;
case CPUI_CALL:
case CPUI_CALLIND:
{
FuncCallSpecs *fspec = data.getCallSpecs(op);
if (fspec != (FuncCallSpecs *)0 && !fspec->isOutputActive()) {
res = true;
}
break;
}
default:
op = (PcodeOp *)0;
break;
}
}
if (res) break;
if (pos >= worklist.size()) break;
op = worklist[pos];
if (slot < op->numInput()) {
vn = op->getIn(slot);
slot += 1;
}
else {
pos += 1;
if (pos >= worklist.size()) break;
vn = worklist[pos]->getIn(0);
slot = 1;
}
}
for(int4 i=0;i<worklist.size();++i)
worklist[i]->clearMark();
return res;
}
int4 RulePiecePathology::tracePathologyForward(PcodeOp *op,Funcdata &data)
{
int4 count = 0;
const FuncCallSpecs *fProto;
vector<PcodeOp *> worklist;
int4 pos = 0;
op->setMark();
worklist.push_back(op);
while(pos < worklist.size()) {
PcodeOp *curOp = worklist[pos];
pos += 1;
Varnode *outVn = curOp->getOut();
list<PcodeOp *>::const_iterator iter;
list<PcodeOp *>::const_iterator enditer = outVn->endDescend();
for(iter=outVn->beginDescend();iter!=enditer;++iter) {
curOp = *iter;
switch(curOp->code()) {
case CPUI_COPY:
case CPUI_INDIRECT:
case CPUI_MULTIEQUAL:
if (!curOp->isMark()) {
curOp->setMark();
worklist.push_back(curOp);
}
break;
case CPUI_CALL:
case CPUI_CALLIND:
fProto = data.getCallSpecs(curOp);
if (fProto != (FuncProto *)0 && !fProto->isInputActive() && !fProto->isInputLocked()) {
int4 bytesConsumed = op->getIn(1)->getSize();
for(int4 i=1;i<curOp->numInput();++i) {
if (curOp->getIn(i) == outVn) {
if (fProto->setInputBytesConsumed(i, bytesConsumed))
count += 1;
}
}
}
break;
case CPUI_RETURN:
if (!data.getFuncProto().isOutputLocked()) {
if (data.getFuncProto().setReturnBytesConsumed(op->getIn(1)->getSize()))
count += 1;
}
break;
default:
break;
}
}
}
for(int4 i=0;i<worklist.size();++i)
worklist[i]->clearMark();
return count;
}
void RulePiecePathology::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_PIECE);
}
int4 RulePiecePathology::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
if (!vn->isWritten()) return 0;
PcodeOp *subOp = vn->getDef();
OpCode opc = subOp->code();
if (opc == CPUI_SUBPIECE) {
if (subOp->getIn(1)->getOffset() == 0) return 0;
if (!isPathology(subOp->getIn(0),data)) return 0;
}
else if (opc == CPUI_INDIRECT) {
if (!subOp->isIndirectCreation()) return 0;
Varnode *retVn = op->getIn(1);
if (!retVn->isWritten()) return 0;
PcodeOp *callOp = retVn->getDef();
if (!callOp->isCall()) return 0;
FuncCallSpecs *fc = data.getCallSpecs(callOp);
if (fc == (FuncCallSpecs *)0) return 0;
if (!fc->isOutputLocked()) return 0;
Address addr = retVn->getAddr();
if (addr.getSpace()->isBigEndian())
addr = addr - vn->getSize();
else
addr = addr + retVn->getSize();
if (addr != vn->getAddr()) return 0;
}
else
return 0;
return tracePathologyForward(op, data);
}
void RuleXorSwap::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_XOR);
}
int4 RuleXorSwap::applyOp(PcodeOp *op,Funcdata &data)
{
for(int4 i=0;i<2;++i) {
Varnode *vn = op->getIn(i);
if (!vn->isWritten()) continue;
PcodeOp *op2 = vn->getDef();
if (op2->code() != CPUI_INT_XOR) continue;
Varnode *othervn = op->getIn(1-i);
Varnode *vn0 = op2->getIn(0);
Varnode *vn1 = op2->getIn(1);
if (othervn == vn0 && !vn1->isFree()) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
data.opSetInput(op, vn1, 0);
return 1;
}
else if (othervn == vn1 && !vn0->isFree()) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
data.opSetInput(op, vn0, 0);
return 1;
}
}
return 0;
}