mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Support for per function unaffected/killedbycall/likelytrash
This commit is contained in:
parent
156ce7ef80
commit
75b7d5fe14
8 changed files with 703 additions and 245 deletions
|
@ -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">
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()];
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue