#include "memstate.hh"
#include "translate.hh"
uintb MemoryBank::constructValue(const uint1 *ptr,int4 size,bool bigendian)
{
uintb res = 0;
if (bigendian) {
for(int4 i=0;i<size;++i) {
res <<= 8;
res += (uintb) ptr[i];
}
}
else {
for(int4 i=size-1;i>=0;--i) {
res <<= 8;
res += (uintb) ptr[i];
}
}
return res;
}
void MemoryBank::deconstructValue(uint1 *ptr,uintb val,int4 size,bool bigendian)
{
if (bigendian) {
for(int4 i=size-1;i>=0;--i) {
ptr[i] = (uint1) (val & 0xff);
val >>= 8;
}
}
else {
for(int4 i=0;i<size;++i) {
ptr[i] = (uint1) (val & 0xff);
val >>= 8;
}
}
}
MemoryBank::MemoryBank(AddrSpace *spc,int4 ws,int4 ps)
{
space = spc;
wordsize = ws;
pagesize = ps;
}
void MemoryBank::getPage(uintb addr,uint1 *res,int4 skip,int4 size) const
{ uintb ptraddr = addr + skip;
uintb endaddr = ptraddr + size;
uintb startalign = ptraddr & ~((uintb)(wordsize-1));
uintb endalign = endaddr & ~((uintb)(wordsize-1));
if ((endaddr & ((uintb)(wordsize-1))) != 0)
endalign += wordsize;
uintb curval;
bool bswap = ((HOST_ENDIAN==1) != space->isBigEndian());
uint1 *ptr;
do {
curval = find(startalign);
if (bswap)
curval = byte_swap(curval,wordsize);
ptr = (uint1 *)&curval;
int4 sz = wordsize;
if (startalign < addr) {
ptr += (addr-startalign);
sz = wordsize - (addr-startalign);
}
if (startalign + wordsize > endaddr)
sz -= (startalign + wordsize -endaddr);
memcpy(res,ptr,sz);
res += sz;
startalign += wordsize;
} while(startalign != endalign);
}
void MemoryBank::setPage(uintb addr,const uint1 *val,int4 skip,int4 size)
{ uintb ptraddr = addr + skip;
uintb endaddr = ptraddr + size;
uintb startalign = ptraddr & ~((uintb)(wordsize-1));
uintb endalign = endaddr & ~((uintb)(wordsize-1));
if ((endaddr & ((uintb)(wordsize-1))) != 0)
endalign += wordsize;
uintb curval;
bool bswap = ((HOST_ENDIAN==1) != space->isBigEndian());
uint1 *ptr;
do {
ptr = (uint1 *)&curval;
int4 sz = wordsize;
if (startalign < addr) {
ptr += (addr-startalign);
sz = wordsize - (addr-startalign);
}
if (startalign + wordsize > endaddr)
sz -= (startalign + wordsize - endaddr);
if (sz != wordsize) {
curval = find(startalign); memcpy(ptr,val,sz); }
else
curval = *((const uintb *)val); if (bswap)
curval = byte_swap(curval,wordsize);
insert(startalign,curval);
val += sz;
startalign += wordsize;
} while(startalign != endalign);
}
void MemoryBank::setValue(uintb offset,int4 size,uintb val)
{
uintb alignmask = (uintb)(wordsize-1);
uintb ind = offset & (~alignmask);
int4 skip = offset & alignmask;
int4 size1 = wordsize-skip;
int4 size2;
int4 gap;
uintb val1,val2;
if (size > size1) { size2 = size - size1;
val1 = find(ind);
val2 = find(ind+wordsize);
gap = wordsize - size2;
}
else {
if (size == wordsize) {
insert(ind,val);
return;
}
val1 = find(ind);
val2 = 0;
gap = size1-size;
size1 = size;
size2 = 0;
}
skip = skip * 8; gap = gap * 8; if (space->isBigEndian()) {
if (size2 == 0) {
val1 &= ~(calc_mask(size1)<<gap);
val1 |= val << gap;
insert(ind,val1);
}
else {
val1 &= (~((uintb)0)) << 8*size1;
val1 |= val >> 8*size2;
insert(ind,val1);
val2 &= (~((uintb)0)) >> 8*size2;
val2 |= val << gap;
insert(ind+wordsize,val2);
}
}
else {
if (size2 == 0) {
val1 &= ~(calc_mask(size1)<<skip);
val1 |= val << skip;
insert(ind,val1);
}
else {
val1 &= (~((uintb)0)) >> 8*size1;
val1 |= val << skip;
insert(ind,val1);
val2 &= (~((uintb)0)) << 8*size2;
val2 |= val >> 8*size1;
insert(ind+wordsize,val2);
}
}
}
uintb MemoryBank::getValue(uintb offset,int4 size) const
{
uintb res;
uintb alignmask = (uintb) (wordsize-1);
uintb ind = offset & (~alignmask);
int4 skip = offset & alignmask;
int4 size1 = wordsize-skip;
int4 size2;
int4 gap;
uintb val1,val2;
if (size > size1) { size2 = size - size1;
val1 = find(ind);
val2 = find(ind+wordsize);
gap = wordsize - size2;
}
else {
val1 = find(ind);
val2 = 0;
if (size == wordsize)
return val1;
gap = size1-size;
size1 = size;
size2 = 0;
}
if (space->isBigEndian()) {
if (size2 == 0)
res = val1>>(8*gap);
else
res = (val1<<(8*size2)) | (val2 >> (8*gap));
}
else {
if (size2 == 0)
res = val1 >> (skip*8);
else
res = (val1>>(skip*8)) | (val2<<(size1*8) );
}
res &= (uintb)calc_mask(size);
return res;
}
void MemoryBank::setChunk(uintb offset,int4 size,const uint1 *val)
{
int4 cursize;
int4 count;
uintb pagemask = (uintb) (pagesize - 1);
uintb offalign;
int4 skip;
count = 0;
while(count < size) {
cursize = pagesize;
offalign = offset & ~pagemask;
skip = 0;
if (offalign != offset) {
skip = offset - offalign;
cursize -= skip;
}
if (size - count < cursize)
cursize = size - count;
setPage(offalign,val,skip,cursize);
count += cursize;
offset += cursize;
val += cursize;
}
}
void MemoryBank::getChunk(uintb offset,int4 size,uint1 *res) const
{
int4 cursize,count;
uintb pagemask = (uintb) (pagesize-1);
uintb offalign;
int4 skip;
count = 0;
while(count < size) {
cursize = pagesize;
offalign = offset & ~pagemask;
skip = 0;
if (offalign != offset) {
skip = offset-offalign;
cursize -= skip;
}
if (size - count < cursize)
cursize = size - count;
getPage(offalign,res,skip,cursize);
count += cursize;
offset += cursize;
res += cursize;
}
}
uintb MemoryImage::find(uintb addr) const
{ uintb res = 0; AddrSpace *spc = getSpace();
try {
uint1 *ptr = (uint1 *)&res;
ptr += (HOST_ENDIAN==1) ? (sizeof(uintb) - getWordSize()) : 0;
loader->loadFill(ptr,getWordSize(),Address(spc,addr));
} catch(DataUnavailError &err) {
res = 0;
}
if ((HOST_ENDIAN==1) != spc->isBigEndian())
res = byte_swap(res,getWordSize());
return res;
}
void MemoryImage::getPage(uintb addr,uint1 *res,int4 skip,int4 size) const
{ AddrSpace *spc = getSpace();
try {
loader->loadFill(res,size,Address(spc,addr+skip));
}
catch(DataUnavailError &err) {
for(int4 i=0;i<size;++i)
res[i] = 0;
}
}
MemoryImage::MemoryImage(AddrSpace *spc,int4 ws,int4 ps,LoadImage *ld)
: MemoryBank(spc,ws,ps)
{
loader = ld;
}
void MemoryPageOverlay::insert(uintb addr,uintb val)
{
uintb pageaddr = addr & ~((uintb)(getPageSize()-1));
map<uintb,uint1 *>::iterator iter;
uint1 *pageptr;
iter = page.find(pageaddr);
if (iter != page.end())
pageptr = (*iter).second;
else {
pageptr = new uint1[getPageSize()];
page[pageaddr] = pageptr;
if (underlie == (MemoryBank *)0) {
for(int4 i=0;i<getPageSize();++i)
pageptr[i] = 0;
}
else
underlie->getPage(pageaddr,pageptr,0,getPageSize());
}
uintb pageoffset = addr & ((uintb)(getPageSize()-1));
deconstructValue(pageptr + pageoffset,val,getWordSize(),getSpace()->isBigEndian());
}
uintb MemoryPageOverlay::find(uintb addr) const
{
uintb pageaddr = addr & ~((uintb)(getPageSize()-1));
map<uintb,uint1 *>::const_iterator iter;
iter = page.find(pageaddr);
if (iter == page.end()) {
if (underlie == (MemoryBank *)0)
return (uintb)0;
return underlie->find(addr);
}
const uint1 *pageptr = (*iter).second;
uintb pageoffset = addr & ((uintb)(getPageSize()-1));
return constructValue(pageptr+pageoffset,getWordSize(),getSpace()->isBigEndian());
}
void MemoryPageOverlay::getPage(uintb addr,uint1 *res,int4 skip,int4 size) const
{
map<uintb,uint1 *>::const_iterator iter;
iter = page.find(addr);
if (iter == page.end()) {
if (underlie == (MemoryBank *)0) {
for(int4 i=0;i<size;++i)
res[i] = 0;
return;
}
underlie->getPage(addr,res,skip,size);
return;
}
const uint1 *pageptr = (*iter).second;
memcpy(res,pageptr+skip,size);
}
void MemoryPageOverlay::setPage(uintb addr,const uint1 *val,int4 skip,int4 size)
{
map<uintb,uint1 *>::iterator iter;
uint1 *pageptr;
iter = page.find(addr);
if (iter == page.end()) {
pageptr = new uint1[getPageSize()];
page[addr] = pageptr;
if (size != getPageSize()) {
if (underlie == (MemoryBank *)0) {
for(int4 i=0;i<getPageSize();++i)
pageptr[i] = 0;
}
else
underlie->getPage(addr,pageptr,0,getPageSize());
}
}
else
pageptr = (*iter).second;
memcpy(pageptr+skip,val,size);
}
MemoryPageOverlay::MemoryPageOverlay(AddrSpace *spc,int4 ws,int4 ps,MemoryBank *ul)
: MemoryBank(spc,ws,ps)
{
underlie = ul;
}
MemoryPageOverlay::~MemoryPageOverlay(void)
{
map<uintb,uint1 *>::iterator iter;
for(iter=page.begin();iter!=page.end();++iter)
delete [] (*iter).second;
}
void MemoryHashOverlay::insert(uintb addr,uintb val)
{
int4 size = address.size();
uintb offset = (addr>>alignshift) % size;
for(int4 i=0;i<size;++i) {
if (address[offset] == addr) { value[offset] = val; return;
}
else if (address[offset] == (uintb)0xBADBEEF) { address[offset] = addr; value[offset] = val; return;
}
offset = (offset + collideskip) % size;
}
throw LowlevelError("Memory state hash_table is full");
}
uintb MemoryHashOverlay::find(uintb addr) const
{ int4 size = address.size();
uintb offset = (addr>>alignshift) % size;
for(int4 i=0;i<size;++i) {
if (address[offset] == addr) return value[offset];
else if (address[offset] == 0xBADBEEF) break;
offset = (offset + collideskip) % size;
}
if (underlie == (MemoryBank *)0)
return (uintb)0;
return underlie->find(addr);
}
MemoryHashOverlay::MemoryHashOverlay(AddrSpace *spc,int4 ws,int4 ps,int4 hashsize,MemoryBank *ul)
: MemoryBank(spc,ws,ps), address(hashsize,0xBADBEEF), value(hashsize,0)
{
underlie = ul;
collideskip = 1023;
uint4 tmp = ws - 1;
alignshift = 0;
while(tmp != 0) {
alignshift += 1;
tmp >>= 1;
}
}
void MemoryState::setMemoryBank(MemoryBank *bank)
{
AddrSpace *spc = bank->getSpace();
int4 index = spc->getIndex();
while(index >= memspace.size())
memspace.push_back((MemoryBank *)0);
memspace[index] = bank;
}
MemoryBank *MemoryState::getMemoryBank(AddrSpace *spc) const
{
int4 index = spc->getIndex();
if (index >= memspace.size())
return (MemoryBank *)0;
return memspace[index];
}
void MemoryState::setValue(AddrSpace *spc,uintb off,int4 size,uintb cval)
{
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Setting value for unmapped memory space: "+spc->getName());
mspace->setValue(off,size,cval);
}
uintb MemoryState::getValue(AddrSpace *spc,uintb off,int4 size) const
{
if (spc->getType() == IPTR_CONSTANT) return off;
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Getting value from unmapped memory space: "+spc->getName());
return mspace->getValue(off,size);
}
void MemoryState::setValue(const string &nm,uintb cval)
{ const VarnodeData &vdata( trans->getRegister(nm) );
setValue(vdata.space,vdata.offset,vdata.size,cval);
}
uintb MemoryState::getValue(const string &nm) const
{ const VarnodeData &vdata( trans->getRegister(nm) );
return getValue(vdata.space,vdata.offset,vdata.size);
}
void MemoryState::getChunk(uint1 *res,AddrSpace *spc,uintb off,int4 size) const
{
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Getting chunk from unmapped memory space: "+spc->getName());
mspace->getChunk(off,size,res);
}
void MemoryState::setChunk(const uint1 *val,AddrSpace *spc,uintb off,int4 size)
{
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Setting chunk of unmapped memory space: "+spc->getName());
mspace->setChunk(off,size,val);
}