mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch 'origin/GP-1871_OverlappingPentry'
This commit is contained in:
commit
06c8cfc24a
7 changed files with 282 additions and 179 deletions
|
@ -39,6 +39,7 @@ public class ParamEntry {
|
|||
//private static final int EXTRACHECK_HIGH = 128;
|
||||
//private static final int EXTRACHECK_LOW = 256;
|
||||
private static final int IS_GROUPED = 512; // The entry is grouped with other entries
|
||||
private static final int OVERLAPPING = 0x100; // This overlaps an earlier entry
|
||||
|
||||
public static final int TYPE_UNKNOWN = 8; // Default type restriction
|
||||
public static final int TYPE_PTR = 2; // pointer types
|
||||
|
@ -100,6 +101,10 @@ public class ParamEntry {
|
|||
return ((flags & IS_GROUPED) != 0);
|
||||
}
|
||||
|
||||
public boolean isOverlap() {
|
||||
return ((flags & OVERLAPPING) != 0);
|
||||
}
|
||||
|
||||
public boolean isBigEndian() {
|
||||
return ((flags & IS_BIG_ENDIAN) != 0);
|
||||
}
|
||||
|
@ -112,16 +117,6 @@ public class ParamEntry {
|
|||
return (((flags & IS_BIG_ENDIAN) == 0) || ((flags & FORCE_LEFT_JUSTIFY) != 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if at least one piece of a join doesn't overlap with another ParamEntry
|
||||
*/
|
||||
public boolean isNonOverlappingJoin() {
|
||||
if (joinrec == null) {
|
||||
return false;
|
||||
}
|
||||
return (joinrec.length != groupsize);
|
||||
}
|
||||
|
||||
public AddressSpace getSpace() {
|
||||
return spaceid;
|
||||
}
|
||||
|
@ -130,22 +125,61 @@ public class ParamEntry {
|
|||
return joinrec;
|
||||
}
|
||||
|
||||
public boolean contains(ParamEntry op2) {
|
||||
if ((type != TYPE_UNKNOWN) && (op2.type != type)) {
|
||||
/**
|
||||
* Is this ParamEntry, as a memory range, contained by the given memory range.
|
||||
* @param addr is the starting address of the given memory range
|
||||
* @param sz is the number of bytes in the given memory range
|
||||
* @return true if this is contained
|
||||
*/
|
||||
public boolean containedBy(Address addr, int sz) {
|
||||
if (spaceid != addr.getAddressSpace()) {
|
||||
return false;
|
||||
}
|
||||
if (spaceid != op2.spaceid) {
|
||||
if (Long.compareUnsigned(addressbase, addr.getOffset()) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (unsignedCompare(op2.addressbase, addressbase)) {
|
||||
long rangeEnd = addr.getOffset() + sz - 1;
|
||||
long thisEnd = addressbase + size - 1;
|
||||
return (Long.compareUnsigned(thisEnd, rangeEnd) <= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this ParamEntry intersect the given range in some way
|
||||
* @param addr is the starting address of the given range
|
||||
* @param sz is the number of bytes in the given range
|
||||
* @return true if there is an intersection
|
||||
*/
|
||||
public boolean intersects(Address addr, int sz) {
|
||||
long rangeend;
|
||||
if (joinrec != null) {
|
||||
rangeend = addr.getOffset() + sz - 1;
|
||||
for (Varnode vn : joinrec) {
|
||||
if (addr.getAddressSpace().getSpaceID() != vn.getSpace()) {
|
||||
continue;
|
||||
}
|
||||
long vnend = vn.getOffset() + vn.getSize() - 1;
|
||||
if (Long.compareUnsigned(addr.getOffset(), vn.getOffset()) < 0 &&
|
||||
Long.compareUnsigned(rangeend, vnend) < 0) {
|
||||
continue;
|
||||
}
|
||||
if (Long.compareUnsigned(addr.getOffset(), vn.getOffset()) > 0 &&
|
||||
Long.compareUnsigned(rangeend, vnend) > 0) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (spaceid.getSpaceID() != addr.getAddressSpace().getSpaceID()) {
|
||||
return false;
|
||||
}
|
||||
long op2end = op2.addressbase + op2.size - 1;
|
||||
long end = addressbase + size - 1;
|
||||
if (unsignedCompare(end, op2end)) {
|
||||
rangeend = addr.getOffset() + sz - 1;
|
||||
long thisend = addressbase + size - 1;
|
||||
if (Long.compareUnsigned(addr.getOffset(), addressbase) < 0 &&
|
||||
Long.compareUnsigned(rangeend, thisend) < 0) {
|
||||
return false;
|
||||
}
|
||||
if (alignment != op2.alignment) {
|
||||
if (Long.compareUnsigned(addr.getOffset(), addressbase) > 0 &&
|
||||
Long.compareUnsigned(rangeend, thisend) > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -177,14 +211,14 @@ public class ParamEntry {
|
|||
return -1;
|
||||
}
|
||||
long startaddr = addr.getOffset();
|
||||
if (unsignedCompare(startaddr, addressbase)) {
|
||||
if (Long.compareUnsigned(startaddr, addressbase) < 0) {
|
||||
return -1;
|
||||
}
|
||||
long endaddr = startaddr + sz - 1;
|
||||
if (unsignedCompare(endaddr, startaddr)) {
|
||||
if (Long.compareUnsigned(endaddr, startaddr) < 0) {
|
||||
return -1; // Don't allow wrap around
|
||||
}
|
||||
if (unsignedCompare(addressbase + size - 1, endaddr)) {
|
||||
if (Long.compareUnsigned(addressbase + size - 1, endaddr) < 0) {
|
||||
return -1;
|
||||
}
|
||||
startaddr -= addressbase;
|
||||
|
@ -199,6 +233,27 @@ public class ParamEntry {
|
|||
return (int) (startaddr % alignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this ParamEntry contain another entry (as a subpiece)
|
||||
* @param otherEntry is the other entry
|
||||
* @return true if this contains the other entry
|
||||
*/
|
||||
public boolean contains(ParamEntry otherEntry) {
|
||||
if (otherEntry.joinrec != null) {
|
||||
return false; // Assume a join entry cannot be contained
|
||||
}
|
||||
if (joinrec == null) {
|
||||
Address addr = spaceid.getAddress(addressbase);
|
||||
return otherEntry.containedBy(addr, size);
|
||||
}
|
||||
for (Varnode vn : joinrec) {
|
||||
if (otherEntry.containedBy(vn.getAddress(), vn.getSize())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming the address is contained in this entry and we -skip- to a certain byte
|
||||
* return the slot associated with that byte
|
||||
|
@ -299,20 +354,6 @@ public class ParamEntry {
|
|||
return null;
|
||||
}
|
||||
|
||||
public int countJoinOverlap(List<ParamEntry> curList) {
|
||||
if (joinrec == null) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (Varnode vn : joinrec) {
|
||||
ParamEntry match = findEntryByStorage(curList, vn);
|
||||
if (match != null) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the group and groupsize based on the ParamEntrys being overlapped
|
||||
* @param curList is the current list of ParamEntry
|
||||
|
@ -341,11 +382,61 @@ public class ParamEntry {
|
|||
}
|
||||
group = mingrp;
|
||||
groupsize = (maxgrp - mingrp);
|
||||
flags |= OVERLAPPING;
|
||||
if (groupsize > joinrec.length) {
|
||||
throw new XmlParseException("<pentry> join must overlap sequential entries");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for overlap with any previous ParamEntry. Reassign group and groupsize to
|
||||
* reflect this overlap.
|
||||
* @param curList is the list of previous ParamEntry
|
||||
* @throws XmlParseException if overlaps do not take the correct form
|
||||
*/
|
||||
private void resolveOverlap(List<ParamEntry> curList) throws XmlParseException {
|
||||
if (joinrec != null) {
|
||||
return;
|
||||
}
|
||||
int grpsize = 0;
|
||||
int mingrp = 1000;
|
||||
int maxgrp = -1;
|
||||
Address addr = spaceid.getAddress(addressbase);
|
||||
for (ParamEntry entry : curList) {
|
||||
if (entry == this) {
|
||||
continue;
|
||||
}
|
||||
if (!entry.intersects(addr, size)) {
|
||||
continue;
|
||||
}
|
||||
if (contains(entry)) {
|
||||
if (entry.isOverlap()) {
|
||||
continue; // Don't count resources (already counted overlapped pentry)
|
||||
}
|
||||
if (entry.group < mingrp) {
|
||||
mingrp = entry.group;
|
||||
}
|
||||
int max = entry.group + entry.groupsize;
|
||||
if (max > maxgrp) {
|
||||
maxgrp = max;
|
||||
}
|
||||
grpsize += entry.groupsize;
|
||||
}
|
||||
else {
|
||||
throw new XmlParseException("Illegal overlap of <pentry> in compiler spec");
|
||||
}
|
||||
}
|
||||
if (grpsize == 0) {
|
||||
return; // No overlaps
|
||||
}
|
||||
if (grpsize != (maxgrp - mingrp)) {
|
||||
throw new XmlParseException("<pentry> must overlap sequential entries");
|
||||
}
|
||||
group = mingrp;
|
||||
groupsize = grpsize;
|
||||
flags |= OVERLAPPING;
|
||||
}
|
||||
|
||||
public void saveXml(StringBuilder buffer) {
|
||||
buffer.append("<pentry");
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "minsize", minsize);
|
||||
|
@ -491,6 +582,7 @@ public class ParamEntry {
|
|||
flags |= IS_GROUPED;
|
||||
}
|
||||
resolveJoin(curList);
|
||||
resolveOverlap(curList);
|
||||
parser.end(el);
|
||||
}
|
||||
|
||||
|
@ -521,16 +613,6 @@ public class ParamEntry {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsigned less-than operation
|
||||
* @param a is the first operand
|
||||
* @param b is the second operand
|
||||
* @return return true is a is less than b, where a and b are interpreted as unsigned integers
|
||||
*/
|
||||
public static boolean unsignedCompare(long a, long b) {
|
||||
return (a + 0x8000000000000000L < b + 0x8000000000000000L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return -1 if (op2,sz2) is not properly contained in (op1,sz1)
|
||||
* If it is contained, return the endian aware offset of (op2,sz2)
|
||||
|
@ -551,12 +633,12 @@ public class ParamEntry {
|
|||
if (spc1 != spc2) {
|
||||
return -1;
|
||||
}
|
||||
if (unsignedCompare(offset2, offset1)) {
|
||||
if (Long.compareUnsigned(offset2, offset1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
long off1 = offset1 + (sz1 - 1);
|
||||
long off2 = offset2 + (sz2 - 1);
|
||||
if (unsignedCompare(off1, off2)) {
|
||||
if (Long.compareUnsigned(off1, off2) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (isBigEndian && (!forceleft)) {
|
||||
|
|
|
@ -317,14 +317,6 @@ public class ParamListStandard implements ParamList {
|
|||
parseGroup(parser, cspec, pe, numgroup, splitFloat);
|
||||
}
|
||||
}
|
||||
// Check that any pentry tags with join storage don't overlap following tags
|
||||
for (ParamEntry curEntry : pe) {
|
||||
if (curEntry.isNonOverlappingJoin()) {
|
||||
if (curEntry.countJoinOverlap(pe) != 1) {
|
||||
throw new XmlParseException("pentry tag must be listed after all its overlaps");
|
||||
}
|
||||
}
|
||||
}
|
||||
parser.end(mainel);
|
||||
entry = new ParamEntry[pe.size()];
|
||||
pe.toArray(entry);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue