#include "heritage.hh"
#include "funcdata.hh"
#include "prefersplit.hh"
LocationMap::iterator LocationMap::add(Address addr,int4 size,int4 pass,int4 &intersect)
{
iterator iter = themap.lower_bound(addr);
if (iter != themap.begin())
--iter;
if ((iter!=themap.end())&&(-1 == addr.overlap(0,(*iter).first,(*iter).second.size)))
++iter;
int4 where=0;
intersect = 0;
if ((iter!=themap.end())&&(-1!=(where=addr.overlap(0,(*iter).first,(*iter).second.size)))) {
if (where+size<=(*iter).second.size) {
intersect = ((*iter).second.pass < pass) ? 2 : 0; return iter;
}
addr = (*iter).first;
size = where+size;
if ((*iter).second.pass < pass)
intersect = 1; themap.erase(iter++);
}
while((iter!=themap.end())&&(-1!=(where=(*iter).first.overlap(0,addr,size)))) {
if (where+(*iter).second.size>size)
size = where+(*iter).second.size;
if ((*iter).second.pass < pass)
intersect = 1;
themap.erase(iter++);
}
iter = themap.insert(pair<Address,SizePass>( addr, SizePass() )).first;
(*iter).second.size = size;
(*iter).second.pass = pass;
return iter;
}
LocationMap::iterator LocationMap::find(const Address &addr)
{
iterator iter = themap.upper_bound(addr); if (iter == themap.begin()) return themap.end();
--iter; if (-1!=addr.overlap(0,(*iter).first,(*iter).second.size))
return iter;
return themap.end();
}
int4 LocationMap::findPass(const Address &addr) const
{
map<Address,SizePass>::const_iterator iter = themap.upper_bound(addr); if (iter == themap.begin()) return -1;
--iter; if (-1!=addr.overlap(0,(*iter).first,(*iter).second.size))
return (*iter).second.pass;
return -1;
}
void PriorityQueue::reset(int4 maxdepth)
{
if ((curdepth==-1)&&(maxdepth==queue.size()-1)) return; queue.clear();
queue.resize(maxdepth+1);
curdepth = -1;
}
void PriorityQueue::insert(FlowBlock *bl,int4 depth)
{
queue[depth].push_back(bl);
if (depth > curdepth)
curdepth = depth;
}
FlowBlock *PriorityQueue::extract(void)
{
FlowBlock *res = queue[curdepth].back();
queue[curdepth].pop_back();
while(queue[curdepth].empty()) {
curdepth -= 1;
if (curdepth <0) break;
}
return res;
}
HeritageInfo::HeritageInfo(AddrSpace *spc)
{
if (spc == (AddrSpace *)0) {
space = (AddrSpace *)0;
delay = 0;
deadcodedelay = 0;
hasCallPlaceholders = false;
}
else if (!spc->isHeritaged()) {
space = (AddrSpace *)0;
delay = spc->getDelay();
deadcodedelay = spc->getDeadcodeDelay();
hasCallPlaceholders = false;
}
else {
space = spc;
delay = spc->getDelay();
deadcodedelay = spc->getDeadcodeDelay();
hasCallPlaceholders = (spc->getType() == IPTR_SPACEBASE);
}
deadremoved = 0;
warningissued = false;
loadGuardSearch = false;
}
void HeritageInfo::reset(void)
{
deadremoved = 0;
if (space != (AddrSpace *)0)
hasCallPlaceholders = (space->getType() == IPTR_SPACEBASE);
warningissued = false;
loadGuardSearch = false;
}
Heritage::Heritage(Funcdata *data)
{
fd = data;
pass = 0;
maxdepth = -1;
}
void Heritage::clearInfoList(void)
{
vector<HeritageInfo>::iterator iter;
for(iter=infolist.begin();iter!=infolist.end();++iter)
(*iter).reset();
}
void Heritage::removeRevisitedMarkers(const vector<Varnode *> &remove,const Address &addr,int4 size)
{
vector<Varnode *> newInputs;
list<PcodeOp *>::iterator pos;
for(int4 i=0;i<remove.size();++i) {
Varnode *vn = remove[i];
PcodeOp *op = vn->getDef();
BlockBasic *bl = op->getParent();
if (op->code() == CPUI_INDIRECT) {
Varnode *iopVn = op->getIn(1);
PcodeOp *targetOp = PcodeOp::getOpFromConst(iopVn->getAddr());
if (targetOp->isDead())
pos = op->getBasicIter();
else
pos = targetOp->getBasicIter();
++pos; }
else {
pos = op->getBasicIter(); ++pos;
while(pos != bl->endOp() && (*pos)->code() == CPUI_MULTIEQUAL)
++pos;
}
int4 offset = vn->overlap(addr,size);
fd->opUninsert(op);
newInputs.clear();
Varnode *big = fd->newVarnode(size,addr);
big->setActiveHeritage();
newInputs.push_back(big);
newInputs.push_back(fd->newConstant(4, offset));
fd->opSetOpcode(op, CPUI_SUBPIECE);
fd->opSetAllInput(op, newInputs);
fd->opInsert(op, bl, pos);
vn->setWriteMask();
}
}
int4 Heritage::collect(Address addr,int4 size,
vector<Varnode *> &read,vector<Varnode *> &write,
vector<Varnode *> &input,vector<Varnode *> &remove) const
{
Varnode *vn;
VarnodeLocSet::const_iterator viter = fd->beginLoc(addr);
VarnodeLocSet::const_iterator enditer;
uintb start = addr.getOffset();
addr = addr + size;
if (addr.getOffset() < start) { Address tmp(addr.getSpace(),addr.getSpace()->getHighest());
enditer = fd->endLoc(tmp);
}
else
enditer = fd->beginLoc(addr);
int4 maxsize = 0;
while( viter != enditer ) {
vn = *viter;
if (!vn->isWriteMask()) {
if (vn->isWritten()) {
if (vn->getSize() < size && vn->getDef()->isMarker())
remove.push_back(vn);
else {
if (vn->getSize() > maxsize) maxsize = vn->getSize();
write.push_back(vn);
}
}
else if ((!vn->isHeritageKnown())&&(!vn->hasNoDescend()))
read.push_back(vn);
else if (vn->isInput())
input.push_back(vn);
}
++viter;
}
return maxsize;
}
bool Heritage::callOpIndirectEffect(const Address &addr,int4 size,PcodeOp *op) const
{
if ((op->code() == CPUI_CALL)||(op->code() == CPUI_CALLIND)) {
FuncCallSpecs *fc = fd->getCallSpecs(op);
if (fc == (FuncCallSpecs *)0) return true; return (fc->hasEffectTranslate(addr,size) != EffectRecord::unaffected);
}
return false;
}
Varnode *Heritage::normalizeReadSize(Varnode *vn,const Address &addr,int4 size)
{
int4 overlap;
Varnode *vn1,*vn2;
PcodeOp *op,*newop;
list<PcodeOp *>::const_iterator oiter = vn->beginDescend();
op = *oiter++;
if (oiter != vn->endDescend())
throw LowlevelError("Free varnode with multiple reads");
newop = fd->newOp(2,op->getAddr());
fd->opSetOpcode(newop,CPUI_SUBPIECE);
vn1 = fd->newVarnode(size,addr);
overlap = vn->overlap(addr,size);
vn2 = fd->newConstant(addr.getAddrSize(),(uintb)overlap);
fd->opSetInput(newop,vn1,0);
fd->opSetInput(newop,vn2,1);
fd->opSetOutput(newop,vn); newop->getOut()->setWriteMask();
fd->opInsertBefore(newop,op);
return vn1; }
Varnode *Heritage::normalizeWriteSize(Varnode *vn,const Address &addr,int4 size)
{
int4 overlap;
int4 mostsigsize;
PcodeOp *op,*newop;
Varnode *mostvn,*leastvn,*big,*bigout,*midvn;
mostvn = (Varnode *)0;
op = vn->getDef();
overlap = vn->overlap(addr,size);
mostsigsize = size-(overlap+vn->getSize());
if (mostsigsize != 0) {
Address pieceaddr;
if (addr.isBigEndian())
pieceaddr = addr;
else
pieceaddr = addr + (overlap+vn->getSize());
if (op->isCall() && callOpIndirectEffect(pieceaddr,mostsigsize,op)) { newop = fd->newIndirectCreation(op,pieceaddr,mostsigsize,false); mostvn = newop->getOut();
}
else {
newop = fd->newOp(2,op->getAddr());
mostvn = fd->newVarnodeOut(mostsigsize,pieceaddr,newop);
big = fd->newVarnode(size,addr); big->setActiveHeritage();
fd->opSetOpcode(newop,CPUI_SUBPIECE);
fd->opSetInput(newop,big,0);
fd->opSetInput(newop,fd->newConstant(addr.getAddrSize(),(uintb)overlap+vn->getSize()),1);
fd->opInsertBefore(newop,op);
}
}
if (overlap != 0) {
Address pieceaddr;
if (addr.isBigEndian())
pieceaddr = addr + (size-overlap);
else
pieceaddr = addr;
if (op->isCall() && callOpIndirectEffect(pieceaddr,overlap,op)) { newop = fd->newIndirectCreation(op,pieceaddr,overlap,false); leastvn = newop->getOut();
}
else {
newop = fd->newOp(2,op->getAddr());
leastvn = fd->newVarnodeOut(overlap,pieceaddr,newop);
big = fd->newVarnode(size,addr); big->setActiveHeritage();
fd->opSetOpcode(newop,CPUI_SUBPIECE);
fd->opSetInput(newop,big,0);
fd->opSetInput(newop,fd->newConstant(addr.getAddrSize(),0),1);
fd->opInsertBefore(newop,op);
}
}
if (overlap !=0 ) {
newop = fd->newOp(2,op->getAddr());
if (addr.isBigEndian())
midvn = fd->newVarnodeOut(overlap+vn->getSize(),vn->getAddr(),newop);
else
midvn = fd->newVarnodeOut(overlap+vn->getSize(),addr,newop);
fd->opSetOpcode(newop,CPUI_PIECE);
fd->opSetInput(newop,vn,0); fd->opSetInput(newop,leastvn,1); fd->opInsertAfter(newop,op);
}
else
midvn = vn;
if (mostsigsize != 0) {
newop = fd->newOp(2,op->getAddr());
bigout = fd->newVarnodeOut(size,addr,newop);
fd->opSetOpcode(newop,CPUI_PIECE);
fd->opSetInput(newop,mostvn,0);
fd->opSetInput(newop,midvn,1);
fd->opInsertAfter(newop,midvn->getDef());
}
else
bigout = midvn;
vn->setWriteMask();
return bigout; }
Varnode *Heritage::concatPieces(const vector<Varnode *> &vnlist,PcodeOp *insertop,Varnode *finalvn)
{
Varnode *preexist = vnlist[0];
bool isbigendian = preexist->getAddr().isBigEndian();
Address opaddress;
BlockBasic *bl;
list<PcodeOp *>::iterator insertiter;
if (insertop == (PcodeOp *)0) { bl = (BlockBasic *)fd->getBasicBlocks().getStartBlock();
insertiter = bl->beginOp();
opaddress = fd->getAddress();
}
else {
bl = insertop->getParent();
insertiter = insertop->getBasicIter();
opaddress = insertop->getAddr();
}
for(uint4 i=1;i<vnlist.size();++i) {
Varnode *vn = vnlist[i];
PcodeOp *newop = fd->newOp(2,opaddress);
fd->opSetOpcode(newop,CPUI_PIECE);
Varnode *newvn;
if (i==vnlist.size()-1) {
newvn = finalvn;
fd->opSetOutput(newop,newvn);
}
else
newvn = fd->newUniqueOut(preexist->getSize()+vn->getSize(),newop);
if (isbigendian) {
fd->opSetInput(newop,preexist,0); fd->opSetInput(newop,vn,1); }
else {
fd->opSetInput(newop,vn,0);
fd->opSetInput(newop,preexist,1);
}
fd->opInsert(newop,bl,insertiter);
preexist = newvn;
}
return preexist;
}
void Heritage::splitPieces(const vector<Varnode *> &vnlist,PcodeOp *insertop,
const Address &addr,int4 size,Varnode *startvn)
{
Address opaddress;
uintb baseoff;
bool isbigendian;
BlockBasic *bl;
list<PcodeOp *>::iterator insertiter;
isbigendian = addr.isBigEndian();
if (isbigendian)
baseoff = addr.getOffset() + size;
else
baseoff = addr.getOffset();
if (insertop == (PcodeOp *)0) {
bl = (BlockBasic *)fd->getBasicBlocks().getStartBlock();
insertiter = bl->beginOp();
opaddress = fd->getAddress();
}
else {
bl = insertop->getParent();
insertiter = insertop->getBasicIter();
++insertiter; opaddress = insertop->getAddr();
}
for(uint4 i=0;i<vnlist.size();++i) {
Varnode *vn = vnlist[i];
PcodeOp *newop = fd->newOp(2,opaddress);
fd->opSetOpcode(newop,CPUI_SUBPIECE);
uintb diff;
if (isbigendian)
diff = baseoff - (vn->getOffset() + vn->getSize());
else
diff = vn->getOffset() - baseoff;
fd->opSetInput(newop,startvn,0);
fd->opSetInput(newop,fd->newConstant(4,diff),1);
fd->opSetOutput(newop,vn);
fd->opInsert(newop,bl,insertiter);
}
}
void Heritage::findAddressForces(vector<PcodeOp *> ©Sinks,vector<PcodeOp *> &forces)
{
for(int4 i=0;i<copySinks.size();++i) {
PcodeOp *op = copySinks[i];
op->setMark();
}
int4 pos = 0;
while(pos < copySinks.size()) {
PcodeOp *op = copySinks[pos];
Address addr = op->getOut()->getAddr(); pos += 1;
int4 maxIn = op->numInput();
for(int4 i=0;i<maxIn;++i) {
Varnode *vn = op->getIn(i);
if (!vn->isWritten()) continue;
if (vn->isAddrForce()) continue; PcodeOp *newOp = vn->getDef();
if (newOp->isMark()) continue; newOp->setMark();
OpCode opc = newOp->code();
bool isArtificial = false;
if (opc == CPUI_COPY || opc == CPUI_MULTIEQUAL) {
isArtificial = true;
int4 maxInNew = newOp->numInput();
for(int4 j=0;j<maxInNew;++j) {
Varnode *inVn = newOp->getIn(j);
if (addr != inVn->getAddr()) {
isArtificial = false;
break;
}
}
}
else if (opc == CPUI_INDIRECT && newOp->isIndirectStore()) {
Varnode *inVn = newOp->getIn(0);
if (addr == inVn->getAddr())
isArtificial = true;
}
if (isArtificial)
copySinks.push_back(newOp);
else
forces.push_back(newOp);
}
}
}
void Heritage::propagateCopyAway(PcodeOp *op)
{
Varnode *inVn = op->getIn(0);
while(inVn->isWritten()) { PcodeOp *nextOp = inVn->getDef();
if (nextOp->code() != CPUI_COPY) break;
Varnode *nextIn = nextOp->getIn(0);
if (nextIn->getAddr() != inVn->getAddr()) break;
inVn = nextIn;
}
fd->totalReplace(op->getOut(),inVn);
fd->opDestroy(op);
}
void Heritage::handleNewLoadCopies(void)
{
if (loadCopyOps.empty()) return;
vector<PcodeOp *> forces;
int4 copySinkSize = loadCopyOps.size();
findAddressForces(loadCopyOps, forces);
if (!forces.empty()) {
RangeList loadRanges;
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter) {
const LoadGuard &guard( *iter );
loadRanges.insertRange(guard.spc, guard.minimumOffset, guard.maximumOffset);
}
for(int4 i=0;i<forces.size();++i) {
PcodeOp *op = forces[i];
Varnode *vn = op->getOut();
if (loadRanges.inRange(vn->getAddr(), 1)) vn->setAddrForce(); op->clearMark();
}
}
for(int4 i=0;i<copySinkSize;++i) {
PcodeOp *op = loadCopyOps[i];
propagateCopyAway(op); }
for(int4 i=copySinkSize;i<loadCopyOps.size();++i) {
PcodeOp *op = loadCopyOps[i];
op->clearMark();
}
loadCopyOps.clear(); }
void LoadGuard::establishRange(const ValueSetRead &valueSet)
{
const CircleRange &range( valueSet.getRange() );
uintb rangeSize = range.getSize();
uintb size;
if (range.isEmpty()) {
minimumOffset = pointerBase;
size = 0x1000;
}
else if (range.isFull() || rangeSize > 0xffffff) {
minimumOffset = pointerBase;
size = 0x1000;
analysisState = 1; }
else {
step = (rangeSize == 3) ? range.getStep() : 0; size = 0x1000;
if (valueSet.isLeftStable()) {
minimumOffset = range.getMin();
}
else if (valueSet.isRightStable()) {
if (pointerBase < range.getEnd()) {
minimumOffset = pointerBase;
size = (range.getEnd() - pointerBase);
}
else {
minimumOffset = range.getMin();
size = rangeSize * range.getStep();
}
}
else
minimumOffset = pointerBase;
}
uintb max = spc->getHighest();
if (minimumOffset > max) {
minimumOffset = max;
maximumOffset = minimumOffset; }
else {
uintb maxSize = (max - minimumOffset) + 1;
if (size > maxSize)
size = maxSize;
maximumOffset = minimumOffset + size -1;
}
}
void LoadGuard::finalizeRange(const ValueSetRead &valueSet)
{
analysisState = 1; const CircleRange &range( valueSet.getRange() );
uintb rangeSize = range.getSize();
if (rangeSize == 0x100 || rangeSize == 0x10000) {
if (step == 0) rangeSize = 0; }
if (rangeSize > 1 && rangeSize < 0xffffff) { analysisState = 2; if (rangeSize > 2)
step = range.getStep();
minimumOffset = range.getMin();
maximumOffset = (range.getEnd() - 1) & range.getMask(); if (maximumOffset < minimumOffset) { maximumOffset = spc->getHighest();
analysisState = 1; }
}
if (minimumOffset > spc->getHighest())
minimumOffset = spc->getHighest();
if (maximumOffset > spc->getHighest())
maximumOffset = spc->getHighest();
}
bool LoadGuard::isGuarded(const Address &addr) const
{
if (addr.getSpace() != spc) return false;
if (addr.getOffset() < minimumOffset) return false;
if (addr.getOffset() > maximumOffset) return false;
return true;
}
void Heritage::analyzeNewLoadGuards(void)
{
bool nothingToDo = true;
if (!loadGuard.empty()) {
if (loadGuard.back().analysisState == 0) nothingToDo = false;
}
if (!storeGuard.empty()) {
if (storeGuard.back().analysisState == 0)
nothingToDo = false;
}
if (nothingToDo) return;
vector<Varnode *> sinks;
vector<PcodeOp *> reads;
list<LoadGuard>::iterator loadIter = loadGuard.end();
while(loadIter != loadGuard.begin()) {
--loadIter;
LoadGuard &guard( *loadIter );
if (guard.analysisState != 0) break;
reads.push_back(guard.op);
sinks.push_back(guard.op->getIn(1)); }
list<LoadGuard>::iterator storeIter = storeGuard.end();
while(storeIter != storeGuard.begin()) {
--storeIter;
LoadGuard &guard( *storeIter );
if (guard.analysisState != 0) break;
reads.push_back(guard.op);
sinks.push_back(guard.op->getIn(1)); }
AddrSpace *stackSpc = fd->getArch()->getStackSpace();
Varnode *stackReg = (Varnode *)0;
if (stackSpc != (AddrSpace *)0 && stackSpc->numSpacebase() > 0)
stackReg = fd->findSpacebaseInput(stackSpc);
ValueSetSolver vsSolver;
vsSolver.establishValueSets(sinks, reads, stackReg, false);
WidenerNone widener;
vsSolver.solve(10000,widener);
list<LoadGuard>::iterator iter;
bool runFullAnalysis = false;
for(iter=loadIter;iter!=loadGuard.end(); ++iter) {
LoadGuard &guard( *iter );
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
if (guard.analysisState == 0)
runFullAnalysis = true;
}
for(iter=storeIter;iter!=storeGuard.end(); ++iter) {
LoadGuard &guard( *iter );
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
if (guard.analysisState == 0)
runFullAnalysis = true;
}
if (runFullAnalysis) {
WidenerFull fullWidener;
vsSolver.solve(10000, fullWidener);
for (iter = loadIter; iter != loadGuard.end(); ++iter) {
LoadGuard &guard(*iter);
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
}
for (iter = storeIter; iter != storeGuard.end(); ++iter) {
LoadGuard &guard(*iter);
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
}
}
}
void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
{
if (!op->usesSpacebasePtr()) {
loadGuard.emplace_back();
loadGuard.back().set(op,spc,node.offset);
fd->opMarkSpacebasePtr(op);
}
}
void Heritage::generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
{
if (!op->usesSpacebasePtr()) {
storeGuard.emplace_back();
storeGuard.back().set(op,spc,node.offset);
fd->opMarkSpacebasePtr(op);
}
}
bool Heritage::protectFreeStores(AddrSpace *spc,vector<PcodeOp *> &freeStores)
{
list<PcodeOp *>::const_iterator iter = fd->beginOp(CPUI_STORE);
list<PcodeOp *>::const_iterator enditer = fd->endOp(CPUI_STORE);
bool hasNew = false;
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->isDead()) continue;
Varnode *vn = op->getIn(1);
while (vn->isWritten()) {
PcodeOp *defOp = vn->getDef();
OpCode opc = defOp->code();
if (opc == CPUI_COPY)
vn = defOp->getIn(0);
else if (opc == CPUI_INT_ADD && defOp->getIn(1)->isConstant())
vn = defOp->getIn(0);
else
break;
}
if (vn->isFree() && vn->getSpace() == spc) {
fd->opMarkSpacebasePtr(op); freeStores.push_back(op);
hasNew = true;
}
}
return hasNew;
}
bool Heritage::discoverIndexedStackPointers(AddrSpace *spc,vector<PcodeOp *> &freeStores,bool checkFreeStores)
{
vector<Varnode *> markedVn;
vector<StackNode> path;
bool unknownStackStorage = false;
for(int4 i=0;i<spc->numSpacebase();++i) {
const VarnodeData &stackPointer(spc->getSpacebase(i));
Varnode *spInput = fd->findVarnodeInput(stackPointer.size, stackPointer.getAddr());
if (spInput == (Varnode *)0) continue;
path.push_back(StackNode(spInput,0,0));
while(!path.empty()) {
StackNode &curNode(path.back());
if (curNode.iter == curNode.vn->endDescend()) {
path.pop_back();
continue;
}
PcodeOp *op = *curNode.iter;
++curNode.iter;
Varnode *outVn = op->getOut();
if (outVn != (Varnode *)0 && outVn->isMark()) continue; switch(op->code()) {
case CPUI_INT_ADD:
{
Varnode *otherVn = op->getIn(1-op->getSlot(curNode.vn));
if (otherVn->isConstant()) {
uintb newOffset = spc->wrapOffset(curNode.offset + otherVn->getOffset());
StackNode nextNode(outVn,newOffset,curNode.traversals);
if (nextNode.iter != nextNode.vn->endDescend()) {
outVn->setMark();
path.push_back(nextNode);
markedVn.push_back(outVn);
}
else if (outVn->getSpace()->getType() == IPTR_SPACEBASE)
unknownStackStorage = true;
}
else {
StackNode nextNode(outVn,curNode.offset,curNode.traversals | StackNode::nonconstant_index);
if (nextNode.iter != nextNode.vn->endDescend()) {
outVn->setMark();
path.push_back(nextNode);
markedVn.push_back(outVn);
}
else if (outVn->getSpace()->getType() == IPTR_SPACEBASE)
unknownStackStorage = true;
}
break;
}
case CPUI_INDIRECT:
case CPUI_COPY:
{
StackNode nextNode(outVn,curNode.offset,curNode.traversals);
if (nextNode.iter != nextNode.vn->endDescend()) {
outVn->setMark();
path.push_back(nextNode);
markedVn.push_back(outVn);
}
else if (outVn->getSpace()->getType() == IPTR_SPACEBASE)
unknownStackStorage = true;
break;
}
case CPUI_MULTIEQUAL:
{
StackNode nextNode(outVn,curNode.offset,curNode.traversals | StackNode::multiequal);
if (nextNode.iter != nextNode.vn->endDescend()) {
outVn->setMark();
path.push_back(nextNode);
markedVn.push_back(outVn);
}
else if (outVn->getSpace()->getType() == IPTR_SPACEBASE)
unknownStackStorage = true;
break;
}
case CPUI_LOAD:
{
if (curNode.traversals != 0) {
generateLoadGuard(curNode,op,spc);
}
break;
}
case CPUI_STORE:
{
if (op->getIn(1) == curNode.vn) { if (curNode.traversals != 0) {
generateStoreGuard(curNode, op, spc);
}
else {
fd->opMarkSpacebasePtr(op);
}
}
break;
}
default:
break;
}
}
}
for(int4 i=0;i<markedVn.size();++i)
markedVn[i]->clearMark();
if (unknownStackStorage && checkFreeStores)
return protectFreeStores(spc, freeStores);
return false;
}
void Heritage::reprocessFreeStores(AddrSpace *spc,vector<PcodeOp *> &freeStores)
{
for(int4 i=0;i<freeStores.size();++i)
fd->opClearSpacebasePtr(freeStores[i]);
discoverIndexedStackPointers(spc, freeStores, false);
for(int4 i=0;i<freeStores.size();++i) {
PcodeOp *op = freeStores[i];
if (op->usesSpacebasePtr()) continue;
PcodeOp *indOp = op->previousOp();
while(indOp != (PcodeOp *)0) {
if (indOp->code() != CPUI_INDIRECT) break;
Varnode *iopVn = indOp->getIn(1);
if (iopVn->getSpace()->getType()!=IPTR_IOP) break;
if (op != PcodeOp::getOpFromConst(iopVn->getAddr())) break;
PcodeOp *nextOp = indOp->previousOp();
if (indOp->getOut()->getSpace() == spc) {
fd->totalReplace(indOp->getOut(),indOp->getIn(0));
fd->opDestroy(indOp); }
indOp = nextOp;
}
}
}
void Heritage::guard(const Address &addr,int4 size,vector<Varnode *> &read,vector<Varnode *> &write,
vector<Varnode *> &inputvars)
{
uint4 fl;
Varnode *vn;
vector<Varnode *>::iterator iter;
bool guardneeded = true;
for(iter=read.begin();iter!=read.end();++iter) {
vn = *iter;
if (vn->getSize() < size)
*iter = vn = normalizeReadSize(vn,addr,size);
vn->setActiveHeritage();
}
for(iter=write.begin();iter!=write.end();++iter) {
vn = *iter;
if (vn->getSize() < size)
*iter = vn = normalizeWriteSize(vn,addr,size);
vn->setActiveHeritage();
if (vn->isAddrForce())
guardneeded = false;
else {
if (vn->isWritten()) {
if (vn->getDef()->code() == CPUI_INDIRECT) guardneeded = false;
}
}
}
if (read.empty() && write.empty() && inputvars.empty()) return;
if (guardneeded) {
fl = 0;
fd->getScopeLocal()->queryProperties(addr,size,Address(),fl);
guardCalls(fl,addr,size,write);
guardReturns(fl,addr,size,write);
if (fd->getArch()->highPtrPossible(addr,size)) {
guardStores(addr,size,write);
guardLoads(fl,addr,size,write);
}
}
}
void Heritage::guardCallOverlappingInput(FuncCallSpecs *fc,const Address &addr,const Address &transAddr,int4 size)
{
VarnodeData vData;
if (fc->getBiggestContainedInputParam(transAddr, size, vData)) {
ParamActive *active = fc->getActiveInput();
Address truncAddr(vData.space,vData.offset);
if (active->whichTrial(truncAddr, size) < 0) { int4 truncateAmount = transAddr.justifiedContain(size, truncAddr, vData.size, false);
int4 diff = (int4)(truncAddr.getOffset() - transAddr.getOffset());
truncAddr = addr + diff; PcodeOp *op = fc->getOp();
PcodeOp *subpieceOp = fd->newOp(2,op->getAddr());
fd->opSetOpcode(subpieceOp, CPUI_SUBPIECE);
Varnode *wholeVn = fd->newVarnode(size,addr);
wholeVn->setActiveHeritage();
fd->opSetInput(subpieceOp,wholeVn,0);
fd->opSetInput(subpieceOp,fd->newConstant(4,truncateAmount),1);
Varnode *vn = fd->newVarnodeOut(vData.size, truncAddr, subpieceOp);
fd->opInsertBefore(subpieceOp,op);
active->registerTrial(truncAddr, vData.size);
fd->opInsertInput(op, vn, op->numInput());
}
}
}
void Heritage::guardCalls(uint4 fl,const Address &addr,int4 size,vector<Varnode *> &write)
{
FuncCallSpecs *fc;
PcodeOp *indop;
uint4 effecttype;
bool holdind = ((fl&Varnode::addrtied)!=0);
for(int4 i=0;i<fd->numCalls();++i) {
fc = fd->getCallSpecs(i);
if (fc->getOp()->isAssignment()) {
Varnode *vn = fc->getOp()->getOut();
if ((vn->getAddr()==addr)&&(vn->getSize()==size)) continue;
}
effecttype = fc->hasEffectTranslate(addr,size);
bool possibleoutput = false;
if (fc->isOutputActive()) {
ParamActive *active = fc->getActiveOutput();
if (fc->possibleOutputParam(addr,size)) {
if (active->whichTrial(addr,size)<0) { active->registerTrial(addr,size);
effecttype = EffectRecord::killedbycall; possibleoutput = true;
}
}
}
if (fc->isInputActive()) {
AddrSpace *spc = addr.getSpace();
uintb off = addr.getOffset();
bool tryregister = true;
if (spc->getType() == IPTR_SPACEBASE) {
if (fc->getSpacebaseOffset() != FuncCallSpecs::offset_unknown)
off = spc->wrapOffset(off - fc->getSpacebaseOffset());
else
tryregister = false; }
Address transAddr(spc,off); if (tryregister) {
int4 inputCharacter = fc->characterizeAsInputParam(transAddr,size);
if (inputCharacter == 1) { ParamActive *active = fc->getActiveInput();
if (active->whichTrial(transAddr,size)<0) { PcodeOp *op = fc->getOp();
active->registerTrial(transAddr,size);
Varnode *vn = fd->newVarnode(size,addr);
vn->setActiveHeritage();
fd->opInsertInput(op,vn,op->numInput());
}
}
else if (inputCharacter == 2) guardCallOverlappingInput(fc, addr, transAddr, size);
}
}
if ((effecttype == EffectRecord::unknown_effect)||(effecttype == EffectRecord::return_address)) {
indop = fd->newIndirectOp(fc->getOp(),addr,size,0);
indop->getIn(0)->setActiveHeritage();
indop->getOut()->setActiveHeritage();
write.push_back(indop->getOut());
if (holdind)
indop->getOut()->setAddrForce();
if (effecttype == EffectRecord::return_address)
indop->getOut()->setReturnAddress();
}
else if (effecttype == EffectRecord::killedbycall) {
indop = fd->newIndirectCreation(fc->getOp(),addr,size,possibleoutput);
indop->getOut()->setActiveHeritage();
write.push_back(indop->getOut());
}
}
}
void Heritage::guardStores(const Address &addr,int4 size,vector<Varnode *> &write)
{
list<PcodeOp *>::const_iterator iter,iterend;
PcodeOp *op,*indop;
AddrSpace *spc = addr.getSpace();
AddrSpace *container = spc->getContain();
iterend = fd->endOp(CPUI_STORE);
for(iter=fd->beginOp(CPUI_STORE);iter!=iterend;++iter) {
op = *iter;
if (op->isDead()) continue;
AddrSpace *storeSpace = Address::getSpaceFromConst(op->getIn(0)->getAddr());
if ((container == storeSpace && op->usesSpacebasePtr()) ||
(spc == storeSpace)) {
indop = fd->newIndirectOp(op,addr,size,PcodeOp::indirect_store);
indop->getIn(0)->setActiveHeritage();
indop->getOut()->setActiveHeritage();
write.push_back(indop->getOut());
}
}
}
void Heritage::guardLoads(uint4 fl,const Address &addr,int4 size,vector<Varnode *> &write)
{
PcodeOp *copyop;
list<LoadGuard>::iterator iter;
if ((fl & Varnode::addrtied)==0) return; iter = loadGuard.begin();
while(iter!=loadGuard.end()) {
LoadGuard &guardRec(*iter);
if (!guardRec.isValid(CPUI_LOAD)) {
list<LoadGuard>::iterator copyIter = iter;
++iter;
loadGuard.erase(copyIter);
continue;
}
++iter;
if (guardRec.spc != addr.getSpace()) continue;
if (addr.getOffset() < guardRec.minimumOffset) continue;
if (addr.getOffset() > guardRec.maximumOffset) continue;
copyop = fd->newOp(1,guardRec.op->getAddr());
Varnode *vn = fd->newVarnodeOut(size,addr,copyop);
vn->setActiveHeritage();
vn->setAddrForce();
fd->opSetOpcode(copyop,CPUI_COPY);
Varnode *invn = fd->newVarnode(size,addr);
invn->setActiveHeritage();
fd->opSetInput(copyop,invn,0);
fd->opInsertBefore(copyop,guardRec.op);
loadCopyOps.push_back(copyop);
}
}
void Heritage::guardReturns(uint4 fl,const Address &addr,int4 size,vector<Varnode *> &write)
{
list<PcodeOp *>::const_iterator iter,iterend;
PcodeOp *op,*copyop;
ParamActive *active = fd->getActiveOutput();
if (active != (ParamActive *)0) {
if (fd->getFuncProto().possibleOutputParam(addr,size)) {
active->registerTrial(addr,size);
iterend = fd->endOp(CPUI_RETURN);
for(iter=fd->beginOp(CPUI_RETURN);iter!=iterend;++iter) {
op = *iter;
if (op->isDead()) continue;
if (op->getHaltType() != 0) continue; Varnode *invn = fd->newVarnode(size,addr);
invn->setActiveHeritage();
fd->opInsertInput(op,invn,op->numInput());
}
}
}
if ((fl&Varnode::persist)==0) return;
iterend = fd->endOp(CPUI_RETURN);
for(iter=fd->beginOp(CPUI_RETURN);iter!=iterend;++iter) {
op = *iter;
if (op->isDead()) continue;
copyop = fd->newOp(1,op->getAddr());
Varnode *vn = fd->newVarnodeOut(size,addr,copyop);
vn->setAddrForce();
vn->setActiveHeritage();
fd->opSetOpcode(copyop,CPUI_COPY);
Varnode *invn = fd->newVarnode(size,addr);
invn->setActiveHeritage();
fd->opSetInput(copyop,invn,0);
fd->opInsertBefore(copyop,op);
}
}
void Heritage::buildRefinement(vector<int4> &refine,const Address &addr,int4 size,const vector<Varnode *> &vnlist)
{
for(uint4 i=0;i<vnlist.size();++i) {
Address curaddr = vnlist[i]->getAddr();
int4 sz = vnlist[i]->getSize();
uint4 diff = (uint4)(curaddr.getOffset() - addr.getOffset());
refine[diff] = 1;
refine[diff+sz] = 1;
}
}
void Heritage::splitByRefinement(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &split)
{
Address curaddr = vn->getAddr();
int4 sz = vn->getSize();
AddrSpace *spc = curaddr.getSpace();
uint4 diff = (uint4)spc->wrapOffset(curaddr.getOffset() - addr.getOffset());
int4 cutsz = refine[diff];
if (sz <= cutsz) return; while(sz > 0) {
Varnode *vn2 = fd->newVarnode(cutsz,curaddr);
split.push_back(vn2);
curaddr = curaddr + cutsz;
sz -= cutsz;
diff = (uint4)spc->wrapOffset(curaddr.getOffset() - addr.getOffset());
cutsz = refine[diff];
if (cutsz > sz)
cutsz = sz; }
}
void Heritage::refineRead(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &newvn)
{
newvn.clear();
splitByRefinement(vn,addr,refine,newvn);
if (newvn.empty()) return;
Varnode *replacevn = fd->newUnique(vn->getSize());
PcodeOp *op = vn->loneDescend(); int4 slot = op->getSlot(vn);
concatPieces(newvn,op,replacevn);
fd->opSetInput(op,replacevn,slot);
if (vn->hasNoDescend())
fd->deleteVarnode(vn);
else
throw LowlevelError("Refining non-free varnode");
}
void Heritage::refineWrite(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &newvn)
{
newvn.clear();
splitByRefinement(vn,addr,refine,newvn);
if (newvn.empty()) return;
Varnode *replacevn = fd->newUnique(vn->getSize());
PcodeOp *def = vn->getDef();
fd->opSetOutput(def,replacevn);
splitPieces(newvn,def,vn->getAddr(),vn->getSize(),replacevn);
fd->totalReplace(vn,replacevn);
fd->deleteVarnode(vn);
}
void Heritage::refineInput(Varnode *vn,const Address &addr,const vector<int4> &refine,vector<Varnode *> &newvn)
{
newvn.clear();
splitByRefinement(vn,addr,refine,newvn);
if (newvn.empty()) return;
splitPieces(newvn,(PcodeOp *)0,vn->getAddr(),vn->getSize(),vn);
vn->setWriteMask();
}
void Heritage::remove13Refinement(vector<int4> &refine)
{
if (refine.empty()) return;
int4 pos = 0;
int4 lastsize = refine[pos];
int4 cursize;
pos += lastsize;
while(pos < refine.size()) {
cursize = refine[pos];
if (cursize == 0) break;
if (((lastsize==1)&&(cursize==3))||((lastsize==3)&&(cursize==1))) {
refine[pos-lastsize] = 4;
lastsize = 4;
pos += cursize;
}
else {
lastsize = cursize;
pos += lastsize;
}
}
}
bool Heritage::refinement(const Address &addr,int4 size,const vector<Varnode *> &readvars,const vector<Varnode *> &writevars,const vector<Varnode *> &inputvars)
{
if (size > 1024) return false;
vector<int4> refine(size+1,0);
buildRefinement(refine,addr,size,readvars);
buildRefinement(refine,addr,size,writevars);
buildRefinement(refine,addr,size,inputvars);
int4 lastpos = 0;
for(int4 curpos=1;curpos < size;++curpos) { if (refine[curpos] != 0) {
refine[lastpos] = curpos - lastpos;
lastpos = curpos;
}
}
if (lastpos == 0) return false; refine[lastpos] = size-lastpos;
remove13Refinement(refine);
vector<Varnode *> newvn;
for(uint4 i=0;i<readvars.size();++i)
refineRead(readvars[i],addr,refine,newvn);
for(uint4 i=0;i<writevars.size();++i)
refineWrite(writevars[i],addr,refine,newvn);
for(uint4 i=0;i<inputvars.size();++i)
refineInput(inputvars[i],addr,refine,newvn);
LocationMap::iterator iter = disjoint.find(addr);
int4 addrPass = (*iter).second.pass;
disjoint.erase(iter);
iter = globaldisjoint.find(addr);
globaldisjoint.erase(iter);
Address curaddr = addr;
int4 cut = 0;
int4 intersect;
while(cut < size) {
int4 sz = refine[cut];
disjoint.add(curaddr,sz,addrPass,intersect);
globaldisjoint.add(curaddr,sz,addrPass,intersect);
cut += sz;
curaddr = curaddr + sz;
}
return true;
}
void Heritage::guardInput(const Address &addr,int4 size,vector<Varnode *> &input)
{
if (input.empty()) return;
if ((input.size()==1)&&(input[0]->getSize() == size)) return;
int4 i = 0;
uintb cur = addr.getOffset(); uintb end = cur + size;
Varnode *vn;
vector<Varnode *> newinput;
while(cur < end) {
if (i<input.size()) {
vn = input[i];
if (vn->getOffset()>cur) {
int4 sz = vn->getOffset() - cur;
vn = fd->newVarnode(sz,Address(addr.getSpace(),cur));
vn = fd->setInputVarnode(vn);
}
else {
i += 1;
}
}
else {
int4 sz = end-cur;
vn = fd->newVarnode(sz,Address(addr.getSpace(),cur));
vn = fd->setInputVarnode(vn);
}
newinput.push_back(vn);
cur += vn->getSize();
}
if (newinput.size()==1) return; for(uint4 j=0;j<newinput.size();++j)
newinput[j]->setWriteMask();
Varnode *newout = fd->newVarnode(size,addr);
concatPieces(newinput,(PcodeOp *)0,newout)->setActiveHeritage();
}
#ifdef DFSVERIFY_DEBUG
static void verify_dfs(const vector<FlowBlock *> &list,vector<vector<FlowBlock *>> &domchild)
{
int4 count = 0;
vector<int4> path;
path.push_back(0);
if (list[0]->getIndex() != 0)
throw LowlevelError("Initial block is not index 0");
count += 1;
while(!path.empty()) {
int4 cur = path.back();
int4 child;
FlowBlock *bl;
for(child=0;child<domchild[cur].size();++child) {
bl = domchild[cur][child];
if (bl->getIndex() == count)
break;
}
if (child == domchild[cur].size())
path.pop_back();
else {
path.push_back(bl->getIndex());
count += 1;
}
}
if (count != list.size())
throw LowlevelError("dfs does not verify");
}
#endif
void Heritage::clearStackPlaceholders(HeritageInfo *info)
{
int4 numCalls = fd->numCalls();
for(int4 i=0;i<numCalls;++i) {
fd->getCallSpecs(i)->abortSpacebaseRelative(*fd);
}
info->hasCallPlaceholders = false; }
void Heritage::splitJoinLevel(vector<Varnode *> &lastcombo,vector<Varnode *> &nextlev,JoinRecord *joinrec)
{
int4 numpieces = joinrec->numPieces();
int4 recnum=0;
for(int4 i=0;i<lastcombo.size();++i) {
Varnode *curvn = lastcombo[i];
if (curvn->getSize() == joinrec->getPiece(recnum).size) {
nextlev.push_back(curvn);
nextlev.push_back((Varnode *)0);
recnum += 1;
}
else {
int4 sizeaccum = 0;
int4 j;
for(j=recnum;j<numpieces;++j) {
sizeaccum += joinrec->getPiece(recnum).size;
if (sizeaccum == curvn->getSize()) {
j += 1;
break;
}
}
int4 numinhalf = (j-recnum) / 2; sizeaccum = 0;
for(int4 k=0;k<numinhalf;++k)
sizeaccum += joinrec->getPiece(recnum+k).size;
Varnode *mosthalf,*leasthalf;
if (numinhalf == 1)
mosthalf = fd->newVarnode(sizeaccum,joinrec->getPiece(recnum).space,joinrec->getPiece(recnum).offset);
else
mosthalf = fd->newUnique(sizeaccum);
if ((j-recnum)==2) {
const VarnodeData &vdata( joinrec->getPiece(recnum+1) );
leasthalf = fd->newVarnode(vdata.size,vdata.space,vdata.offset);
}
else
leasthalf = fd->newUnique(curvn->getSize() - sizeaccum);
nextlev.push_back(mosthalf);
nextlev.push_back(leasthalf);
recnum = j;
}
}
}
void Heritage::splitJoinRead(Varnode *vn,JoinRecord *joinrec)
{
PcodeOp *op = vn->loneDescend();
vector<Varnode *> lastcombo;
vector<Varnode *> nextlev;
lastcombo.push_back(vn);
while(lastcombo.size() < joinrec->numPieces()) {
nextlev.clear();
splitJoinLevel(lastcombo,nextlev,joinrec);
for(int4 i=0;i<lastcombo.size();++i) {
Varnode *curvn = lastcombo[i];
Varnode *mosthalf = nextlev[2*i];
Varnode *leasthalf = nextlev[2*i+1];
if (leasthalf == (Varnode *)0) continue; PcodeOp *concat = fd->newOp(2,op->getAddr());
fd->opSetOpcode(concat,CPUI_PIECE);
fd->opSetOutput(concat,curvn);
fd->opSetInput(concat,mosthalf,0);
fd->opSetInput(concat,leasthalf,1);
fd->opInsertBefore(concat,op);
mosthalf->setPrecisHi(); leasthalf->setPrecisLo();
op = concat; }
lastcombo.clear();
for(int4 i=0;i<nextlev.size();++i) {
Varnode *curvn = nextlev[i];
if (curvn != (Varnode *)0)
lastcombo.push_back(curvn);
}
}
}
void Heritage::splitJoinWrite(Varnode *vn,JoinRecord *joinrec)
{
PcodeOp *op = vn->getDef(); BlockBasic *bb = (BlockBasic *)fd->getBasicBlocks().getBlock(0);
vector<Varnode *> lastcombo;
vector<Varnode *> nextlev;
lastcombo.push_back(vn);
while(lastcombo.size() < joinrec->numPieces()) {
nextlev.clear();
splitJoinLevel(lastcombo,nextlev,joinrec);
for(int4 i=0;i<lastcombo.size();++i) {
Varnode *curvn = lastcombo[i];
Varnode *mosthalf = nextlev[2*i];
Varnode *leasthalf = nextlev[2*i+1];
if (leasthalf == (Varnode *)0) continue; PcodeOp *split;
if (vn->isInput())
split = fd->newOp(2,bb->getStart());
else
split = fd->newOp(2,op->getAddr());
fd->opSetOpcode(split,CPUI_SUBPIECE);
fd->opSetOutput(split,mosthalf);
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,leasthalf->getSize()),1);
if (op == (PcodeOp *)0)
fd->opInsertBegin(split,bb);
else
fd->opInsertAfter(split,op);
op = split;
split = fd->newOp(2,op->getAddr());
fd->opSetOpcode(split,CPUI_SUBPIECE);
fd->opSetOutput(split,leasthalf);
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,0),1);
fd->opInsertAfter(split,op);
mosthalf->setPrecisHi(); leasthalf->setPrecisLo();
op = split; }
lastcombo.clear();
for(int4 i=0;i<nextlev.size();++i) {
Varnode *curvn = nextlev[i];
if (curvn != (Varnode *)0)
lastcombo.push_back(curvn);
}
}
}
void Heritage::floatExtensionRead(Varnode *vn,JoinRecord *joinrec)
{
PcodeOp *op = vn->loneDescend(); PcodeOp *trunc = fd->newOp(1,op->getAddr());
const VarnodeData &vdata( joinrec->getPiece(0) ); Varnode *bigvn = fd->newVarnode(vdata.size,vdata.space,vdata.offset);
fd->opSetOpcode(trunc,CPUI_FLOAT_FLOAT2FLOAT);
fd->opSetOutput(trunc,vn);
fd->opSetInput(trunc,bigvn,0);
fd->opInsertBefore(trunc,op);
}
void Heritage::floatExtensionWrite(Varnode *vn,JoinRecord *joinrec)
{
PcodeOp *op = vn->getDef();
BlockBasic *bb = (BlockBasic *)fd->getBasicBlocks().getBlock(0);
PcodeOp *ext;
if (vn->isInput())
ext = fd->newOp(1,bb->getStart());
else
ext = fd->newOp(1,op->getAddr());
const VarnodeData &vdata( joinrec->getPiece(0) ); fd->opSetOpcode(ext,CPUI_FLOAT_FLOAT2FLOAT);
fd->newVarnodeOut( vdata.size, vdata.getAddr(),ext);
fd->opSetInput( ext, vn, 0);
if (op == (PcodeOp *)0)
fd->opInsertBegin(ext,bb);
else
fd->opInsertAfter(ext,op);
}
void Heritage::processJoins(void)
{
AddrSpace *joinspace = fd->getArch()->getJoinSpace();
VarnodeLocSet::const_iterator iter,enditer;
iter = fd->beginLoc(joinspace);
enditer = fd->endLoc(joinspace);
while(iter != enditer) {
Varnode *vn = *iter++;
if (vn->getSpace() != joinspace) break; JoinRecord *joinrec = fd->getArch()->findJoin(vn->getOffset());
AddrSpace *piecespace = joinrec->getPiece(0).space;
if (joinrec->getUnified().size != vn->getSize())
throw LowlevelError("Joined varnode does not match size of record");
if (vn->isFree()) {
if (joinrec->isFloatExtension())
floatExtensionRead(vn,joinrec);
else
splitJoinRead(vn,joinrec);
}
HeritageInfo *info = getInfo(piecespace);
if (pass != info->delay) continue;
if (joinrec->isFloatExtension())
floatExtensionWrite(vn,joinrec);
else
splitJoinWrite(vn,joinrec); }
}
void Heritage::buildADT(void)
{
const BlockGraph &bblocks(fd->getBasicBlocks());
int4 size = bblocks.getSize();
vector<int4> a(size);
vector<int4> b(size,0);
vector<int4> t(size,0);
vector<int4> z(size);
vector<FlowBlock *> upstart,upend; FlowBlock *x,*u,*v;
int4 i,j,k,l;
augment.clear();
augment.resize(size);
flags.clear();
flags.resize(size,0);
bblocks.buildDomTree(domchild);
#ifdef DFSVERIFY_DEBUG
verify_dfs(bblocks.getList(),domchild);
#endif
maxdepth = bblocks.buildDomDepth(depth);
for(i=0;i<size;++i) {
x = bblocks.getBlock(i);
for(j=0;j<domchild[i].size();++j) {
v = domchild[i][j];
for(k=0;k<v->sizeIn();++k) {
u = v->getIn(k);
if (u != v->getImmedDom()) { upstart.push_back(u); upend.push_back(v);
b[u->getIndex()] += 1;
t[x->getIndex()] += 1;
}
}
}
}
for(i=size-1;i>=0;--i) {
k=0;
l=0;
for(j=0;j<domchild[i].size();++j) {
k += a[ domchild[i][j]->getIndex() ];
l += z[ domchild[i][j]->getIndex() ];
}
a[i] = b[i] - t[i] + k;
z[i] = 1 + l;
if ((domchild[i].size()==0)||(z[i] > a[i] + 1)) {
flags[i] |= boundary_node; z[i] = 1;
}
}
z[0] = -1;
for(i=1;i<size;++i) {
j = bblocks.getBlock(i)->getImmedDom()->getIndex();
if ((flags[j]&boundary_node)!=0) z[i] = j;
else
z[i] = z[j];
}
for(i=0;i<upstart.size();++i) {
v = upend[i];
j = v->getImmedDom()->getIndex();
k = upstart[i]->getIndex();
while(j < k) { augment[ k ].push_back(v);
k = z[k];
}
}
}
void Heritage::visitIncr(FlowBlock *qnode,FlowBlock *vnode)
{
int4 i,j,k;
FlowBlock *v,*child;
vector<FlowBlock *>::iterator iter,enditer;
i = vnode->getIndex();
j = qnode->getIndex();
iter = augment[i].begin();
enditer = augment[i].end();
for(;iter!=enditer;++iter) {
v = *iter;
if (v->getImmedDom()->getIndex() < j) { k = v->getIndex();
if ((flags[k]&merged_node)==0) {
merge.push_back(v);
flags[k] |= merged_node;
}
if ((flags[k]&mark_node)==0) { flags[k] |= mark_node; pq.insert(v,depth[k]); }
}
else
break;
}
if ((flags[i]&boundary_node)==0) { for(j=0;j<domchild[i].size();++j) {
child = domchild[i][j];
if ((flags[child->getIndex()]&mark_node)==0) visitIncr(qnode,child);
}
}
}
void Heritage::calcMultiequals(const vector<Varnode *> &write)
{
pq.reset(maxdepth);
merge.clear();
int4 i,j;
FlowBlock *bl;
for(i=0;i<write.size();++i) {
bl = write[i]->getDef()->getParent(); j = bl->getIndex();
if ((flags[j]&mark_node)!=0) continue; pq.insert(bl,depth[j]); flags[j] |= mark_node; }
if ((flags[0]&mark_node)==0) { pq.insert(fd->getBasicBlocks().getBlock(0),depth[0]);
flags[0] |= mark_node;
}
while(!pq.empty()) {
bl = pq.extract(); visitIncr(bl,bl);
}
for(i=0;i<flags.size();++i)
flags[i] &= ~(mark_node|merged_node); }
void Heritage::renameRecurse(BlockBasic *bl,VariableStack &varstack)
{
vector<Varnode *> writelist; BlockBasic *subbl;
list<PcodeOp *>::iterator oiter,suboiter;
PcodeOp *op,*multiop;
Varnode *vnout,*vnin,*vnnew;
int4 i,slot;
for(oiter=bl->beginOp();oiter!=bl->endOp();++oiter) {
op = *oiter;
if (op->code() != CPUI_MULTIEQUAL) {
for(slot=0;slot<op->numInput();++slot) {
vnin = op->getIn(slot);
if (vnin->isHeritageKnown()) continue; if (!vnin->isActiveHeritage()) continue; vnin->clearActiveHeritage();
vector<Varnode *> &stack( varstack[ vnin->getAddr() ] );
if (stack.empty()) {
vnnew = fd->newVarnode(vnin->getSize(),vnin->getAddr());
vnnew = fd->setInputVarnode(vnnew);
stack.push_back(vnnew);
}
else
vnnew = stack.back();
if (vnnew->isWritten() && (vnnew->getDef()->code()==CPUI_INDIRECT)) {
if (PcodeOp::getOpFromConst(vnnew->getDef()->getIn(1)->getAddr()) == op) {
if (stack.size()==1) {
vnnew = fd->newVarnode(vnin->getSize(),vnin->getAddr());
vnnew = fd->setInputVarnode(vnnew);
stack.insert(stack.begin(),vnnew);
}
else
vnnew = stack[stack.size()-2];
}
}
fd->opSetInput(op,vnnew,slot);
if (vnin->hasNoDescend())
fd->deleteVarnode(vnin);
}
}
vnout = op->getOut();
if (vnout == (Varnode *)0) continue;
if (!vnout->isActiveHeritage()) continue; vnout->clearActiveHeritage();
varstack[ vnout->getAddr() ].push_back(vnout); writelist.push_back(vnout);
}
for(i=0;i<bl->sizeOut();++i) {
subbl = (BlockBasic *)bl->getOut(i);
slot = bl->getOutRevIndex(i);
for(suboiter=subbl->beginOp();suboiter!=subbl->endOp();++suboiter) {
multiop = *suboiter;
if (multiop->code()!=CPUI_MULTIEQUAL) break; vnin = multiop->getIn(slot);
if (!vnin->isHeritageKnown()) {
vector<Varnode *> &stack( varstack[ vnin->getAddr() ] );
if (stack.empty()) {
vnnew = fd->newVarnode(vnin->getSize(),vnin->getAddr());
vnnew = fd->setInputVarnode(vnnew);
stack.push_back(vnnew);
}
else
vnnew = stack.back();
fd->opSetInput(multiop,vnnew,slot);
if (vnin->hasNoDescend())
fd->deleteVarnode(vnin);
}
}
}
i = bl->getIndex();
for(slot=0;slot<domchild[i].size();++slot)
renameRecurse((BlockBasic *)domchild[i][slot],varstack);
for(i=0;i<writelist.size();++i) {
vnout = writelist[i];
varstack[vnout->getAddr()].pop_back();
}
}
void Heritage::bumpDeadcodeDelay(Varnode *vn)
{
AddrSpace *spc = vn->getSpace();
if ((spc->getType() != IPTR_PROCESSOR)&&(spc->getType() != IPTR_SPACEBASE))
return; if (spc->getDelay() != spc->getDeadcodeDelay())
return; if (fd->getOverride().hasDeadcodeDelay(spc))
return; fd->getOverride().insertDeadcodeDelay(spc,spc->getDeadcodeDelay()+1);
fd->setRestartPending(true);
}
void Heritage::rename(void)
{
VariableStack varstack;
renameRecurse((BlockBasic *)fd->getBasicBlocks().getBlock(0),varstack);
disjoint.clear();
}
void Heritage::placeMultiequals(void)
{
LocationMap::iterator iter;
vector<Varnode *> readvars;
vector<Varnode *> writevars;
vector<Varnode *> inputvars;
vector<Varnode *> removevars;
PcodeOp *multiop;
Varnode *vnin;
BlockBasic *bl;
int4 max;
for(iter=disjoint.begin();iter!=disjoint.end();++iter) {
Address addr = (*iter).first;
int4 size = (*iter).second.size;
readvars.clear();
writevars.clear();
inputvars.clear();
removevars.clear();
max = collect(addr,size,readvars,writevars,inputvars,removevars); if ((size > 4)&&(max < size)) {
if (refinement(addr,size,readvars,writevars,inputvars)) {
iter = disjoint.find(addr);
size =(*iter).second.size;
readvars.clear();
writevars.clear();
inputvars.clear();
removevars.clear();
collect(addr,size,readvars,writevars,inputvars,removevars);
}
}
if (readvars.empty() && (addr.getSpace()->getType() == IPTR_INTERNAL))
continue;
if (!removevars.empty())
removeRevisitedMarkers(removevars, addr, size);
guardInput(addr,size,inputvars);
guard(addr,size,readvars,writevars,inputvars);
if (readvars.empty()&&writevars.empty()) continue;
calcMultiequals(writevars); for(int4 i=0;i<merge.size();++i) {
bl = (BlockBasic *) merge[i];
multiop = fd->newOp(bl->sizeIn(),bl->getStart());
Varnode *vnout = fd->newVarnodeOut(size,addr,multiop);
vnout->setActiveHeritage();
fd->opSetOpcode(multiop,CPUI_MULTIEQUAL); for(int4 j=0;j<bl->sizeIn();++j) {
vnin = fd->newVarnode(size,addr);
fd->opSetInput(multiop,vnin,j);
}
fd->opInsertBegin(multiop,bl); }
}
merge.clear();
}
void Heritage::buildInfoList(void)
{
if (!infolist.empty()) return;
const AddrSpaceManager *manage = fd->getArch();
infolist.reserve(manage->numSpaces());
for(int4 i=0;i<manage->numSpaces();++i)
infolist.emplace_back(manage->getSpace(i));
}
void Heritage::heritage(void)
{
VarnodeLocSet::const_iterator iter,enditer;
HeritageInfo *info;
Varnode *vn;
bool needwarning;
Varnode *warnvn = (Varnode *)0;
int4 reprocessStackCount = 0;
AddrSpace *stackSpace = (AddrSpace *)0;
vector<PcodeOp *> freeStores;
PreferSplitManager splitmanage;
if (maxdepth == -1) buildADT();
processJoins();
if (pass == 0) {
splitmanage.init(fd,&fd->getArch()->splitrecords);
splitmanage.split();
}
for(int4 i=0;i<infolist.size();++i) {
info = &infolist[i];
if (!info->isHeritaged()) continue;
if (pass < info->delay) continue; if (info->hasCallPlaceholders)
clearStackPlaceholders(info);
if (!info->loadGuardSearch) {
info->loadGuardSearch = true;
if (discoverIndexedStackPointers(info->space,freeStores,true)) {
reprocessStackCount += 1;
stackSpace = info->space;
}
}
needwarning = false;
iter = fd->beginLoc(info->space);
enditer = fd->endLoc(info->space);
while(iter != enditer) {
vn = *iter++;
if ((!vn->isWritten())&&vn->hasNoDescend()&&(!vn->isUnaffected())&&(!vn->isInput()))
continue;
if (vn->isWriteMask()) continue;
int4 prev = 0;
LocationMap::iterator liter = globaldisjoint.add(vn->getAddr(),vn->getSize(),pass,prev);
if (prev == 0) disjoint.add((*liter).first,(*liter).second.size,pass,prev);
else if (prev==2) { if (vn->isHeritageKnown()) continue; if (vn->hasNoDescend()) continue;
if ((!needwarning)&&(info->deadremoved>0)) {
needwarning = true;
bumpDeadcodeDelay(vn);
warnvn = vn;
}
disjoint.add((*liter).first,(*liter).second.size,pass,prev);
}
else { disjoint.add((*liter).first,(*liter).second.size,pass,prev);
if ((!needwarning)&&(info->deadremoved>0)) {
if (vn->isHeritageKnown()) continue; needwarning = true;
bumpDeadcodeDelay(vn);
warnvn = vn;
}
}
}
if (needwarning) {
if (!info->warningissued) {
info->warningissued = true;
ostringstream errmsg;
errmsg << "Heritage AFTER dead removal. Example location: ";
warnvn->printRawNoMarkup(errmsg);
if (!warnvn->hasNoDescend()) {
PcodeOp *warnop = *warnvn->beginDescend();
errmsg << " : ";
warnop->getAddr().printRaw(errmsg);
}
fd->warningHeader(errmsg.str());
}
}
}
placeMultiequals();
rename();
if (reprocessStackCount > 0)
reprocessFreeStores(stackSpace, freeStores);
analyzeNewLoadGuards();
handleNewLoadCopies();
if (pass == 0)
splitmanage.splitAdditional();
pass += 1;
}
const LoadGuard *Heritage::getStoreGuard(PcodeOp *op) const
{
list<LoadGuard>::const_iterator iter;
for(iter=storeGuard.begin();iter!=storeGuard.end();++iter) {
if ((*iter).op == op)
return &(*iter);
}
return (const LoadGuard *)0;
}
int4 Heritage::numHeritagePasses(AddrSpace *spc) const
{
const HeritageInfo *info = getInfo(spc);
if (!info->isHeritaged())
throw LowlevelError("Trying to calculate passes for non-heritaged space");
return (pass - info->delay);
}
void Heritage::seenDeadCode(AddrSpace *spc)
{
HeritageInfo *info = getInfo(spc);
info->deadremoved = 1;
}
int4 Heritage::getDeadCodeDelay(AddrSpace *spc) const
{
const HeritageInfo *info = getInfo(spc);
return info->deadcodedelay;
}
void Heritage::setDeadCodeDelay(AddrSpace *spc,int4 delay)
{
HeritageInfo *info = getInfo(spc);
if (delay < info->delay)
throw LowlevelError("Illegal deadcode delay setting");
info->deadcodedelay = delay;
}
bool Heritage::deadRemovalAllowed(AddrSpace *spc) const
{
const HeritageInfo *info = getInfo(spc);
return (pass > info->deadcodedelay);
}
bool Heritage::deadRemovalAllowedSeen(AddrSpace *spc)
{
HeritageInfo *info = getInfo(spc);
bool res = (pass > info->deadcodedelay);
if (res)
info->deadremoved = 1;
return res;
}
void Heritage::clear(void)
{
disjoint.clear();
globaldisjoint.clear();
domchild.clear();
augment.clear();
flags.clear();
depth.clear();
merge.clear();
clearInfoList();
loadGuard.clear();
storeGuard.clear();
maxdepth = -1;
pass = 0;
}