#include "space.hh"
#include "translate.hh"
void AddrSpace::calcScaleMask(void)
{
pointerLowerBound = (addressSize < 3) ? 0x100: 0x1000;
highest = calc_mask(addressSize); highest = highest * wordsize + (wordsize-1); pointerUpperBound = highest;
}
AddrSpace::AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp,const string &nm,
uint4 size,uint4 ws, int4 ind,uint4 fl,int4 dl)
{
refcount = 0; manage = m;
trans = t;
type = tp;
name = nm;
addressSize = size;
wordsize = ws;
index = ind;
delay = dl;
deadcodedelay = dl; minimumPointerSize = 0; shortcut = ' ';
flags = (fl & hasphysical);
if (t->isBigEndian())
flags |= big_endian;
flags |= (heritaged | does_deadcode);
calcScaleMask();
}
AddrSpace::AddrSpace(AddrSpaceManager *m,const Translate *t,spacetype tp)
{
refcount = 0;
manage = m;
trans = t;
type = tp;
flags = (heritaged | does_deadcode); wordsize = 1;
minimumPointerSize = 0;
shortcut = ' ';
}
void AddrSpace::saveBasicAttributes(ostream &s) const
{
a_v(s,"name",name);
a_v_i(s,"index",index);
a_v_b(s,"bigendian",isBigEndian());
a_v_i(s,"delay",delay);
if (delay != deadcodedelay)
a_v_i(s,"deadcodedelay",deadcodedelay);
a_v_i(s,"size",addressSize);
if (wordsize > 1) a_v_i(s,"wordsize",wordsize);
a_v_b(s,"physical",hasPhysical());
}
void AddrSpace::truncateSpace(uint4 newsize)
{
setFlags(truncated);
addressSize = newsize;
minimumPointerSize = newsize;
calcScaleMask();
}
void AddrSpace::saveXmlAttributes(ostream &s,uintb offset) const
{
a_v(s,"space",getName()); s << ' ' << "offset=\"";
printOffset(s,offset);
s << "\"";
}
void AddrSpace::saveXmlAttributes(ostream &s,uintb offset,int4 size) const
{
a_v(s,"space",getName()); s << ' ' << "offset=\"";
printOffset(s,offset);
s << "\"";
a_v_i(s,"size",size);
}
uintb AddrSpace::restoreXmlAttributes(const Element *el,uint4 &size) const
{
uintb offset;
int4 num = el->getNumAttributes();
bool foundoffset = false;
for(int4 i=0;i<num;++i) {
if (el->getAttributeName(i)=="offset") {
foundoffset = true;
istringstream s1(el->getAttributeValue(i));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> offset;
}
else if (el->getAttributeName(i)=="size") {
istringstream s2(el->getAttributeValue(i));
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> size;
}
}
if (!foundoffset)
throw LowlevelError("Address is missing offset");
return offset;
}
void AddrSpace::printOffset(ostream &s,uintb offset) const
{
s << "0x" << hex << offset;
}
void AddrSpace::printRaw(ostream &s,uintb offset) const
{
int4 sz = getAddrSize();
if (sz > 4) {
if ((offset>>32) == 0)
sz = 4; else if ((offset>>48) == 0)
sz = 6;
}
s << "0x" << setfill('0') << setw(2*sz) << hex << byteToAddress(offset,wordsize);
if (wordsize>1) {
int4 cut = offset % wordsize;
if (cut != 0)
s << '+' << dec << cut;
}
}
static int4 get_offset_size(const char *ptr,uintb &offset)
{ int4 size;
uint4 val;
char *ptr2;
val = 0; size = -1;
if (*ptr == ':') {
size = strtoul(ptr+1,&ptr2,0);
if (*ptr2 == '+')
val = strtoul(ptr2+1,&ptr2,0);
}
if (*ptr == '+')
val = strtoul(ptr+1,&ptr2,0);
offset += val; return size;
}
uintb AddrSpace::read(const string &s,int4 &size) const
{
const char *enddata;
char *tmpdata;
int4 expsize;
string::size_type append;
string frontpart;
uintb offset;
append = s.find_first_of(":+");
try {
if (append == string::npos) {
const VarnodeData &point(trans->getRegister(s));
offset = point.offset;
size = point.size;
}
else {
frontpart = s.substr(0,append);
const VarnodeData &point(trans->getRegister(frontpart));
offset = point.offset;
size = point.size;
}
}
catch(LowlevelError &err) { offset = strtoul(s.c_str(),&tmpdata,0);
offset = addressToByte(offset,wordsize);
enddata = (const char *) tmpdata;
if (enddata - s.c_str() == s.size()) { size = manage->getDefaultSize(); return offset;
}
size = manage->getDefaultSize();
}
if (append != string::npos) {
enddata = s.c_str()+append;
expsize = get_offset_size( enddata, offset );
if (expsize!=-1) {
size = expsize;
return offset;
}
}
return offset;
}
void AddrSpace::saveXml(ostream &s) const
{
s << "<space"; saveBasicAttributes(s);
s << "/>\n";
}
void AddrSpace::restoreXml(const Element *el)
{
int4 numAttribs = el->getNumAttributes();
deadcodedelay = -1;
for (int4 i=0; i < numAttribs; i++) {
string attrName = el->getAttributeName(i);
string attrValue = el->getAttributeValue(i);
if (attrName == "name") {
name = attrValue;
}
if (attrName == "index")
{
istringstream s1(attrValue);
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> index;
}
if (attrName == "size")
{
istringstream s1(attrValue);
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> addressSize;
}
if (attrName == "wordsize")
{
istringstream s1(attrValue);
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> wordsize;
}
if (attrName == "bigendian") {
if (xml_readbool(attrValue))
flags |= big_endian;
}
if (attrName == "delay") {
istringstream s1(attrValue);
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> delay;
}
if (attrName == "deadcodedelay") {
istringstream s1(attrValue);
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> deadcodedelay;
}
if (attrName == "physical") {
if (xml_readbool(attrValue))
flags |= hasphysical;
}
}
if (deadcodedelay == -1)
deadcodedelay = delay; calcScaleMask();
}
const string ConstantSpace::NAME = "const";
const int4 ConstantSpace::INDEX = 0;
ConstantSpace::ConstantSpace(AddrSpaceManager *m,const Translate *t)
: AddrSpace(m,t,IPTR_CONSTANT,NAME,sizeof(uintb),1,INDEX,0,0)
{
clearFlags(heritaged|does_deadcode|big_endian);
if (HOST_ENDIAN==1) setFlags(big_endian);
}
void ConstantSpace::printRaw(ostream &s,uintb offset) const
{
s << "0x" << hex << offset;
}
void ConstantSpace::saveXml(ostream &s) const
{
throw LowlevelError("Should never save the constant space as XML");
}
void ConstantSpace::restoreXml(const Element *el)
{
throw LowlevelError("Should never restore the constant space from XML");
}
const string OtherSpace::NAME = "OTHER";
const int4 OtherSpace::INDEX = 1;
OtherSpace::OtherSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
: AddrSpace(m,t,IPTR_PROCESSOR,NAME,sizeof(uintb),1,INDEX,0,0)
{
clearFlags(heritaged|does_deadcode);
setFlags(is_otherspace);
}
OtherSpace::OtherSpace(AddrSpaceManager *m,const Translate *t)
: AddrSpace(m,t,IPTR_PROCESSOR)
{
clearFlags(heritaged|does_deadcode);
setFlags(is_otherspace);
}
void OtherSpace::printRaw(ostream &s,uintb offset) const
{
s << "0x" << hex << offset;
}
void OtherSpace::saveXml(ostream &s) const
{
s << "<space_other";
saveBasicAttributes(s);
s << "/>\n";
}
const string UniqueSpace::NAME = "unique";
const uint4 UniqueSpace::SIZE = 4;
UniqueSpace::UniqueSpace(AddrSpaceManager *m,const Translate *t,int4 ind,uint4 fl)
: AddrSpace(m,t,IPTR_INTERNAL,NAME,SIZE,1,ind,fl,0)
{
setFlags(hasphysical);
}
UniqueSpace::UniqueSpace(AddrSpaceManager *m,const Translate *t)
: AddrSpace(m,t,IPTR_INTERNAL)
{
setFlags(hasphysical);
}
void UniqueSpace::saveXml(ostream &s) const
{
s << "<space_unique";
saveBasicAttributes(s);
s << "/>\n";
}
const string JoinSpace::NAME = "join";
JoinSpace::JoinSpace(AddrSpaceManager *m,const Translate *t,int4 ind)
: AddrSpace(m,t,IPTR_JOIN,NAME,sizeof(uintm),1,ind,0,0)
{
clearFlags(heritaged); }
void JoinSpace::saveXmlAttributes(ostream &s,uintb offset) const
{
JoinRecord *rec = getManager()->findJoin(offset); a_v(s,"space",getName());
int4 num = rec->numPieces();
for(int4 i=0;i<num;++i) {
const VarnodeData &vdata( rec->getPiece(i) );
ostringstream t;
t << " piece" << dec << (i+1) << "=\"";
t << vdata.space->getName() << ":0x";
t << hex << vdata.offset << ':' << dec << vdata.size << '\"';
s << t.str();
}
if (num == 1)
a_v_i(s,"logicalsize",rec->getUnified().size);
}
void JoinSpace::saveXmlAttributes(ostream &s,uintb offset,int4 size) const
{
JoinRecord *rec = getManager()->findJoin(offset); a_v(s,"space",getName());
int4 num = rec->numPieces();
int4 count = 0;
for(int4 i=0;i<num;++i) {
const VarnodeData &vdata( rec->getPiece(i) );
ostringstream t;
t << " piece" << dec << (i+1) << "=\"";
t << vdata.space->getName() << ":0x";
t << hex << vdata.offset << ':' << dec << vdata.size << '\"';
count += vdata.size;
s << t.str();
}
if (num == 1)
a_v_i(s,"logicalsize",rec->getUnified().size);
if ((count != size)&&(num>1))
throw LowlevelError("size attribute in join tag does not match size of pieces");
}
uintb JoinSpace::restoreXmlAttributes(const Element *el,uint4 &size) const
{
vector<VarnodeData> pieces;
int4 numAttribs = el->getNumAttributes();
uint4 sizesum = 0;
uint4 logicalsize = 0;
for(int4 i=0;i<numAttribs;++i) {
string attrName = el->getAttributeName(i);
if (0!=attrName.compare(0,5,"piece")) {
if (attrName == "logicalsize") {
istringstream s3(el->getAttributeValue(i));
s3.unsetf(ios::dec | ios::hex | ios::oct);
s3 >> logicalsize;
}
continue;
}
int4 pos = (int4)(attrName[5] - '1');
while(pieces.size() <= pos)
pieces.emplace_back();
VarnodeData &vdat( pieces[pos] );
string attrVal = el->getAttributeValue(i);
string::size_type offpos = attrVal.find(':');
if (offpos == string::npos) {
const Translate *tr = getTrans();
const VarnodeData &point(tr->getRegister(attrVal));
vdat = point;
}
else {
string::size_type szpos = attrVal.find(':',offpos+1);
if (szpos==string::npos)
throw LowlevelError("join address piece attribute is malformed");
string spcname = attrVal.substr(0,offpos);
vdat.space = getManager()->getSpaceByName(spcname);
istringstream s1(attrVal.substr(offpos+1,szpos));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> vdat.offset;
istringstream s2(attrVal.substr(szpos+1));
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> vdat.size;
}
sizesum += vdat.size;
}
JoinRecord *rec = getManager()->findAddJoin(pieces,logicalsize);
size = rec->getUnified().size;
return rec->getUnified().offset;
}
void JoinSpace::printRaw(ostream &s,uintb offset) const
{
JoinRecord *rec = getManager()->findJoin(offset);
int4 szsum = 0;
int4 num = rec->numPieces();
s << '{';
for(int4 i=0;i<num;++i) {
const VarnodeData &vdat( rec->getPiece(i) );
szsum += vdat.size;
if (i!=0)
s << ',';
vdat.space->printRaw(s,vdat.offset);
}
if (num == 1) {
szsum = rec->getUnified().size;
s << ':' << szsum;
}
s << '}';
}
uintb JoinSpace::read(const string &s,int4 &size) const
{
vector<VarnodeData> pieces;
int4 szsum = 0;
int4 i=0;
while(i < s.size()) {
pieces.emplace_back(); string token;
while((i<s.size())&&(s[i]!=',')) {
token += s[i];
i += 1;
}
i += 1; try {
pieces.back() = getTrans()->getRegister(token);
}
catch(LowlevelError &err) { char tryShortcut = token[0];
AddrSpace *spc = getManager()->getSpaceByShortcut(tryShortcut);
if (spc == (AddrSpace *)0)
throw LowlevelError("Could not parse join string");
int4 subsize;
pieces.back().space = spc;
pieces.back().offset = spc->read(token.substr(1),subsize);
pieces.back().size = subsize;
}
szsum += pieces.back().size;
}
JoinRecord *rec = getManager()->findAddJoin(pieces,0);
size = szsum;
return rec->getUnified().offset;
}
void JoinSpace::saveXml(ostream &s) const
{
throw LowlevelError("Should never save join space to XML");
}
void JoinSpace::restoreXml(const Element *el)
{
throw LowlevelError("Should never restore join space from XML");
}
OverlaySpace::OverlaySpace(AddrSpaceManager *m,const Translate *t)
: AddrSpace(m,t,IPTR_PROCESSOR)
{
baseSpace = (AddrSpace *)0;
setFlags(overlay);
}
AddrSpace *OverlaySpace::getBaseSpace(void) const
{
return baseSpace;
}
void OverlaySpace::saveXml(ostream &s) const
{
s << "<space_overlay";
a_v(s,"name",name);
a_v_i(s,"index",index);
a_v(s,"base",baseSpace->getName());
s << "/>\n";
}
void OverlaySpace::restoreXml(const Element *el)
{
name = el->getAttributeValue("name");
istringstream s1(el->getAttributeValue("index"));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> index;
string basename = el->getAttributeValue("base");
baseSpace = getManager()->getSpaceByName(basename);
if (baseSpace == (AddrSpace *)0)
throw LowlevelError("Base space does not exist for overlay space: "+name);
addressSize = baseSpace->getAddrSize();
wordsize = baseSpace->getWordSize();
delay = baseSpace->getDelay();
deadcodedelay = baseSpace->getDeadcodeDelay();
calcScaleMask();
if (baseSpace->isBigEndian())
setFlags(big_endian);
if (baseSpace->hasPhysical())
setFlags(hasphysical);
}