#include "funcdata.hh"
void Funcdata::setVarnodeProperties(Varnode *vn) const
{
if (!vn->isMapped()) {
uint4 vflags=0;
SymbolEntry *entry = localmap->queryProperties(vn->getAddr(),vn->getSize(),vn->getUsePoint(*this),vflags);
if (entry != (SymbolEntry *)0) vn->setSymbolProperties(entry);
else
vn->setFlags(vflags & ~Varnode::typelock); }
if (vn->cover == (Cover *)0) {
if (isHighOn())
vn->calcCover();
}
}
HighVariable *Funcdata::assignHigh(Varnode *vn)
{
if ((flags & highlevel_on)!=0) {
if (vn->hasCover())
vn->calcCover();
if (!vn->isAnnotation()) {
return new HighVariable(vn);
}
}
return (HighVariable *)0;
}
Varnode *Funcdata::newConstant(int4 s,uintb constant_val)
{
Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
Varnode *vn = vbank.create(s,glb->getConstant(constant_val),ct);
assignHigh(vn);
return vn;
}
Varnode *Funcdata::newUnique(int4 s,Datatype *ct)
{
if (ct == (Datatype *)0)
ct = glb->types->getBase(s,TYPE_UNKNOWN);
Varnode *vn = vbank.createUnique(s,ct);
assignHigh(vn);
if (s >= minLanedSize)
checkForLanedRegister(s, vn->getAddr());
return vn;
}
Varnode *Funcdata::newVarnodeOut(int4 s,const Address &m,PcodeOp *op)
{
Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
Varnode *vn = vbank.createDef(s,m,ct,op);
op->setOutput(vn);
assignHigh(vn);
if (s >= minLanedSize)
checkForLanedRegister(s,m);
uint4 vflags = 0;
SymbolEntry *entry = localmap->queryProperties(m,s,op->getAddr(),vflags);
if (entry != (SymbolEntry *)0)
vn->setSymbolProperties(entry);
else
vn->setFlags(vflags & ~Varnode::typelock);
return vn;
}
Varnode *Funcdata::newUniqueOut(int4 s,PcodeOp *op)
{
Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
Varnode *vn = vbank.createDefUnique(s,ct,op);
op->setOutput(vn);
assignHigh(vn);
if (s >= minLanedSize)
checkForLanedRegister(s, vn->getAddr());
return vn;
}
Varnode *Funcdata::newVarnode(int4 s,const Address &m,Datatype *ct)
{
Varnode *vn;
if (ct == (const Datatype *)0)
ct = glb->types->getBase(s,TYPE_UNKNOWN);
vn = vbank.create(s,m,ct);
assignHigh(vn);
if (s >= minLanedSize)
checkForLanedRegister(s,m);
uint4 vflags=0;
SymbolEntry *entry = localmap->queryProperties(vn->getAddr(),vn->getSize(),Address(),vflags);
if (entry != (SymbolEntry *)0) vn->setSymbolProperties(entry);
else
vn->setFlags(vflags & ~Varnode::typelock);
return vn;
}
Varnode *Funcdata::newVarnodeIop(PcodeOp *op)
{
Datatype *ct = glb->types->getBase(sizeof(op),TYPE_UNKNOWN);
AddrSpace *cspc = glb->getIopSpace();
Varnode *vn = vbank.create(sizeof(op),Address(cspc,(uintb)(uintp)op),ct);
assignHigh(vn);
return vn;
}
Varnode *Funcdata::newVarnodeSpace(AddrSpace *spc)
{
Datatype *ct = glb->types->getBase(sizeof(spc),TYPE_UNKNOWN);
Varnode *vn = vbank.create(sizeof(spc),glb->createConstFromSpace(spc),ct);
assignHigh(vn);
return vn;
}
Varnode *Funcdata::newVarnodeCallSpecs(FuncCallSpecs *fc)
{
Datatype *ct = glb->types->getBase(sizeof(fc),TYPE_UNKNOWN);
AddrSpace *cspc = glb->getFspecSpace();
Varnode *vn = vbank.create(sizeof(fc),Address(cspc,(uintb)(uintp)fc),ct);
assignHigh(vn);
return vn;
}
Varnode *Funcdata::newCodeRef(const Address &m)
{
Varnode *vn;
Datatype *ct;
ct = glb->types->getTypeCode();
vn = vbank.create(1,m,ct);
vn->setFlags(Varnode::annotation);
assignHigh(vn);
return vn;
}
Varnode *Funcdata::newVarnode(int4 s,AddrSpace *base,uintb off)
{
Varnode *vn;
vn = newVarnode(s,Address(base,off));
return vn;
}
Varnode *Funcdata::cloneVarnode(const Varnode *vn)
{
Varnode *newvn;
newvn = vbank.create(vn->getSize(),vn->getAddr(),vn->getType());
uint4 vflags = vn->getFlags();
vflags &= (Varnode::annotation | Varnode::externref |
Varnode::readonly | Varnode::persist |
Varnode::addrtied | Varnode::addrforce |
Varnode::indirect_creation | Varnode::incidental_copy |
Varnode::volatil | Varnode::mapped);
newvn->setFlags(vflags);
return newvn;
}
void Funcdata::destroyVarnode(Varnode *vn)
{
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
#ifdef OPACTION_DEBUG
if (opactdbg_active)
debugModCheck(op);
#endif
op->clearInput(op->getSlot(vn));
}
if (vn->def != (PcodeOp *)0) {
vn->def->setOutput((Varnode *)0);
vn->def = (PcodeOp *)0;
}
vn->destroyDescend();
vbank.destroy(vn);
}
void Funcdata::checkForLanedRegister(int4 sz,const Address &addr)
{
const LanedRegister *lanedRegister = glb->getLanedRegister(addr,sz);
if (lanedRegister == (const LanedRegister *)0)
return;
VarnodeData storage;
storage.space = addr.getSpace();
storage.offset = addr.getOffset();
storage.size = sz;
lanedMap[storage] = lanedRegister;
}
HighVariable *Funcdata::findHigh(const string &nm) const
{
vector<Symbol *> symList;
localmap->queryByName(nm,symList);
if (symList.empty()) return (HighVariable *)0;
Symbol *sym = symList[0];
Varnode *vn = findLinkedVarnode(sym->getFirstWholeMap());
if (vn != (Varnode *)0)
return vn->getHigh();
return (HighVariable *)0;
}
Varnode *Funcdata::setInputVarnode(Varnode *vn)
{
Varnode *invn;
if (vn->isInput()) return vn; VarnodeDefSet::const_iterator iter;
iter = vbank.beginDef(Varnode::input,vn->getAddr()+vn->getSize());
if (iter != vbank.beginDef()) {
--iter; invn = *iter; if (invn->isInput()) {
if ((-1 != vn->overlap(*invn))||(-1 != invn->overlap(*vn))) {
if ((vn->getSize() == invn->getSize())&&(vn->getAddr() == invn->getAddr()))
return invn;
throw LowlevelError("Overlapping input varnodes");
}
}
}
vn = vbank.setInput(vn);
setVarnodeProperties(vn);
uint4 effecttype = funcp.hasEffect(vn->getAddr(),vn->getSize());
if (effecttype == EffectRecord::unaffected)
vn->setUnaffected();
if (effecttype == EffectRecord::return_address) {
vn->setUnaffected(); vn->setReturnAddress();
}
return vn;
}
void Funcdata::adjustInputVarnodes(const Address &addr,int4 sz)
{
Address endaddr = addr + (sz-1);
vector<Varnode *> inlist;
VarnodeDefSet::const_iterator iter,enditer;
iter = vbank.beginDef(Varnode::input,addr);
enditer = vbank.endDef(Varnode::input,endaddr);
while(iter != enditer) {
Varnode *vn = *iter;
++iter;
if (vn->getOffset() + (vn->getSize()-1) > endaddr.getOffset())
throw LowlevelError("Cannot properly adjust input varnodes");
inlist.push_back(vn);
}
for(uint4 i=0;i<inlist.size();++i) {
Varnode *vn = inlist[i];
int4 sa = addr.justifiedContain(sz,vn->getAddr(),vn->getSize(),false);
if ((!vn->isInput())||(sa < 0)||(sz<=vn->getSize()))
throw LowlevelError("Bad adjustment to input varnode");
PcodeOp *subop = newOp(2,getAddress());
opSetOpcode(subop,CPUI_SUBPIECE);
opSetInput(subop,newConstant(4,sa),1);
Varnode *newvn = newVarnodeOut(vn->getSize(),vn->getAddr(),subop);
opInsertBegin(subop,(BlockBasic *)bblocks.getBlock(0));
totalReplace(vn,newvn);
deleteVarnode(vn); inlist[i] = newvn;
}
Varnode *invn = newVarnode(sz,addr);
invn = setInputVarnode(invn);
invn->setWriteMask();
for(uint4 i=0;i<inlist.size();++i) {
PcodeOp *op = inlist[i]->getDef();
opSetInput(op,invn,0);
}
}
bool Funcdata::descend2Undef(Varnode *vn)
{
PcodeOp *op,*copyop;
BlockBasic *inbl;
Varnode *badconst;
list<PcodeOp *>::const_iterator iter;
int4 i,sz;
bool res;
res = false;
sz = vn->getSize();
iter = vn->beginDescend();
while(iter != vn->endDescend()) {
op = *iter++; if (op->getParent()->isDead()) continue;
if (op->getParent()->sizeIn()!=0) res = true;
i = op->getSlot(vn);
badconst = newConstant(sz,0xBADDEF);
if (op->code()==CPUI_MULTIEQUAL) { inbl = (BlockBasic *) op->getParent()->getIn(i);
copyop = newOp(1,inbl->getStart());
Varnode *inputvn = newUniqueOut(sz,copyop);
opSetOpcode(copyop,CPUI_COPY);
opSetInput(copyop,badconst,0);
opInsertEnd(copyop,inbl);
opSetInput(op,inputvn,i);
}
else if (op->code()==CPUI_INDIRECT) { copyop = newOp(1,op->getAddr());
Varnode *inputvn = newUniqueOut(sz,copyop);
opSetOpcode(copyop,CPUI_COPY);
opSetInput(copyop,badconst,0);
opInsertBefore(copyop,op);
opSetInput(op,inputvn,i);
}
else
opSetInput(op,badconst,i);
}
return res;
}
void Funcdata::initActiveOutput(void)
{
activeoutput = new ParamActive(false);
int4 maxdelay = funcp.getMaxOutputDelay();
if (maxdelay > 0)
maxdelay = 3;
activeoutput->setMaxPass(maxdelay);
}
void Funcdata::setHighLevel(void)
{
if ((flags & highlevel_on)!=0) return;
flags |= highlevel_on;
high_level_index = vbank.getCreateIndex();
VarnodeLocSet::const_iterator iter;
for(iter=vbank.beginLoc();iter!=vbank.endLoc();++iter)
assignHigh(*iter);
}
void Funcdata::transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset)
{
uintb newConsume = (vn->getConsume() >> 8*lsbOffset) & calc_mask(newVn->getSize());
uint4 vnFlags = vn->getFlags() & (Varnode::directwrite|Varnode::addrforce);
newVn->setFlags(vnFlags); newVn->setConsume(newConsume);
}
bool Funcdata::fillinReadOnly(Varnode *vn)
{
if (vn->isWritten()) { PcodeOp *defop = vn->getDef();
if (defop->isMarker())
defop->setAdditionalFlag(PcodeOp::warning); else if (!defop->isWarning()) { defop->setAdditionalFlag(PcodeOp::warning);
ostringstream s;
if ((!vn->isAddrForce())||(!vn->hasNoDescend())) {
s << "Read-only address (";
s << vn->getSpace()->getName();
s << ',';
vn->getAddr().printRaw(s);
s << ") is written";
warning(s.str(),defop->getAddr());
}
}
return false; }
if (vn->getSize() > sizeof(uintb))
return false;
uintb res;
uint1 bytes[32];
try {
glb->loader->loadFill(bytes,vn->getSize(),vn->getAddr());
} catch(DataUnavailError &err) { vn->clearFlags(Varnode::readonly); return true;
}
if (vn->getSpace()->isBigEndian()) { res = 0;
for(int4 i=0;i<vn->getSize();++i) {
res <<= 8;
res |= bytes[i];
}
}
else {
res = 0;
for(int4 i=vn->getSize()-1;i>=0;--i) {
res <<= 8;
res |= bytes[i];
}
}
bool changemade = false;
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
int4 i;
Datatype *locktype = vn->isTypeLock() ? vn->getType() : (Datatype *)0;
iter = vn->beginDescend();
while(iter != vn->endDescend()) {
op = *iter++;
i = op->getSlot(vn);
if (op->isMarker()) { if ((op->code()!=CPUI_INDIRECT)||(i!=0)) continue;
Varnode *outvn = op->getOut();
if (outvn->getAddr() == vn->getAddr()) continue; opRemoveInput(op,1);
opSetOpcode(op,CPUI_COPY);
}
Varnode *cvn = newConstant(vn->getSize(),res);
if (locktype != (Datatype *)0)
cvn->updateType(locktype,true,true); opSetInput(op,cvn,i);
changemade = true;
}
return changemade;
}
bool Funcdata::replaceVolatile(Varnode *vn)
{
PcodeOp *newop;
if (vn->isWritten()) { VolatileWriteOp *vw_op = glb->userops.getVolatileWrite();
if (!vn->hasNoDescend()) throw LowlevelError("Volatile memory was propagated");
PcodeOp *defop = vn->getDef();
newop = newOp(3,defop->getAddr());
opSetOpcode(newop,CPUI_CALLOTHER);
opSetInput(newop,newConstant(4,vw_op->getIndex()),0);
opSetInput(newop,newCodeRef(vn->getAddr()),1);
Varnode *tmp = newUnique(vn->getSize());
opSetOutput(defop,tmp);
opSetInput(newop,tmp,2);
opInsertAfter(newop,defop); }
else { VolatileReadOp *vr_op = glb->userops.getVolatileRead();
if (vn->hasNoDescend()) return false; PcodeOp *readop = vn->loneDescend();
if (readop == (PcodeOp *)0)
throw LowlevelError("Volatile memory value used more than once");
newop = newOp(2,readop->getAddr());
opSetOpcode(newop,CPUI_CALLOTHER);
Varnode *tmp = newUniqueOut(vn->getSize(),newop);
opSetInput(newop,newConstant(4,vr_op->getIndex()),0);
opSetInput(newop,newCodeRef(vn->getAddr()),1);
opSetInput(readop,tmp,readop->getSlot(vn));
opInsertBefore(newop,readop); }
if (vn->isTypeLock()) newop->setAdditionalFlag(PcodeOp::special_prop); return true;
}
bool Funcdata::checkIndirectUse(Varnode *vn)
{
vector<Varnode *> vlist;
int4 i = 0;
vlist.push_back(vn);
vn->setMark();
bool result = true;
while((i<vlist.size())&&result) {
vn = vlist[i++];
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
OpCode opc = op->code();
if (opc == CPUI_INDIRECT) {
if (op->isIndirectStore()) {
Varnode *outvn = op->getOut();
if (!outvn->isMark()) {
vlist.push_back(outvn);
outvn->setMark();
}
}
}
else if (opc == CPUI_MULTIEQUAL) {
Varnode *outvn = op->getOut();
if (!outvn->isMark()) {
vlist.push_back(outvn);
outvn->setMark();
}
}
else {
result = false;
break;
}
}
}
for(i=0;i<vlist.size();++i)
vlist[i]->clearMark();
return result;
}
void Funcdata::markIndirectOnly(void)
{
VarnodeDefSet::const_iterator iter,enditer;
iter = beginDef(Varnode::input);
enditer = endDef(Varnode::input);
for(;iter!=enditer;++iter) { Varnode *vn = *iter;
if (!vn->isIllegalInput()) continue; if (checkIndirectUse(vn))
vn->setFlags(Varnode::indirectonly);
}
}
void Funcdata::clearDeadVarnodes(void)
{
VarnodeLocSet::const_iterator iter;
Varnode *vn;
iter = vbank.beginLoc();
while(iter!=vbank.endLoc()) {
vn = *iter++;
if (vn->hasNoDescend()) {
if (vn->isInput() && !vn->isLockedInput()) {
vbank.makeFree(vn);
vn->clearCover();
}
if (vn->isFree())
vbank.destroy(vn);
}
}
}
void Funcdata::calcNZMask(void)
{
vector<PcodeOpNode> opstack;
list<PcodeOp *>::const_iterator oiter;
for(oiter=beginOpAlive();oiter!=endOpAlive();++oiter) {
PcodeOp *op = *oiter;
if (op->isMark()) continue;
opstack.push_back(PcodeOpNode(op,0));
op->setMark();
do {
PcodeOpNode &node( opstack.back() );
if (node.slot >= node.op->numInput()) { Varnode *outvn = node.op->getOut();
if (outvn != (Varnode *)0) {
outvn->nzm = node.op->getNZMaskLocal(true);
}
opstack.pop_back(); continue;
}
int4 oldslot = node.slot;
node.slot += 1; if (node.op->code() == CPUI_MULTIEQUAL) {
if (node.op->getParent()->isLoopIn(oldslot)) continue;
}
Varnode *vn = node.op->getIn(oldslot);
if (!vn->isWritten()) {
if (vn->isConstant())
vn->nzm = vn->getOffset();
else {
vn->nzm = calc_mask(vn->getSize());
if (vn->isSpacebase())
vn->nzm &= ~((uintb)0xff); }
}
else if (!vn->getDef()->isMark()) { opstack.push_back(PcodeOpNode(vn->getDef(),0));
vn->getDef()->setMark();
}
} while(!opstack.empty());
}
vector<PcodeOp *> worklist;
for(oiter=beginOpAlive();oiter!=endOpAlive();++oiter) {
PcodeOp *op = *oiter;
op->clearMark();
if (op->code() == CPUI_MULTIEQUAL)
worklist.push_back(op);
}
while(!worklist.empty()) {
PcodeOp *op = worklist.back();
worklist.pop_back();
Varnode *vn = op->getOut();
if (vn == (Varnode *)0) continue;
uintb nzmask = op->getNZMaskLocal(false);
if (nzmask != vn->nzm) {
vn->nzm = nzmask;
for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter)
worklist.push_back(*oiter);
}
}
}
bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes)
{
bool updateoccurred = false;
VarnodeLocSet::const_iterator iter,enditer;
Datatype *ct;
SymbolEntry *entry;
uint4 fl;
iter = vbank.beginLoc(lm->getSpaceId());
enditer = vbank.endLoc(lm->getSpaceId());
while(iter != enditer) {
Varnode *vnexemplar = *iter;
entry = lm->findOverlap(vnexemplar->getAddr(),vnexemplar->getSize());
ct = (Datatype *)0;
if (entry != (SymbolEntry *)0) {
fl = entry->getAllFlags();
if (entry->getSize() >= vnexemplar->getSize()) {
if (typesyes) {
uintb off = (vnexemplar->getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
Datatype *cur = entry->getSymbol()->getType();
do {
ct = cur;
cur = cur->getSubType(off,&off);
} while(cur != (Datatype *)0);
if ((ct->getSize() != vnexemplar->getSize())||(ct->getMetatype() == TYPE_UNKNOWN))
ct = (Datatype *)0;
}
}
else { fl &= ~((uint4)(Varnode::typelock|Varnode::namelock));
}
}
else { if (lm->inScope(vnexemplar->getAddr(),vnexemplar->getSize(),
vnexemplar->getUsePoint(*this))) {
fl = Varnode::mapped | Varnode::addrtied;
}
else
fl = 0;
}
if (syncVarnodesWithSymbol(iter,fl,ct))
updateoccurred = true;
}
return updateoccurred;
}
Symbol *Funcdata::handleSymbolConflict(SymbolEntry *entry,Varnode *vn)
{
if (vn->isInput() || vn->isAddrTied() ||
vn->isPersist() || vn->isConstant() || entry->isDynamic()) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
HighVariable *high = vn->getHigh();
Varnode *otherVn;
HighVariable *otherHigh = (HighVariable *)0;
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
while(iter != endLoc()) {
otherVn = *iter;
if (otherVn->getSize() != entry->getSize()) break;
if (otherVn->getAddr() != entry->getAddr()) break;
HighVariable *tmpHigh = otherVn->getHigh();
if (tmpHigh != high) {
otherHigh = tmpHigh;
break;
}
++iter;
}
if (otherHigh == (HighVariable *)0) {
vn->setSymbolEntry(entry);
return entry->getSymbol();
}
buildDynamicSymbol(vn);
return vn->getSymbolEntry()->getSymbol();
}
bool Funcdata::syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4 fl,Datatype *ct)
{
VarnodeLocSet::const_iterator enditer;
Varnode *vn;
uint4 vnflags;
bool updateoccurred = false;
uint4 mask = Varnode::mapped;
if ((fl&Varnode::addrtied)==0) mask |= Varnode::addrtied | Varnode::addrforce;
if ((fl&Varnode::nolocalalias)!=0)
mask |= Varnode::nolocalalias | Varnode::addrforce;
fl &= mask;
vn = *iter;
enditer = vbank.endLoc(vn->getSize(),vn->getAddr());
do {
vn = *iter++;
if (vn->isFree()) continue;
vnflags = vn->getFlags();
if (vn->mapentry != (SymbolEntry *)0) { uint4 localMask = mask & ~Varnode::mapped; uint4 localFlags = fl & localMask;
if ((vnflags & localMask) != localFlags) {
updateoccurred = true;
vn->setFlags(localFlags);
vn->clearFlags((~localFlags)&localMask);
}
}
else if ((vnflags & mask) != fl) { updateoccurred = true;
vn->setFlags(fl);
vn->clearFlags((~fl)&mask);
}
if (ct != (Datatype *)0) {
if (vn->updateType(ct,false,false))
updateoccurred = true;
vn->getHigh()->finalizeDatatype(ct); }
} while(iter != enditer);
return updateoccurred;
}
void Funcdata::clearSymbolLinks(HighVariable *high)
{
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
vn->mapentry = (SymbolEntry *)0;
vn->clearFlags(Varnode::namelock | Varnode::typelock | Varnode::mapped);
}
}
void Funcdata::remapVarnode(Varnode *vn,Symbol *sym,const Address &usepoint)
{
clearSymbolLinks(vn->getHigh());
SymbolEntry *entry = localmap->remapSymbol(sym, vn->getAddr(), usepoint);
vn->setSymbolEntry(entry);
}
void Funcdata::remapDynamicVarnode(Varnode *vn,Symbol *sym,const Address &usepoint,uint8 hash)
{
clearSymbolLinks(vn->getHigh());
SymbolEntry *entry = localmap->remapSymbolDynamic(sym, hash, usepoint);
vn->setSymbolEntry(entry);
}
Symbol *Funcdata::linkSymbol(Varnode *vn)
{
HighVariable *high = vn->getHigh();
SymbolEntry *entry;
uint4 fl = 0;
Symbol *sym = high->getSymbol();
if (sym != (Symbol *)0) return sym;
Address usepoint = vn->getUsePoint(*this);
entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, fl);
if (entry != (SymbolEntry *) 0) {
sym = handleSymbolConflict(entry, vn);
}
else { if (!vn->isPersist()) { entry = localmap->addSymbol("", high->getType(), vn->getAddr(), usepoint);
sym = entry->getSymbol();
vn->setSymbolEntry(entry);
}
}
return sym;
}
Symbol *Funcdata::linkSymbolReference(Varnode *vn)
{
PcodeOp *op = vn->loneDescend();
Varnode *in0 = op->getIn(0);
TypePointer *ptype = (TypePointer *)in0->getHigh()->getType();
if (ptype->getMetatype() != TYPE_PTR) return (Symbol *)0;
TypeSpacebase *sb = (TypeSpacebase *)ptype->getPtrTo();
if (sb->getMetatype() != TYPE_SPACEBASE)
return (Symbol *)0;
Scope *scope = sb->getMap();
Address addr = sb->getAddress(vn->getOffset(),in0->getSize(),op->getAddr());
if (addr.isInvalid())
throw LowlevelError("Unable to generate proper address from spacebase");
SymbolEntry *entry = scope->queryContainer(addr,1,Address());
if (entry == (SymbolEntry *)0)
return (Symbol *)0;
int4 off = (int4)(addr.getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
vn->setSymbolReference(entry, off);
return entry->getSymbol();
}
Varnode *Funcdata::findLinkedVarnode(SymbolEntry *entry) const
{
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), entry->getHash());
if (vn == (Varnode *)0 || vn->isAnnotation())
return (Varnode *)0;
return vn;
}
VarnodeLocSet::const_iterator iter,enditer;
Address usestart = entry->getFirstUseAddress();
enditer = vbank.endLoc(entry->getSize(),entry->getAddr());
if (usestart.isInvalid()) {
iter = vbank.beginLoc(entry->getSize(),entry->getAddr());
if (iter == enditer)
return (Varnode *)0;
Varnode *vn = *iter;
if (!vn->isAddrTied())
return (Varnode *)0; return vn;
}
iter = vbank.beginLoc(entry->getSize(),entry->getAddr(),usestart,~((uintm)0));
for(;iter!=enditer;++iter) {
Varnode *vn = *iter;
Address usepoint = vn->getUsePoint(*this);
if (entry->inUse(usepoint))
return vn;
}
return (Varnode *)0;
}
void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) const
{
if (entry->isDynamic()) {
DynamicHash dhash;
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
if (vn != (Varnode *)0)
res.push_back(vn);
}
else {
VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
VarnodeLocSet::const_iterator enditer = endLoc(entry->getSize(),entry->getAddr());
for(;iter!=enditer;++iter) {
Varnode *vn = *iter;
Address addr = vn->getUsePoint(*this);
if (entry->inUse(addr)) {
res.push_back(vn);
}
}
}
}
void Funcdata::buildDynamicSymbol(Varnode *vn)
{
if (vn->isTypeLock()||vn->isNameLock())
throw RecovError("Trying to build dynamic symbol on locked varnode");
if (!isHighOn())
throw RecovError("Cannot create dynamic symbols until decompile has completed");
HighVariable *high = vn->getHigh();
if (high->getSymbol() != (Symbol *)0)
return; DynamicHash dhash;
dhash.uniqueHash(vn,this); if (dhash.getHash() == 0)
throw RecovError("Unable to find unique hash for varnode");
Symbol *sym = localmap->addDynamicSymbol("",high->getType(),dhash.getAddress(),dhash.getHash());
vn->setSymbolEntry(sym->getFirstWholeMap());
}
bool Funcdata::attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash)
{
Symbol *sym = entry->getSymbol();
if (sym->getScope() != localmap)
throw LowlevelError("Cannot currently have a dynamic symbol outside the local scope");
dhash.clear();
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
if (vn == (Varnode *)0) return false;
if (entry->getSymbol()->getCategory() == 1) { if (vn->mapentry != entry) { vn->setSymbolEntry(entry);
return true;
}
}
else if (entry->getSize() == vn->getSize()) {
if (vn->setSymbolProperties(entry))
return true;
}
return false;
}
bool Funcdata::attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash)
{
dhash.clear();
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
if (vn == (Varnode *)0)
return false;
if (vn->getSymbolEntry() == entry) return false; Symbol *sym = entry->getSymbol();
if (sym->getCategory() == 1) { vn->setSymbolEntry(entry);
return true;
}
if (vn->getSize() != entry->getSize()) {
ostringstream s;
s << "Unable to use symbol ";
if (!sym->isNameUndefined())
s << sym->getName() << ' ';
s << ": Size does not match variable it labels";
warningHeader(s.str());
return false;
}
if (vn->isImplied()) { Varnode *newvn = (Varnode *)0;
if (vn->isWritten() && (vn->getDef()->code() == CPUI_CAST))
newvn = vn->getDef()->getIn(0);
else {
PcodeOp *castop = vn->loneDescend();
if ((castop != (PcodeOp *)0)&&(castop->code() == CPUI_CAST))
newvn = castop->getOut();
}
if ((newvn != (Varnode *)0)&&(newvn->isExplicit()))
vn = newvn; }
vn->setSymbolEntry(entry);
if (!sym->isTypeLocked()) { localmap->retypeSymbol(sym,vn->getType()); }
else if (sym->getType() != vn->getType()) {
ostringstream s;
s << "Unable to use type for symbol " << sym->getName();
warningHeader(s.str());
localmap->retypeSymbol(sym,vn->getType()); }
return true;
}
void Funcdata::totalReplace(Varnode *vn,Varnode *newvn)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
int4 i;
iter = vn->beginDescend();
while(iter != vn->endDescend()) {
op = *iter++; i = op->getSlot(vn);
opSetInput(op,newvn,i);
}
}
void Funcdata::totalReplaceConstant(Varnode *vn,uintb val)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
PcodeOp *copyop = (PcodeOp *)0;
Varnode *newrep;
int4 i;
iter = vn->beginDescend();
while(iter != vn->endDescend()) {
op = *iter++; i = op->getSlot(vn);
if (op->isMarker()) { if (copyop == (PcodeOp *)0) {
if (vn->isWritten()) {
copyop = newOp(1,vn->getDef()->getAddr());
opSetOpcode(copyop,CPUI_COPY);
newrep = newUniqueOut(vn->getSize(),copyop);
opSetInput(copyop,newConstant(vn->getSize(),val),0);
opInsertAfter(copyop,vn->getDef());
}
else {
BlockBasic *bb = (BlockBasic *)getBasicBlocks().getBlock(0);
copyop = newOp(1,bb->getStart());
opSetOpcode(copyop,CPUI_COPY);
newrep = newUniqueOut(vn->getSize(),copyop);
opSetInput(copyop,newConstant(vn->getSize(),val),0);
opInsertBegin(copyop,bb);
}
}
else
newrep = copyop->getOut();
}
else
newrep = newConstant(vn->getSize(),val);
opSetInput(op,newrep,i);
}
}
void Funcdata::splitUses(Varnode *vn)
{
PcodeOp *op = vn->getDef();
Varnode *newvn;
PcodeOp *newop,*useop;
list<PcodeOp *>::iterator iter;
int4 slot;
iter = vn->descend.begin();
if (iter == vn->descend.end()) return; useop = *iter++;
if (iter == vn->descend.end()) return; for(;;) {
slot = useop->getSlot(vn); newop = newOp(op->numInput(),op->getAddr());
newvn = newVarnode(vn->getSize(),vn->getAddr(),vn->getType());
opSetOutput(newop,newvn);
opSetOpcode(newop,op->code());
for(int4 i=0;i<op->numInput();++i)
opSetInput(newop,op->getIn(i),i);
opSetInput(useop,newvn,slot);
opInsertBefore(newop,op);
if (iter == vn->descend.end()) break;
useop = *iter++;
}
}
Address Funcdata::findDisjointCover(Varnode *vn,int4 &sz)
{
Address addr = vn->getAddr();
Address endaddr = addr + vn->getSize();
VarnodeLocSet::const_iterator iter = vn->lociter;
while(iter != beginLoc()) {
--iter;
Varnode *curvn = *iter;
Address curEnd = curvn->getAddr() + curvn->getSize();
if (curEnd <= addr) break;
addr = curvn->getAddr();
}
iter = vn->lociter;
while(iter != endLoc()) {
Varnode *curvn = *iter;
++iter;
if (endaddr <= curvn->getAddr()) break;
endaddr = curvn->getAddr() + curvn->getSize();
}
sz = (int4)(endaddr.getOffset() - addr.getOffset());
return addr;
}
void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
{
Scope *scope = entry->getSymbol()->getScope();
for(int4 i=0;i<list.size();++i) {
Varnode *vn = list[i];
if (i+1<list.size() && list[i+1]->getAddr() == vn->getAddr())
continue;
Address usepoint = vn->getUsePoint(*this);
SymbolEntry *overlapEntry = scope->findContainer(vn->getAddr(), vn->getSize(), usepoint);
if (overlapEntry == (SymbolEntry *)0) {
int4 diff = (int4)(vn->getOffset() - entry->getAddr().getOffset());
ostringstream s;
s << entry->getSymbol()->getName() << '_' << diff;
scope->addSymbol(s.str(),vn->getHigh()->getType(),vn->getAddr(),usepoint);
}
}
}
void Funcdata::mapGlobals(void)
{
SymbolEntry *entry;
VarnodeLocSet::const_iterator iter,enditer;
Varnode *vn,*maxvn;
Datatype *ct;
uint4 fl;
vector<Varnode *> uncoveredVarnodes;
bool inconsistentuse = false;
iter = vbank.beginLoc(); enditer = vbank.endLoc();
while(iter != enditer) {
vn = *iter++;
if (vn->isFree()) continue;
if (!vn->isPersist()) continue; if (vn->getSymbolEntry() != (SymbolEntry *)0) continue;
maxvn = vn;
Address addr = vn->getAddr();
Address endaddr = addr + vn->getSize();
uncoveredVarnodes.clear();
while(iter != enditer) {
vn = *iter;
if (!vn->isPersist()) break;
if (vn->getAddr() < endaddr) {
if (vn->getAddr() != addr && vn->getSymbolEntry() == (SymbolEntry *)0)
uncoveredVarnodes.push_back(vn);
endaddr = vn->getAddr() + vn->getSize();
if (vn->getSize() > maxvn->getSize())
maxvn = vn;
++iter;
}
else
break;
}
if ((maxvn->getAddr() == addr)&&(addr+maxvn->getSize() == endaddr))
ct = maxvn->getHigh()->getType();
else
ct = glb->types->getBase(endaddr.getOffset()-addr.getOffset(),TYPE_UNKNOWN);
fl = 0;
Address usepoint;
entry = localmap->queryProperties(addr,1,usepoint,fl);
if (entry==(SymbolEntry *)0) {
Scope *discover = localmap->discoverScope(addr,ct->getSize(),usepoint);
if (discover == (Scope *)0)
throw LowlevelError("Could not discover scope");
int4 index = 0;
string symbolname = discover->buildVariableName(addr,usepoint,ct,index,
Varnode::addrtied|Varnode::persist);
discover->addSymbol(symbolname,ct,addr,usepoint);
}
else if ((addr.getOffset()+ct->getSize())-1 > (entry->getAddr().getOffset()+entry->getSize()) -1) {
inconsistentuse = true;
if (!uncoveredVarnodes.empty()) coverVarnodes(entry, uncoveredVarnodes);
}
}
if (inconsistentuse)
warningHeader("Globals starting with '_' overlap smaller symbols at the same address");
}
bool Funcdata::isAlternatePathValid(const Varnode *vn,uint4 flags)
{
if ((flags & (traverse_indirect | traverse_indirectalt)) == traverse_indirect)
return true; if ((flags & (traverse_indirect | traverse_indirectalt)) == traverse_indirectalt)
return false; if ((flags & traverse_actionalt) != 0)
return true; if (vn->loneDescend() == (PcodeOp*)0) return false;
const PcodeOp *op = vn->getDef();
if (op == (PcodeOp*)0) return true;
return !op->isMarker(); }
bool Funcdata::checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,uint4 fl,const ParamTrial &trial) const
{
int4 j = op->getSlot(vn);
if (j<=0) return false; FuncCallSpecs *fc = getCallSpecs(op);
FuncCallSpecs *matchfc = getCallSpecs(opmatch);
if (op->code() == opmatch->code()) {
bool isdirect = (opmatch->code() == CPUI_CALL);
if ((isdirect&&(matchfc->getEntryAddress() == fc->getEntryAddress())) ||
((!isdirect)&&(op->getIn(0) == opmatch->getIn(0)))) { const ParamTrial &curtrial( fc->getActiveInput()->getTrialForInputVarnode(j) );
if (curtrial.getAddress() == trial.getAddress()) { if (op->getParent() == opmatch->getParent()) {
if (opmatch->getSeqNum().getOrder() < op->getSeqNum().getOrder())
return true; }
else
return true; }
}
}
if (fc->isInputActive()) {
const ParamTrial &curtrial( fc->getActiveInput()->getTrialForInputVarnode(j) );
if (curtrial.isChecked()) {
if (curtrial.isActive())
return false;
}
else if (isAlternatePathValid(vn,fl))
return false;
return true;
}
return false;
}
bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const
{
vector<TraverseNode> varlist;
list<PcodeOp *>::const_iterator iter;
const Varnode *vn,*subvn;
const PcodeOp *op;
int4 i;
bool res = true;
varlist.reserve(64);
invn->setMark(); varlist.emplace_back(invn,mainFlags);
for(i=0;i < varlist.size();++i) {
vn = varlist[i].vn;
uint4 baseFlags = varlist[i].flags;
for(iter=vn->descend.begin();iter!=vn->descend.end();++iter) {
op = *iter;
if (op == opmatch) {
if (op->getIn(trial.getSlot())==vn) continue;
}
uint4 curFlags = baseFlags;
switch(op->code()) {
case CPUI_BRANCH: case CPUI_CBRANCH:
case CPUI_BRANCHIND:
case CPUI_LOAD:
case CPUI_STORE:
res = false;
break;
case CPUI_CALL:
case CPUI_CALLIND:
if (checkCallDoubleUse(opmatch,op,vn,curFlags,trial)) continue;
res = false;
break;
case CPUI_INDIRECT:
curFlags |= Funcdata::traverse_indirectalt;
break;
case CPUI_COPY:
if ((op->getOut()->getSpace()->getType()!=IPTR_INTERNAL)&&!op->isIncidentalCopy()&&!vn->isIncidentalCopy()) {
curFlags |= Funcdata::traverse_actionalt;
}
break;
case CPUI_RETURN:
if (opmatch->code()==CPUI_RETURN) { if (op->getIn(trial.getSlot())==vn) continue;
}
else if (activeoutput != (ParamActive *)0) { if (op->getIn(0) != vn) { if (!isAlternatePathValid(vn,curFlags))
continue; }
}
res = false;
break;
case CPUI_MULTIEQUAL:
case CPUI_PIECE:
case CPUI_SUBPIECE:
case CPUI_INT_SEXT:
case CPUI_INT_ZEXT:
case CPUI_CAST:
break;
default:
curFlags |= Funcdata::traverse_actionalt;
break;
}
if (!res) break;
subvn = op->getOut();
if (subvn != (const Varnode *)0) {
if (subvn->isPersist()) {
res = false;
break;
}
if (!subvn->isMark()) {
varlist.emplace_back(subvn,curFlags);
subvn->setMark();
}
}
}
if (!res) break;
}
for(i=0;i<varlist.size();++i)
varlist[i].vn->clearMark();
return res;
}
bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
const PcodeOp *op,ParamTrial &trial,uint4 mainFlags) const
{
int4 i;
if (maxlevel==0) return false;
if (!invn->isWritten()) {
if (!invn->isInput()) return false;
if (!invn->isTypeLock()) return false;
return onlyOpUse(invn,op,trial,mainFlags); }
const PcodeOp *def = invn->getDef();
switch(def->code()) {
case CPUI_INDIRECT:
if (def->isIndirectCreation())
return false;
return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,mainFlags | Funcdata::traverse_indirect);
case CPUI_MULTIEQUAL:
if (def->isMark()) return false; def->setMark(); for(i=0;i<def->numInput();++i) {
if (ancestorOpUse(maxlevel-1,def->getIn(i),op,trial, mainFlags)) {
def->clearMark();
return true;
}
}
def->clearMark();
return false;
case CPUI_COPY:
if ((invn->getSpace()->getType()==IPTR_INTERNAL)||def->isIncidentalCopy()||def->getIn(0)->isIncidentalCopy()) {
return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,mainFlags);
}
break;
case CPUI_PIECE:
return ancestorOpUse(maxlevel-1,def->getIn(1),op,trial,mainFlags);
case CPUI_SUBPIECE:
if (def->getIn(1)->getOffset()==0) {
const Varnode *vn = def->getIn(0);
if (vn->isWritten()) {
const PcodeOp *remop = vn->getDef();
if ((remop->code()==CPUI_INT_REM)||(remop->code()==CPUI_INT_SREM))
trial.setRemFormed();
}
}
break;
case CPUI_CALL:
case CPUI_CALLIND:
return false; default:
break;
}
return onlyOpUse(invn,op,trial,mainFlags); }
bool AncestorRealistic::checkConditionalExe(State &state)
{
const BlockBasic *bl = state.op->getParent();
if (bl->sizeIn() != 2)
return false;
const FlowBlock *solidBlock = bl->getIn(state.getSolidSlot());
if (solidBlock->sizeOut() != 1)
return false;
return true;
}
int4 AncestorRealistic::enterNode(State &state)
{
if (state.vn->isMark()) return pop_success;
if (!state.vn->isWritten()) {
if (state.vn->isInput()) {
if (state.vn->isUnaffected()) return pop_fail;
if (state.vn->isPersist()) return pop_success; if (!state.vn->isDirectWrite()) return pop_fail;
}
return pop_success; }
mark(state.vn); PcodeOp *op = state.vn->getDef();
switch(op->code()) {
case CPUI_INDIRECT:
if (op->isIndirectCreation()) { trial->setIndCreateFormed();
if (op->getIn(0)->isIndirectZero()) return pop_failkill; return pop_success; }
if (!op->isIndirectStore()) { if (op->getOut()->isReturnAddress()) return pop_fail; if (trial->isKilledByCall()) return pop_fail; }
stateStack.push_back(State(op,0));
return enter_node; case CPUI_SUBPIECE:
if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL
|| op->isIncidentalCopy() || op->getIn(0)->isIncidentalCopy()
|| (op->getOut()->overlap(*op->getIn(0)) == (int4)op->getIn(1)->getOffset())) {
stateStack.push_back(State(op,0));
return enter_node; }
do {
Varnode *vn = op->getIn(0);
if ((!vn->isMark())&&(vn->isInput())) {
if (vn->isUnaffected()||(!vn->isDirectWrite()))
return pop_fail;
}
op = vn->getDef();
} while((op!=(PcodeOp *)0)&&((op->code() == CPUI_COPY)||(op->code()==CPUI_SUBPIECE)));
return pop_solid; case CPUI_COPY:
if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL
|| op->isIncidentalCopy() || op->getIn(0)->isIncidentalCopy()
|| (op->getOut()->getAddr() == op->getIn(0)->getAddr())) {
stateStack.push_back(State(op,0));
return enter_node; }
do {
Varnode *vn = op->getIn(0);
if ((!vn->isMark())&&(vn->isInput())) {
if (!vn->isDirectWrite())
return pop_fail;
}
op = vn->getDef();
} while((op!=(PcodeOp *)0)&&((op->code() == CPUI_COPY)||(op->code()==CPUI_SUBPIECE)));
return pop_solid; case CPUI_MULTIEQUAL:
multiDepth += 1;
stateStack.push_back(State(op,0));
return enter_node; case CPUI_PIECE:
if (state.vn->getSize() > trial->getSize() && state.vn->getSpace()->getType() != IPTR_SPACEBASE)
return pop_fail;
return pop_solid;
default:
return pop_solid; }
}
int4 AncestorRealistic::uponPop(State &state,int4 pop_command)
{
if (state.op->code() == CPUI_MULTIEQUAL) { State &prevstate( stateStack[ stateStack.size()-2 ]); if (pop_command == pop_fail) { multiDepth -= 1;
stateStack.pop_back();
return pop_command;
}
else if ((pop_command == pop_solid)&&(multiDepth == 1)&&(state.op->numInput()==2))
prevstate.markSolid(state.slot); else if (pop_command == pop_failkill)
prevstate.markKill(); state.slot += 1; if (state.slot == state.op->numInput()) { if (prevstate.seenSolid()) { pop_command = pop_success; if (prevstate.seenKill()) { if (allowFailingPath) {
if (!checkConditionalExe(state)) pop_command = pop_fail; else
trial->setCondExeEffect(); }
else
pop_command = pop_fail;
}
}
else if (prevstate.seenKill()) pop_command = pop_failkill; else
pop_command = pop_success; multiDepth -= 1;
stateStack.pop_back();
return pop_command;
}
state.vn = state.op->getIn(state.slot); return enter_node;
}
else {
stateStack.pop_back();
return pop_command;
}
}
bool AncestorRealistic::execute(PcodeOp *op,int4 slot,ParamTrial *t,bool allowFail)
{
trial = t;
allowFailingPath = allowFail;
markedVn.clear(); stateStack.clear();
multiDepth = 0;
if (op->getIn(slot)->isInput()) {
if (!trial->hasCondExeEffect()) return false;
}
int4 command = enter_node;
stateStack.push_back(State(op,slot)); while(!stateStack.empty()) { switch(command) {
case enter_node:
command = enterNode(stateStack.back());
break;
case pop_success:
case pop_solid:
case pop_fail:
case pop_failkill:
command = uponPop(stateStack.back(),command);
break;
}
}
for(int4 i=0;i<markedVn.size();++i) markedVn[i]->clearMark();
if ((command != pop_success)&&(command != pop_solid))
return false;
return true;
}