#include "type.hh"
#include "funcdata.hh"
sub_metatype Datatype::base2sub[13] = {
SUB_STRUCT, SUB_PARTIALSTRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
};
void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseaddr)
{
int4 i;
uintb start,addr,endaddr;
if (buffer == (uint1 *)0) {
s << "Address not present in binary image\n";
return;
}
addr = baseaddr.getOffset();
endaddr = addr + size;
start = addr & ~((uintb)0xf);
while(start < endaddr) {
s << setfill('0') << setw(8) << hex << start << ": ";
for(i=0;i<16;++i) {
if ((start+i < addr)||(start+i>=endaddr))
s << " ";
else
s << setfill('0') << setw(2) << hex << (uint4) buffer[start+i-addr] << ' ';
}
s << " ";
for(i=0;i<16;++i)
if ((start+i < addr)||(start+i>=endaddr))
s << ' ';
else {
if (isprint( buffer[start+i-addr] ))
s << buffer[start+i-addr];
else
s << '.';
}
s << endl;
start += 16;
}
}
bool Datatype::hasSameVariableBase(const Datatype *ct) const
{
if (!isVariableLength()) return false;
if (!ct->isVariableLength()) return false;
uint8 thisId = hashSize(id, size);
uint8 themId = hashSize(ct->id, ct->size);
return (thisId == themId);
}
void Datatype::printRaw(ostream &s) const
{
if (name.size()>0)
s << name;
else
s << "unkbyte" << dec << size;
}
Datatype *Datatype::getSubType(uintb off,uintb *newoff) const
{ *newoff = off;
return (Datatype *)0;
}
Datatype *Datatype::nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const
{
return (TypeArray *)0;
}
Datatype *Datatype::nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const
{
return (TypeArray *)0;
}
int4 Datatype::compare(const Datatype &op,int4 level) const
{
if (size != op.size) return (op.size - size);
if (submeta != op.submeta) return (submeta < op.submeta) ? -1 : 1;
return 0;
}
int4 Datatype::compareDependency(const Datatype &op) const
{
if (submeta != op.submeta) return (submeta < op.submeta) ? -1 : 1;
if (size != op.size) return (op.size-size);
return 0;
}
void metatype2string(type_metatype metatype,string &res)
{
switch(metatype) {
case TYPE_VOID:
res = "void";
break;
case TYPE_PTR:
res = "ptr";
break;
case TYPE_PTRREL:
res = "ptrrel";
break;
case TYPE_ARRAY:
res = "array";
break;
case TYPE_PARTIALSTRUCT:
res = "part";
break;
case TYPE_STRUCT:
res = "struct";
break;
case TYPE_SPACEBASE:
res = "spacebase";
break;
case TYPE_UNKNOWN:
res = "unknown";
break;
case TYPE_UINT:
res = "uint";
break;
case TYPE_INT:
res = "int";
break;
case TYPE_BOOL:
res = "bool";
break;
case TYPE_CODE:
res = "code";
break;
case TYPE_FLOAT:
res = "float";
break;
default:
throw LowlevelError("Unknown metatype");
}
}
type_metatype string2metatype(const string &metastring)
{
switch(metastring[0]) {
case 'p':
if (metastring=="ptr")
return TYPE_PTR;
else if (metastring=="part")
return TYPE_PARTIALSTRUCT;
else if (metastring=="ptrrel")
return TYPE_PTRREL;
break;
case 'a':
if (metastring=="array")
return TYPE_ARRAY;
break;
case 's':
if (metastring=="struct")
return TYPE_STRUCT;
if (metastring=="spacebase")
return TYPE_SPACEBASE;
break;
case 'u':
if (metastring=="unknown")
return TYPE_UNKNOWN;
else if (metastring=="uint")
return TYPE_UINT;
break;
case 'i':
if (metastring == "int")
return TYPE_INT;
break;
case 'f':
if (metastring == "float")
return TYPE_FLOAT;
break;
case 'b':
if (metastring == "bool")
return TYPE_BOOL;
break;
case 'c':
if (metastring == "code")
return TYPE_CODE;
break;
case 'v':
if (metastring == "void")
return TYPE_VOID;
break;
default:
break;
}
throw LowlevelError("Unknown metatype: "+metastring);
}
void Datatype::saveXml(ostream &s) const
{
s << "<type";
saveXmlBasic(metatype,s);
s << "/>";
}
void Datatype::saveXmlBasic(type_metatype meta,ostream &s) const
{
a_v(s,"name",name);
uint8 saveId;
if (isVariableLength())
saveId = hashSize(id, size);
else
saveId = id;
if (saveId != 0) {
s << " id=\"0x" << hex << saveId << '\"';
}
a_v_i(s,"size",size);
string metastring;
metatype2string(meta,metastring);
a_v(s,"metatype",metastring);
if ((flags & coretype)!=0)
a_v_b(s,"core",true);
if (isVariableLength())
a_v_b(s,"varlength",true);
if ((flags & opaque_string)!=0)
a_v_b(s,"opaquestring",true);
}
void Datatype::saveXmlRef(ostream &s) const
{ if ((id!=0)&&(metatype != TYPE_VOID)) {
s << "<typeref";
a_v(s,"name",name);
if (isVariableLength()) { a_v_u(s,"id",hashSize(id,size)); a_v_i(s,"size",size); }
else {
a_v_u(s,"id",id);
}
s << "/>";
}
else
saveXml(s);
}
void Datatype::saveXmlTypedef(ostream &s) const
{
s << "<def";
a_v(s,"name",name);
a_v_u(s,"id",id);
s << ">";
typedefImm->saveXmlRef(s);
s << "</def>";
}
bool Datatype::isPtrsubMatching(uintb off) const
{
return false;
}
Datatype *Datatype::getStripped(void) const
{
return (Datatype *)0;
}
void Datatype::restoreXmlBasic(const Element *el)
{
name = el->getAttributeValue("name");
istringstream s(el->getAttributeValue("size"));
s.unsetf(ios::dec | ios::hex | ios::oct);
size = -1;
s >> size;
if (size < 0)
throw LowlevelError("Bad size for type "+name);
metatype = string2metatype( el->getAttributeValue("metatype") );
submeta = base2sub[metatype];
id = 0;
for(int4 i=0;i<el->getNumAttributes();++i) {
const string &attribName( el->getAttributeName(i) );
if (attribName == "core") {
if (xml_readbool(el->getAttributeValue(i)))
flags |= coretype;
}
else if (attribName == "id") {
istringstream s1(el->getAttributeValue(i));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> id;
}
else if (attribName == "varlength") {
if (xml_readbool(el->getAttributeValue(i)))
flags |= variable_length;
}
else if (attribName == "opaquestring") {
if (xml_readbool(el->getAttributeValue(i)))
flags |= opaque_string;
}
}
if ((id==0)&&(name.size()>0)) id = hashName(name); if (isVariableLength()) {
id = hashSize(id, size);
}
}
uint8 Datatype::hashName(const string &nm)
{
uint8 res = 123;
for(uint4 i=0;i<nm.size();++i) {
res = (res<<8) | (res >> 56);
res += (uint8)nm[i];
if ((res&1)==0)
res ^= 0xfeabfeab; }
uint8 tmp=1;
tmp <<= 63;
res |= tmp; return res;
}
uint8 Datatype::hashSize(uint8 id,int4 size)
{
uint8 sizeHash = size;
sizeHash *= 0x98251033aecbabaf; id ^= sizeHash;
return id;
}
void TypeChar::restoreXml(const Element *el,TypeFactory &typegrp)
{
restoreXmlBasic(el);
submeta = (metatype == TYPE_INT) ? SUB_INT_CHAR : SUB_UINT_CHAR;
}
void TypeChar::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
a_v_b(s,"char",true);
s << "/>";
}
void TypeUnicode::setflags(void)
{
if (size==2)
flags |= Datatype::utf16; else if (size==4)
flags |= Datatype::utf32; else if (size==1)
flags |= Datatype::chartype; }
void TypeUnicode::restoreXml(const Element *el,TypeFactory &typegrp)
{
restoreXmlBasic(el);
setflags();
submeta = (metatype == TYPE_INT) ? SUB_INT_UNICODE : SUB_UINT_UNICODE;
}
TypeUnicode::TypeUnicode(const string &nm,int4 sz,type_metatype m)
: TypeBase(sz,m,nm)
{
setflags(); submeta = (m == TYPE_INT) ? SUB_INT_UNICODE : SUB_UINT_UNICODE;
}
void TypeUnicode::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
a_v_b(s,"utf",true);
s << "/>";
}
void TypeVoid::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<void/>";
}
void TypePointer::printRaw(ostream &s) const
{
ptrto->printRaw(s);
s << " *";
}
int4 TypePointer::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
TypePointer *tp = (TypePointer *) &op;
if (wordsize != tp->wordsize) return (wordsize < tp->wordsize) ? -1 : 1;
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
return ptrto->compare(*tp->ptrto,level); }
int4 TypePointer::compareDependency(const Datatype &op) const
{
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
TypePointer *tp = (TypePointer *) &op; if (ptrto != tp->ptrto) return (ptrto < tp->ptrto) ? -1 : 1; if (wordsize != tp->wordsize) return (wordsize < tp->wordsize) ? -1 : 1;
return (op.getSize()-size);
}
void TypePointer::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
if (wordsize != 1)
a_v_i(s,"wordsize",wordsize);
s << '>';
ptrto->saveXmlRef(s);
s << "</type>";
}
void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp)
{
restoreXmlBasic(el);
for(int4 i=0;i<el->getNumAttributes();++i)
if (el->getAttributeName(i) == "wordsize") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> wordsize;
}
ptrto = typegrp.restoreXmlType( *el->getChildren().begin() );
calcSubmeta();
if (name.size() == 0) flags = ptrto->getInheritable();
}
void TypePointer::calcSubmeta(void)
{
if (ptrto->getMetatype() == TYPE_STRUCT) {
if (ptrto->numDepend() > 1 || ptrto->isIncomplete())
submeta = SUB_PTR_STRUCT;
else
submeta = SUB_PTR;
}
}
TypePointer *TypePointer::downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp)
{
int4 ptrtoSize = ptrto->getSize();
if (off >= ptrtoSize) { if (ptrtoSize != 0 && !ptrto->isVariableLength()) { if (!allowArrayWrap)
return (TypePointer *)0;
intb signOff = (intb)off;
sign_extend(signOff,size*8-1);
signOff = signOff % ptrtoSize;
if (signOff < 0)
signOff = signOff + ptrtoSize;
off = signOff;
if (off == 0) return this; }
}
type_metatype meta = ptrto->getMetatype();
bool isArray = (meta == TYPE_ARRAY);
if (isArray || meta == TYPE_STRUCT) {
par = this;
parOff = off;
}
Datatype *pt = ptrto->getSubType(off,&off);
if (pt == (Datatype *)0)
return (TypePointer *)0;
if (!isArray)
return typegrp.getTypePointerStripArray(size, pt, wordsize);
return typegrp.getTypePointer(size,pt,wordsize);
}
bool TypePointer::isPtrsubMatching(uintb off) const
{
if (ptrto->getMetatype()==TYPE_SPACEBASE) {
uintb newoff = AddrSpace::addressToByte(off,wordsize);
ptrto->getSubType(newoff,&newoff);
if (newoff != 0)
return false;
}
else {
int4 sz = off;
int4 typesize = ptrto->getSize();
if ((ptrto->getMetatype() != TYPE_ARRAY)&&(ptrto->getMetatype() != TYPE_STRUCT))
return false; else if ((typesize <= AddrSpace::addressToByteInt(sz,wordsize))&&(typesize!=0))
return false;
}
return true;
}
void TypeArray::printRaw(ostream &s) const
{
arrayof->printRaw(s);
s << " [" << dec << arraysize << ']';
}
int4 TypeArray::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
TypeArray *ta = (TypeArray *) &op; return arrayof->compare(*ta->arrayof,level); }
int4 TypeArray::compareDependency(const Datatype &op) const
{
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
TypeArray *ta = (TypeArray *) &op; if (arrayof != ta->arrayof) return (arrayof < ta->arrayof) ? -1 : 1; return (op.getSize()-size);
}
Datatype *TypeArray::getSubType(uintb off,uintb *newoff) const
{ *newoff = off % arrayof->getSize();
return arrayof;
}
Datatype *TypeArray::getSubEntry(int4 off,int4 sz,int4 *newoff,int4 *el) const
{
int4 noff = off % arrayof->getSize();
int4 nel = off / arrayof->getSize();
if (noff+sz > arrayof->getSize()) return (Datatype *)0;
*newoff = noff;
*el = nel;
return arrayof;
}
void TypeArray::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
a_v_i(s,"arraysize",arraysize);
s << '>';
arrayof->saveXmlRef(s);
s << "</type>";
}
void TypeArray::restoreXml(const Element *el,TypeFactory &typegrp)
{
restoreXmlBasic(el);
arraysize = -1;
istringstream j(el->getAttributeValue("arraysize"));
j.unsetf(ios::dec | ios::hex | ios::oct);
j >> arraysize;
arrayof = typegrp.restoreXmlType(*el->getChildren().begin());
if ((arraysize<=0)||(arraysize*arrayof->getSize()!=size))
throw LowlevelError("Bad size for array of type "+arrayof->getName());
}
TypeEnum::TypeEnum(const TypeEnum &op) : TypeBase(op)
{
namemap = op.namemap;
masklist = op.masklist;
flags |= (op.flags&poweroftwo)|enumtype;
}
void TypeEnum::setNameMap(const map<uintb,string> &nmap)
{
map<uintb,string>::const_iterator iter;
uintb curmask,lastmask;
int4 maxbit;
int4 curmaxbit;
bool fieldisempty;
namemap = nmap;
masklist.clear();
flags &= ~((uint4)poweroftwo);
maxbit = 8 * size - 1;
curmaxbit = 0;
while(curmaxbit <= maxbit) {
curmask = 1;
curmask <<= curmaxbit;
lastmask = 0;
fieldisempty = true;
while(curmask != lastmask) { lastmask = curmask;
for(iter=namemap.begin();iter!=namemap.end();++iter) { uintb val = (*iter).first;
if ((val & curmask) != 0) { curmask |= val; fieldisempty = false;
}
}
int4 lsb = leastsigbit_set(curmask);
int4 msb = mostsigbit_set(curmask);
if (msb > curmaxbit)
curmaxbit = msb;
uintb mask1 = 1;
mask1 = (mask1 << lsb) - 1; uintb mask2 = 1;
mask2 <<= msb;
mask2 <<= 1;
mask2 -= 1; curmask = mask1 ^ mask2;
}
if (fieldisempty) { if (!masklist.empty())
masklist.back() |= curmask; else
masklist.push_back(curmask);
}
else
masklist.push_back(curmask);
curmaxbit += 1;
}
if (masklist.size() > 1)
flags |= poweroftwo;
}
bool TypeEnum::getMatches(uintb val,vector<string> &valnames) const
{
map<uintb,string>::const_iterator iter;
int4 count;
for(count=0;count<2;++count) {
bool allmatch = true;
if (val == 0) { iter = namemap.find(val);
if (iter != namemap.end())
valnames.push_back( (*iter).second );
else
allmatch = false;
}
else {
for(int4 i=0;i<masklist.size();++i) {
uintb maskedval = val & masklist[i];
if (maskedval == 0) continue; iter = namemap.find(maskedval);
if (iter != namemap.end())
valnames.push_back( (*iter).second ); else { allmatch = false; break; }
}
}
if (allmatch) return (count==1); val = val ^ calc_mask(size); valnames.clear(); }
return false; }
int4 TypeEnum::compare(const Datatype &op,int4 level) const
{
return compareDependency(op);
}
int4 TypeEnum::compareDependency(const Datatype &op) const
{
int4 res = TypeBase::compareDependency(op); if (res != 0) return res;
const TypeEnum *te = (const TypeEnum *) &op;
map<uintb,string>::const_iterator iter1,iter2;
if (namemap.size() != te->namemap.size()) {
return (namemap.size() < te->namemap.size()) ? -1 : 1;
}
iter1 = namemap.begin();
iter2 = te->namemap.begin();
while(iter1 != namemap.end()) {
if ((*iter1).first != (*iter2).first)
return ((*iter1).first < (*iter2).first) ? -1:1;
if ((*iter1).second != (*iter2).second)
return ((*iter1).second < (*iter2).second) ? -1:1;
++iter1;
++iter2;
}
return 0;
}
void TypeEnum::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
a_v(s,"enum","true");
s << ">\n";
map<uintb,string>::const_iterator iter;
for(iter=namemap.begin();iter!=namemap.end();++iter) {
s << "<val";
a_v(s,"name",(*iter).second);
a_v_u(s,"value",(*iter).first);
s << "/>\n";
}
s << "</type>";
}
void TypeEnum::restoreXml(const Element *el,TypeFactory &typegrp)
{
restoreXmlBasic(el);
submeta = (metatype == TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM;
const List &list(el->getChildren());
List::const_iterator iter;
map<uintb,string> nmap;
for(iter=list.begin();iter!=list.end();++iter) {
uintb val;
Element *subel = *iter;
istringstream is(subel->getAttributeValue("value"));
is.unsetf(ios::dec|ios::hex|ios::oct);
intb valsign; is >> valsign;
val = (uintb)valsign & calc_mask(size);
nmap[val] = subel->getAttributeValue("name");
}
setNameMap(nmap);
}
TypeStruct::TypeStruct(const TypeStruct &op)
: Datatype(op)
{
setFields(op.field);
size = op.size; }
void TypeStruct::setFields(const vector<TypeField> &fd)
{
vector<TypeField>::const_iterator iter;
int4 end;
size = 0;
for(iter=fd.begin();iter!=fd.end();++iter) {
field.push_back(*iter);
end = (*iter).offset + (*iter).type->getSize();
if (end > size)
size = end;
}
}
int4 TypeStruct::getFieldIter(int4 off) const
{
int4 min = 0;
int4 max = field.size()-1;
while(min <= max) {
int4 mid = (min + max)/2;
const TypeField &curfield( field[mid] );
if (curfield.offset > off)
max = mid - 1;
else { if ((curfield.offset + curfield.type->getSize()) > off)
return mid;
min = mid + 1;
}
}
return -1;
}
int4 TypeStruct::getLowerBoundField(int4 off) const
{
if (field.empty()) return -1;
int4 min = 0;
int4 max = field.size()-1;
while(min < max) {
int4 mid = (min + max + 1)/2;
if (field[mid].offset > off)
max = mid - 1;
else { min = mid;
}
}
if (min == max && field[min].offset <= off)
return min;
return -1;
}
const TypeField *TypeStruct::getField(int4 off,int4 sz,int4 *newoff) const
{
int4 i;
int4 noff;
i = getFieldIter(off);
if (i < 0) return (const TypeField *)0;
const TypeField &curfield( field[i] );
noff = off - curfield.offset;
if (noff+sz > curfield.type->getSize()) return (const TypeField *)0;
*newoff = noff;
return &curfield;
}
Datatype *TypeStruct::getSubType(uintb off,uintb *newoff) const
{ int4 i;
i = getFieldIter(off);
if (i < 0) return Datatype::getSubType(off,newoff);
const TypeField &curfield( field[i] );
*newoff = off - curfield.offset;
return curfield.type;
}
Datatype *TypeStruct::nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const
{
int4 i = getLowerBoundField(off);
while(i >= 0) {
const TypeField &subfield( field[i] );
int4 diff = (int4)off - subfield.offset;
if (diff > 128) break;
Datatype *subtype = subfield.type;
if (subtype->getMetatype() == TYPE_ARRAY) {
*newoff = (intb)diff;
*elSize = ((TypeArray *)subtype)->getBase()->getSize();
return subtype;
}
else {
uintb suboff;
Datatype *res = subtype->nearestArrayedComponentBackward(subtype->getSize(), &suboff, elSize);
if (res != (Datatype *)0) {
*newoff = (intb)diff;
return subtype;
}
}
i -= 1;
}
return (Datatype *)0;
}
Datatype *TypeStruct::nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const
{
int4 i = getLowerBoundField(off);
i += 1;
while(i<field.size()) {
const TypeField &subfield( field[i] );
int4 diff = subfield.offset - off;
if (diff > 128) break;
Datatype *subtype = subfield.type;
if (subtype->getMetatype() == TYPE_ARRAY) {
*newoff = (intb)-diff;
*elSize = ((TypeArray *)subtype)->getBase()->getSize();
return subtype;
}
else {
uintb suboff;
Datatype *res = subtype->nearestArrayedComponentForward(0, &suboff, elSize);
if (res != (Datatype *)0) {
*newoff = (intb)-diff;
return subtype;
}
}
i += 1;
}
return (Datatype *)0;
}
int4 TypeStruct::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
const TypeStruct *ts = (const TypeStruct *)&op;
vector<TypeField>::const_iterator iter1,iter2;
if (field.size() != ts->field.size()) return (ts->field.size()-field.size());
iter1 = field.begin();
iter2 = ts->field.begin();
while(iter1 != field.end()) {
if ((*iter1).offset != (*iter2).offset)
return ((*iter1).offset < (*iter2).offset) ? -1:1;
if ((*iter1).name != (*iter2).name)
return ((*iter1).name < (*iter2).name) ? -1:1;
if ((*iter1).type->getMetatype() != (*iter2).type->getMetatype())
return ((*iter1).type->getMetatype() < (*iter2).type->getMetatype()) ? -1 : 1;
++iter1;
++iter2;
}
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
iter1 = field.begin();
iter2 = ts->field.begin();
while(iter1 != field.end()) {
if ((*iter1).type != (*iter2).type) { int4 c = (*iter1).type->compare( *(*iter2).type, level );
if (c != 0) return c;
}
++iter1;
++iter2;
}
return 0;
}
int4 TypeStruct::compareDependency(const Datatype &op) const
{
int4 res = Datatype::compareDependency(op);
if (res != 0) return res;
const TypeStruct *ts = (const TypeStruct *)&op;
vector<TypeField>::const_iterator iter1,iter2;
if (field.size() != ts->field.size()) return (ts->field.size()-field.size());
iter1 = field.begin();
iter2 = ts->field.begin();
while(iter1 != field.end()) {
if ((*iter1).offset != (*iter2).offset)
return ((*iter1).offset < (*iter2).offset) ? -1:1;
if ((*iter1).name != (*iter2).name)
return ((*iter1).name < (*iter2).name) ? -1:1;
Datatype *fld1 = (*iter1).type;
Datatype *fld2 = (*iter2).type;
if (fld1 != fld2)
return (fld1 < fld2) ? -1 : 1; ++iter1;
++iter2;
}
return 0;
}
void TypeStruct::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
s << ">\n";
vector<TypeField>::const_iterator iter;
for(iter=field.begin();iter!=field.end();++iter) {
s << "<field";
a_v(s,"name",(*iter).name);
a_v_i(s,"offset",(*iter).offset);
s << '>';
(*iter).type->saveXmlRef(s);
s << "</field>\n";
}
s << "</type>";
}
void TypeStruct::restoreFields(const Element *el,TypeFactory &typegrp)
{
const List &list(el->getChildren());
List::const_iterator iter;
int4 maxoffset = 0;
for(iter=list.begin();iter!=list.end();++iter) {
field.push_back( TypeField() );
field.back().name = (*iter)->getAttributeValue("name");
istringstream j((*iter)->getAttributeValue("offset"));
j.unsetf(ios::dec | ios::hex | ios::oct);
j >> field.back().offset;
field.back().type = typegrp.restoreXmlType( *(*iter)->getChildren().begin() );
int4 trialmax = field.back().offset + field.back().type->getSize();
if (trialmax > maxoffset)
maxoffset = trialmax;
if (field.back().name.size()==0) {
ostringstream s;
s << "unlabelled" << dec << field.back().offset;
field.back().name = s.str();
}
}
if (maxoffset > size)
throw LowlevelError("Size too small for fields of structure "+name);
if (size == 0) flags |= type_incomplete;
else
markComplete(); }
void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp)
{
flags |= is_ptrrel;
restoreXmlBasic(el);
metatype = TYPE_PTR; for(int4 i=0;i<el->getNumAttributes();++i)
if (el->getAttributeName(i) == "wordsize") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> wordsize;
}
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
ptrto = typegrp.restoreXmlType( *iter );
++iter;
parent = typegrp.restoreXmlType( *iter );
++iter;
istringstream s1((*iter)->getContent());
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> offset;
if (offset == 0)
throw new LowlevelError("For metatype=\"ptrstruct\", <off> tag must not be zero");
submeta = (ptrto->getMetatype()==TYPE_UNKNOWN) ? SUB_PTRREL_UNK: SUB_PTRREL;
if (name.size() == 0) cacheStrippedType(typegrp); }
bool TypePointerRel::evaluateThruParent(uintb addrOff) const
{
uintb byteOff = AddrSpace::addressToByte(addrOff, wordsize);
if (ptrto->getMetatype() == TYPE_STRUCT && byteOff < ptrto->getSize())
return false;
byteOff = (byteOff + offset) & calc_mask(size);
return (byteOff < parent->getSize());
}
void TypePointerRel::printRaw(ostream &s) const
{
ptrto->printRaw(s);
s << " *+";
s << dec << offset;
s << '[' ;
parent->printRaw(s);
s << ']';
}
int4 TypePointerRel::compareDependency(const Datatype &op) const
{
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
const TypePointerRel *tp = (const TypePointerRel*)&op; if (ptrto != tp->ptrto) return (ptrto < tp->ptrto) ? -1 : 1; if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
if (parent != tp->parent) return (parent < tp->parent) ? -1 : 1;
if (wordsize != tp->wordsize) return (wordsize < tp->wordsize) ? -1 : 1;
return (op.getSize()-size);
}
void TypePointerRel::saveXml(ostream &s) const
{
s << "<type";
saveXmlBasic(TYPE_PTRREL,s); if (wordsize != 1)
a_v_i(s,"wordsize",wordsize);
s << ">\n";
ptrto->saveXml(s);
s << '\n';
parent->saveXmlRef(s);
s << "\n<off>" << dec << offset << "</off>\n";
s << "</type>";
}
TypePointer *TypePointerRel::downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,
TypeFactory &typegrp)
{
type_metatype ptrtoMeta = ptrto->getMetatype();
if (off < ptrto->getSize() && (ptrtoMeta == TYPE_STRUCT || ptrtoMeta == TYPE_ARRAY)) {
return TypePointer::downChain(off,par,parOff,allowArrayWrap,typegrp);
}
uintb relOff = (off + offset) & calc_mask(size); if (relOff >= parent->getSize())
return (TypePointer *)0;
TypePointer *origPointer = typegrp.getTypePointer(size, parent, wordsize);
off = relOff;
if (relOff == 0 && offset != 0) return origPointer; return origPointer->downChain(off,par,parOff,allowArrayWrap,typegrp);
}
bool TypePointerRel::isPtrsubMatching(uintb off) const
{
if (stripped != (TypePointer *)0)
return TypePointer::isPtrsubMatching(off);
int4 iOff = AddrSpace::addressToByteInt((int4)off,wordsize);
iOff += offset;
return (iOff >= 0 && iOff <= parent->getSize());
}
Datatype *TypePointerRel::getPtrToFromParent(Datatype *base,int4 off,TypeFactory &typegrp)
{
if (off > 0) {
uintb curoff = off;
do {
base = base->getSubType(curoff,&curoff);
} while(curoff != 0 && base != (Datatype *)0);
if (base == (Datatype *)0)
base = typegrp.getBase(1, TYPE_UNKNOWN);
}
else
base = typegrp.getBase(1, TYPE_UNKNOWN);
return base;
}
void TypeCode::setPrototype(TypeFactory *tfact,ProtoModel *model,
Datatype *outtype,const vector<Datatype *> &intypes,
bool dotdotdot,Datatype *voidtype)
{
factory = tfact;
flags |= variable_length;
if (proto != (FuncProto *)0)
delete proto;
proto = new FuncProto();
proto->setInternal(model,voidtype);
vector<Datatype *> typelist;
vector<string> blanknames(intypes.size()+1);
if (outtype == (Datatype *)0)
typelist.push_back(voidtype);
else
typelist.push_back(outtype);
for(int4 i=0;i<intypes.size();++i)
typelist.push_back(intypes[i]);
proto->updateAllTypes(blanknames,typelist,dotdotdot);
proto->setInputLock(true);
proto->setOutputLock(true);
}
void TypeCode::setPrototype(TypeFactory *typegrp,const FuncProto *fp)
{
if (proto != (FuncProto *)0) {
delete proto;
proto = (FuncProto *)0;
factory = (TypeFactory *)0;
}
if (fp != (const FuncProto *)0) {
factory = typegrp;
proto = new FuncProto();
proto->copy(*fp);
}
}
TypeCode::TypeCode(const TypeCode &op) : Datatype(op)
{
proto = (FuncProto *)0;
factory = op.factory;
if (op.proto != (FuncProto *)0) {
proto = new FuncProto();
proto->copy(*op.proto);
}
}
TypeCode::TypeCode(void) : Datatype(1,TYPE_CODE)
{
proto = (FuncProto *)0;
factory = (TypeFactory *)0;
flags |= type_incomplete;
}
TypeCode::~TypeCode(void)
{
if (proto != (FuncProto *)0)
delete proto;
}
void TypeCode::printRaw(ostream &s) const
{
if (name.size()>0)
s << name;
else
s << "funcptr";
s << "()";
}
int4 TypeCode::compareBasic(const TypeCode *op) const
{
if (proto == (FuncProto *)0) {
if (op->proto == (FuncProto *)0) return 0;
return 1;
}
if (op->proto == (FuncProto *)0)
return -1;
if (!proto->hasModel()) {
if (op->proto->hasModel()) return 1;
}
else {
if (!op->proto->hasModel()) return -1;
const string &model1(proto->getModelName());
const string &model2(op->proto->getModelName());
if (model1 != model2)
return (model1 < model2) ? -1 : 1;
}
int4 nump = proto->numParams();
int4 opnump = op->proto->numParams();
if (nump != opnump)
return (opnump < nump) ? -1 : 1;
uint4 myflags = proto->getComparableFlags();
uint4 opflags = op->proto->getComparableFlags();
if (myflags != opflags)
return (myflags < opflags) ? -1 : 1;
return 2; }
Datatype *TypeCode::getSubType(uintb off,uintb *newoff) const
{
if (factory == (TypeFactory *)0) return (Datatype *)0;
*newoff = 0;
return factory->getBase(1, TYPE_CODE); }
int4 TypeCode::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
const TypeCode *tc = (const TypeCode *)&op;
res = compareBasic(tc);
if (res != 2) return res;
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
int4 nump = proto->numParams();
for(int4 i=0;i<nump;++i) {
Datatype *param = proto->getParam(i)->getType();
Datatype *opparam = tc->proto->getParam(i)->getType();
int4 c = param->compare(*opparam,level);
if (c != 0)
return c;
}
Datatype *otype = proto->getOutputType();
Datatype *opotype = tc->proto->getOutputType();
if (otype == (Datatype *)0) {
if (opotype == (Datatype *)0) return 0;
return 1;
}
if (opotype == (Datatype *)0) return -1;
return otype->compare(*opotype,level);
}
int4 TypeCode::compareDependency(const Datatype &op) const
{
int4 res = Datatype::compareDependency(op);
if (res != 0) return res;
const TypeCode *tc = (const TypeCode *)&op;
res = compareBasic(tc);
if (res != 2) return res;
int4 nump = proto->numParams();
for(int4 i=0;i<nump;++i) {
Datatype *param = proto->getParam(i)->getType();
Datatype *opparam = tc->proto->getParam(i)->getType();
if (param != opparam)
return (param < opparam) ? -1 : 1; }
Datatype *otype = proto->getOutputType();
Datatype *opotype = tc->proto->getOutputType();
if (otype == (Datatype *)0) {
if (opotype == (Datatype *)0) return 0;
return 1;
}
if (opotype == (Datatype *)0) return -1;
if (otype != opotype)
return (otype < opotype) ? -1 : 1;
return 0;
}
void TypeCode::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
s << ">\n";
if (proto != (FuncProto *)0)
proto->saveXml(s);
s << "</type>";
}
void TypeCode::restoreStub(const Element *el)
{
if (!el->getChildren().empty()) {
flags |= variable_length;
}
restoreXmlBasic(el);
}
void TypeCode::restorePrototype(const Element *el,bool isConstructor,bool isDestructor,TypeFactory &typegrp)
{
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
if (iter != list.end()) {
Architecture *glb = typegrp.getArch();
factory = &typegrp;
proto = new FuncProto();
proto->setInternal( glb->defaultfp, typegrp.getTypeVoid() );
proto->restoreXml(*iter,glb);
proto->setConstructor(isConstructor);
proto->setDestructor(isDestructor);
}
markComplete();
}
Scope *TypeSpacebase::getMap(void) const
{
Scope *res = glb->symboltab->getGlobalScope();
if (!localframe.isInvalid()) { Funcdata *fd = res->queryFunction(localframe);
if (fd != (Funcdata *)0)
res = fd->getScopeLocal();
}
return res;
}
Datatype *TypeSpacebase::getSubType(uintb off,uintb *newoff) const
{
Scope *scope = getMap();
off = AddrSpace::byteToAddress(off, spaceid->getWordSize()); Address nullPoint;
uintb fullEncoding;
Address addr = glb->resolveConstant(spaceid, off, -1, nullPoint, fullEncoding);
SymbolEntry *smallest;
smallest = scope->queryContainer(addr,1,nullPoint);
if (smallest == (SymbolEntry *)0) {
*newoff = 0;
return glb->types->getBase(1,TYPE_UNKNOWN);
}
*newoff = (addr.getOffset() - smallest->getAddr().getOffset()) + smallest->getOffset();
return smallest->getSymbol()->getType();
}
Datatype *TypeSpacebase::nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const
{
Scope *scope = getMap();
off = AddrSpace::byteToAddress(off, spaceid->getWordSize()); Address nullPoint;
uintb fullEncoding;
Address addr = glb->resolveConstant(spaceid, off, -1, nullPoint, fullEncoding);
SymbolEntry *smallest = scope->queryContainer(addr,1,nullPoint);
Address nextAddr;
Datatype *symbolType;
if (smallest == (SymbolEntry *)0 || smallest->getOffset() != 0)
nextAddr = addr + 32;
else {
symbolType = smallest->getSymbol()->getType();
if (symbolType->getMetatype() == TYPE_STRUCT) {
uintb structOff = addr.getOffset() - smallest->getAddr().getOffset();
uintb dummyOff;
Datatype *res = symbolType->nearestArrayedComponentForward(structOff, &dummyOff, elSize);
if (res != (Datatype *)0) {
*newoff = structOff;
return symbolType;
}
}
int4 sz = AddrSpace::byteToAddressInt(smallest->getSize(), spaceid->getWordSize());
nextAddr = smallest->getAddr() + sz;
}
if (nextAddr < addr)
return (Datatype *)0; smallest = scope->queryContainer(nextAddr,1,nullPoint);
if (smallest == (SymbolEntry *)0 || smallest->getOffset() != 0)
return (Datatype *)0;
symbolType = smallest->getSymbol()->getType();
*newoff = addr.getOffset() - smallest->getAddr().getOffset();
if (symbolType->getMetatype() == TYPE_ARRAY) {
*elSize = ((TypeArray *)symbolType)->getBase()->getSize();
return symbolType;
}
if (symbolType->getMetatype() == TYPE_STRUCT) {
uintb dummyOff;
Datatype *res = symbolType->nearestArrayedComponentForward(0, &dummyOff, elSize);
if (res != (Datatype *)0)
return symbolType;
}
return (Datatype *)0;
}
Datatype *TypeSpacebase::nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const
{
Datatype *subType = getSubType(off, newoff);
if (subType == (Datatype *)0)
return (Datatype *)0;
if (subType->getMetatype() == TYPE_ARRAY) {
*elSize = ((TypeArray *)subType)->getBase()->getSize();
return subType;
}
if (subType->getMetatype() == TYPE_STRUCT) {
uintb dummyOff;
Datatype *res = subType->nearestArrayedComponentBackward(*newoff,&dummyOff,elSize);
if (res != (Datatype *)0)
return subType;
}
return (Datatype *)0;
}
int4 TypeSpacebase::compare(const Datatype &op,int4 level) const
{
return compareDependency(op);
}
int4 TypeSpacebase::compareDependency(const Datatype &op) const
{
int4 res = Datatype::compareDependency(op);
if (res != 0) return res;
TypeSpacebase *tsb = (TypeSpacebase *) &op;
if (spaceid != tsb->spaceid) return (spaceid < tsb->spaceid) ? -1:1;
if (localframe.isInvalid()) return 0; if (localframe != tsb->localframe) return (localframe < tsb->localframe) ? -1:1;
return 0;
}
Address TypeSpacebase::getAddress(uintb off,int4 sz,const Address &point) const
{
uintb fullEncoding;
if (localframe.isInvalid())
sz = -1; return glb->resolveConstant(spaceid,off,sz,point,fullEncoding);
}
void TypeSpacebase::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
a_v(s,"space",spaceid->getName());
s << '>';
localframe.saveXml(s);
s << "</type>";
}
void TypeSpacebase::restoreXml(const Element *el,TypeFactory &typegrp)
{
restoreXmlBasic(el);
spaceid = glb->getSpaceByName(el->getAttributeValue("space"));
const List &list(el->getChildren());
localframe = Address::restoreXml(list.front(),typegrp.getArch());
}
TypeFactory::TypeFactory(Architecture *g)
{
glb = g;
sizeOfInt = 0;
align = 0;
enumsize = 0;
clearCache();
}
void TypeFactory::clearCache(void)
{
int4 i,j;
for(i=0;i<9;++i)
for(j=0;j<8;++j)
typecache[i][j] = (Datatype *)0;
typecache10 = (Datatype *)0;
typecache16 = (Datatype *)0;
type_nochar = (Datatype *)0;
}
void TypeFactory::setupSizes(void)
{
if (sizeOfInt == 0) {
sizeOfInt = 1; AddrSpace *spc = glb->getStackSpace();
if (spc != (AddrSpace *)0) {
const VarnodeData &spdata(spc->getSpacebase(0)); sizeOfInt = spdata.size;
if (sizeOfInt > 4) sizeOfInt = 4;
}
}
if (align == 0)
align = glb->getDefaultSize();
if (enumsize == 0) {
enumsize = align;
enumtype = TYPE_UINT;
}
}
void TypeFactory::setCoreType(const string &name,int4 size,
type_metatype meta,bool chartp)
{
Datatype *ct;
if (chartp) {
if (size == 1)
ct = getTypeChar(name);
else
ct = getTypeUnicode(name,size,meta);
}
else if (meta == TYPE_CODE)
ct = getTypeCode(name);
else if (meta == TYPE_VOID)
ct = getTypeVoid();
else
ct = getBase(size,meta,name);
ct->flags |= Datatype::coretype;
}
void TypeFactory::cacheCoreTypes(void)
{
DatatypeSet::iterator iter;
for(iter=tree.begin();iter!=tree.end();++iter) {
Datatype *ct = *iter;
Datatype *testct;
if (!ct->isCoreType()) continue;
if (ct->getSize() > 8) {
if (ct->getMetatype() == TYPE_FLOAT) {
if (ct->getSize() == 10)
typecache10 = ct;
else if (ct->getSize() == 16)
typecache16 = ct;
}
continue;
}
switch(ct->getMetatype()) {
case TYPE_INT:
if ((ct->getSize()==1)&&(!ct->isASCII()))
type_nochar = ct;
case TYPE_UINT:
if (ct->isEnumType()) break; if (ct->isASCII()) { typecache[ct->getSize()][ct->getMetatype()-TYPE_FLOAT] = ct;
break;
}
if (ct->isCharPrint()) break; case TYPE_VOID:
case TYPE_UNKNOWN:
case TYPE_BOOL:
case TYPE_CODE:
case TYPE_FLOAT:
testct = typecache[ct->getSize()][ct->getMetatype()-TYPE_FLOAT];
if (testct == (Datatype *)0)
typecache[ct->getSize()][ct->getMetatype()-TYPE_FLOAT] = ct;
break;
default:
break;
}
}
}
void TypeFactory::clear(void)
{
DatatypeSet::iterator iter;
for(iter=tree.begin();iter!=tree.end();++iter)
delete *iter;
tree.clear();
nametree.clear();
clearCache();
}
void TypeFactory::clearNoncore(void)
{
DatatypeSet::iterator iter;
Datatype *ct;
iter = tree.begin();
while(iter != tree.end()) {
ct = *iter;
if (ct->isCoreType()) {
++iter;
continue;
}
nametree.erase(ct);
tree.erase(iter++);
delete ct;
}
}
TypeFactory::~TypeFactory(void)
{
clear();
}
Datatype *TypeFactory::findByIdLocal(const string &n,uint8 id) const
{ DatatypeNameSet::const_iterator iter;
TypeBase ct(1,TYPE_UNKNOWN,n);
if (id != 0) { ct.id = id;
iter = nametree.find((Datatype *)&ct);
if (iter == nametree.end()) return (Datatype *)0; }
else { ct.id = 0;
iter = nametree.lower_bound((Datatype *)&ct);
if (iter == nametree.end()) return (Datatype *)0; if ((*iter)->getName() != n) return (Datatype *)0; }
return *iter;
}
Datatype *TypeFactory::findById(const string &n,uint8 id,int4 sz)
{
if (sz > 0) { id = Datatype::hashSize(id, sz); }
return findByIdLocal(n,id);
}
Datatype *TypeFactory::findByName(const string &n)
{
return findById(n,0,0);
}
Datatype *TypeFactory::findNoName(Datatype &ct)
{
DatatypeSet::const_iterator iter;
Datatype *res = (Datatype *)0;
iter = tree.find(&ct);
if (iter != tree.end())
res = *iter;
return res;
}
void TypeFactory::insert(Datatype *newtype)
{
pair<DatatypeSet::iterator,bool> insres = tree.insert(newtype);
if (!insres.second) {
ostringstream s;
s << "Shared type id: " << hex << newtype->getId() << endl;
s << " ";
newtype->printRaw(s);
s << " : ";
(*insres.first)->printRaw(s);
delete newtype;
throw LowlevelError(s.str());
}
if (newtype->id!=0)
nametree.insert(newtype);
}
Datatype *TypeFactory::findAdd(Datatype &ct)
{
Datatype *newtype,*res;
if (ct.name.size()!=0) { if (ct.id == 0) throw LowlevelError("Datatype must have a valid id");
res = findByIdLocal(ct.name,ct.id); if (res != (Datatype *)0) { if (0!=res->compareDependency( ct )) throw LowlevelError("Trying to alter definition of type: "+ct.name);
return res;
}
}
else {
res = findNoName(ct);
if (res != (Datatype *)0) return res; }
newtype = ct.clone(); insert(newtype);
return newtype;
}
Datatype *TypeFactory::setName(Datatype *ct,const string &n)
{
if (ct->id != 0)
nametree.erase( ct ); tree.erase(ct); ct->name = n; if (ct->id == 0)
ct->id = Datatype::hashName(n);
tree.insert(ct);
nametree.insert( ct ); return ct;
}
bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,uint4 flags)
{
int4 offset,cursize,curalign;
if (!ot->isIncomplete())
throw LowlevelError("Can only set fields on an incomplete structure");
offset = 0;
vector<TypeField>::iterator iter;
for(iter=fd.begin();iter!=fd.end();++iter) {
Datatype *ct = (*iter).type;
if (ct->getMetatype() == TYPE_VOID) return false;
if ((*iter).name.size() == 0) return false;
if ((*iter).offset != -1) {
int4 end = (*iter).offset + ct->getSize();
if (end > offset)
offset = end;
}
}
for(iter=fd.begin();iter!=fd.end();++iter) {
if ((*iter).offset != -1) continue;
cursize = (*iter).type->getSize();
curalign = 0;
if (align > 1) {
curalign = align;
while((curalign>>1) >= cursize)
curalign >>= 1;
curalign -= 1;
}
if ((offset & curalign)!=0)
offset = (offset-(offset & curalign) + (curalign+1));
(*iter).offset = offset;
offset += cursize;
}
sort(fd.begin(),fd.end());
tree.erase(ot);
ot->setFields(fd);
ot->flags &= ~(uint4)Datatype::type_incomplete;
ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length | Datatype::type_incomplete));
if (fixedsize > 0) { if (fixedsize > ot->size) ot->size = fixedsize; else if (fixedsize < ot->size) throw LowlevelError("Trying to force too small a size on "+ot->getName());
}
tree.insert(ot);
recalcPointerSubmeta(ot, SUB_PTR);
recalcPointerSubmeta(ot, SUB_PTR_STRUCT);
return true;
}
void TypeFactory::setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags)
{
if (!newCode->isIncomplete())
throw LowlevelError("Can only set prototype on incomplete data-type");
tree.erase(newCode);
newCode->setPrototype(this,fp);
newCode->flags &= ~(uint4)Datatype::type_incomplete;
newCode->flags |= (flags & (Datatype::variable_length | Datatype::type_incomplete));
tree.insert(newCode);
}
bool TypeFactory::setEnumValues(const vector<string> &namelist,
const vector<uintb> &vallist,
const vector<bool> &assignlist,
TypeEnum *te)
{
map<uintb,string> nmap;
map<uintb,string>::iterator mapiter;
uintb mask = calc_mask(te->getSize());
uintb maxval = 0;
for(uint4 i=0;i<namelist.size();++i) {
uintb val;
if (assignlist[i]) { val = vallist[i];
if (val > maxval)
maxval = val;
val &= mask;
mapiter = nmap.find(val);
if (mapiter != nmap.end()) return false; nmap[val] = namelist[i];
}
}
for(uint4 i=0;i<namelist.size();++i) {
uintb val;
if (!assignlist[i]) {
val = maxval;
maxval += 1;
val &= mask;
mapiter = nmap.find(val);
if (mapiter != nmap.end()) return false;
nmap[val] = namelist[i];
}
}
tree.erase(te);
te->setNameMap(nmap);
tree.insert(te);
return true;
}
void TypeFactory::orderRecurse(vector<Datatype *> &deporder,DatatypeSet &mark,
Datatype *ct) const
{ pair<DatatypeSet::iterator,bool> res = mark.insert(ct);
if (!res.second) return; if (ct->typedefImm != (Datatype *)0)
orderRecurse(deporder,mark,ct->typedefImm);
int4 size = ct->numDepend();
for(int4 i=0;i<size;++i)
orderRecurse(deporder,mark,ct->getDepend(i));
deporder.push_back(ct);
}
void TypeFactory::dependentOrder(vector<Datatype *> &deporder) const
{
DatatypeSet mark;
DatatypeSet::const_iterator iter;
for(iter=tree.begin();iter!=tree.end();++iter)
orderRecurse(deporder,mark,*iter);
}
TypeVoid *TypeFactory::getTypeVoid(void)
{
TypeVoid *ct = (TypeVoid *)typecache[0][TYPE_VOID-TYPE_FLOAT];
if (ct != (TypeVoid *)0)
return ct;
TypeVoid tv;
tv.id = Datatype::hashName(tv.getName());
ct = (TypeVoid *)tv.clone();
tree.insert(ct);
nametree.insert(ct);
typecache[0][TYPE_VOID-TYPE_FLOAT] = ct; return ct;
}
TypeChar *TypeFactory::getTypeChar(const string &n)
{
TypeChar tc(n);
tc.id = Datatype::hashName(n);
return (TypeChar *) findAdd(tc);
}
TypeUnicode *TypeFactory::getTypeUnicode(const string &nm,int4 sz,type_metatype m)
{
TypeUnicode tu(nm,sz,m);
tu.id = Datatype::hashName(nm);
return (TypeUnicode *) findAdd(tu);
}
Datatype *TypeFactory::getBaseNoChar(int4 s,type_metatype m)
{
if ((s==1)&&(m == TYPE_INT)&&(type_nochar != (Datatype *)0)) return type_nochar; return getBase(s,m); }
Datatype *TypeFactory::getBase(int4 s,type_metatype m)
{
Datatype *ct;
if (s<9) {
if (m >= TYPE_FLOAT) {
ct = typecache[s][m-TYPE_FLOAT];
if (ct != (Datatype *)0)
return ct;
}
}
else if (m==TYPE_FLOAT) {
if (s==10)
ct = typecache10;
else if (s==16)
ct = typecache16;
else
ct = (Datatype *)0;
if (ct != (Datatype *)0)
return ct;
}
if (s > glb->max_basetype_size) {
ct = typecache[1][TYPE_UNKNOWN-TYPE_FLOAT];
ct = getTypeArray(s,ct);
return findAdd(*ct);
}
TypeBase tmp(s,m);
return findAdd(tmp);
}
Datatype *TypeFactory::getBase(int4 s,type_metatype m,const string &n)
{
TypeBase tmp(s,m,n);
tmp.id = Datatype::hashName(n);
return findAdd(tmp);
}
TypeCode *TypeFactory::getTypeCode(void)
{
Datatype *ct = typecache[1][TYPE_CODE-TYPE_FLOAT];
if (ct != (Datatype *)0)
return (TypeCode *)ct;
TypeCode tmp; tmp.markComplete(); return (TypeCode *) findAdd(tmp);
}
TypeCode *TypeFactory::getTypeCode(const string &nm)
{
if (nm.size()==0) return getTypeCode();
TypeCode tmp; tmp.name = nm; tmp.id = Datatype::hashName(nm);
tmp.markComplete(); return (TypeCode *) findAdd(tmp);
}
void TypeFactory::recalcPointerSubmeta(Datatype *base,sub_metatype sub)
{
DatatypeSet::const_iterator iter;
TypePointer top(1,base,0); sub_metatype curSub = top.submeta;
if (curSub == sub) return; top.submeta = sub; iter = tree.lower_bound(&top);
while(iter != tree.end()) {
TypePointer *ptr = (TypePointer *)*iter;
if (ptr->getMetatype() != TYPE_PTR) break;
if (ptr->ptrto != base) break;
++iter;
if (ptr->submeta == sub) {
tree.erase(ptr);
ptr->submeta = curSub; tree.insert(ptr); }
}
}
Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id)
{
if (id == 0)
id = Datatype::hashName(name);
Datatype *res = findByIdLocal(name, id);
if (res != (Datatype *)0) {
if (ct != res->getTypedef())
throw LowlevelError("Trying to create typedef of existing type: " + name);
return res;
}
res = ct->clone(); res->name = name; res->id = id; res->flags &= ~((uint4)Datatype::coretype); res->typedefImm = ct;
insert(res);
return res;
}
TypePointer *TypeFactory::getTypePointerStripArray(int4 s,Datatype *pt,uint4 ws)
{
if (pt->hasStripped())
pt = pt->getStripped();
if (pt->getMetatype() == TYPE_ARRAY)
pt = ((TypeArray *)pt)->getBase(); TypePointer tmp(s,pt,ws);
return (TypePointer *) findAdd(tmp);
}
TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws)
{
if (pt->hasStripped())
pt = pt->getStripped();
TypePointer tmp(s,pt,ws);
return (TypePointer *) findAdd(tmp);
}
TypePointer *TypeFactory::getTypePointer(int4 s,Datatype *pt,uint4 ws,const string &n)
{
if (pt->hasStripped())
pt = pt->getStripped();
TypePointer tmp(s,pt,ws);
tmp.name = n;
tmp.id = Datatype::hashName(n);
return (TypePointer *) findAdd(tmp);
}
TypePointer *TypeFactory::getTypePointerNoDepth(int4 s,Datatype *pt,uint4 ws)
{
if (pt->getMetatype()==TYPE_PTR) {
Datatype *basetype = ((TypePointer *)pt)->getPtrTo();
type_metatype meta = basetype->getMetatype();
if (meta == TYPE_PTR)
pt = getBase(pt->getSize(),TYPE_UNKNOWN); else if (meta == TYPE_UNKNOWN) {
if (basetype->getSize() == pt->getSize()) return (TypePointer *)pt; pt = getBase(pt->getSize(),TYPE_UNKNOWN); }
}
return getTypePointer(s,pt,ws);
}
TypeArray *TypeFactory::getTypeArray(int4 as,Datatype *ao)
{
TypeArray tmp(as,ao);
return (TypeArray *) findAdd(tmp);
}
TypeStruct *TypeFactory::getTypeStruct(const string &n)
{
TypeStruct tmp;
tmp.name = n;
tmp.id = Datatype::hashName(n);
return (TypeStruct *) findAdd(tmp);
}
TypeEnum *TypeFactory::getTypeEnum(const string &n)
{
TypeEnum tmp(enumsize,enumtype,n);
tmp.id = Datatype::hashName(n);
return (TypeEnum *) findAdd(tmp);
}
TypeSpacebase *TypeFactory::getTypeSpacebase(AddrSpace *id,const Address &addr)
{
TypeSpacebase tsb(id,addr,glb);
return (TypeSpacebase *) findAdd(tsb);
}
TypeCode *TypeFactory::getTypeCode(ProtoModel *model,Datatype *outtype,
const vector<Datatype *> &intypes,
bool dotdotdot)
{
TypeCode tc; tc.setPrototype(this,model,outtype,intypes,dotdotdot,getTypeVoid());
tc.markComplete();
return (TypeCode *) findAdd(tc);
}
TypePointerRel *TypeFactory::getTypePointerRel(TypePointer *parentPtr,Datatype *ptrTo,int4 off)
{
TypePointerRel tp(parentPtr->size,ptrTo,parentPtr->wordsize,parentPtr->ptrto,off);
tp.cacheStrippedType(*this); TypePointerRel *res = (TypePointerRel *) findAdd(tp);
return res;
}
TypePointerRel *TypeFactory::getTypePointerRel(int4 sz,Datatype *parent,Datatype *ptrTo,int4 ws,int4 off,const string &nm)
{
TypePointerRel tp(sz,ptrTo,ws,parent,off);
tp.name = nm;
tp.id = Datatype::hashName(nm);
TypePointerRel *res = (TypePointerRel *)findAdd(tp);
return res;
}
void TypeFactory::destroyType(Datatype *ct)
{
if (ct->isCoreType())
throw LowlevelError("Cannot destroy core type");
nametree.erase(ct);
tree.erase(ct);
delete ct;
}
Datatype *TypeFactory::concretize(Datatype *ct)
{
type_metatype metatype = ct->getMetatype();
if (metatype == TYPE_CODE) {
if (ct->getSize() != 1)
throw LowlevelError("Primitive code data-type that is not size 1");
ct = getBase(1, TYPE_UNKNOWN);
}
return ct;
}
Datatype *TypeFactory::restoreXmlType(const Element *el)
{
Datatype *ct;
if (el->getName() == "typeref") {
uint8 newid = 0;
int4 size = -1;
int4 num = el->getNumAttributes();
for(int4 i=0;i<num;++i) {
const string &nm(el->getAttributeName(i));
if (nm == "id") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> newid;
}
else if (nm == "size") { istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> size;
}
}
const string &newname( el->getAttributeValue("name"));
if (newid == 0) newid = Datatype::hashName(newname);
ct = findById(newname,newid,size);
if (ct == (Datatype *)0)
throw LowlevelError("Unable to resolve type: "+newname);
return ct;
}
return restoreXmlTypeNoRef(el,false);
}
Datatype *TypeFactory::restoreXmlTypeWithCodeFlags(const Element *el,bool isConstructor,bool isDestructor)
{
TypePointer tp;
tp.restoreXmlBasic(el);
if (tp.getMetatype() != TYPE_PTR)
throw LowlevelError("Special type restoreXml does not see pointer");
for(int4 i=0;i<el->getNumAttributes();++i)
if (el->getAttributeName(i) == "wordsize") {
istringstream s(el->getAttributeValue(i));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> tp.wordsize;
}
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
const Element *subel = *iter;
if (subel->getAttributeValue("metatype") != "code")
throw LowlevelError("Special type restoreXml does not see code");
tp.ptrto = restoreCode(subel, isConstructor, isDestructor, false);
return findAdd(tp);
}
void TypeFactory::saveXml(ostream &s) const
{
vector<Datatype *> deporder;
vector<Datatype *>::iterator iter;
dependentOrder(deporder); s << "<typegrp";
a_v_i(s,"intsize",sizeOfInt);
a_v_i(s,"structalign",align);
a_v_i(s,"enumsize",enumsize);
a_v_b(s,"enumsigned",(enumtype==TYPE_INT));
s << ">\n";
for(iter=deporder.begin();iter!=deporder.end();++iter) {
if ((*iter)->getName().size()==0) continue; if ((*iter)->isCoreType()) { type_metatype meta = (*iter)->getMetatype();
if ((meta != TYPE_PTR)&&(meta != TYPE_ARRAY)&&
(meta != TYPE_STRUCT))
continue; }
s << ' ';
(*iter)->saveXml(s);
s << '\n';
}
s << "</typegrp>\n";
}
void TypeFactory::saveXmlCoreTypes(ostream &s) const
{
DatatypeSet::const_iterator iter;
Datatype *ct;
s << "<coretypes>\n";
for(iter=tree.begin();iter!=tree.end();++iter) {
ct = *iter;
if (!ct->isCoreType()) continue;
type_metatype meta = ct->getMetatype();
if ((meta==TYPE_PTR)||(meta==TYPE_ARRAY)||
(meta==TYPE_STRUCT))
continue;
s << ' ';
ct->saveXml(s);
s << '\n';
}
s << "</coretypes>\n";
}
Datatype *TypeFactory::restoreTypedef(const Element *el)
{
uint8 id;
istringstream s1(el->getAttributeValue("id"));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> id;
string nm = el->getAttributeValue("name");
Datatype *defedType = restoreXmlType( *el->getChildren().begin() );
if (defedType->isVariableLength())
id = Datatype::hashSize(id, defedType->size);
if (defedType->getMetatype() == TYPE_STRUCT) {
TypeStruct *prev = (TypeStruct *)findByIdLocal(nm, id);
if (prev != (Datatype *)0) {
if (defedType != prev->getTypedef())
throw LowlevelError("Trying to create typedef of existing type: " + prev->name);
TypeStruct *defedStruct = (TypeStruct *)defedType;
if (prev->field.size() != defedStruct->field.size())
prev->field = defedStruct->field;
return prev;
}
}
return getTypedef(defedType, nm, id);
}
Datatype* TypeFactory::restoreStruct(const Element *el,bool forcecore)
{
TypeStruct ts;
ts.restoreXmlBasic(el);
if (forcecore)
ts.flags |= Datatype::coretype;
Datatype *ct = findByIdLocal(ts.name,ts.id);
if (ct == (Datatype*)0) {
ct = findAdd(ts); }
else if (ct->getMetatype() != TYPE_STRUCT)
throw LowlevelError("Trying to redefine type: " + ts.name);
ts.restoreFields(el,*this);
if (!ct->isIncomplete()) { if (0 != ct->compareDependency(ts))
throw LowlevelError("Redefinition of structure: " + ts.name);
}
else { if (!setFields(ts.field,(TypeStruct*)ct,ts.size,ts.flags)) throw LowlevelError("Bad structure definition");
}
return ct;
}
Datatype *TypeFactory::restoreCode(const Element *el,bool isConstructor,bool isDestructor,bool forcecore)
{
TypeCode tc;
tc.restoreStub(el);
if (forcecore)
tc.flags |= Datatype::coretype;
Datatype *ct = findByIdLocal(tc.name,tc.id);
if (ct == (Datatype *)0) {
ct = findAdd(tc); }
else if (ct->getMetatype() != TYPE_CODE)
throw LowlevelError("Trying to redefine type: " + tc.name);
tc.restorePrototype(el, isConstructor, isDestructor, *this);
if (!ct->isIncomplete()) { if (0 != ct->compareDependency(tc))
throw LowlevelError("Redefinition of code data-type: " + tc.name);
}
else { setPrototype(tc.proto, (TypeCode *)ct, tc.flags);
}
return ct;
}
Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore)
{
string metastring;
Datatype *ct;
char c = el->getName()[0];
if (c != 't') {
if (el->getName() == "void")
return getTypeVoid(); if (el->getName() == "def")
return restoreTypedef(el);
}
metastring = el->getAttributeValue("metatype");
type_metatype meta = string2metatype(metastring);
switch(meta) {
case TYPE_PTR:
{
TypePointer tp;
tp.restoreXml(el,*this);
if (forcecore)
tp.flags |= Datatype::coretype;
ct = findAdd(tp);
}
break;
case TYPE_PTRREL:
{
TypePointerRel tp;
tp.restoreXml(el, *this);
if (forcecore)
tp.flags |= Datatype::coretype;
ct = findAdd(tp);
}
break;
case TYPE_ARRAY:
{
TypeArray ta;
ta.restoreXml(el,*this);
if (forcecore)
ta.flags |= Datatype::coretype;
ct = findAdd(ta);
}
break;
case TYPE_STRUCT:
ct = restoreStruct(el,forcecore);
break;
case TYPE_SPACEBASE:
{
TypeSpacebase tsb((AddrSpace *)0,Address(),glb);
tsb.restoreXml(el,*this);
if (forcecore)
tsb.flags |= Datatype::coretype;
ct = findAdd(tsb);
}
break;
case TYPE_CODE:
ct = restoreCode(el,false, false, forcecore);
break;
default:
for(int4 i=0;i<el->getNumAttributes();++i) {
if ((el->getAttributeName(i) == "char") &&
xml_readbool(el->getAttributeValue(i))) {
TypeChar tc(el->getAttributeValue("name"));
tc.restoreXml(el,*this);
if (forcecore)
tc.flags |= Datatype::coretype;
ct = findAdd(tc);
return ct;
}
else if ((el->getAttributeName(i) == "enum") &&
xml_readbool(el->getAttributeValue(i))) {
TypeEnum te(1,TYPE_INT); te.restoreXml(el,*this);
if (forcecore)
te.flags |= Datatype::coretype;
ct = findAdd(te);
return ct;
}
else if ((el->getAttributeName(i) == "utf") &&
xml_readbool(el->getAttributeValue(i))) {
TypeUnicode tu;
tu.restoreXml(el,*this);
if (forcecore)
tu.flags |= Datatype::coretype;
ct = findAdd(tu);
return ct;
}
}
{
TypeBase tb(0,TYPE_UNKNOWN);
tb.restoreXmlBasic(el);
if (forcecore)
tb.flags |= Datatype::coretype;
ct = findAdd(tb);
}
break;
}
return ct;
}
void TypeFactory::restoreXml(const Element *el)
{
const List &list(el->getChildren());
List::const_iterator iter;
string metastring;
istringstream i3(el->getAttributeValue("intsize"));
i3.unsetf(ios::dec | ios::hex | ios::oct);
i3 >> sizeOfInt;
istringstream i(el->getAttributeValue("structalign"));
i.unsetf(ios::dec | ios::hex | ios::oct);
i >> align;
istringstream i2(el->getAttributeValue("enumsize"));
i2.unsetf(ios::dec | ios::hex | ios::oct);
i2 >> enumsize;
if (xml_readbool(el->getAttributeValue("enumsigned")))
enumtype = TYPE_INT;
else
enumtype = TYPE_UINT;
for(iter=list.begin();iter!=list.end();++iter)
restoreXmlTypeNoRef(*iter,false);
}
void TypeFactory::restoreXmlCoreTypes(const Element *el)
{
clear();
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
restoreXmlTypeNoRef(*iter,true);
cacheCoreTypes();
}
void TypeFactory::parseDataOrganization(const Element *el)
{
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
if (subel->getName() == "integer_size") {
istringstream i(subel->getAttributeValue("value"));
i.unsetf(ios::dec | ios::hex | ios::oct);
i >> sizeOfInt;
}
else if (subel->getName() == "size_alignment_map") {
const List &childlist(subel->getChildren());
List::const_iterator iter2;
align = 0;
for(iter2=childlist.begin();iter2!=childlist.end();++iter2) {
const Element *childel = *iter2;
int4 val;
istringstream i2(childel->getAttributeValue("alignment"));
i2.unsetf(ios::dec | ios::hex | ios::oct);
i2 >> val;
if (val > align) align = val;
}
}
}
}
void TypeFactory::parseEnumConfig(const Element *el)
{
istringstream s(el->getAttributeValue("size"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> enumsize;
if (xml_readbool(el->getAttributeValue("signed")))
enumtype = TYPE_INT;
else
enumtype = TYPE_UINT;
}