#include "varmap.hh"
#include "funcdata.hh"
bool RangeHint::reconcile(const RangeHint *b) const
{
const RangeHint *a = this;
if (a->type->getSize() < b->type->getSize()) {
const RangeHint *tmp = b;
b = a; a = tmp;
}
intb mod = (b->sstart - a->sstart) % a->type->getSize();
if (mod < 0)
mod += a->type->getSize();
Datatype *sub = a->type;
uintb umod = mod;
while((sub!=(Datatype *)0)&&(sub->getSize() > b->type->getSize()))
sub = sub->getSubType(umod,&umod);
if (sub == (Datatype *)0) return false;
if (umod != 0) return false;
if (sub->getSize() < b->type->getSize()) return false;
return true;
}
bool RangeHint::contain(const RangeHint *b) const
{
if (sstart == b->sstart) return true;
if (b->sstart+b->size-1 <= sstart+size-1) return true;
return false;
}
bool RangeHint::preferred(const RangeHint *b,bool reconcile) const
{
if (start != b->start)
return true; if ((b->flags & Varnode::typelock)!=0) {
if ((flags & Varnode::typelock)==0)
return false;
}
else if ((flags & Varnode::typelock)!=0)
return true;
if (!reconcile) { if ((rangeType == RangeHint::open)&&(b->rangeType != RangeHint::open)) return false;
if ((b->rangeType == RangeHint::open)&&(rangeType != RangeHint::open))
return true;
}
return (0>type->typeOrder(*b->type)); }
bool RangeHint::absorb(RangeHint *b)
{
if (rangeType != RangeHint::open) return false;
if (highind < 0) return false;
if (b->rangeType == RangeHint::endpoint) return false; Datatype *settype = type; if (settype->getSize() != b->type->getSize()) return false;
if (settype != b->type) {
Datatype *aTestType = type;
Datatype *bTestType = b->type;
while(aTestType->getMetatype() == TYPE_PTR) {
if (bTestType->getMetatype() != TYPE_PTR)
break;
aTestType = ((TypePointer *)aTestType)->getPtrTo();
bTestType = ((TypePointer *)bTestType)->getPtrTo();
}
if (aTestType->getMetatype() == TYPE_UNKNOWN)
settype = b->type;
else if (bTestType->getMetatype() == TYPE_UNKNOWN) {
}
else if (aTestType->getMetatype() == TYPE_INT && bTestType->getMetatype() == TYPE_UINT) {
}
else if (aTestType->getMetatype() == TYPE_UINT && bTestType->getMetatype() == TYPE_INT) {
}
else if (aTestType != bTestType) return false;
}
if ((flags & Varnode::typelock)!=0) return false;
if ((b->flags & Varnode::typelock)!=0) return false;
if (flags != b->flags) return false;
intb diffsz = b->sstart - sstart;
if ((diffsz % settype->getSize()) != 0) return false;
diffsz /= settype->getSize();
if (diffsz > highind) return false;
type = settype;
if (b->rangeType == RangeHint::open && (0 <= b->highind)) { int4 trialhi = b->highind + diffsz;
if (highind < trialhi)
highind = trialhi;
}
return true;
}
bool RangeHint::merge(RangeHint *b,AddrSpace *space,TypeFactory *typeFactory)
{
uintb aend,bend;
uintb end;
Datatype *resType;
uint4 resFlags;
bool didReconcile;
int4 resHighIndex;
bool overlapProblems = false;
aend = space->wrapOffset(start+size);
bend = space->wrapOffset(b->start+b->size);
RangeHint::RangeType resRangeType = RangeHint::fixed;
resHighIndex = -1;
if ((aend==0)||(bend==0))
end = 0;
else
end = (aend > bend) ? aend : bend;
if (contain(b)) { didReconcile = reconcile(b); if (preferred(b,didReconcile)) { resType = type;
resFlags = flags;
resRangeType = rangeType;
resHighIndex = highind;
}
else {
resType = b->type;
resFlags = b->flags;
resRangeType = b->rangeType;
resHighIndex = b->highind;
}
if ((start==b->start)&&(size==b->size)) {
resRangeType = (rangeType==RangeHint::open || b->rangeType==RangeHint::open) ? RangeHint::open : RangeHint::fixed;
if (resRangeType == RangeHint::open)
resHighIndex = (highind < b->highind) ? b->highind : highind;
}
if (!didReconcile) { if ((b->rangeType != RangeHint::open)&&(rangeType != RangeHint::open))
overlapProblems = true;
}
}
else {
didReconcile = false;
resType = (Datatype *)0; resFlags = 0;
}
if (!didReconcile) {
if ((b->flags & Varnode::typelock)!=0) {
if ((flags & Varnode::typelock)!=0)
throw LowlevelError("Overlapping forced variable types : " + type->getName() + " " + b->type->getName());
}
}
if (resType == (Datatype *)0) resType = typeFactory->getBase(1,TYPE_UNKNOWN);
type = resType;
flags = resFlags;
rangeType = resRangeType;
highind = resHighIndex;
if ((!didReconcile)&&(start != b->start)) { if ((flags & Varnode::typelock)!=0) { return overlapProblems; }
rangeType = RangeHint::fixed;
size = space->wrapOffset(end-start);
if (size != 1 && size != 2 && size != 4 && size != 8) {
size = 1;
rangeType = RangeHint::open;
}
type = typeFactory->getBase(size,TYPE_UNKNOWN);
flags = 0;
highind = -1;
return overlapProblems;
}
size = resType->getSize();
return overlapProblems;
}
int4 RangeHint::compare(const RangeHint &op2) const
{
if (sstart != op2.sstart)
return (sstart < op2.sstart) ? -1 : 1;
if (size != op2.size)
return (size < op2.size) ? -1 : 1; if (rangeType != op2.rangeType)
return (rangeType < op2.rangeType) ? -1 : 1;
uint4 thisLock = flags & Varnode::typelock;
uint4 op2Lock = op2.flags & Varnode::typelock;
if (thisLock != op2Lock)
return (thisLock < op2Lock) ? -1 : 1;
if (highind != op2.highind)
return (highind < op2.highind) ? -1 : 1;
return 0;
}
ScopeLocal::ScopeLocal(uint8 id,AddrSpace *spc,Funcdata *fd,Architecture *g) : ScopeInternal(id,fd->getName(),g)
{
space = spc;
deepestParamOffset = ~((uintb)0);
rangeLocked = false;
stackGrowsNegative = true;
restrictScope(fd);
}
void ScopeLocal::collectNameRecs(void)
{
nameRecommend.clear(); dynRecommend.clear();
SymbolNameTree::iterator iter = nametree.begin();
while(iter!=nametree.end()) {
Symbol *sym = *iter++;
if (sym->isNameLocked()&&(!sym->isTypeLocked())) {
if (sym->isThisPointer()) { Datatype *dt = sym->getType();
if (dt->getMetatype() == TYPE_PTR) {
if (((TypePointer *)dt)->getPtrTo()->getMetatype() == TYPE_STRUCT) {
SymbolEntry *entry = sym->getFirstWholeMap();
typeRecommend.push_back(TypeRecommend(entry->getAddr(),dt));
}
}
}
addRecommendName(sym); }
}
}
void ScopeLocal::resetLocalWindow(void)
{
stackGrowsNegative = fd->getFuncProto().isStackGrowsNegative();
deepestParamOffset = stackGrowsNegative ? ~((uintb)0) : 0;
if (rangeLocked) return;
const RangeList &localRange( fd->getFuncProto().getLocalRange() );
const RangeList ¶mrange( fd->getFuncProto().getParamRange() );
RangeList newrange;
set<Range>::const_iterator iter;
for(iter=localRange.begin();iter!=localRange.end();++iter) {
AddrSpace *spc = (*iter).getSpace();
uintb first = (*iter).getFirst();
uintb last = (*iter).getLast();
newrange.insertRange(spc,first,last);
}
for(iter=paramrange.begin();iter!=paramrange.end();++iter) {
AddrSpace *spc = (*iter).getSpace();
uintb first = (*iter).getFirst();
uintb last = (*iter).getLast();
newrange.insertRange(spc,first,last);
}
glb->symboltab->setRange(this,newrange);
}
void ScopeLocal::saveXml(ostream &s) const
{
s << "<localdb";
a_v(s,"main",space->getName());
a_v_b(s,"lock",rangeLocked);
s << ">\n";
ScopeInternal::saveXml(s);
s << "</localdb>\n";
}
void ScopeLocal::restoreXml(const Element *el)
{
rangeLocked = false;
if (xml_readbool(el->getAttributeValue("lock")))
rangeLocked = true;
space = glb->getSpaceByName(el->getAttributeValue("main"));
ScopeInternal::restoreXml( *(el->getChildren().begin()) );
collectNameRecs();
}
void ScopeLocal::markNotMapped(AddrSpace *spc,uintb first,int4 sz,bool parameter)
{
if (space != spc) return;
uintb last = first + sz - 1;
if (last < first) last = spc->getHighest();
else if (last > spc->getHighest())
last = spc->getHighest();
if (parameter) { if (stackGrowsNegative) {
if (first < deepestParamOffset)
deepestParamOffset = first;
}
else {
if (first > deepestParamOffset)
deepestParamOffset = first;
}
}
Address addr(space,first);
SymbolEntry *overlap = findOverlap(addr,sz);
while(overlap != (SymbolEntry *)0) { Symbol *sym = overlap->getSymbol();
if ((sym->getFlags()&Varnode::typelock)!=0) {
if ((!parameter) || (sym->getCategory() != 0))
fd->warningHeader("Variable defined which should be unmapped: "+sym->getName());
return;
}
removeSymbol(sym);
overlap = findOverlap(addr,sz);
}
glb->symboltab->removeRange(this,space,first,last);
}
string ScopeLocal::buildVariableName(const Address &addr,
const Address &pc,
Datatype *ct,
int4 &index,uint4 flags) const
{
if (((flags & (Varnode::addrtied|Varnode::persist))==Varnode::addrtied) &&
addr.getSpace() == space) {
if (fd->getFuncProto().getLocalRange().inRange(addr,1)) {
intb start = (intb) AddrSpace::byteToAddress(addr.getOffset(),space->getWordSize());
sign_extend(start,addr.getAddrSize()*8-1);
if (stackGrowsNegative)
start = -start;
ostringstream s;
if (ct != (Datatype *)0)
ct->printNameBase(s);
string spacename = addr.getSpace()->getName();
spacename[0] = toupper(spacename[0]);
s << spacename;
if (start <= 0) {
s << 'X'; start = -start;
}
else {
if (deepestParamOffset + 1 > 1 && stackGrowsNegative == (addr.getOffset() < deepestParamOffset)) {
s << 'Y'; }
}
s << dec << start;
return makeNameUnique(s.str());
}
}
return ScopeInternal::buildVariableName(addr,pc,ct,index,flags);
}
bool ScopeLocal::adjustFit(RangeHint &a) const
{
if (a.size==0) return false; if ((a.flags & Varnode::typelock)!=0) return false; Address addr(space,a.start);
uintb maxsize = getRangeTree().longestFit(addr,a.size);
if (maxsize==0) return false;
if (maxsize < a.size) { if (maxsize < a.type->getSize()) return false; a.size = (int4)maxsize;
}
SymbolEntry *entry = findOverlap(addr,a.size);
if (entry == (SymbolEntry *)0)
return true;
if (entry->getAddr() <= addr) {
return false;
}
maxsize = entry->getAddr().getOffset() - a.start;
if (maxsize < a.type->getSize()) return false; a.size = maxsize;
return true;
}
void ScopeLocal::createEntry(const RangeHint &a)
{
Address addr(space,a.start);
Address usepoint;
Datatype *ct = glb->types->concretize(a.type);
int4 num = a.size/ct->getSize();
if (num>1)
ct = glb->types->getTypeArray(num,ct);
addSymbol("",ct,addr,usepoint);
}
void AliasChecker::deriveBoundaries(const FuncProto &proto)
{
localExtreme = ~((uintb)0); localBoundary = 0x1000000;
if (direction == -1)
localExtreme = localBoundary;
if (proto.hasModel()) {
const RangeList &localrange( proto.getLocalRange() );
const RangeList ¶mrange( proto.getParamRange() );
const Range *local = localrange.getFirstRange();
const Range *param = paramrange.getLastRange();
if ((local != (const Range *)0)&&(param != (const Range *)0)) {
localBoundary = param->getLast();
if (direction == -1) {
localBoundary = paramrange.getFirstRange()->getFirst();
localExtreme = localBoundary;
}
}
}
}
void AliasChecker::gatherInternal(void) const
{
calculated = true;
aliasBoundary = localExtreme;
Varnode *spacebase = fd->findSpacebaseInput(space);
if (spacebase == (Varnode *)0) return;
gatherAdditiveBase(spacebase,addBase);
for(vector<AddBase>::iterator iter=addBase.begin();iter!=addBase.end();++iter) {
uintb offset = gatherOffset((*iter).base);
offset = AddrSpace::addressToByte(offset,space->getWordSize()); alias.push_back(offset);
if (direction == 1) {
if (offset < localBoundary) continue; }
else {
if (offset > localBoundary) continue; }
if (offset < aliasBoundary)
aliasBoundary = offset;
}
}
void AliasChecker::gather(const Funcdata *f,AddrSpace *spc,bool defer)
{
fd = f;
space = spc;
calculated = false; addBase.clear();
alias.clear();
direction = space->stackGrowsNegative() ? 1 : -1; deriveBoundaries(fd->getFuncProto());
if (!defer)
gatherInternal();
}
bool AliasChecker::hasLocalAlias(Varnode *vn) const
{
if (vn == (Varnode *)0) return false;
if (!calculated)
gatherInternal();
if (vn->getSpace() != space) return false;
if (direction == -1)
return false;
return (vn->getOffset() >= aliasBoundary);
}
void AliasChecker::sortAlias(void) const
{
sort(alias.begin(),alias.end());
}
void AliasChecker::gatherAdditiveBase(Varnode *startvn,vector<AddBase> &addbase)
{
vector<AddBase> vnqueue; Varnode *vn,*subvn,*indexvn,*othervn;
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
bool nonadduse;
int4 i=0;
vn = startvn;
vn->setMark();
vnqueue.push_back(AddBase(vn,(Varnode *)0));
while(i<vnqueue.size()) {
vn = vnqueue[i].base;
indexvn = vnqueue[i++].index;
nonadduse = false;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
op = *iter;
switch(op->code()) {
case CPUI_COPY:
nonadduse = true; subvn = op->getOut();
if (!subvn->isMark()) {
subvn->setMark();
vnqueue.push_back(AddBase(subvn,indexvn));
}
break;
case CPUI_INT_SUB:
if (vn == op->getIn(1)) { nonadduse = true;
break;
}
othervn = op->getIn(1);
if (!othervn->isConstant())
indexvn = othervn;
subvn = op->getOut();
if (!subvn->isMark()) {
subvn->setMark();
vnqueue.push_back(AddBase(subvn,indexvn));
}
break;
case CPUI_INT_ADD:
case CPUI_PTRADD:
othervn = op->getIn(1); if (othervn == vn)
othervn = op->getIn(0);
if (!othervn->isConstant())
indexvn = othervn;
case CPUI_PTRSUB:
case CPUI_SEGMENTOP:
subvn = op->getOut();
if (!subvn->isMark()) {
subvn->setMark();
vnqueue.push_back(AddBase(subvn,indexvn));
}
break;
default:
nonadduse = true; }
}
if (nonadduse)
addbase.push_back(AddBase(vn,indexvn));
}
for(i=0;i<vnqueue.size();++i)
vnqueue[i].base->clearMark();
}
uintb AliasChecker::gatherOffset(Varnode *vn)
{
uintb retval;
Varnode *othervn;
if (vn->isConstant()) return vn->getOffset();
PcodeOp *def = vn->getDef();
if (def == (PcodeOp *)0) return 0;
switch(def->code()) {
case CPUI_COPY:
retval = gatherOffset(def->getIn(0));
break;
case CPUI_PTRSUB:
case CPUI_INT_ADD:
retval = gatherOffset(def->getIn(0));
retval += gatherOffset(def->getIn(1));
break;
case CPUI_INT_SUB:
retval = gatherOffset(def->getIn(0));
retval -= gatherOffset(def->getIn(1));
break;
case CPUI_PTRADD:
othervn = def->getIn(2);
retval = gatherOffset(def->getIn(0));
if (othervn->isConstant() && (othervn->getOffset()==1))
retval = retval + gatherOffset(def->getIn(1));
break;
case CPUI_SEGMENTOP:
retval = gatherOffset(def->getIn(2));
break;
default:
retval = 0;
}
return retval & calc_mask(vn->getSize());
}
MapState::MapState(AddrSpace *spc,const RangeList &rn,
const RangeList &pm,Datatype *dt) : range(rn)
{
spaceid = spc;
defaultType = dt;
set<Range>::const_iterator pmiter;
for(pmiter=pm.begin();pmiter!=pm.end();++pmiter) {
AddrSpace *pmSpc = (*pmiter).getSpace();
uintb first = (*pmiter).getFirst();
uintb last = (*pmiter).getLast();
range.removeRange(pmSpc,first,last); }
#ifdef OPACTION_DEBUG
debugon = false;
#endif
}
MapState::~MapState(void)
{
vector<RangeHint *>::iterator riter;
for(riter=maplist.begin();riter!=maplist.end();++riter)
delete *riter;
}
void MapState::addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi)
{
if ((ct == (Datatype *)0)||(ct->getSize()==0)) ct = defaultType;
int4 sz = ct->getSize();
if (!range.inRange(Address(spaceid,st),sz))
return;
intb sst = (intb)AddrSpace::byteToAddress(st,spaceid->getWordSize());
sign_extend(sst,spaceid->getAddrSize()*8-1);
sst = (intb)AddrSpace::addressToByte(sst,spaceid->getWordSize());
RangeHint *newRange = new RangeHint(st,sz,sst,ct,fl,rt,hi);
maplist.push_back(newRange);
#ifdef OPACTION_DEBUG
if (debugon) {
ostringstream s;
s << "Add Range: " << hex << st << ":" << dec << sz;
s << " ";
ct->printRaw(s);
s << endl;
glb->printDebug(s.str());
}
#endif
}
void MapState::reconcileDatatypes(void)
{
vector<RangeHint *> newList;
newList.reserve(maplist.size());
int4 startPos = 0;
RangeHint *startHint = maplist[0];
Datatype *startDatatype = startHint->type;
newList.push_back(startHint);
int4 curPos = 1;
while(curPos < maplist.size()) {
RangeHint *curHint = maplist[curPos++];
if (curHint->start == startHint->start && curHint->size == startHint->size) {
Datatype *curDatatype = curHint->type;
if (curDatatype->typeOrder(*startDatatype) < 0) startDatatype = curDatatype;
if (curHint->compare(*newList.back()) != 0)
newList.push_back(curHint); else
delete curHint; }
else {
while(startPos < newList.size()) {
newList[startPos]->type = startDatatype;
startPos += 1;
}
startHint = curHint;
startDatatype = startHint->type;
newList.push_back(startHint);
}
}
while(startPos < newList.size()) {
newList[startPos]->type = startDatatype;
startPos += 1;
}
maplist.swap(newList);
}
void MapState::addGuard(const LoadGuard &guard,OpCode opc,TypeFactory *typeFactory)
{
if (!guard.isValid(opc)) return;
int4 step = guard.getStep();
if (step == 0) return; Datatype *ct = guard.getOp()->getIn(1)->getType();
if (ct->getMetatype() == TYPE_PTR) {
ct = ((TypePointer *) ct)->getPtrTo();
while (ct->getMetatype() == TYPE_ARRAY)
ct = ((TypeArray *) ct)->getBase();
}
int4 outSize;
if (opc == CPUI_STORE)
outSize = guard.getOp()->getIn(2)->getSize(); else
outSize = guard.getOp()->getOut()->getSize(); if (outSize != step) {
if (outSize > step || (step % outSize) != 0)
return;
step = outSize;
}
if (ct->getSize() != step) { if (step > 8)
return; ct = typeFactory->getBase(step, TYPE_UNKNOWN);
}
if (guard.isRangeLocked()) {
int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step;
addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1);
}
else
addRange(guard.getMinimum(),ct,0,RangeHint::open,3);
}
void MapState::gatherSymbols(const EntryMap *rangemap)
{
list<SymbolEntry>::const_iterator riter;
Symbol *sym;
if (rangemap == (EntryMap *)0) return;
for(riter=rangemap->begin_list();riter!=rangemap->end_list();++riter) {
sym = (*riter).getSymbol();
if (sym == (Symbol *)0) continue;
uintb start = (*riter).getAddr().getOffset();
Datatype *ct = sym->getType();
addRange(start,ct,sym->getFlags(),RangeHint::fixed,-1);
}
}
bool MapState::initialize(void)
{
const Range *lastrange = range.getLastSignedRange(spaceid);
if (lastrange == (Range *)0) return false;
if (maplist.empty()) return false;
uintb high = spaceid->wrapOffset(lastrange->getLast()+1);
intb sst = (intb)AddrSpace::byteToAddress(high,spaceid->getWordSize());
sign_extend(sst,spaceid->getAddrSize()*8-1);
sst = (intb)AddrSpace::addressToByte(sst,spaceid->getWordSize());
RangeHint *termRange = new RangeHint(high,1,sst,defaultType,0,RangeHint::endpoint,-2);
maplist.push_back(termRange);
stable_sort(maplist.begin(),maplist.end(),RangeHint::compareRanges);
reconcileDatatypes();
iter = maplist.begin();
return true;
}
void MapState::gatherVarnodes(const Funcdata &fd)
{
VarnodeLocSet::const_iterator riter,iterend;
Varnode *vn;
riter = fd.beginLoc(spaceid);
iterend = fd.endLoc(spaceid);
while(riter != iterend) {
vn = *riter++;
if (vn->isFree()) continue;
uintb start = vn->getOffset();
Datatype *ct = vn->getType();
addRange(start,ct,0,RangeHint::fixed,-1);
}
}
void MapState::gatherHighs(const Funcdata &fd)
{
vector<HighVariable *> varvec;
VarnodeLocSet::const_iterator riter,iterend;
Varnode *vn;
HighVariable *high;
riter = fd.beginLoc(spaceid);
iterend = fd.endLoc(spaceid);
while(riter != iterend) {
vn = *riter++;
high = vn->getHigh();
if (high == (HighVariable *)0) continue;
if (high->isMark()) continue;
if (!high->isAddrTied()) continue;
vn = high->getTiedVarnode(); high->setMark();
varvec.push_back(high);
uintb start = vn->getOffset();
Datatype *ct = high->getType(); addRange(start,ct,0,RangeHint::fixed,-1);
}
for(int4 i=0;i<varvec.size();++i)
varvec[i]->clearMark();
}
void MapState::gatherOpen(const Funcdata &fd)
{
checker.gather(&fd,spaceid,false);
const vector<AliasChecker::AddBase> &addbase( checker.getAddBase() );
const vector<uintb> &alias( checker.getAlias() );
uintb offset;
Datatype *ct;
for(int4 i=0;i<addbase.size();++i) {
offset = alias[i];
ct = addbase[i].base->getType();
if (ct->getMetatype() == TYPE_PTR) {
ct = ((TypePointer *)ct)->getPtrTo();
while(ct->getMetatype() == TYPE_ARRAY)
ct = ((TypeArray *)ct)->getBase();
}
else
ct = (Datatype *)0; int4 minItems;
if ( addbase[i].index != (Varnode *)0) {
minItems = 3; }
else {
minItems = -1;
}
addRange(offset,ct,0,RangeHint::open,minItems);
}
TypeFactory *typeFactory = fd.getArch()->types;
const list<LoadGuard> &loadGuard( fd.getLoadGuards() );
for(list<LoadGuard>::const_iterator giter=loadGuard.begin();giter!=loadGuard.end();++giter)
addGuard(*giter,CPUI_LOAD,typeFactory);
const list<LoadGuard> &storeGuard( fd.getStoreGuards() );
for(list<LoadGuard>::const_iterator siter=storeGuard.begin();siter!=storeGuard.end();++siter)
addGuard(*siter,CPUI_STORE,typeFactory);
}
void ScopeLocal::restructureVarnode(bool aliasyes)
{
clearUnlockedCategory(-1); MapState state(space,getRangeTree(),fd->getFuncProto().getParamRange(),
glb->types->getBase(1,TYPE_UNKNOWN));
#ifdef OPACTION_DEBUG
if (debugon)
state.turnOnDebug(glb);
#endif
state.gatherVarnodes(*fd); state.gatherOpen(*fd);
state.gatherSymbols(maptable[space->getIndex()]);
restructure(state);
clearUnlockedCategory(0);
fakeInputSymbols();
state.sortAlias();
if (aliasyes)
markUnaliased(state.getAlias());
}
void ScopeLocal::restructureHigh(void)
{ clearUnlockedCategory(-1); MapState state(space,getRangeTree(),fd->getFuncProto().getParamRange(),
glb->types->getBase(1,TYPE_UNKNOWN));
#ifdef OPACTION_DEBUG
if (debugon)
state.turnOnDebug(glb);
#endif
state.gatherHighs(*fd); state.gatherOpen(*fd);
state.gatherSymbols(maptable[space->getIndex()]);
bool overlapProblems = restructure(state);
if (overlapProblems)
fd->warningHeader("Could not reconcile some variable overlaps");
}
bool ScopeLocal::restructure(MapState &state)
{
RangeHint cur;
RangeHint *next;
bool overlapProblems = false;
if (!state.initialize())
return overlapProblems;
cur = *state.next();
while(state.getNext()) {
next = state.next();
if (next->sstart < cur.sstart+cur.size) { if (cur.merge(next,space,glb->types)) overlapProblems = true;
}
else {
if (!cur.absorb(next)) {
if (cur.rangeType == RangeHint::open)
cur.size = next->sstart-cur.sstart;
if (adjustFit(cur))
createEntry(cur);
cur = *next;
}
}
}
return overlapProblems;
}
void ScopeLocal::markUnaliased(const vector<uintb> &alias)
{
EntryMap *rangemap = maptable[space->getIndex()];
if (rangemap == (EntryMap *)0) return;
list<SymbolEntry>::iterator iter,enditer;
set<Range>::const_iterator rangeIter, rangeEndIter;
rangeIter = getRangeTree().begin();
rangeEndIter = getRangeTree().end();
int4 alias_block_level = glb->alias_block_level;
bool aliason = false;
uintb curalias=0;
int4 i=0;
iter = rangemap->begin_list();
enditer = rangemap->end_list();
while(iter!=enditer) {
SymbolEntry &entry(*iter++);
uintb curoff = entry.getAddr().getOffset() + entry.getSize() - 1;
while ((i<alias.size()) && (alias[i] <= curoff)) {
aliason = true;
curalias = alias[i++];
}
while(rangeIter != rangeEndIter) {
const Range &rng(*rangeIter);
if (rng.getSpace() == space) {
if (rng.getFirst() > curalias && curoff >= rng.getFirst())
aliason = false;
if (rng.getLast() >= curoff) break; if (rng.getLast() > curalias) aliason = false; }
++rangeIter;
}
Symbol *symbol = entry.getSymbol();
if (aliason && (curoff - curalias > 0xffff)) aliason = false;
if (!aliason) symbol->getScope()->setAttribute(symbol,Varnode::nolocalalias);
if (symbol->isTypeLocked() && alias_block_level != 0) {
if (alias_block_level == 3)
aliason = false; else {
type_metatype meta = symbol->getType()->getMetatype();
if (meta == TYPE_STRUCT)
aliason = false; else if (meta == TYPE_ARRAY && alias_block_level > 1) aliason = false; }
}
}
}
void ScopeLocal::fakeInputSymbols(void)
{
int4 lockedinputs = getCategorySize(0);
VarnodeDefSet::const_iterator iter,enditer;
iter = fd->beginDef(Varnode::input);
enditer = fd->endDef(Varnode::input);
while(iter != enditer) {
Varnode *vn = *iter++;
bool locked = vn->isTypeLock();
Address addr = vn->getAddr();
if (addr.getSpace() != space) continue;
if (!fd->getFuncProto().getParamRange().inRange(addr,1)) continue;
uintb endpoint = addr.getOffset() + vn->getSize() - 1;
while(iter != enditer) {
vn = *iter;
if (vn->getSpace() != space) break;
if (endpoint < vn->getOffset()) break;
uintb newendpoint = vn->getOffset() + vn->getSize() -1;
if (endpoint < newendpoint)
endpoint = newendpoint;
if (vn->isTypeLock())
locked = true;
++iter;
}
if (!locked) {
Address usepoint;
if (lockedinputs != 0) {
uint4 vflags = 0;
SymbolEntry *entry = queryProperties(vn->getAddr(),vn->getSize(),usepoint,vflags);
if (entry != (SymbolEntry *)0) {
if (entry->getSymbol()->getCategory()==0)
continue; }
}
int4 size = (endpoint - addr.getOffset()) + 1;
Datatype *ct = fd->getArch()->types->getBase(size,TYPE_UNKNOWN);
try {
addSymbol("",ct,addr,usepoint)->getSymbol();
}
catch(LowlevelError &err) {
fd->warningHeader(err.explain);
}
}
}
}
SymbolEntry *ScopeLocal::remapSymbol(Symbol *sym,const Address &addr,const Address &usepoint)
{
SymbolEntry *entry = sym->getFirstWholeMap();
int4 size = entry->getSize();
if (!entry->isDynamic()) {
if (entry->getAddr() == addr) {
if (usepoint.isInvalid() && entry->getFirstUseAddress().isInvalid())
return entry;
if (entry->getFirstUseAddress() == usepoint)
return entry;
}
}
removeSymbolMappings(sym);
RangeList rnglist;
if (!usepoint.isInvalid())
rnglist.insertRange(usepoint.getSpace(),usepoint.getOffset(),usepoint.getOffset());
return addMapInternal(sym,Varnode::mapped,addr,0,size,rnglist);
}
SymbolEntry *ScopeLocal::remapSymbolDynamic(Symbol *sym,uint8 hash,const Address &usepoint)
{
SymbolEntry *entry = sym->getFirstWholeMap();
int4 size = entry->getSize();
if (entry->isDynamic()) {
if (entry->getHash() == hash && entry->getFirstUseAddress() == usepoint)
return entry;
}
removeSymbolMappings(sym);
RangeList rnglist;
if (!usepoint.isInvalid())
rnglist.insertRange(usepoint.getSpace(),usepoint.getOffset(),usepoint.getOffset());
return addDynamicMapInternal(sym,Varnode::mapped,hash,0,size,rnglist);
}
void ScopeLocal::recoverNameRecommendationsForSymbols(void)
{
Address param_usepoint = fd->getAddress() - 1;
list<NameRecommend>::const_iterator iter;
for(iter=nameRecommend.begin();iter!=nameRecommend.end();++iter) {
const Address &addr((*iter).getAddr());
const Address &usepoint((*iter).getUseAddr());
int4 size = (*iter).getSize();
Symbol *sym;
Varnode *vn = (Varnode *)0;
if (usepoint.isInvalid()) {
SymbolEntry *entry = findOverlap(addr, size); if (entry == (SymbolEntry *)0) continue;
if (entry->getAddr() != addr) continue;
sym = entry->getSymbol();
if ((sym->getFlags() & Varnode::addrtied)==0)
continue; vn = fd->findLinkedVarnode(entry);
}
else {
if (usepoint == param_usepoint)
vn = fd->findVarnodeInput(size, addr);
else
vn = fd->findVarnodeWritten(size,addr,usepoint);
if (vn == (Varnode *)0) continue;
sym = vn->getHigh()->getSymbol();
if (sym == (Symbol *)0) continue;
if ((sym->getFlags() & Varnode::addrtied)!=0)
continue; SymbolEntry *entry = sym->getFirstWholeMap();
if (entry->getSize() != size) continue;
}
if (!sym->isNameUndefined()) continue;
renameSymbol(sym,makeNameUnique((*iter).getName()));
setSymbolId(sym, (*iter).getSymbolId());
setAttribute(sym, Varnode::namelock);
if (vn != (Varnode *)0) {
fd->remapVarnode(vn, sym, usepoint);
}
}
if (dynRecommend.empty()) return;
list<DynamicRecommend>::const_iterator dyniter;
DynamicHash dhash;
for(dyniter=dynRecommend.begin();dyniter!=dynRecommend.end();++dyniter) {
dhash.clear();
const DynamicRecommend &dynEntry(*dyniter);
Varnode *vn = dhash.findVarnode(fd, dynEntry.getAddress(), dynEntry.getHash());
if (vn == (Varnode *)0) continue;
if (vn->isAnnotation()) continue;
Symbol *sym = vn->getHigh()->getSymbol();
if (sym == (Symbol *)0) continue;
if (sym->getScope() != this) continue;
if (!sym->isNameUndefined()) continue;
renameSymbol(sym,makeNameUnique( dynEntry.getName() ));
setAttribute(sym, Varnode::namelock);
setSymbolId(sym, dynEntry.getSymbolId());
fd->remapDynamicVarnode(vn, sym, dynEntry.getAddress(), dynEntry.getHash());
}
}
void ScopeLocal::applyTypeRecommendations(void)
{
list<TypeRecommend>::const_iterator iter;
for(iter=typeRecommend.begin();iter!=typeRecommend.end();++iter) {
Datatype *dt = (*iter).getType();
Varnode *vn = fd->findVarnodeInput(dt->getSize(), (*iter).getAddress());
if (vn != (Varnode *)0)
vn->updateType(dt, true, false);
}
}
void ScopeLocal::addRecommendName(Symbol *sym)
{
SymbolEntry *entry = sym->getFirstWholeMap();
if (entry == (SymbolEntry *) 0) return;
if (entry->isDynamic()) {
dynRecommend.emplace_back(entry->getFirstUseAddress(), entry->getHash(), sym->getName(), sym->getId());
}
else {
Address usepoint((AddrSpace *)0,0);
if (!entry->getUseLimit().empty()) {
const Range *range = entry->getUseLimit().getFirstRange();
usepoint = Address(range->getSpace(), range->getFirst());
}
nameRecommend.emplace_back(entry->getAddr(),usepoint, entry->getSize(), sym->getName(), sym->getId());
}
if (sym->getCategory() < 0)
removeSymbol(sym);
}