#include "rangeutil.hh"
#include "block.hh"
const char CircleRange::arrange[] = "gcgbegdagggggggeggggcgbggggggggcdfgggggggegdggggbgggfggggcgbegda";
void CircleRange::normalize(void)
{
if (left == right) {
if (step != 1)
left = left % step;
else
left = 0;
right = left;
}
}
void CircleRange::complement(void)
{
if (isempty) {
left=0;
right=0;
isempty = false;
return;
}
if (left==right) {
isempty = true;
return;
}
uintb tmp = left;
left = right;
right = tmp;
}
bool CircleRange::convertToBoolean(void)
{
if (isempty) return false;
bool contains_zero = contains(0);
bool contains_one = contains(1);
mask = 0xff;
step = 1;
if (contains_zero && contains_one) {
left = 0;
right = 2;
isempty = false;
return true;
}
else if (contains_zero) {
left = 0;
right = 1;
isempty = false;
}
else if (contains_one) {
left = 1;
right = 2;
isempty = false;
}
else
isempty = true;
return false;
}
bool CircleRange::newStride(uintb mask,int4 step,int4 oldStep,uint4 rem,uintb &myleft,uintb &myright)
{
if (oldStep != 1) {
uint4 oldRem = (uint4)(myleft % oldStep);
if (oldRem != (rem % oldStep))
return true; }
bool origOrder = (myleft < myright);
uint4 leftRem = (uint4)(myleft % step);
uint4 rightRem = (uint4)(myright % step);
if (leftRem > rem)
myleft += rem + step - leftRem;
else
myleft += rem - leftRem;
if (rightRem > rem)
myright += rem + step - rightRem;
else
myright += rem - rightRem;
myleft &= mask;
myright &= mask;
bool newOrder = (myleft < myright);
if (origOrder != newOrder)
return true;
return false; }
bool CircleRange::newDomain(uintb newMask,int4 newStep,uintb &myleft,uintb &myright)
{
uintb rem;
if (newStep != 1)
rem = myleft % newStep;
else
rem = 0;
if (myleft > newMask) {
if (myright > newMask) { if (myleft < myright) return true; myleft = rem;
myright = rem; return false;
}
myleft = rem; }
if (myright > newMask) {
myright = rem; }
if (myleft == myright) {
myleft = rem; myright = rem;
}
return false; }
CircleRange::CircleRange(uintb lft,uintb rgt,int4 size,int4 stp)
{
mask = calc_mask(size);
step = stp;
left = lft;
right = rgt;
isempty = false;
}
CircleRange::CircleRange(bool val)
{
mask = 0xff;
step = 1;
left = val ? 1: 0;
right = val + 1;
isempty = false;
}
CircleRange::CircleRange(uintb val,int4 size)
{
mask = calc_mask(size);
step = 1;
left = val;
right = (left+1)&mask;
isempty = false;
}
void CircleRange::setRange(uintb lft,uintb rgt,int4 size,int4 stp)
{
mask = calc_mask(size);
left = lft;
right = rgt;
step = stp;
isempty = false;
}
void CircleRange::setRange(uintb val,int4 size)
{
mask = calc_mask(size);
step = 1;
left = val;
right = (left+1)&mask;
isempty = false;
}
void CircleRange::setFull(int4 size)
{
mask = calc_mask(size);
step = 1;
left = 0;
right = 0;
isempty = false;
}
uintb CircleRange::getSize(void) const
{
if (isempty) return 0;
uintb val;
if (left < right)
val = (right-left) / step;
else {
val = (mask - (left-right) + step) / step;
if (val == 0) { val = mask; if (step > 1) {
val = val / step;
val += 1;
}
}
}
return val;
}
int4 CircleRange::getMaxInfo(void) const
{
uintb halfPoint = mask ^ (mask >> 1);
if (contains(halfPoint))
return 8*sizeof(uintb) - count_leading_zeros(halfPoint);
int4 sizeLeft,sizeRight;
if ((halfPoint & left) == 0)
sizeLeft = count_leading_zeros(left);
else
sizeLeft = count_leading_zeros(~left & mask);
if ((halfPoint & right) == 0)
sizeRight = count_leading_zeros(right);
else
sizeRight = count_leading_zeros(~right & mask);
int4 size1 = 8*sizeof(uintb) - (sizeRight < sizeLeft ? sizeRight : sizeLeft);
return size1;
}
bool CircleRange::contains(const CircleRange &op2) const
{
if (isempty)
return op2.isempty;
if (op2.isempty)
return true;
if (step > op2.step) {
if (!op2.isSingle())
return false;
}
if (left == right) return true;
if (op2.left == op2.right) return false;
if (left % step != op2.left % step) return false; if (left == op2.left && right == op2.right) return true;
char overlapCode = encodeRangeOverlaps(left, right, op2.left, op2.right);
if (overlapCode == 'c')
return true;
if (overlapCode == 'b' && (right == op2.right))
return true;
return false;
}
bool CircleRange::contains(uintb val) const
{
if (isempty) return false;
if (step != 1) {
if ((left % step)!=(val%step))
return false; }
if (left < right) {
if (val < left) return false;
if (right <= val) return false;
}
else if (right < left) {
if (val<right) return true;
if (val>=left) return true;
return false;
}
return true;
}
int4 CircleRange::circleUnion(const CircleRange &op2)
{
if (op2.isempty) return 0;
if (isempty) {
*this = op2;
return 0;
}
if (mask != op2.mask) return 2; uintb aRight = right;
uintb bRight = op2.right;
int4 newStep = step;
if (step < op2.step) {
if (isSingle()) {
newStep = op2.step;
aRight = (left + newStep) & mask;
}
else
return 2;
}
else if (op2.step < step) {
if (op2.isSingle()) {
newStep = step;
bRight = (op2.left + newStep) & mask;
}
else
return 2;
}
uintb rem;
if (newStep != 1) {
rem = left % newStep;
if (rem != (op2.left % newStep))
return 2;
}
else
rem = 0;
if ((left==aRight)||(op2.left==bRight)) {
left = rem;
right = rem;
step = newStep;
return 0;
}
char overlapCode = encodeRangeOverlaps(left, aRight, op2.left, bRight);
switch(overlapCode) {
case 'a': case 'f': if (aRight==op2.left) {
right = bRight;
step = newStep;
return 0;
}
if (left==bRight) {
left = op2.left;
right = aRight;
step = newStep;
return 0;
}
return 2; case 'b': right = bRight;
step = newStep;
return 0;
case 'c': right = aRight;
step = newStep;
return 0;
case 'd': left = op2.left;
right = bRight;
step = newStep;
return 0;
case 'e': left = op2.left;
right = aRight;
step = newStep;
return 0;
case 'g': left = rem;
right = rem;
step = newStep;
return 0; }
return -1; }
bool CircleRange::minimalContainer(const CircleRange &op2,int4 maxStep)
{
if (isSingle() && op2.isSingle()) {
uintb min,max;
if (getMin() < op2.getMin()) {
min = getMin();
max = op2.getMin();
}
else {
min = op2.getMin();
max = getMin();
}
uintb diff = max - min;
if (diff > 0 && diff <= maxStep) {
if (leastsigbit_set(diff) == mostsigbit_set(diff)) {
step = (int4) diff;
left = min;
right = (max + step) & mask;
return false;
}
}
}
uintb aRight = right - step + 1; uintb bRight = op2.right - op2.step + 1;
step = 1;
mask |= op2.mask;
uintb vacantSize1,vacantSize2;
char overlapCode = encodeRangeOverlaps(left, aRight, op2.left, bRight);
switch(overlapCode) {
case 'a': vacantSize1 = left + (mask - bRight) + 1;
vacantSize2 = op2.left - aRight;
if (vacantSize1 < vacantSize2) {
left = op2.left;
right = aRight;
}
else {
right = bRight;
}
break;
case 'f': vacantSize1 = op2.left + (mask-aRight) + 1;
vacantSize2 = left - bRight;
if (vacantSize1 < vacantSize2) {
right = bRight;
}
else {
left = op2.left;
right = aRight;
}
break;
case 'b': right = bRight;
break;
case 'c': right = aRight;
break;
case 'd': left = op2.left;
right = bRight;
break;
case 'e': left = op2.left;
right = aRight;
break;
case 'g': left = 0; right = 0;
break;
}
normalize();
return (left == right);
}
int4 CircleRange::invert(void)
{
int4 res = step;
step = 1;
complement();
return res;
}
int4 CircleRange::intersect(const CircleRange &op2)
{
int4 retval,newStep;
uintb newMask,myleft,myright,op2left,op2right;
if (isempty) return 0; if (op2.isempty) {
isempty = true;
return 0;
}
myleft = left;
myright = right;
op2left = op2.left;
op2right = op2.right;
if (step < op2.step) {
newStep = op2.step;
uint4 rem = (uint4)(op2left % newStep);
if (newStride(mask,newStep,step,rem,myleft,myright)) { isempty = true;
return 0;
}
}
else if (op2.step < step) {
newStep = step;
uint4 rem = (uint4)(myleft % newStep);
if (newStride(op2.mask,newStep,op2.step,rem,op2left,op2right)) {
isempty = true;
return 0;
}
}
else
newStep = step;
newMask = mask & op2.mask;
if (mask != newMask) {
if (newDomain(newMask,newStep,myleft,myright)) {
isempty = true;
return 0;
}
}
else if (op2.mask != newMask) {
if (newDomain(newMask,newStep,op2left,op2right)) {
isempty = true;
return 0;
}
}
if (myleft==myright) { left = op2left;
right = op2right;
retval = 0;
}
else if (op2left == op2right) { left = myleft;
right = myright;
retval = 0;
}
else {
char overlapCode = encodeRangeOverlaps(myleft, myright, op2left, op2right);
switch(overlapCode) {
case 'a': case 'f': isempty = true;
retval = 0; break;
case 'b': left = op2left;
right = myright;
if (left==right)
isempty = true;
retval = 0;
break;
case 'c': left = op2left;
right = op2right;
retval = 0;
break;
case 'd': left = myleft;
right = myright;
retval = 0;
break;
case 'e': left = myleft;
right = op2right;
if (left==right)
isempty = true;
retval = 0;
break;
case 'g': if (myleft==op2right) {
left = op2left;
right = myright;
if (left==right)
isempty = true;
retval = 0;
}
else if (op2left==myright) {
left = myleft;
right = op2right;
if (left==right)
isempty = true;
retval = 0;
}
else
retval = 2; break;
default:
retval = 2; break;
}
}
if (retval != 0) return retval;
mask = newMask;
step = newStep;
return 0;
}
bool CircleRange::setNZMask(uintb nzmask,int4 size)
{
int4 trans = bit_transitions(nzmask,size);
if (trans>2) return false; bool hasstep = ((nzmask&1)==0);
if ((!hasstep)&&(trans==2)) return false; isempty = false;
if (trans == 0) {
mask = calc_mask(size);
if (hasstep) { step = 1;
left = 0;
right = 1; }
else { step = 1;
left = 0;
right = 0; }
return true;
}
int4 shift = leastsigbit_set(nzmask);
step = 1;
step <<= shift;
mask = calc_mask(size);
left = 0;
right = (nzmask + step) & mask;
return true;
}
void CircleRange::setStride(int4 newStep,uintb rem)
{
bool iseverything = (!isempty) && (left==right);
if (newStep == step) return;
uintb aRight = right - step;
step = newStep;
if (step == 1) return; uintb curRem = left % step;
left = (left - curRem) + rem;
curRem = aRight % step;
aRight = (aRight - curRem) + rem;
right = aRight + step;
if ((!iseverything)&&(left == right))
isempty = true;
}
bool CircleRange::pullBackUnary(OpCode opc,int4 inSize,int4 outSize)
{
uintb val;
if (isempty) return true;
switch(opc) {
case CPUI_BOOL_NEGATE:
if (convertToBoolean())
break; left = left ^ 1; right = left +1;
break;
case CPUI_COPY:
break; case CPUI_INT_2COMP:
val = (~left + 1 + step) & mask;
left = (~right + 1 + step) & mask;
right = val;
break;
case CPUI_INT_NEGATE:
val = (~left + step) & mask;
left = (~right + step) & mask;
right = val;
break;
case CPUI_INT_ZEXT:
{
val = calc_mask(inSize); uintb rem = left % step;
CircleRange zextrange;
zextrange.left = rem;
zextrange.right = val + 1 + rem; zextrange.mask = mask;
zextrange.step = step; zextrange.isempty = false;
if (0 != intersect(zextrange))
return false;
left &= val;
right &= val;
mask &= val; break;
}
case CPUI_INT_SEXT:
{
val = calc_mask(inSize); uintb rem = left & step;
CircleRange sextrange;
sextrange.left = val ^ (val >> 1); sextrange.left += rem;
sextrange.right = sign_extend(sextrange.left, inSize, outSize);
sextrange.mask = mask;
sextrange.step = step; sextrange.isempty = false;
if (sextrange.intersect(*this) != 0)
return false;
else {
if (!sextrange.isEmpty())
return false;
else {
left &= val;
right &= val;
mask &= val; }
}
break;
}
default:
return false;
}
return true;
}
bool CircleRange::pullBackBinary(OpCode opc,uintb val,int4 slot,int4 inSize,int4 outSize)
{
bool yescomplement;
bool bothTrueFalse;
if (isempty) return true;
switch(opc) {
case CPUI_INT_EQUAL:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse)
break; yescomplement = (left == 0);
left = val;
right = (val + 1) & mask;
if (yescomplement)
complement();
break;
case CPUI_INT_NOTEQUAL:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse) break; yescomplement = (left==0);
left = (val+1)&mask;
right = val;
if (yescomplement)
complement();
break;
case CPUI_INT_LESS:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse) break; yescomplement = (left==0);
if (slot==0) {
if (val==0)
isempty = true; else {
left = 0;
right = val;
}
}
else {
if (val==mask)
isempty = true; else {
left = (val+1)&mask;
right = 0;
}
}
if (yescomplement)
complement();
break;
case CPUI_INT_LESSEQUAL:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse) break; yescomplement = (left==0);
if (slot==0) {
left = 0;
right = (val+1)&mask;
}
else {
left = val;
right = 0;
}
if (yescomplement)
complement();
break;
case CPUI_INT_SLESS:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse) break; yescomplement = (left==0);
if (slot==0) {
if (val == (mask>>1)+1)
isempty = true; else {
left = (mask >> 1)+1; right = val;
}
}
else {
if ( val == (mask>>1) )
isempty = true; else {
left = (val+1)&mask;
right = (mask >> 1)+1; }
}
if (yescomplement)
complement();
break;
case CPUI_INT_SLESSEQUAL:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse) break; yescomplement = (left==0);
if (slot==0) {
left = (mask >> 1)+1; right = (val+1)&mask;
}
else {
left = val;
right = (mask >> 1)+1; }
if (yescomplement)
complement();
break;
case CPUI_INT_CARRY:
bothTrueFalse = convertToBoolean();
mask = calc_mask(inSize);
if (bothTrueFalse) break; yescomplement = (left==0);
if (val==0)
isempty = true; else {
left = ((mask-val)+1)&mask;
right = 0;
}
if (yescomplement)
complement();
break;
case CPUI_INT_ADD:
left = (left-val)&mask;
right = (right-val)&mask;
break;
case CPUI_INT_SUB:
if (slot==0) {
left = (left+val)&mask;
right = (right+val)&mask;
}
else {
left = (val-left)&mask;
right = (val-right)&mask;
}
break;
case CPUI_INT_RIGHT:
{
if (step == 1) {
uintb rightBound = (calc_mask(inSize) >> val) + 1; if (((left >= rightBound) && (right >= rightBound) && (left >= right))
|| ((left == 0) && (right >= rightBound)) || (left == right)) {
left = 0; right = 0;
}
else {
if (left > rightBound)
left = rightBound;
if (right > rightBound)
right = 0;
left = (left << val) & mask;
right = (right << val) & mask;
if (left == right)
isempty = true;
}
}
else
return false;
break;
}
case CPUI_INT_SRIGHT:
{
if (step == 1) {
uintb rightb = calc_mask(inSize);
uintb leftb = rightb >> (val + 1);
rightb = leftb ^ rightb; leftb += 1; if (((left >= leftb) && (left <= rightb) && (right >= leftb)
&& (right <= rightb) && (left >= right)) || (left == right)) {
left = 0; right = 0;
}
else {
if ((left > leftb) && (left < rightb))
left = leftb;
if ((right > leftb) && (right < rightb))
right = rightb;
left = (left << val) & mask;
right = (right << val) & mask;
if (left == right)
isempty = true;
}
}
else
return false;
break;
}
default:
return false;
}
return true;
}
Varnode *CircleRange::pullBack(PcodeOp *op,Varnode **constMarkup,bool usenzmask)
{
Varnode *res;
if (op->numInput() == 1) {
res = op->getIn(0);
if (res->isConstant()) return (Varnode *)0;
if (!pullBackUnary(op->code(),res->getSize(),op->getOut()->getSize()))
return (Varnode *)0;
}
else if (op->numInput() == 2) {
Varnode *constvn;
uintb val;
int4 slot = 0;
res = op->getIn(slot);
constvn = op->getIn(1 - slot);
if (res->isConstant()) {
slot = 1;
constvn = res;
res = op->getIn(slot);
if (res->isConstant())
return (Varnode *) 0;
}
else if (!constvn->isConstant())
return (Varnode *) 0;
val = constvn->getOffset();
OpCode opc = op->code();
if (!pullBackBinary(opc, val, slot, res->getSize(), op->getOut()->getSize())) {
if (usenzmask && opc == CPUI_SUBPIECE && val == 0) {
int4 msbset = mostsigbit_set(res->getNZMask());
msbset = (msbset + 8) / 8;
if (op->getOut()->getSize() < msbset) return (Varnode *) 0;
else {
mask = calc_mask(res->getSize()); }
}
else
return (Varnode *) 0;
}
if (constvn->getSymbolEntry() != (SymbolEntry *) 0)
*constMarkup = constvn;
}
else return (Varnode *)0;
if (usenzmask) {
CircleRange nzrange;
if (!nzrange.setNZMask(res->getNZMask(),res->getSize()))
return res;
intersect(nzrange);
}
return res;
}
bool CircleRange::pushForwardUnary(OpCode opc,const CircleRange &in1,int4 inSize,int4 outSize)
{
if (in1.isempty) {
isempty = true;
return true;
}
switch(opc) {
case CPUI_CAST:
case CPUI_COPY:
*this = in1;
break;
case CPUI_INT_ZEXT:
isempty = false;
step = in1.step;
mask = calc_mask(outSize);
if (in1.left == in1.right) {
left = in1.left % step;
right = in1.mask + 1 + left;
}
else {
left = in1.left;
right = (in1.right - in1.step) & in1.mask;
if (right < left)
return false; right += step; }
break;
case CPUI_INT_SEXT:
isempty = false;
step = in1.step;
mask = calc_mask(outSize);
if (in1.left == in1.right) {
uintb rem = in1.left % step;
right = calc_mask(inSize) >> 1;
left = (calc_mask(outSize) ^ right) + rem;
right = right + 1 + rem;
}
else {
left = sign_extend(in1.left, inSize, outSize);
right = sign_extend((in1.right - in1.step)&in1.mask, inSize, outSize);
if ((intb)right < (intb)left)
return false; right = (right + step) & mask;
}
break;
case CPUI_INT_2COMP:
isempty = false;
step = in1.step;
mask = in1.mask;
right = (~in1.left + 1 + step) & mask;
left = (~in1.right + 1 + step) & mask;
normalize();
break;
case CPUI_INT_NEGATE:
isempty = false;
step = in1.step;
mask = in1.mask;
left = (~in1.right + step) & mask;
right =(~in1.left + step) & mask;
normalize();
break;
case CPUI_BOOL_NEGATE:
case CPUI_FLOAT_NAN:
isempty = false;
mask = 0xff;
step = 1;
left = 0;
right = 2;
break;
default:
return false;
}
return true;
}
bool CircleRange::pushForwardBinary(OpCode opc,const CircleRange &in1,const CircleRange &in2,int4 inSize,int4 outSize,int4 maxStep)
{
if (in1.isempty || in2.isempty) {
isempty = true;
return true;
}
switch(opc) {
case CPUI_PTRSUB:
case CPUI_INT_ADD:
isempty = false;
mask = in1.mask | in2.mask;
if (in1.left == in1.right || in2.left == in2.right) {
step = (in1.step < in2.step) ? in1.step : in2.step; left = (in1.left + in2.left) % step;
right = left;
}
else if (in2.isSingle()) {
step = in1.step;
left = (in1.left + in2.left) & mask;
right = (in1.right + in2.left) & mask;
}
else if (in1.isSingle()) {
step = in2.step;
left = (in2.left + in1.left) & mask;
right = (in2.right +in1.left) & mask;
}
else {
step = (in1.step < in2.step) ? in1.step : in2.step; uintb size1 = (in1.left < in1.right) ? (in1.right-in1.left) : (in1.mask - (in1.left-in1.right) + in1.step);
left = (in1.left + in2.left) & mask;
right = (in1.right - in1.step + in2.right - in2.step + step) & mask;
uintb sizenew = (left < right) ? (right-left) : (mask - (left-right) + step);
if (sizenew < size1) {
right = left; }
normalize();
}
break;
case CPUI_INT_MULT:
{
isempty = false;
mask = in1.mask | in2.mask;
uintb constVal;
if (in1.isSingle()) {
constVal = in1.getMin();
step = in2.step;
}
else if (in2.isSingle()) {
constVal = in2.getMin();
step = in1.step;
}
else
return false;
uint4 tmp = (uint4)constVal;
while(step < maxStep) {
if ((tmp & 1) != 0) break;
step <<= 1;
tmp >>= 1;
}
int4 wholeSize = 8*sizeof(uintb) - count_leading_zeros(mask);
if (in1.getMaxInfo() + in2.getMaxInfo() > wholeSize) {
left = in1.left; right = in1.left;
normalize();
return true;
}
if ((constVal & (mask ^ (mask >> 1))) != 0) { left = ((in1.right - in1.step) * (in2.right - in2.step)) & mask;
right = ((in1.left * in2.left) + step) & mask;
}
else {
left = (in1.left * in2.left)&mask;
right = ((in1.right - in1.step) * (in2.right - in2.step) + step) & mask;
}
break;
}
case CPUI_INT_LEFT:
{
if (!in2.isSingle()) return false;
isempty = false;
mask = in1.mask;
step = in1.step;
uint4 sa = (uint4)in2.getMin();
uint4 tmp = sa;
while(step < maxStep && tmp > 0) {
step <<= 1;
sa -= 1;
}
left = (in1.left << sa)&mask;
right = (in1.right << sa)&mask;
int4 wholeSize = 8*sizeof(uintb) - count_leading_zeros(mask);
if (in1.getMaxInfo() + sa > wholeSize) {
right = left; normalize();
return true;
}
break;
}
case CPUI_SUBPIECE:
{
if (!in2.isSingle()) return false;
isempty = false;
int4 sa = (int4)in2.left * 8;
mask = calc_mask(outSize);
step = (sa == 0) ? in1.step : 1;
left = (in1.left >> sa)&mask;
right = (in1.right >> sa)&mask;
if ((left& ~mask) != (right & ~mask)) { left = right = 0; }
else {
left &= mask;
right &= mask;
normalize();
}
break;
}
case CPUI_INT_RIGHT:
{
if (!in2.isSingle()) return false;
isempty = false;
int4 sa = (int4)in2.left;
mask = calc_mask(outSize);
step = 1; if (in1.left < in1.right) {
left = in1.left >> sa;
right = ((in1.right - in1.step) >> sa) + 1;
}
else {
left = 0;
right = in1.mask >> sa;
}
if (left == right) right = (left + 1)&mask;
break;
}
case CPUI_INT_SRIGHT:
{
if (!in2.isSingle()) return false;
isempty = false;
int4 sa = (int4)in2.left;
mask = calc_mask(outSize);
step = 1; intb valLeft = in1.left;
intb valRight = in1.right;
int4 bitPos = 8*inSize - 1;
sign_extend(valLeft,bitPos);
sign_extend(valRight,bitPos);
if (valLeft >= valRight) {
valRight = (intb)(mask >> 1); valLeft = valRight + 1; sign_extend(valLeft,bitPos);
}
left = (valLeft >> sa) & mask;
right = (valRight >> sa) & mask;
if (left == right) right = (left + 1)&mask;
break;
}
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:
isempty = false;
mask = 0xff;
step = 1;
left = 0; right = 2;
break;
default:
return false;
}
return true;
}
bool CircleRange::pushForwardTrinary(OpCode opc,const CircleRange &in1,const CircleRange &in2,const CircleRange &in3,
int4 inSize,int4 outSize,int4 maxStep)
{
if (opc != CPUI_PTRADD) return false;
CircleRange tmpRange;
if (!tmpRange.pushForwardBinary(CPUI_INT_MULT, in2, in3, inSize, inSize, maxStep))
return false;
return pushForwardBinary(CPUI_INT_ADD, in1, tmpRange, inSize, outSize, maxStep);
}
void CircleRange::widen(const CircleRange &op2,bool leftIsStable)
{
if (leftIsStable) {
uintb lmod = left % step;
uintb mod = op2.right % step;
if (mod <= lmod)
right = op2.right + (lmod - mod);
else
right = op2.right - (mod - lmod);
right &= mask;
}
else {
left = op2.left & mask;
}
normalize();
}
int4 CircleRange::translate2Op(OpCode &opc,uintb &c,int4 &cslot) const
{
if (isempty) return 3;
if (step != 1) return 2; if (right==((left+1)&mask)) { opc = CPUI_INT_EQUAL;
cslot = 0;
c = left;
return 0;
}
if (left==((right+1)&mask)) { opc = CPUI_INT_NOTEQUAL;
cslot = 0;
c = right;
return 0;
}
if (left==right) return 1; if (left==0) {
opc = CPUI_INT_LESS;
cslot = 1;
c = right;
return 0;
}
if (right==0) {
opc = CPUI_INT_LESS;
cslot = 0;
c = (left-1)&mask;
return 0;
}
if (left==(mask>>1)+1) {
opc = CPUI_INT_SLESS;
cslot = 1;
c = right;
return 0;
}
if (right==(mask>>1)+1) {
opc = CPUI_INT_SLESS;
cslot = 0;
c = (left-1)&mask;
return 0;
}
return 2; }
void CircleRange::printRaw(ostream &s) const
{
if (isempty) {
s << "(empty)";
return;
}
if (left == right) {
s << "(full";
if (step != 1)
s << ',' << dec << step;
s << ')';
}
else if (right == ((left+1)&mask)) {
s << '[' << hex << left << ']';
}
else {
s << '[' << hex << left << ',' << right;
if (step != 1)
s << ',' << dec << step;
s << ')';
}
}
const int4 ValueSet::MAX_STEP = 32;
void ValueSet::setVarnode(Varnode *v,int4 tCode)
{
typeCode = tCode;
vn = v;
vn->setValueSet(this);
if (typeCode != 0) {
opCode = CPUI_MAX;
numParams = 0;
range.setRange(0,vn->getSize()); leftIsStable = true;
rightIsStable = true;
}
else if (vn->isWritten()) {
PcodeOp *op = vn->getDef();
opCode = op->code();
if (opCode == CPUI_INDIRECT) { numParams = 1;
opCode = CPUI_COPY;
}
else
numParams = op->numInput();
leftIsStable = false;
rightIsStable = false;
}
else if (vn->isConstant()) {
opCode = CPUI_MAX;
numParams = 0;
range.setRange(vn->getOffset(),vn->getSize());
leftIsStable = true;
rightIsStable = true;
}
else { opCode = CPUI_MAX;
numParams = 0;
typeCode = 0;
range.setFull(vn->getSize());
leftIsStable = false;
rightIsStable = false;
}
}
void ValueSet::addEquation(int4 slot,int4 type,const CircleRange &constraint)
{
vector<Equation>::iterator iter;
iter = equations.begin();
while(iter != equations.end()) {
if ((*iter).slot > slot)
break;
++iter;
}
equations.insert(iter,Equation(slot,type,constraint));
}
bool ValueSet::computeTypeCode(void)
{
int4 relCount = 0;
int4 lastTypeCode = 0;
PcodeOp *op = vn->getDef();
for(int4 i=0;i<numParams;++i) {
ValueSet *valueSet = op->getIn(i)->getValueSet();
if (valueSet->typeCode != 0) {
relCount += 1;
lastTypeCode = valueSet->typeCode;
}
}
if (relCount == 0) {
typeCode = 0;
return false;
}
switch(opCode) {
case CPUI_PTRSUB:
case CPUI_PTRADD:
case CPUI_INT_ADD:
case CPUI_INT_SUB:
if (relCount == 1)
typeCode = lastTypeCode;
else
return true;
break;
case CPUI_CAST:
case CPUI_COPY:
case CPUI_INDIRECT:
case CPUI_MULTIEQUAL:
typeCode = lastTypeCode;
break;
default:
return true;
}
return false;
}
bool ValueSet::iterate(Widener &widener)
{
if (!vn->isWritten()) return false;
if (widener.checkFreeze(*this)) return false;
if (count == 0) {
if (computeTypeCode()) {
setFull();
return true;
}
}
count += 1; CircleRange res;
PcodeOp *op = vn->getDef();
int4 eqPos = 0;
if (opCode == CPUI_MULTIEQUAL) {
int4 pieces = 0;
for(int4 i=0;i<numParams;++i) {
ValueSet *inSet = op->getIn(i)->getValueSet();
if (doesEquationApply(eqPos, i)) {
CircleRange rangeCopy(inSet->range);
if (0 !=rangeCopy.intersect(equations[eqPos].range)) {
rangeCopy = equations[eqPos].range;
}
pieces = res.circleUnion(rangeCopy);
eqPos += 1; }
else {
pieces = res.circleUnion(inSet->range);
}
if (pieces == 2) {
if (res.minimalContainer(inSet->range,MAX_STEP)) break;
}
}
if (0 != res.circleUnion(range)) { res.minimalContainer(range,MAX_STEP);
}
if (!range.isEmpty() && !res.isEmpty()) {
leftIsStable = range.getMin() == res.getMin();
rightIsStable = range.getEnd() == res.getEnd();
}
}
else if (numParams == 1) {
ValueSet *inSet1 = op->getIn(0)->getValueSet();
if (doesEquationApply(eqPos, 0)) {
CircleRange rangeCopy(inSet1->range);
if (0 != rangeCopy.intersect(equations[eqPos].range)) {
rangeCopy = equations[eqPos].range;
}
if (!res.pushForwardUnary(opCode, rangeCopy, inSet1->vn->getSize(), vn->getSize())) {
setFull();
return true;
}
eqPos += 1;
}
else if (!res.pushForwardUnary(opCode, inSet1->range, inSet1->vn->getSize(), vn->getSize())) {
setFull();
return true;
}
leftIsStable = inSet1->leftIsStable;
rightIsStable = inSet1->rightIsStable;
}
else if (numParams == 2) {
ValueSet *inSet1 = op->getIn(0)->getValueSet();
ValueSet *inSet2 = op->getIn(1)->getValueSet();
if (equations.size() == 0) {
if (!res.pushForwardBinary(opCode, inSet1->range, inSet2->range, inSet1->vn->getSize(), vn->getSize(), MAX_STEP)) {
setFull();
return true;
}
}
else {
CircleRange range1 = inSet1->range;
CircleRange range2 = inSet2->range;
if (doesEquationApply(eqPos, 0)) {
if (0 != range1.intersect(equations[eqPos].range))
range1 = equations[eqPos].range;
eqPos += 1;
}
if (doesEquationApply(eqPos, 1)) {
if (0 != range2.intersect(equations[eqPos].range))
range2 = equations[eqPos].range;
}
if (!res.pushForwardBinary(opCode, range1, range2, inSet1->vn->getSize(), vn->getSize(), MAX_STEP)) {
setFull();
return true;
}
}
leftIsStable = inSet1->leftIsStable && inSet2->leftIsStable;
rightIsStable = inSet1->rightIsStable && inSet2->rightIsStable;
}
else if (numParams == 3) {
ValueSet *inSet1 = op->getIn(0)->getValueSet();
ValueSet *inSet2 = op->getIn(1)->getValueSet();
ValueSet *inSet3 = op->getIn(2)->getValueSet();
CircleRange range1 = inSet1->range;
CircleRange range2 = inSet2->range;
if (doesEquationApply(eqPos, 0)) {
if (0 != range1.intersect(equations[eqPos].range))
range1 = equations[eqPos].range;
eqPos += 1;
}
if (doesEquationApply(eqPos, 1)) {
if (0 != range2.intersect(equations[eqPos].range))
range2 = equations[eqPos].range;
}
if (!res.pushForwardTrinary(opCode, range1, range2, inSet3->range, inSet1->vn->getSize(), vn->getSize(), MAX_STEP)) {
setFull();
return true;
}
leftIsStable = inSet1->leftIsStable && inSet2->leftIsStable;
rightIsStable = inSet1->rightIsStable && inSet2->rightIsStable;
}
else
return false;
if (res == range)
return false;
if (partHead != (Partition *)0) {
if (!widener.doWidening(*this, range, res))
setFull();
}
else
range = res;
return true;
}
const CircleRange *ValueSet::getLandMark(void) const
{
for(int4 i=0;i<equations.size();++i) {
if (equations[i].typeCode == typeCode)
return &equations[i].range;
}
return (const CircleRange *)0;
}
void ValueSet::printRaw(ostream &s) const
{
if (vn == (Varnode *)0)
s << "root";
else
vn->printRaw(s);
if (typeCode == 0)
s << " absolute";
else
s << " stackptr";
if (opCode == CPUI_MAX) {
if (vn->isConstant())
s << " const";
else
s << " input";
}
else
s << ' ' << get_opname(opCode);
s << ' ';
range.printRaw(s);
}
void ValueSetRead::setPcodeOp(PcodeOp *o,int4 slt)
{
typeCode = 0;
op = o;
slot = slt;
equationTypeCode = -1;
}
void ValueSetRead::addEquation(int4 slt,int4 type,const CircleRange &constraint)
{
if (slot == slt) {
equationTypeCode = type;
equationConstraint = constraint;
}
}
void ValueSetRead::compute(void)
{
Varnode *vn = op->getIn(slot);
ValueSet *valueSet = vn->getValueSet();
typeCode = valueSet->getTypeCode();
range = valueSet->getRange();
leftIsStable = valueSet->isLeftStable();
rightIsStable = valueSet->isRightStable();
if (typeCode == equationTypeCode) {
if (0 != range.intersect(equationConstraint)) {
range = equationConstraint;
}
}
}
void ValueSetRead::printRaw(ostream &s) const
{
s << "Read: " << get_opname(op->code());
s << '(' << op->getSeqNum() << ')';
if (typeCode == 0)
s << " absolute ";
else
s << " stackptr ";
range.printRaw(s);
}
int4 WidenerFull::determineIterationReset(const ValueSet &valueSet)
{
if (valueSet.getCount() >= widenIteration)
return widenIteration; return 0; }
bool WidenerFull::checkFreeze(const ValueSet &valueSet)
{
return valueSet.getRange().isFull();
}
bool WidenerFull::doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange)
{
if (valueSet.getCount() < widenIteration) {
range = newRange;
return true;
}
else if (valueSet.getCount() == widenIteration) {
const CircleRange *landmark = valueSet.getLandMark();
if (landmark != (const CircleRange *)0) {
bool leftIsStable = range.getMin() == newRange.getMin();
range = newRange; if (landmark->contains(range)) {
range.widen(*landmark,leftIsStable);
return true;
}
else {
CircleRange constraint = *landmark;
constraint.invert();
if (constraint.contains(range)) {
range.widen(constraint,leftIsStable);
return true;
}
}
}
}
else if (valueSet.getCount() < fullIteration) {
range = newRange;
return true;
}
return false; }
int4 WidenerNone::determineIterationReset(const ValueSet &valueSet)
{
if (valueSet.getCount() >= freezeIteration)
return freezeIteration; return valueSet.getCount();
}
bool WidenerNone::checkFreeze(const ValueSet &valueSet)
{
if (valueSet.getRange().isFull())
return true;
return (valueSet.getCount() >= freezeIteration);
}
bool WidenerNone::doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange)
{
range = newRange;
return true;
}
ValueSetSolver::ValueSetEdge::ValueSetEdge(ValueSet *node,const vector<ValueSet *> &roots)
{
vn = node->getVarnode();
if (vn == (Varnode *)0) { rootEdges = &roots; rootPos = 0;
}
else {
rootEdges = (const vector<ValueSet *> *)0;
iter = vn->beginDescend();
}
}
ValueSet *ValueSetSolver::ValueSetEdge::getNext(void)
{
if (vn == (Varnode *)0) {
if (rootPos < rootEdges->size()) {
ValueSet *res = (*rootEdges)[rootPos];
rootPos += 1;
return res;
}
return (ValueSet *)0;
}
while(iter != vn->endDescend()) {
PcodeOp *op = *iter;
++iter;
Varnode *outVn = op->getOut();
if (outVn != (Varnode *)0 && outVn->isMark()) {
return outVn->getValueSet();
}
}
return (ValueSet *)0;
}
void ValueSetSolver::newValueSet(Varnode *vn,int4 tCode)
{
valueNodes.emplace_back();
valueNodes.back().setVarnode(vn, tCode);
}
void ValueSetSolver::partitionSurround(Partition &part)
{
recordStorage.push_back(part);
part.startNode->partHead = &recordStorage.back();
}
void ValueSetSolver::component(ValueSet *vertex,Partition &part)
{
ValueSetEdge edgeIterator(vertex,rootNodes);
ValueSet *succ = edgeIterator.getNext();
while(succ != (ValueSet *)0) {
if (succ->count == 0)
visit(succ,part);
succ = edgeIterator.getNext();
}
partitionPrepend(vertex, part);
partitionSurround(part);
}
int4 ValueSetSolver::visit(ValueSet *vertex,Partition &part)
{
nodeStack.push_back(vertex);
depthFirstIndex += 1;
vertex->count = depthFirstIndex;
int4 head = depthFirstIndex;
bool loop = false;
ValueSetEdge edgeIterator(vertex,rootNodes);
ValueSet *succ = edgeIterator.getNext();
while(succ != (ValueSet *)0) {
int4 min;
if (succ->count == 0)
min = visit(succ,part);
else
min = succ->count;
if (min <= head) {
head = min;
loop = true;
}
succ = edgeIterator.getNext();
}
if (head == vertex->count) {
vertex->count = 0x7fffffff; ValueSet *element = nodeStack.back();
nodeStack.pop_back();
if (loop) {
while(element != vertex) {
element->count = 0;
element = nodeStack.back();
nodeStack.pop_back();
}
Partition compPart; component(vertex,compPart);
partitionPrepend(compPart, part);
}
else {
partitionPrepend(vertex, part);
}
}
return head;
}
void ValueSetSolver::establishTopologicalOrder(void)
{
for(list<ValueSet>::iterator iter=valueNodes.begin();iter!=valueNodes.end();++iter) {
(*iter).count = 0;
(*iter).next = (ValueSet *)0;
(*iter).partHead = (Partition *)0;
}
ValueSet rootNode;
rootNode.vn = (Varnode *)0;
depthFirstIndex = 0;
visit(&rootNode,orderPartition);
orderPartition.startNode = orderPartition.startNode->next; }
void ValueSetSolver::generateTrueEquation(Varnode *vn,PcodeOp *op,int4 slot,int4 type,const CircleRange &range)
{
if (vn != (Varnode *) 0)
vn->getValueSet()->addEquation(slot, type, range);
else
readNodes[op->getSeqNum()].addEquation(slot, type, range);}
void ValueSetSolver::generateFalseEquation(Varnode *vn,PcodeOp *op,int4 slot,int4 type,const CircleRange &range)
{
CircleRange falseRange(range);
falseRange.invert();
if (vn != (Varnode *) 0)
vn->getValueSet()->addEquation(slot, type, falseRange);
else
readNodes[op->getSeqNum()].addEquation(slot, type, falseRange);}
void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &range,PcodeOp *cbranch)
{
FlowBlock *splitPoint = cbranch->getParent();
FlowBlock *trueBlock,*falseBlock;
if (cbranch->isBooleanFlip()) {
trueBlock = splitPoint->getFalseOut();
falseBlock = splitPoint->getTrueOut();
}
else {
trueBlock = splitPoint->getTrueOut();
falseBlock = splitPoint->getFalseOut();
}
bool trueIsRestricted = trueBlock->restrictedByConditional(splitPoint);
bool falseIsRestricted = falseBlock->restrictedByConditional(splitPoint);
list<PcodeOp *>::const_iterator iter;
if (vn->isWritten()) {
ValueSet *vSet = vn->getValueSet();
if (vSet->opCode == CPUI_MULTIEQUAL) {
vSet->addLandmark(type,range); }
}
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
Varnode *outVn = (Varnode *)0;
if (!op->isMark()) { outVn = op->getOut(); if (outVn == (Varnode *)0) continue;
if (!outVn->isMark()) continue;
}
FlowBlock *curBlock = op->getParent();
int4 slot = op->getSlot(vn);
if (op->code() == CPUI_MULTIEQUAL) {
if (curBlock == trueBlock) {
if (trueIsRestricted || trueBlock->getIn(slot) == splitPoint)
generateTrueEquation(outVn, op, slot, type, range);
continue;
}
else if (curBlock == falseBlock) {
if (falseIsRestricted || falseBlock->getIn(slot) == splitPoint)
generateFalseEquation(outVn, op, slot, type, range);
continue;
}
else
curBlock = curBlock->getIn(slot); }
for(;;) {
if (curBlock == trueBlock) {
if (trueIsRestricted)
generateTrueEquation(outVn, op, slot, type, range);
break;
}
else if (curBlock == falseBlock) {
if (falseIsRestricted)
generateFalseEquation(outVn, op, slot, type, range);
break;
}
else if (curBlock == splitPoint || curBlock == (FlowBlock *)0)
break;
curBlock = curBlock->getImmedDom();
}
}
}
void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,PcodeOp *cbranch)
{
while(startVn != endVn) {
Varnode *constVn;
startVn = lift.pullBack(startVn->getDef(),&constVn,false);
if (startVn == (Varnode *)0) return; }
for(;;) {
Varnode *constVn;
applyConstraints(endVn,type,lift,cbranch);
if (!endVn->isWritten()) break;
PcodeOp *op = endVn->getDef();
if (op->isCall() || op->isMarker()) break;
endVn = lift.pullBack(op,&constVn,false);
if (endVn == (Varnode *)0) break;
if (!endVn->isMark()) break;
}
}
void ValueSetSolver::constraintsFromCBranch(PcodeOp *cbranch)
{
Varnode *vn = cbranch->getIn(1); while(!vn->isMark()) {
if (!vn->isWritten()) break;
PcodeOp *op = vn->getDef();
if (op->isCall() || op->isMarker())
break;
int4 num = op->numInput();
if (num == 0 || num > 2) break;
vn = op->getIn(0);
if (num == 2) {
if (vn->isConstant())
vn = op->getIn(1);
else if (!op->getIn(1)->isConstant()) {
generateRelativeConstraint(op, cbranch);
return;
}
}
}
if (vn->isMark()) {
CircleRange lift(true);
Varnode *startVn = cbranch->getIn(1);
constraintsFromPath(0,lift,startVn,vn,cbranch);
}
}
void ValueSetSolver::generateConstraints(const vector<Varnode *> &worklist,const vector<PcodeOp *> &reads)
{
vector<FlowBlock *> blockList;
for(int4 i=0;i<worklist.size();++i) {
PcodeOp *op = worklist[i]->getDef();
if (op == (PcodeOp *)0) continue;
FlowBlock *bl = op->getParent();
if (op->code() == CPUI_MULTIEQUAL) {
for(int4 j=0;j<bl->sizeIn();++j) {
FlowBlock *curBl = bl->getIn(j);
do {
if (curBl->isMark()) break;
curBl->setMark();
blockList.push_back(curBl);
curBl = curBl->getImmedDom();
} while(curBl != (FlowBlock *)0);
}
}
else {
do {
if (bl->isMark()) break;
bl->setMark();
blockList.push_back(bl);
bl = bl->getImmedDom();
} while(bl != (FlowBlock *)0);
}
}
for(int4 i=0;i<reads.size();++i) {
FlowBlock *bl = reads[i]->getParent();
do {
if (bl->isMark()) break;
bl->setMark();
blockList.push_back(bl);
bl = bl->getImmedDom();
} while(bl != (FlowBlock *)0);
}
for(int4 i=0;i<blockList.size();++i)
blockList[i]->clearMark();
vector<FlowBlock *> finalList;
for(int4 i=0;i<blockList.size();++i) {
FlowBlock *bl = blockList[i];
for(int4 j=0;j<bl->sizeIn();++j) {
BlockBasic *splitPoint = (BlockBasic *)bl->getIn(j);
if (splitPoint->isMark()) continue;
if (splitPoint->sizeOut() != 2) continue;
PcodeOp *lastOp = splitPoint->lastOp();
if (lastOp != (PcodeOp *)0 && lastOp->code() == CPUI_CBRANCH) {
splitPoint->setMark();
finalList.push_back(splitPoint);
constraintsFromCBranch(lastOp); }
}
}
for(int4 i=0;i<finalList.size();++i)
finalList[i]->clearMark();
}
bool ValueSetSolver::checkRelativeConstant(Varnode *vn,int4 &typeCode,uintb &value) const
{
value = 0;
for(;;) {
if (vn->isMark()) {
ValueSet *valueSet = vn->getValueSet();
if (valueSet->typeCode != 0) {
typeCode = valueSet->typeCode;
break;
}
}
if (!vn->isWritten()) return false;
PcodeOp *op = vn->getDef();
OpCode opc = op->code();
if (opc == CPUI_COPY || opc == CPUI_INDIRECT)
vn = op->getIn(0);
else if (opc == CPUI_INT_ADD || opc == CPUI_PTRSUB) {
Varnode *constVn = op->getIn(1);
if (!constVn->isConstant())
return false;
value = (value + constVn->getOffset()) & calc_mask(constVn->getSize());
vn = op->getIn(0);
}
else
return false;
}
return true;
}
void ValueSetSolver::generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch)
{
OpCode opc = compOp->code();
switch(opc) {
case CPUI_INT_LESS:
opc = CPUI_INT_SLESS; break;
case CPUI_INT_LESSEQUAL:
opc = CPUI_INT_SLESSEQUAL;
break;
case CPUI_INT_SLESS:
case CPUI_INT_SLESSEQUAL:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
break;
default:
return;
}
int4 typeCode;
uintb value;
Varnode *vn;
Varnode *inVn0 = compOp->getIn(0);
Varnode *inVn1 = compOp->getIn(1);
CircleRange lift(true);
if (checkRelativeConstant(inVn0, typeCode, value)) {
vn = inVn1;
if (!lift.pullBackBinary(opc, value, 1, vn->getSize(), 1))
return;
}
else if (checkRelativeConstant(inVn1,typeCode,value)) {
vn = inVn0;
if (!lift.pullBackBinary(opc, value, 0, vn->getSize(), 1))
return;
}
else
return;
Varnode *endVn = vn;
while(!endVn->isMark()) {
if (!endVn->isWritten()) return;
PcodeOp *op = endVn->getDef();
opc = op->code();
if (opc == CPUI_COPY || opc == CPUI_PTRSUB) {
endVn = op->getIn(0);
}
else if (opc == CPUI_INT_ADD) { if (!op->getIn(1)->isConstant()) return;
endVn = op->getIn(0);
}
else
return;
}
constraintsFromPath(typeCode,lift,vn,endVn,cbranch);
}
void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,const vector<PcodeOp *> &reads,Varnode *stackReg,
bool indirectAsCopy)
{
vector<Varnode *> worklist;
int4 workPos = 0;
if (stackReg != (Varnode *)0) {
newValueSet(stackReg,1); stackReg->setMark();
worklist.push_back(stackReg);
workPos += 1;
rootNodes.push_back(stackReg->getValueSet());
}
for(int4 i=0;i<sinks.size();++i) {
Varnode *vn = sinks[i];
newValueSet(vn,0);
vn->setMark();
worklist.push_back(vn);
}
while(workPos < worklist.size()) {
Varnode *vn = worklist[workPos];
workPos += 1;
if (!vn->isWritten()) {
if (vn->isConstant()) {
if (vn->isSpacebase() || vn->loneDescend()->numInput() == 1)
rootNodes.push_back(vn->getValueSet());
}
else
rootNodes.push_back(vn->getValueSet());
continue;
}
PcodeOp *op = vn->getDef();
switch(op->code()) { case CPUI_INDIRECT:
if (indirectAsCopy || op->isIndirectStore()) {
Varnode *inVn = op->getIn(0);
if (!inVn->isMark()) {
newValueSet(inVn,0);
inVn->setMark();
worklist.push_back(inVn);
}
}
else {
vn->getValueSet()->setFull();
rootNodes.push_back(vn->getValueSet());
}
break;
case CPUI_CALL:
case CPUI_CALLIND:
case CPUI_CALLOTHER:
case CPUI_LOAD:
case CPUI_NEW:
case CPUI_SEGMENTOP:
case CPUI_CPOOLREF:
case CPUI_FLOAT_ADD:
case CPUI_FLOAT_DIV:
case CPUI_FLOAT_MULT:
case CPUI_FLOAT_SUB:
case CPUI_FLOAT_NEG:
case CPUI_FLOAT_ABS:
case CPUI_FLOAT_SQRT:
case CPUI_FLOAT_INT2FLOAT:
case CPUI_FLOAT_FLOAT2FLOAT:
case CPUI_FLOAT_TRUNC:
case CPUI_FLOAT_CEIL:
case CPUI_FLOAT_FLOOR:
case CPUI_FLOAT_ROUND:
vn->getValueSet()->setFull();
rootNodes.push_back(vn->getValueSet());
break;
default:
for(int4 i=0;i<op->numInput();++i) {
Varnode *inVn = op->getIn(i);
if (inVn->isMark() || inVn->isAnnotation()) continue;
newValueSet(inVn,0);
inVn->setMark();
worklist.push_back(inVn);
}
break;
}
}
for(int4 i=0;i<reads.size();++i) {
PcodeOp *op = reads[i];
for(int4 slot=0;slot<op->numInput();++slot) {
Varnode *vn = op->getIn(slot);
if (vn->isMark()) {
readNodes[op->getSeqNum()].setPcodeOp(op, slot);
op->setMark(); break; }
}
}
generateConstraints(worklist,reads);
for(int4 i=0;i<reads.size();++i)
reads[i]->clearMark();
establishTopologicalOrder();
for(int4 i=0;i<worklist.size();++i)
worklist[i]->clearMark();
}
void ValueSetSolver::solve(int4 max,Widener &widener)
{
maxIterations = max;
numIterations = 0;
for(list<ValueSet>::iterator iter=valueNodes.begin();iter!=valueNodes.end();++iter)
(*iter).count = 0;
vector<Partition *> componentStack;
Partition *curComponent = (Partition *)0;
ValueSet *curSet = orderPartition.startNode;
while(curSet != (ValueSet *)0) {
numIterations += 1;
if (numIterations > maxIterations) break; if (curSet->partHead != (Partition *)0 && curSet->partHead != curComponent) {
componentStack.push_back(curSet->partHead);
curComponent = curSet->partHead;
curComponent->isDirty = false;
curComponent->startNode->count = widener.determineIterationReset(*curComponent->startNode);
}
if (curComponent != (Partition *)0) {
if (curSet->iterate(widener))
curComponent->isDirty = true;
if (curComponent->stopNode != curSet) {
curSet = curSet->next;
}
else {
for(;;) {
if (curComponent->isDirty) {
curComponent->isDirty = false;
curSet = curComponent->startNode;
if (componentStack.size() > 1) { componentStack[componentStack.size()-2]->isDirty = true;
}
break;
}
componentStack.pop_back();
if (componentStack.empty()) {
curComponent = (Partition *)0;
curSet = curSet->next;
break;
}
curComponent = componentStack.back();
if (curComponent->stopNode != curSet) {
curSet = curSet->next;
break;
}
}
}
}
else {
curSet->iterate(widener);
curSet = curSet->next;
}
}
map<SeqNum,ValueSetRead>::iterator riter;
for(riter=readNodes.begin();riter!=readNodes.end();++riter)
(*riter).second.compute(); }
#ifdef CPUI_DEBUG
void ValueSetSolver::dumpValueSets(ostream &s) const
{
list<ValueSet>::const_iterator iter;
for(iter=valueNodes.begin();iter!=valueNodes.end();++iter) {
(*iter).printRaw(s);
s << endl;
}
map<SeqNum,ValueSetRead>::const_iterator riter;
for(riter=readNodes.begin();riter!=readNodes.end();++riter) {
(*riter).second.printRaw(s);
s << endl;
}
}
#endif