#include "translate.hh"
void TruncationTag::restoreXml(const Element *el)
{
spaceName = el->getAttributeValue("space");
istringstream s(el->getAttributeValue("size"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> size;
}
SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind,int4 sz,
AddrSpace *base,int4 dl)
: AddrSpace(m,t,IPTR_SPACEBASE,nm,sz,base->getWordSize(),ind,0,dl)
{
contain = base;
hasbaseregister = false; isNegativeStack = true; }
SpacebaseSpace::SpacebaseSpace(AddrSpaceManager *m,const Translate *t)
: AddrSpace(m,t,IPTR_SPACEBASE)
{
hasbaseregister = false;
isNegativeStack = true;
setFlags(programspecific);
}
void SpacebaseSpace::setBaseRegister(const VarnodeData &data,int4 truncSize,bool stackGrowth)
{
if (hasbaseregister) {
if ((baseloc != data)||(isNegativeStack != stackGrowth))
throw LowlevelError("Attempt to assign more than one base register to space: "+getName());
}
hasbaseregister = true;
isNegativeStack = stackGrowth;
baseOrig = data;
baseloc = data;
if (truncSize != baseloc.size) {
if (baseloc.space->isBigEndian())
baseloc.offset += (baseloc.size - truncSize);
baseloc.size = truncSize;
}
}
int4 SpacebaseSpace::numSpacebase(void) const
{
return hasbaseregister ? 1 : 0;
}
const VarnodeData &SpacebaseSpace::getSpacebase(int4 i) const
{
if ((!hasbaseregister)||(i!=0))
throw LowlevelError("No base register specified for space: "+getName());
return baseloc;
}
const VarnodeData &SpacebaseSpace::getSpacebaseFull(int4 i) const
{
if ((!hasbaseregister)||(i!=0))
throw LowlevelError("No base register specified for space: "+getName());
return baseOrig;
}
void SpacebaseSpace::saveXml(ostream &s) const
{
s << "<space_base";
saveBasicAttributes(s);
a_v(s,"contain",contain->getName());
s << "/>\n";
}
void SpacebaseSpace::restoreXml(const Element *el)
{
AddrSpace::restoreXml(el); contain = getManager()->getSpaceByName(el->getAttributeValue("contain"));
}
Address JoinRecord::getEquivalentAddress(uintb offset,int4 &pos) const
{
if (offset < unified.offset)
return Address(); int4 smallOff = (int4)(offset - unified.offset);
if (pieces[0].space->isBigEndian()) {
for(pos=0;pos<pieces.size();++pos) {
int4 pieceSize = pieces[pos].size;
if (smallOff < pieceSize)
break;
smallOff -= pieceSize;
}
if (pos == pieces.size())
return Address(); }
else {
for (pos = pieces.size() - 1; pos >= 0; --pos) {
int4 pieceSize = pieces[pos].size;
if (smallOff < pieceSize)
break;
smallOff -= pieceSize;
}
if (pos < 0)
return Address(); }
return Address(pieces[pos].space,pieces[pos].offset + smallOff);
}
bool JoinRecord::operator<(const JoinRecord &op2) const
{
if (unified.size != op2.unified.size) return (unified.size < op2.unified.size);
int4 i=0;
for(;;) {
if (pieces.size()==i) {
return (op2.pieces.size()>i); }
if (op2.pieces.size()==i) return false; if (pieces[i] != op2.pieces[i])
return (pieces[i] < op2.pieces[i]);
i += 1;
}
}
AddrSpaceManager::AddrSpaceManager(void)
{
defaultcodespace = (AddrSpace *)0;
defaultdataspace = (AddrSpace *)0;
constantspace = (AddrSpace *)0;
iopspace = (AddrSpace *)0;
fspecspace = (AddrSpace *)0;
joinspace = (AddrSpace *)0;
stackspace = (AddrSpace *)0;
uniqspace = (AddrSpace *)0;
joinallocate = 0;
}
AddrSpace *AddrSpaceManager::restoreXmlSpace(const Element *el,const Translate *trans)
{
AddrSpace *res;
const string &tp(el->getName());
if (tp == "space_base")
res = new SpacebaseSpace(this,trans);
else if (tp == "space_unique")
res = new UniqueSpace(this,trans);
else if (tp == "space_other")
res = new OtherSpace(this,trans);
else if (tp == "space_overlay")
res = new OverlaySpace(this,trans);
else
res = new AddrSpace(this,trans,IPTR_PROCESSOR);
res->restoreXml(el);
return res;
}
void AddrSpaceManager::restoreXmlSpaces(const Element *el,const Translate *trans)
{
insertSpace(new ConstantSpace(this,trans));
string defname(el->getAttributeValue("defaultspace"));
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
while(iter!=list.end()) {
AddrSpace *spc = restoreXmlSpace(*iter,trans);
insertSpace(spc);
++iter;
}
AddrSpace *spc = getSpaceByName(defname);
if (spc == (AddrSpace *)0)
throw LowlevelError("Bad 'defaultspace' attribute: "+defname);
setDefaultCodeSpace(spc->getIndex());
}
void AddrSpaceManager::setDefaultCodeSpace(int4 index)
{
if (defaultcodespace != (AddrSpace *)0)
throw LowlevelError("Default space set multiple times");
if (baselist.size()<=index || baselist[index] == (AddrSpace *)0)
throw LowlevelError("Bad index for default space");
defaultcodespace = baselist[index];
defaultdataspace = defaultcodespace; }
void AddrSpaceManager::setDefaultDataSpace(int4 index)
{
if (defaultcodespace == (AddrSpace *)0)
throw LowlevelError("Default data space must be set after the code space");
if (baselist.size()<=index || baselist[index] == (AddrSpace *)0)
throw LowlevelError("Bad index for default data space");
defaultdataspace = baselist[index];
}
void AddrSpaceManager::setReverseJustified(AddrSpace *spc)
{
spc->setFlags(AddrSpace::reverse_justification);
}
void AddrSpaceManager::insertSpace(AddrSpace *spc)
{
bool nameTypeMismatch = false;
bool duplicateName = false;
bool duplicateId = false;
switch(spc->getType()) {
case IPTR_CONSTANT:
if (spc->getName() != ConstantSpace::NAME)
nameTypeMismatch = true;
if (spc->index != ConstantSpace::INDEX)
throw LowlevelError("const space must be assigned index 0");
constantspace = spc;
break;
case IPTR_INTERNAL:
if (spc->getName() != UniqueSpace::NAME)
nameTypeMismatch = true;
if (uniqspace != (AddrSpace *)0)
duplicateName = true;
uniqspace = spc;
break;
case IPTR_FSPEC:
if (spc->getName() != "fspec")
nameTypeMismatch = true;
if (fspecspace != (AddrSpace *)0)
duplicateName = true;
fspecspace = spc;
break;
case IPTR_JOIN:
if (spc->getName() != JoinSpace::NAME)
nameTypeMismatch = true;
if (joinspace != (AddrSpace *)0)
duplicateName = true;
joinspace = spc;
break;
case IPTR_IOP:
if (spc->getName() != "iop")
nameTypeMismatch = true;
if (iopspace != (AddrSpace *)0)
duplicateName = true;
iopspace = spc;
break;
case IPTR_SPACEBASE:
if (spc->getName() == "stack") {
if (stackspace != (AddrSpace *)0)
duplicateName = true;
stackspace = spc;
}
case IPTR_PROCESSOR:
if (spc->isOverlay()) { OverlaySpace *ospc = (OverlaySpace *)spc;
ospc->getBaseSpace()->setFlags(AddrSpace::overlaybase); }
else if (spc->isOtherSpace()) {
if (spc->index != OtherSpace::INDEX)
throw LowlevelError("OTHER space must be assigned index 1");
}
break;
}
if (baselist.size() <= spc->index)
baselist.resize(spc->index+1, (AddrSpace *)0);
duplicateId = baselist[spc->index] != (AddrSpace *)0;
if (!nameTypeMismatch && !duplicateName && !duplicateId) {
duplicateName = !name2Space.insert(pair<string,AddrSpace *>(spc->getName(),spc)).second;
}
if (nameTypeMismatch || duplicateName || duplicateId) {
if (spc->refcount == 0)
delete spc;
spc = (AddrSpace *)0;
}
if (nameTypeMismatch)
throw LowlevelError("Space "+spc->getName()+" was initialized with wrong type");
if (duplicateName)
throw LowlevelError("Space "+spc->getName()+" was initialized more than once");
if (duplicateId)
throw LowlevelError("Space "+spc->getName()+" was assigned as id duplicating: "+baselist[spc->index]->getName());
baselist[spc->index] = spc;
spc->refcount += 1;
assignShortcut(spc);
}
void AddrSpaceManager::copySpaces(const AddrSpaceManager *op2)
{ for(int4 i=0;i<op2->baselist.size();++i) {
AddrSpace *spc = op2->baselist[i];
if (spc != (AddrSpace *)0)
insertSpace(spc);
}
setDefaultCodeSpace(op2->getDefaultCodeSpace()->getIndex());
setDefaultDataSpace(op2->getDefaultDataSpace()->getIndex());
}
void AddrSpaceManager::addSpacebasePointer(SpacebaseSpace *basespace,const VarnodeData &ptrdata,int4 truncSize,bool stackGrowth)
{
basespace->setBaseRegister(ptrdata,truncSize,stackGrowth);
}
void AddrSpaceManager::insertResolver(AddrSpace *spc,AddressResolver *rsolv)
{
int4 ind = spc->getIndex();
while(resolvelist.size() <= ind)
resolvelist.push_back((AddressResolver *)0);
if (resolvelist[ind] != (AddressResolver *)0)
delete resolvelist[ind];
resolvelist[ind] = rsolv;
}
void AddrSpaceManager::setInferPtrBounds(const Range &range)
{
range.getSpace()->pointerLowerBound = range.getFirst();
range.getSpace()->pointerUpperBound = range.getLast();
}
AddrSpaceManager::~AddrSpaceManager(void)
{
for(vector<AddrSpace *>::iterator iter=baselist.begin();iter!=baselist.end();++iter) {
AddrSpace *spc = *iter;
if (spc == (AddrSpace *)0) continue;
if (spc->refcount > 1)
spc->refcount -= 1;
else
delete spc;
}
for(int4 i=0;i<resolvelist.size();++i) {
if (resolvelist[i] != (AddressResolver *)0)
delete resolvelist[i];
}
for(int4 i=0;i<splitlist.size();++i)
delete splitlist[i]; }
void AddrSpaceManager::assignShortcut(AddrSpace *spc)
{
if (spc->shortcut != ' ') { shortcut2Space.insert(pair<int4,AddrSpace *>(spc->shortcut,spc));
return;
}
char shortcut;
switch(spc->getType()) {
case IPTR_CONSTANT:
shortcut = '#';
break;
case IPTR_PROCESSOR:
if (spc->getName() == "register")
shortcut = '%';
else
shortcut = spc->getName()[0];
break;
case IPTR_SPACEBASE:
shortcut = 's';
break;
case IPTR_INTERNAL:
shortcut = 'u';
break;
case IPTR_FSPEC:
shortcut = 'f';
break;
case IPTR_JOIN:
shortcut = 'j';
break;
case IPTR_IOP:
shortcut = 'i';
break;
default:
shortcut = 'x';
break;
}
if (shortcut >= 'A' && shortcut <= 'Z')
shortcut += 0x20;
int4 collisionCount = 0;
while(!shortcut2Space.insert(pair<int4,AddrSpace *>(shortcut,spc)).second) {
collisionCount += 1;
if (collisionCount >26) {
spc->shortcut = 'z';
return;
}
shortcut += 1;
if (shortcut < 'a' || shortcut > 'z')
shortcut = 'a';
}
spc->shortcut = (char)shortcut;
}
void AddrSpaceManager::markNearPointers(AddrSpace *spc,int4 size)
{
spc->setFlags(AddrSpace::has_nearpointers);
if (spc->minimumPointerSize == 0 && spc->addressSize != size)
spc->minimumPointerSize = size;
}
AddrSpace *AddrSpaceManager::getSpaceByName(const string &nm) const
{
map<string,AddrSpace *>::const_iterator iter = name2Space.find(nm);
if (iter == name2Space.end())
return (AddrSpace *)0;
return (*iter).second;
}
AddrSpace *AddrSpaceManager::getSpaceByShortcut(char sc) const
{
map<int4,AddrSpace *>::const_iterator iter;
iter = shortcut2Space.find(sc);
if (iter == shortcut2Space.end())
return (AddrSpace *)0;
return (*iter).second;
}
Address AddrSpaceManager::resolveConstant(AddrSpace *spc,uintb val,int4 sz,const Address &point,uintb &fullEncoding) const
{
int4 ind = spc->getIndex();
if (ind < resolvelist.size()) {
AddressResolver *resolve = resolvelist[ind];
if (resolve != (AddressResolver *)0)
return resolve->resolve(val,sz,point,fullEncoding);
}
fullEncoding = val;
val = AddrSpace::addressToByte(val,spc->getWordSize());
val = spc->wrapOffset(val);
return Address(spc,val);
}
AddrSpace *AddrSpaceManager::getNextSpaceInOrder(AddrSpace *spc) const
{
if (spc == (AddrSpace *)0) {
return baselist[0];
}
if (spc == (AddrSpace *) ~((uintp)0)) {
return (AddrSpace *)0;
}
int4 index = spc->getIndex() + 1;
while (index < baselist.size()) {
AddrSpace *res = baselist[index];
if (res != (AddrSpace *)0)
return res;
index += 1;
}
return (AddrSpace *) ~((uintp)0);
}
JoinRecord *AddrSpaceManager::findAddJoin(const vector<VarnodeData> &pieces,uint4 logicalsize)
{ if (pieces.size() == 0)
throw LowlevelError("Cannot create a join without pieces");
if ((pieces.size()==1)&&(logicalsize==0))
throw LowlevelError("Cannot create a single piece join without a logical size");
uint4 totalsize;
if (logicalsize != 0) {
if (pieces.size() != 1)
throw LowlevelError("Cannot specify logical size for multiple piece join");
totalsize = logicalsize;
}
else {
totalsize = 0;
for(int4 i=0;i<pieces.size();++i) totalsize += pieces[i].size;
if (totalsize == 0)
throw LowlevelError("Cannot create a zero size join");
}
JoinRecord testnode;
testnode.pieces = pieces;
testnode.unified.size = totalsize;
set<JoinRecord *,JoinRecordCompare>::const_iterator iter;
iter = splitset.find(&testnode);
if (iter != splitset.end()) return *iter;
JoinRecord *newjoin = new JoinRecord();
newjoin->pieces = pieces;
uint4 roundsize = (totalsize + 15) & ~((uint4)0xf);
newjoin->unified.space = joinspace;
newjoin->unified.offset = joinallocate;
joinallocate += roundsize;
newjoin->unified.size = totalsize;
splitset.insert(newjoin);
splitlist.push_back(newjoin);
return splitlist.back();
}
JoinRecord *AddrSpaceManager::findJoinInternal(uintb offset) const
{
int4 min=0;
int4 max=splitlist.size()-1;
while(min<=max) { int4 mid = (min+max)/2;
JoinRecord *rec = splitlist[mid];
uintb val = rec->unified.offset;
if (val + rec->unified.size <= offset)
min = mid + 1;
else if (val > offset)
max = mid - 1;
else
return rec;
}
return (JoinRecord *)0;
}
JoinRecord *AddrSpaceManager::findJoin(uintb offset) const
{
int4 min=0;
int4 max=splitlist.size()-1;
while(min<=max) { int4 mid = (min+max)/2;
JoinRecord *rec = splitlist[mid];
uintb val = rec->unified.offset;
if (val == offset) return rec;
if (val < offset)
min = mid + 1;
else
max = mid - 1;
}
throw LowlevelError("Unlinked join address");
}
void AddrSpaceManager::setDeadcodeDelay(AddrSpace *spc,int4 delaydelta)
{
spc->deadcodedelay = delaydelta;
}
void AddrSpaceManager::truncateSpace(const TruncationTag &tag)
{
AddrSpace *spc = getSpaceByName(tag.getName());
if (spc == (AddrSpace *)0)
throw LowlevelError("Unknown space in <truncate_space> command: "+tag.getName());
spc->truncateSpace(tag.getSize());
}
Address AddrSpaceManager::constructFloatExtensionAddress(const Address &realaddr,int4 realsize,
int4 logicalsize)
{
if (logicalsize == realsize)
return realaddr;
vector<VarnodeData> pieces;
pieces.emplace_back();
pieces.back().space = realaddr.getSpace();
pieces.back().offset = realaddr.getOffset();
pieces.back().size = realsize;
JoinRecord *join = findAddJoin(pieces,logicalsize);
return join->getUnified().getAddr();
}
Address AddrSpaceManager::constructJoinAddress(const Translate *translate,
const Address &hiaddr,int4 hisz,
const Address &loaddr,int4 losz)
{
spacetype hitp = hiaddr.getSpace()->getType();
spacetype lotp = loaddr.getSpace()->getType();
bool usejoinspace = true;
if (((hitp != IPTR_SPACEBASE)&&(hitp != IPTR_PROCESSOR))||
((lotp != IPTR_SPACEBASE)&&(lotp != IPTR_PROCESSOR)))
throw LowlevelError("Trying to join in appropriate locations");
if ((hitp == IPTR_SPACEBASE)||(lotp == IPTR_SPACEBASE)||
(hiaddr.getSpace() == getDefaultCodeSpace())||
(loaddr.getSpace() == getDefaultCodeSpace()))
usejoinspace = false;
if (hiaddr.isContiguous(hisz,loaddr,losz)) { if (!usejoinspace) { if (hiaddr.isBigEndian())
return hiaddr;
return loaddr;
}
else { if (hiaddr.isBigEndian()) {
if (translate->getRegisterName(hiaddr.getSpace(),hiaddr.getOffset(),(hisz+losz)).size() != 0)
return hiaddr;
}
else {
if (translate->getRegisterName(loaddr.getSpace(),loaddr.getOffset(),(hisz+losz)).size() != 0)
return loaddr;
}
}
}
vector<VarnodeData> pieces;
pieces.emplace_back();
pieces.emplace_back();
pieces[0].space = hiaddr.getSpace();
pieces[0].offset = hiaddr.getOffset();
pieces[0].size = hisz;
pieces[1].space = loaddr.getSpace();
pieces[1].offset = loaddr.getOffset();
pieces[1].size = losz;
JoinRecord *join = findAddJoin(pieces,0);
return join->getUnified().getAddr();
}
void AddrSpaceManager::renormalizeJoinAddress(Address &addr,int4 size)
{
JoinRecord *joinRecord = findJoinInternal(addr.getOffset());
if (joinRecord == (JoinRecord *)0)
throw LowlevelError("Join address not covered by a JoinRecord");
if (addr.getOffset() == joinRecord->unified.offset && size == joinRecord->unified.size)
return; int4 pos1;
Address addr1 = joinRecord->getEquivalentAddress(addr.getOffset(), pos1);
int4 pos2;
Address addr2 = joinRecord->getEquivalentAddress(addr.getOffset() + (size-1), pos2);
if (addr2.isInvalid())
throw LowlevelError("Join address range not covered");
if (pos1 == pos2) {
addr = addr1;
return;
}
vector<VarnodeData> newPieces;
newPieces.push_back(joinRecord->pieces[pos1]);
int4 sizeTrunc1 = (int4)(addr1.getOffset() - joinRecord->pieces[pos1].offset);
pos1 += 1;
while(pos1 <= pos2) {
newPieces.push_back(joinRecord->pieces[pos1]);
pos1 += 1;
}
int4 sizeTrunc2 = joinRecord->pieces[pos2].size - (int4)(addr2.getOffset() - joinRecord->pieces[pos2].offset) - 1;
newPieces.front().offset = addr1.getOffset();
newPieces.front().size -= sizeTrunc1;
newPieces.back().size -= sizeTrunc2;
JoinRecord *newJoinRecord = findAddJoin(newPieces, size);
addr = Address(newJoinRecord->unified.space,newJoinRecord->unified.offset);
}
Translate::Translate(void)
{
target_isbigendian = false;
unique_base=0;
alignment = 1;
}
void Translate::setDefaultFloatFormats(void)
{
if (floatformats.empty()) { floatformats.push_back(FloatFormat(4));
floatformats.push_back(FloatFormat(8));
}
}
const FloatFormat *Translate::getFloatFormat(int4 size) const
{
vector<FloatFormat>::const_iterator iter;
for(iter=floatformats.begin();iter!=floatformats.end();++iter) {
if ((*iter).getSize() == size)
return &(*iter);
}
return (const FloatFormat *)0;
}
void PcodeEmit::restoreXmlOp(const Element *el,const AddrSpaceManager *manage)
{ int4 opcode;
VarnodeData outvar;
VarnodeData invar[30];
VarnodeData *outptr;
istringstream i(el->getAttributeValue("code"));
i >> opcode;
const List &list(el->getChildren());
List::const_iterator iter = list.begin();
Address pc = Address::restoreXml(*iter,manage);
++iter;
if ((*iter)->getName() == "void")
outptr = (VarnodeData *)0;
else {
outvar.restoreXml(*iter,manage);
outptr = &outvar;
}
++iter;
int4 isize = 0;
while(iter != list.end() && isize < 30) {
if ((*iter)->getName() == "spaceid") {
invar[isize].space = manage->getConstantSpace();
invar[isize].offset = (uintb)(uintp)manage->getSpaceByName( (*iter)->getAttributeValue("name") );
invar[isize].size = sizeof(void *);
}
else
invar[isize].restoreXml(*iter,manage);
isize += 1;
++iter;
}
dump(pc,(OpCode)opcode,outptr,invar,isize);
}
const uint1 *PcodeEmit::unpackOffset(const uint1 *ptr,uintb &off)
{
uintb res = 0;
int4 shift;
for(shift=0;shift<67;shift+=6) {
uint1 val = *ptr++;
if (val == end_tag) {
off = res;
return ptr;
}
uintb bits = ((uintb)(val-0x20))<<shift;
res |= bits;
}
throw LowlevelError("Bad packed offset");
}
const uint1 *PcodeEmit::unpackVarnodeData(const uint1 *ptr,VarnodeData &v,const AddrSpaceManager *manage)
{
uint1 tag = *ptr++;
if (tag == addrsz_tag) {
int4 spcindex = (int4)(*ptr++ - 0x20);
v.space = manage->getSpace(spcindex);
ptr = unpackOffset(ptr,v.offset);
v.size = (uint4)(*ptr++ - 0x20);
}
else if (tag == spaceid_tag) {
v.space = manage->getConstantSpace();
int4 spcindex = (int4)(*ptr++ - 0x20);
v.offset = (uintb)(uintp)manage->getSpace( spcindex );
v.size = sizeof(void *);
}
else
throw LowlevelError("Bad packed VarnodeData");
return ptr;
}
const uint1 *PcodeEmit::restorePackedOp(const Address &addr,const uint1 *ptr,const AddrSpaceManager *manage)
{
int4 opcode;
VarnodeData outvar;
VarnodeData invar[30];
VarnodeData *outptr;
ptr += 1; opcode = (int4)(*ptr++ - 0x20); if (*ptr == void_tag) {
ptr += 1;
outptr = (VarnodeData *)0;
}
else {
ptr = unpackVarnodeData(ptr,outvar,manage);
outptr = &outvar;
}
int4 isize = 0;
while(*ptr != end_tag) {
ptr = unpackVarnodeData(ptr,invar[isize],manage);
isize += 1;
}
ptr += 1; dump(addr,(OpCode)opcode,outptr,invar,isize);
return ptr;
}