Support for per function unaffected/killedbycall/likelytrash

This commit is contained in:
caheckman 2021-05-18 11:46:19 -04:00
parent 156ce7ef80
commit 75b7d5fe14
8 changed files with 703 additions and 245 deletions

View file

@ -296,6 +296,14 @@
<ref name="addr_tags_type"/>
</define>
<define name="pentry_group_type">
<oneOrMore>
<element name="pentry">
<ref name="pentry_type"/>
</element>
</oneOrMore>
</define>
<define name="rangelist_type">
<oneOrMore>
<ref name="range_type"/>
@ -359,11 +367,19 @@
<optional> <attribute name="pointermax"/> </optional>
<optional> <attribute name="thisbeforeretpointer"/> </optional>
<optional> <attribute name="killedbycall"/> </optional>
<zeroOrMore>
<element name="pentry">
<ref name="pentry_type"/>
</element>
</zeroOrMore>
<optional> <attribute name="separatefloat"/> </optional>
<interleave>
<zeroOrMore>
<element name="pentry">
<ref name="pentry_type"/>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="group">
<ref name="pentry_group_type"/>
</element>
</zeroOrMore>
</interleave>
</element>
<element name="output">

View file

@ -15,7 +15,7 @@
*/
package ghidra.program.model.lang;
import java.util.Iterator;
import java.util.*;
import java.util.Map.Entry;
import ghidra.app.plugin.processors.sleigh.VarnodeData;
@ -36,6 +36,9 @@ public class ParamEntry {
private static final int IS_BIG_ENDIAN = 16; // Interpret values in this container as big endian
private static final int SMALLSIZE_INTTYPE = 32; // Assume values that are below max size are extended based on integer type
private static final int SMALLSIZE_FLOAT = 64; // Assume values smaller than max -size- are floating-point extended to full size
//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
public static final int TYPE_UNKNOWN = 8; // Default type restriction
public static final int TYPE_PTR = 2; // pointer types
@ -93,6 +96,10 @@ public class ParamEntry {
return ((flags & REVERSE_STACK) != 0);
}
public boolean isGrouped() {
return ((flags & IS_GROUPED) != 0);
}
public boolean isBigEndian() {
return ((flags & IS_BIG_ENDIAN) != 0);
}
@ -105,6 +112,16 @@ 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;
}
@ -264,6 +281,71 @@ public class ParamEntry {
return slotnum;
}
/**
* Find the ParamEntry in the list whose storage matches the given Varnode
* @param curList is the list of ParamEntry
* @param varnode is the given Varnode
* @return the matching entry or null
*/
private static ParamEntry findEntryByStorage(List<ParamEntry> curList, Varnode varnode) {
ListIterator<ParamEntry> iter = curList.listIterator(curList.size());
while (iter.hasPrevious()) {
ParamEntry entry = iter.previous();
if (entry.spaceid.getSpaceID() == varnode.getSpace() &&
entry.addressbase == varnode.getOffset() && entry.size == varnode.getSize()) {
return entry;
}
}
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
* @throws XmlParseException if no overlap is found
*/
private void resolveJoin(List<ParamEntry> curList) throws XmlParseException {
if (joinrec == null) {
return;
}
int mingrp = 1000;
int maxgrp = -1;
for (Varnode piece : joinrec) {
ParamEntry entry = findEntryByStorage(curList, piece);
if (entry != null) {
if (entry.group < mingrp) {
mingrp = entry.group;
}
int max = entry.group + entry.groupsize;
if (max > maxgrp) {
maxgrp = max;
}
}
}
if (maxgrp < 0 || mingrp >= 1000) {
throw new XmlParseException("<pentry> join must overlap at least one previous entry");
}
group = mingrp;
groupsize = (maxgrp - mingrp);
if (groupsize > joinrec.length) {
throw new XmlParseException("<pentry> join must overlap sequential entries");
}
}
public void saveXml(StringBuilder buffer) {
buffer.append("<pentry");
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "minsize", minsize);
@ -275,9 +357,6 @@ public class ParamEntry {
String tok = (type == TYPE_FLOAT) ? "float" : "ptr";
SpecXmlUtils.encodeStringAttribute(buffer, "metatype", tok);
}
if (groupsize != 1) {
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "groupsize", groupsize);
}
String extString = null;
if ((flags & SMALLSIZE_SEXT) != 0) {
extString = "sign";
@ -307,7 +386,8 @@ public class ParamEntry {
buffer.append("</pentry>");
}
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
public void restoreXml(XmlPullParser parser, CompilerSpec cspec, List<ParamEntry> curList,
boolean grouped) throws XmlParseException {
flags = 0;
type = TYPE_UNKNOWN;
size = minsize = -1; // Must be filled in
@ -344,12 +424,6 @@ public class ParamEntry {
}
}
}
else if (name.equals("group")) {
group = SpecXmlUtils.decodeInt(entry.getValue());
}
else if (name.equals("groupsize")) {
groupsize = SpecXmlUtils.decodeInt(entry.getValue());
}
else if (name.equals("extension")) {
flags &= ~(SMALLSIZE_ZEXT | SMALLSIZE_SEXT | SMALLSIZE_INTTYPE | SMALLSIZE_FLOAT);
String value = entry.getValue();
@ -413,7 +487,10 @@ public class ParamEntry {
}
}
}
// resolveJoin
if (grouped) {
flags |= IS_GROUPED;
}
resolveJoin(curList);
parser.end(el);
}
@ -518,4 +595,26 @@ public class ParamEntry {
}
return TYPE_UNKNOWN;
}
/**
* ParamEntry within a group must be distinguishable by size or by type
* @param entry1 is the first being compared
* @param entry2 is the second being compared
* @throws XmlParseException if the pair is not distinguishable
*/
public static void orderWithinGroup(ParamEntry entry1, ParamEntry entry2)
throws XmlParseException {
if (entry2.minsize > entry1.size || entry1.minsize > entry2.size) {
return;
}
if (entry1.type != entry2.type) {
if (entry1.type == TYPE_UNKNOWN) {
throw new XmlParseException(
"<pentry> tags with a specific type must come before the general type");
}
return;
}
throw new XmlParseException(
"<pentry> tags within a group must be distinguished by size or type");
}
}

