Fixes to support unaligned stack locations

This commit is contained in:
caheckman 2019-10-01 12:37:21 -04:00
parent 2ce191d865
commit fdcf0744ec
3 changed files with 142 additions and 64 deletions

View file

@ -113,16 +113,19 @@ int4 ParamEntry::justifiedContain(const Address &addr,int4 sz) const
return entry.justifiedContain(size,addr,sz,((flags&force_left_justify)!=0)); return entry.justifiedContain(size,addr,sz,((flags&force_left_justify)!=0));
} }
if (spaceid != addr.getSpace()) return -1; if (spaceid != addr.getSpace()) return -1;
if (addr.getOffset() < addressbase) return -1; uintb startaddr = addr.getOffset();
uintb endaddr = addr.getOffset() + sz - 1; if (startaddr < addressbase) return -1;
if (endaddr < addr.getOffset()) return -1; // Don't allow wrap around uintb endaddr = startaddr + sz - 1;
if (endaddr < startaddr) return -1; // Don't allow wrap around
if (endaddr > (addressbase+size-1)) return -1; if (endaddr > (addressbase+size-1)) return -1;
startaddr -= addressbase;
endaddr -= addressbase;
if (!isLeftJustified()) { // For right justified (big endian), endaddr must be aligned if (!isLeftJustified()) { // For right justified (big endian), endaddr must be aligned
int4 res = (int4)((endaddr+1) % alignment); int4 res = (int4)((endaddr+1) % alignment);
if (res==0) return 0; if (res==0) return 0;
return (alignment-res); return (alignment-res);
} }
return (int4)(addr.getOffset() % alignment); return (int4)(startaddr % alignment);
} }
/// \brief Calculate the containing memory range /// \brief Calculate the containing memory range
@ -160,7 +163,7 @@ bool ParamEntry::getContainer(const Address &addr,int4 sz,VarnodeData &res) cons
res.size = size; res.size = size;
return true; return true;
} }
uintb al = addr.getOffset() % alignment; uintb al = (addr.getOffset() - addressbase) % alignment;
res.space = spaceid; res.space = spaceid;
res.offset = addr.getOffset() - al; res.offset = addr.getOffset() - al;
res.size = (int4)(endaddr.getOffset()-res.offset) + 1; res.size = (int4)(endaddr.getOffset()-res.offset) + 1;
@ -203,7 +206,8 @@ OpCode ParamEntry::assumedExtension(const Address &addr,int4 sz,VarnodeData &res
} }
else { // Otherwise take up whole alignment else { // Otherwise take up whole alignment
res.space = spaceid; res.space = spaceid;
res.offset = addr.getOffset() - addr.getOffset() % alignment; int4 alignAdjust = (addr.getOffset() - addressbase) % alignment;
res.offset = addr.getOffset() - alignAdjust;
res.size = alignment; res.size = alignment;
} }
if ((flags & smallsize_zext)!=0) if ((flags & smallsize_zext)!=0)
@ -229,7 +233,7 @@ int4 ParamEntry::getSlot(const Address &addr,int4 skip) const
{ {
int4 res = group; int4 res = group;
if (alignment != 0) { if (alignment != 0) {
uintb diff = addr.getOffset() + skip - addressbase; // Assume addressbase % alignment == 0 uintb diff = addr.getOffset() + skip - addressbase;
int4 baseslot = (int4)diff / alignment; int4 baseslot = (int4)diff / alignment;
if (isReverseStack()) if (isReverseStack())
res += (numslots -1) - baseslot; res += (numslots -1) - baseslot;
@ -365,8 +369,8 @@ void ParamEntry::restoreXml(const Element *el,const AddrSpaceManager *manage,boo
spaceid = addr.getSpace(); spaceid = addr.getSpace();
addressbase = addr.getOffset(); addressbase = addr.getOffset();
if (alignment != 0) { if (alignment != 0) {
if ((addressbase % alignment) != 0) // if ((addressbase % alignment) != 0)
throw LowlevelError("Stack <pentry> address must match alignment"); // throw LowlevelError("Stack <pentry> address must match alignment");
numslots = size / alignment; numslots = size / alignment;
} }
if (spaceid->isReverseJustified()) { if (spaceid->isReverseJustified()) {
@ -890,8 +894,8 @@ bool ParamListStandard::checkJoin(const Address &hiaddr,int4 hisize,const Addres
if (entryHi->getGroup() == entryLo->getGroup()) { if (entryHi->getGroup() == entryLo->getGroup()) {
if (entryHi->isExclusion()||entryLo->isExclusion()) return false; if (entryHi->isExclusion()||entryLo->isExclusion()) return false;
if (!hiaddr.isContiguous(hisize,loaddr,losize)) return false; if (!hiaddr.isContiguous(hisize,loaddr,losize)) return false;
if ((hiaddr.getOffset() % entryHi->getAlign()) != 0) return false; if (((hiaddr.getOffset() - entryHi->getBase()) % entryHi->getAlign()) != 0) return false;
if ((loaddr.getOffset() % entryLo->getAlign()) != 0) return false; if (((loaddr.getOffset() - entryLo->getBase()) % entryLo->getAlign()) != 0) return false;
return true; return true;
} }
else { else {

View file

@ -113,13 +113,23 @@ public class ParamEntry {
} }
public boolean contains(ParamEntry op2) { public boolean contains(ParamEntry op2) {
if ((type != TYPE_UNKNOWN)&&(op2.type != type)) return false; if ((type != TYPE_UNKNOWN)&&(op2.type != type)) {
if (spaceid != op2.spaceid) return false; return false;
if (unsignedCompare(op2.addressbase,addressbase)) return false; }
if (spaceid != op2.spaceid) {
return false;
}
if (unsignedCompare(op2.addressbase,addressbase)) {
return false;
}
long op2end = op2.addressbase + op2.size -1; long op2end = op2.addressbase + op2.size -1;
long end = addressbase+size-1; long end = addressbase+size-1;
if (unsignedCompare(end,op2end)) return false; if (unsignedCompare(end,op2end)) {
if (alignment != op2.alignment) return false; return false;
}
if (alignment != op2.alignment) {
return false;
}
return true; return true;
} }
@ -130,10 +140,12 @@ public class ParamEntry {
Varnode vdata = joinrec[i]; Varnode vdata = joinrec[i];
int cur = justifiedContainAddress(vdata.getAddress().getAddressSpace(),vdata.getOffset(),vdata.getSize(), int cur = justifiedContainAddress(vdata.getAddress().getAddressSpace(),vdata.getOffset(),vdata.getSize(),
addr.getAddressSpace(),addr.getOffset(),sz,false,((flags & IS_BIG_ENDIAN)!=0)); addr.getAddressSpace(),addr.getOffset(),sz,false,((flags & IS_BIG_ENDIAN)!=0));
if (cur<0) if (cur<0) {
res += vdata.getSize(); // We skipped this many less significant bytes res += vdata.getSize(); // We skipped this many less significant bytes
else }
else {
return res + cur; return res + cur;
}
} }
return -1; // Not contained at all return -1; // Not contained at all
} }
@ -142,17 +154,30 @@ public class ParamEntry {
addr.getAddressSpace(),addr.getOffset(),sz, addr.getAddressSpace(),addr.getOffset(),sz,
((flags & FORCE_LEFT_JUSTIFY)!=0),((flags & IS_BIG_ENDIAN)!=0)); ((flags & FORCE_LEFT_JUSTIFY)!=0),((flags & IS_BIG_ENDIAN)!=0));
} }
if (spaceid != addr.getAddressSpace()) return -1; if (spaceid != addr.getAddressSpace()) {
if (unsignedCompare(addr.getOffset(), addressbase)) return -1; return -1;
long endaddr = addr.getOffset() + sz -1; }
if (unsignedCompare(endaddr,addr.getOffset())) return -1; // Don't allow wrap around long startaddr = addr.getOffset();
if (unsignedCompare(addressbase + size-1,endaddr)) return -1; if (unsignedCompare(startaddr, addressbase)) {
return -1;
}
long endaddr = startaddr + sz - 1;
if (unsignedCompare(endaddr, startaddr)) {
return -1; // Don't allow wrap around
}
if (unsignedCompare(addressbase + size-1,endaddr)) {
return -1;
}
startaddr -= addressbase;
endaddr -= addressbase;
if (!isLeftJustified()) { // For right justified (big endian), endaddr must be aligned if (!isLeftJustified()) { // For right justified (big endian), endaddr must be aligned
int res = (int)((endaddr+1) % alignment); int res = (int)((endaddr+1) % alignment);
if (res==0) return 0; if (res==0) {
return 0;
}
return (alignment-res); return (alignment-res);
} }
return (int)(addr.getOffset() % alignment); return (int) (startaddr % alignment);
} }
/** /**
@ -165,12 +190,14 @@ public class ParamEntry {
public int getSlot(Address addr,int skip) { public int getSlot(Address addr,int skip) {
int res = group; int res = group;
if (alignment != 0) { if (alignment != 0) {
long diff = addr.getOffset() + skip - addressbase; // Assume addressbase % alignment == 0 long diff = addr.getOffset() + skip - addressbase;
int baseslot = (int)diff / alignment; int baseslot = (int)diff / alignment;
if (isReverseStack()) if (isReverseStack()) {
res += (numslots-1) - baseslot; res += (numslots-1) - baseslot;
else }
else {
res += baseslot; res += baseslot;
}
} }
else if (skip != 0) { else if (skip != 0) {
res += (groupsize -1); res += (groupsize -1);
@ -190,22 +217,31 @@ public class ParamEntry {
public int getAddrBySlot(int slotnum,int sz,VarnodeData res) { public int getAddrBySlot(int slotnum,int sz,VarnodeData res) {
res.space = null; // Start with an invalid result res.space = null; // Start with an invalid result
int spaceused; int spaceused;
if (sz < minsize) return slotnum; if (sz < minsize) {
return slotnum;
}
if (alignment == 0) { // If not an aligned entry (allowing multiple slots) if (alignment == 0) { // If not an aligned entry (allowing multiple slots)
if (slotnum != 0) return slotnum; // Can only allocate slot 0 if (slotnum != 0) {
if (sz > size) return slotnum; // Check on maximum size return slotnum; // Can only allocate slot 0
}
if (sz > size) {
return slotnum; // Check on maximum size
}
res.space = spaceid; res.space = spaceid;
res.offset = addressbase; // Get base address of the slot res.offset = addressbase; // Get base address of the slot
spaceused = size; spaceused = size;
if ((flags & SMALLSIZE_FLOAT)!=0) // If the datatype is smaller than container, still return whole container if ((flags & SMALLSIZE_FLOAT)!=0) {
return slotnum; return slotnum;
}
} }
else { else {
int slotsused = sz / alignment; // How many slots does a -sz- byte object need int slotsused = sz / alignment; // How many slots does a -sz- byte object need
if ( (sz %alignment) != 0) if ( (sz %alignment) != 0) {
slotsused += 1; slotsused += 1;
if (slotnum + slotsused > numslots) // Check if there are enough slots left }
if (slotnum + slotsused > numslots) {
return slotnum; return slotnum;
}
spaceused = slotsused * alignment; spaceused = slotsused * alignment;
int index; int index;
if (isReverseStack()) { if (isReverseStack()) {
@ -213,14 +249,16 @@ public class ParamEntry {
index -= slotnum; index -= slotnum;
index -= slotsused; index -= slotsused;
} }
else else {
index = slotnum; index = slotnum;
}
res.space = spaceid; res.space = spaceid;
res.offset = addressbase + index * alignment; res.offset = addressbase + index * alignment;
slotnum += slotsused; // Inform caller of number of slots used slotnum += slotsused; // Inform caller of number of slots used
} }
if (!isLeftJustified()) // Adjust for right justified (big endian) if (!isLeftJustified()) {
res.offset += (spaceused - sz); res.offset += (spaceused - sz);
}
return slotnum; return slotnum;
} }
@ -236,7 +274,9 @@ public class ParamEntry {
for(;;) { for(;;) {
String attrName = "piece" + Integer.toString(pos+1); String attrName = "piece" + Integer.toString(pos+1);
String attrVal = el.getAttribute(attrName); String attrVal = el.getAttribute(attrName);
if (attrVal == null) break; if (attrVal == null) {
break;
}
int offpos = attrVal.indexOf(':'); int offpos = attrVal.indexOf(':');
Varnode newvn; Varnode newvn;
if (offpos == -1) { if (offpos == -1) {
@ -248,8 +288,9 @@ public class ParamEntry {
} }
else { else {
int szpos = attrVal.indexOf(':', offpos+1); int szpos = attrVal.indexOf(':', offpos+1);
if (szpos == -1) if (szpos == -1) {
throw new XmlParseException("join address piece attribute is malformed"); throw new XmlParseException("join address piece attribute is malformed");
}
String spcname = attrVal.substring(0, offpos); String spcname = attrVal.substring(0, offpos);
AddressSpace spc = cspec.getAddressSpace(spcname); AddressSpace spc = cspec.getAddressSpace(spcname);
long offset = SpecXmlUtils.decodeLong(attrVal.substring(offpos+1,szpos)); long offset = SpecXmlUtils.decodeLong(attrVal.substring(offpos+1,szpos));
@ -312,15 +353,18 @@ public class ParamEntry {
while(iter.hasNext()) { while(iter.hasNext()) {
Entry<String, String> entry = iter.next(); Entry<String, String> entry = iter.next();
String name = entry.getKey(); String name = entry.getKey();
if (name.equals("minsize")) if (name.equals("minsize")) {
minsize = SpecXmlUtils.decodeInt(entry.getValue()); minsize = SpecXmlUtils.decodeInt(entry.getValue());
}
else if (name.equals("size")) { // old style else if (name.equals("size")) { // old style
alignment = SpecXmlUtils.decodeInt(entry.getValue()); alignment = SpecXmlUtils.decodeInt(entry.getValue());
} }
else if (name.equals("align")) // New style else if (name.equals("align")) {
alignment = SpecXmlUtils.decodeInt(entry.getValue()); alignment = SpecXmlUtils.decodeInt(entry.getValue());
else if (name.equals("maxsize")) }
else if (name.equals("maxsize")) {
size = SpecXmlUtils.decodeInt(entry.getValue()); size = SpecXmlUtils.decodeInt(entry.getValue());
}
else if (name.equals("metatype")) { // Not implemented at the moment else if (name.equals("metatype")) { // Not implemented at the moment
String meta = entry.getValue(); String meta = entry.getValue();
// TODO: Currently only supporting "float", "ptr", and "unknown" metatypes // TODO: Currently only supporting "float", "ptr", and "unknown" metatypes
@ -333,41 +377,52 @@ public class ParamEntry {
} }
} }
} }
else if (name.equals("group")) // Override the group else if (name.equals("group")) {
group = SpecXmlUtils.decodeInt(entry.getValue()); group = SpecXmlUtils.decodeInt(entry.getValue());
else if (name.equals("groupsize")) }
else if (name.equals("groupsize")) {
groupsize = SpecXmlUtils.decodeInt(entry.getValue()); groupsize = SpecXmlUtils.decodeInt(entry.getValue());
}
else if (name.equals("extension")) { else if (name.equals("extension")) {
flags &= ~(SMALLSIZE_ZEXT | SMALLSIZE_SEXT | SMALLSIZE_INTTYPE); flags &= ~(SMALLSIZE_ZEXT | SMALLSIZE_SEXT | SMALLSIZE_INTTYPE);
String value = entry.getValue(); String value = entry.getValue();
if (value.equals("sign")) if (value.equals("sign")) {
flags |= SMALLSIZE_SEXT; flags |= SMALLSIZE_SEXT;
else if (value.equals("zero")) }
else if (value.equals("zero")) {
flags |= SMALLSIZE_ZEXT; flags |= SMALLSIZE_ZEXT;
else if (value.equals("inttype")) }
else if (value.equals("inttype")) {
flags |= SMALLSIZE_INTTYPE; flags |= SMALLSIZE_INTTYPE;
else if (value.equals("float")) }
else if (value.equals("float")) {
flags |= SMALLSIZE_FLOAT; flags |= SMALLSIZE_FLOAT;
else if (!value.equals("none")) }
else if (!value.equals("none")) {
throw new XmlParseException("Bad extension attribute: "+value); throw new XmlParseException("Bad extension attribute: "+value);
}
} }
else else {
throw new XmlParseException("Unknown paramentry attribute: "+name); throw new XmlParseException("Unknown paramentry attribute: "+name);
}
} }
if (minsize < 1 || size < minsize) if (minsize < 1 || size < minsize) {
throw new XmlParseException( throw new XmlParseException(
"paramentry size not specified properly: minsize=" + minsize + " maxsize=" + size); "paramentry size not specified properly: minsize=" + minsize + " maxsize=" + size);
if (alignment == size) }
if (alignment == size) {
alignment = 0; alignment = 0;
}
readXMLAddress(parser, cspec, size); readXMLAddress(parser, cspec, size);
boolean isbigendian = cspec.getLanguage().isBigEndian(); boolean isbigendian = cspec.getLanguage().isBigEndian();
if (isbigendian) if (isbigendian) {
flags |= IS_BIG_ENDIAN; flags |= IS_BIG_ENDIAN;
}
if (alignment != 0) { if (alignment != 0) {
if ((addressbase % alignment) != 0) // if ((addressbase % alignment) != 0)
throw new XmlParseException("Stack <pentry> address must match alignment"); // throw new XmlParseException("Stack <pentry> address must match alignment");
numslots = size / alignment; numslots = size / alignment;
} }
if (spaceid.isStackSpace() && (!cspec.isStackRightJustified()) && isbigendian) { if (spaceid.isStackSpace() && (!cspec.isStackRightJustified()) && isbigendian) {
@ -376,8 +431,9 @@ public class ParamEntry {
if (!normalstack) { if (!normalstack) {
flags |= REVERSE_STACK; flags |= REVERSE_STACK;
if (alignment != 0) { if (alignment != 0) {
if ((size % alignment) != 0) if ((size % alignment) != 0) {
throw new XmlParseException("For positive stack growth, <pentry> size must match alignment"); throw new XmlParseException("For positive stack growth, <pentry> size must match alignment");
}
} }
} }
// resolveJoin // resolveJoin
@ -407,24 +463,34 @@ public class ParamEntry {
* @return the endian aware offset or -1 * @return the endian aware offset or -1
*/ */
public static int justifiedContainAddress(AddressSpace spc1,long offset1,int sz1,AddressSpace spc2,long offset2,int sz2,boolean forceleft,boolean isBigEndian) { public static int justifiedContainAddress(AddressSpace spc1,long offset1,int sz1,AddressSpace spc2,long offset2,int sz2,boolean forceleft,boolean isBigEndian) {
if (spc1 != spc2) return -1; if (spc1 != spc2) {
if (unsignedCompare(offset2,offset1)) return -1; return -1;
}
if (unsignedCompare(offset2,offset1)) {
return -1;
}
long off1 = offset1 + (sz1 - 1); long off1 = offset1 + (sz1 - 1);
long off2 = offset2 + (sz2 - 1); long off2 = offset2 + (sz2 - 1);
if (unsignedCompare(off1,off2)) return -1; if (unsignedCompare(off1,off2)) {
if (isBigEndian && (!forceleft)) return -1;
}
if (isBigEndian && (!forceleft)) {
return (int)(off1 - off2); return (int)(off1 - off2);
}
return (int)(offset2 - offset1); return (int)(offset2 - offset1);
} }
public static int getMetatype(DataType tp) { public static int getMetatype(DataType tp) {
// TODO: A complete metatype implementation // TODO: A complete metatype implementation
if (tp instanceof TypeDef) if (tp instanceof TypeDef) {
tp = ((TypeDef)tp).getBaseDataType(); tp = ((TypeDef)tp).getBaseDataType();
if (tp instanceof AbstractFloatDataType) }
if (tp instanceof AbstractFloatDataType) {
return TYPE_FLOAT; return TYPE_FLOAT;
if (tp instanceof Pointer) }
if (tp instanceof Pointer) {
return TYPE_PTR; return TYPE_PTR;
}
return TYPE_UNKNOWN; return TYPE_UNKNOWN;
} }
} }

View file

@ -27,7 +27,7 @@
<register name="o5"/> <register name="o5"/>
</pentry> </pentry>
<pentry minsize="1" maxsize="500" align="8"> <pentry minsize="1" maxsize="500" align="8">
<addr offset="8" space="stack"/> <addr offset="0x8af" space="stack"/> <!-- Big offset is due to SPARC 64-bit "stack bias" -->
</pentry> </pentry>
</input> </input>
<output> <output>
@ -63,6 +63,10 @@
<register name="sp"/> <register name="sp"/>
<register name="didrestore"/> <register name="didrestore"/>
</unaffected> </unaffected>
<localrange>
<range space="stack" first="0xfff0bdc1" last="0xffffffff"/>
<range space="stack" first="0x0" last="0x8ae"/> <!-- Stack bias of 7FF + 0xb0 window size -->
</localrange>
</prototype> </prototype>
</default_proto> </default_proto>
@ -87,7 +91,7 @@
<register name="g6"/> <register name="g6"/>
</pentry> </pentry>
<pentry minsize="1" maxsize="500" align="8"> <pentry minsize="1" maxsize="500" align="8">
<addr offset="8" space="stack"/> <addr offset="0x8af" space="stack"/> <!-- Big offset is due to SPARC 64-bit "stack bias" -->
</pentry> </pentry>
</input> </input>
<output> <output>
@ -123,5 +127,9 @@
<register name="sp"/> <register name="sp"/>
<register name="didrestore"/> <register name="didrestore"/>
</unaffected> </unaffected>
<localrange>
<range space="stack" first="0xfff0bdc1" last="0xffffffff"/>
<range space="stack" first="0x0" last="0x8ae"/> <!-- Stack bias of 7FF + 0xb0 window size -->
</localrange>
</prototype> </prototype>
</compiler_spec> </compiler_spec>