View file

@ -38,6 +38,7 @@ public class ParamListStandard implements ParamList {
// protected int maxdelay;
protected int pointermax; // If non-zero, maximum size of a datatype before converting to a pointer
protected boolean thisbeforeret; // Do hidden return pointers usurp the storage of the this pointer
protected int resourceTwoStart; // Group id starting the section resource section (or 0 if only one section)
protected ParamEntry[] entry;
protected AddressSpace spacebase; // Space containing relative offset parameters
@ -213,22 +214,89 @@ public class ParamListStandard implements ParamList {
if (thisbeforeret) {
SpecXmlUtils.encodeStringAttribute(buffer, "thisbeforeretpointer", "yes");
}
if (isInput && resourceTwoStart == 0) {
SpecXmlUtils.encodeBooleanAttribute(buffer, "separatefloat", false);
}
buffer.append(">\n");
int curgroup = -1;
for (ParamEntry el : entry) {
if (curgroup >= 0) {
if (!el.isGrouped() || el.getGroup() != curgroup) {
buffer.append("</group>\n");
curgroup = -1;
}
}
if (el.isGrouped()) {
if (curgroup < 0) {
buffer.append("<group>\n");
curgroup = el.getGroup();
}
}
el.saveXml(buffer);
buffer.append('\n');
}
if (curgroup >= 0) {
buffer.append("</group>\n");
}
buffer.append(isInput ? "</input>" : "</output>");
}
private void parsePentry(XmlPullParser parser, CompilerSpec cspec, ArrayList<ParamEntry> pe,
int groupid, boolean splitFloat, boolean grouped) throws XmlParseException {
ParamEntry pentry = new ParamEntry(groupid);
pe.add(pentry);
pentry.restoreXml(parser, cspec, pe, grouped);
if (splitFloat) {
if (pentry.getType() == ParamEntry.TYPE_FLOAT) {
if (resourceTwoStart >= 0) {
throw new XmlParseException(
"parameter list floating-point entries must come first");
}
}
else if (resourceTwoStart < 0) {
resourceTwoStart = groupid; // First time we have seen an integer slot
}
}
if (pentry.getSpace().isStackSpace()) {
spacebase = pentry.getSpace();
}
int maxgroup = pentry.getGroup() + pentry.getGroupSize();
if (maxgroup > numgroup) {
numgroup = maxgroup;
}
}
private void parseGroup(XmlPullParser parser, CompilerSpec cspec, ArrayList<ParamEntry> pe,
int groupid, boolean splitFloat) throws XmlParseException {
XmlElement el = parser.start("group");
int basegroup = numgroup;
int count = 0;
while (parser.peek().isStart()) {
parsePentry(parser, cspec, pe, basegroup, splitFloat, true);
count += 1;
ParamEntry lastEntry = pe.get(pe.size() - 1);
if (lastEntry.getSpace().getType() == AddressSpace.TYPE_JOIN) {
throw new XmlParseException(
"<pentry> in the join space not allowed in <group> tag");
}
if (count > 1) {
ParamEntry.orderWithinGroup(pe.get(pe.size() - 2), lastEntry);
if (count > 2) {
ParamEntry.orderWithinGroup(pe.get(pe.size() - 3), lastEntry);
}
}
}
parser.end(el);
}
@Override
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
ArrayList<ParamEntry> pe = new ArrayList<>();
int lastgroup = -1;
numgroup = 0;
spacebase = null;
pointermax = 0;
thisbeforeret = false;
boolean splitFloat = true;
XmlElement mainel = parser.start();
String attribute = mainel.getAttribute("pointermax");
if (attribute != null) {
@ -238,35 +306,30 @@ public class ParamListStandard implements ParamList {
if (attribute != null) {
thisbeforeret = SpecXmlUtils.decodeBoolean(attribute);
}
boolean seennonfloat = false; // Have we seen any integer slots yet
attribute = mainel.getAttribute("separatefloat");
if (attribute != null) {
splitFloat = SpecXmlUtils.decodeBoolean(attribute);
}
resourceTwoStart = splitFloat ? -1 : 0;
for (;;) {
XmlElement el = parser.peek();
if (!el.isStart()) {
break;
}
ParamEntry pentry = new ParamEntry(numgroup);
pentry.restoreXml(parser, cspec);
pe.add(pentry);
if (pentry.getType() == ParamEntry.TYPE_FLOAT) {
if (seennonfloat) {
throw new XmlParseException(
"parameter list floating-point entries must come first");
if (el.getName().equals("pentry")) {
parsePentry(parser, cspec, pe, numgroup, splitFloat, false);
}
else if (el.getName().equals("group")) {
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");
}
}
else {
seennonfloat = true;
}
if (pentry.getSpace().isStackSpace()) {
spacebase = pentry.getSpace();
}
int maxgroup = pentry.getGroup() + pentry.getGroupSize();
if (maxgroup > numgroup) {
numgroup = maxgroup;
}
if (pentry.getGroup() < lastgroup) {
throw new XmlParseException("pentrys must come in group order");
}
lastgroup = pentry.getGroup();
}
parser.end(mainel);
entry = new ParamEntry[pe.size()];

View file

@ -15,12 +15,14 @@
*/
package ghidra.program.model.lang;
import java.util.ArrayList;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.VariableStorage;
import ghidra.util.exception.InvalidInputException;
import java.util.ArrayList;
import ghidra.xml.XmlParseException;
import ghidra.xml.XmlPullParser;
public class ParamListStandardOut extends ParamListStandard {
@ -29,8 +31,9 @@ public class ParamListStandardOut extends ParamListStandard {
ArrayList<VariableStorage> res, boolean addAutoParams) {
int[] status = new int[numgroup];
for (int i = 0; i < numgroup; ++i)
for (int i = 0; i < numgroup; ++i) {
status[i] = 0;
}
VariableStorage store = assignAddress(prog, proto[0], status, false, false);
if (!store.isUnassignedStorage()) {
@ -57,4 +60,16 @@ public class ParamListStandardOut extends ParamListStandard {
}
@Override
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
super.restoreXml(parser, cspec);
// ParamEntry tags in the output list are considered a group
for (int i = 1; i < entry.length; ++i) {
ParamEntry.orderWithinGroup(entry[i - 1], entry[i]);
if (i > 1) {
ParamEntry.orderWithinGroup(entry[i - 2], entry[i]);
}
}
}
}