GP-1647 equivalence check

This commit is contained in:
caheckman 2022-01-07 19:54:07 -05:00
parent 4830d035b3
commit 4bfade4cd8
23 changed files with 409 additions and 380 deletions

View file

@ -86,7 +86,7 @@ public class DecompInterface {
// Last warning messages from the decompiler // Last warning messages from the decompiler
// or other error message // or other error message
protected String decompileMessage; protected String decompileMessage;
protected BasicCompilerSpec compilerSpec; protected CompilerSpec compilerSpec;
protected DecompileProcess decompProcess; protected DecompileProcess decompProcess;
protected DecompileCallback decompCallback; protected DecompileCallback decompCallback;
private DecompileDebug debug; private DecompileDebug debug;
@ -221,7 +221,9 @@ public class DecompInterface {
(SleighLanguageDescription) pcodelanguage.getLanguageDescription(); (SleighLanguageDescription) pcodelanguage.getLanguageDescription();
ResourceFile pspecfile = sleighdescription.getSpecFile(); ResourceFile pspecfile = sleighdescription.getSpecFile();
String pspecxml = fileToString(pspecfile); String pspecxml = fileToString(pspecfile);
String cspecxml = compilerSpec.getXMLString(); StringBuilder buffer = new StringBuilder();
compilerSpec.saveXml(buffer);
String cspecxml = buffer.toString();
decompCallback.setNativeMessage(null); decompCallback.setNativeMessage(null);
decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes); decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes);
@ -313,7 +315,7 @@ public class DecompInterface {
"Language has unsupported compiler spec: " + spec.getClass().getName(); "Language has unsupported compiler spec: " + spec.getClass().getName();
return false; return false;
} }
compilerSpec = (BasicCompilerSpec) spec; compilerSpec = spec;
dtmanage = new PcodeDataTypeManager(prog); dtmanage = new PcodeDataTypeManager(prog);
try { try {

View file

@ -42,4 +42,22 @@ public interface BitFieldPacking {
* a zero-length bit-field * a zero-length bit-field
*/ */
int getZeroLengthBoundary(); int getZeroLengthBoundary();
/**
* Determine if this BitFieldPacking is equivalent to another specified instance
* @param obj is the other instance
* @return true if they are equivalent
*/
public default boolean isEquivalent(BitFieldPacking obj) {
if (isTypeAlignmentEnabled() != obj.isTypeAlignmentEnabled()) {
return false;
}
if (useMSConvention() != obj.useMSConvention()) {
return false;
}
if (getZeroLengthBoundary() != obj.getZeroLengthBoundary()) {
return false;
}
return true;
}
} }

View file

@ -118,24 +118,4 @@ public class BitFieldPackingImpl implements BitFieldPacking {
} }
parser.end(); parser.end();
} }
@Override
public boolean equals(Object obj) {
BitFieldPackingImpl op2 = (BitFieldPackingImpl) obj;
if (typeAlignmentEnabled != op2.typeAlignmentEnabled) {
return false;
}
if (useMSConvention != op2.useMSConvention) {
return false;
}
if (zeroLengthBoundary != op2.zeroLengthBoundary) {
return false;
}
return true;
}
@Override
public int hashCode() {
return (typeAlignmentEnabled ? 1 : 13) + (useMSConvention ? 5 : 27) + zeroLengthBoundary;
}
} }

View file

@ -172,4 +172,69 @@ public interface DataOrganization {
// * @return the aligned offset for the data type // * @return the aligned offset for the data type
// */ // */
// int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize); // int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize);
/**
* Determine if this DataOrganization is equivalent to another specific instance
* @param obj is the other instance
* @return true if they are equivalent
*/
public default boolean isEquivalent(DataOrganization obj) {
if (getAbsoluteMaxAlignment() != obj.getAbsoluteMaxAlignment()) {
return false;
}
if (isBigEndian() != obj.isBigEndian()) {
return false;
}
if (!getBitFieldPacking().isEquivalent(obj.getBitFieldPacking())) {
return false;
}
if (getCharSize() != obj.getCharSize() || getWideCharSize() != obj.getWideCharSize()) {
return false;
}
if (getDefaultAlignment() != obj.getDefaultAlignment()) {
return false;
}
if (getDefaultPointerAlignment() != obj.getDefaultPointerAlignment()) {
return false;
}
if (getDoubleSize() != obj.getDoubleSize() || getFloatSize() != obj.getFloatSize()) {
return false;
}
if (getIntegerSize() != obj.getIntegerSize() ||
getLongLongSize() != obj.getLongLongSize()) {
return false;
}
if (getShortSize() != obj.getShortSize()) {
return false;
}
if (getLongSize() != obj.getLongSize() || getLongDoubleSize() != obj.getLongDoubleSize()) {
return false;
}
if (isSignedChar() != obj.isSignedChar()) {
return false;
}
if (getMachineAlignment() != obj.getMachineAlignment()) {
return false;
}
if (getPointerSize() != obj.getPointerSize() ||
getPointerShift() != obj.getPointerShift()) {
return false;
}
int[] keys = getSizes();
int[] op2keys = obj.getSizes();
if (keys.length != op2keys.length) {
return false;
}
try {
for (int k : keys) {
if (getSizeAlignment(k) != obj.getSizeAlignment(k)) {
return false;
}
}
}
catch (NoValueException ex) {
return false;
}
return true;
}
} }

View file

@ -18,7 +18,6 @@ package ghidra.program.model.data;
import java.util.*; import java.util.*;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.NoValueException; import ghidra.util.exception.NoValueException;
import ghidra.util.xml.SpecXmlUtils; import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.XmlElement; import ghidra.xml.XmlElement;
@ -736,85 +735,4 @@ public class DataOrganizationImpl implements DataOrganization {
parser.end(); parser.end();
} }
@Override
public boolean equals(Object obj) {
DataOrganizationImpl op2 = (DataOrganizationImpl) obj;
if (absoluteMaxAlignment != op2.absoluteMaxAlignment) {
return false;
}
if (bigEndian != op2.bigEndian) {
return false;
}
if (!bitFieldPacking.equals(op2.bitFieldPacking)) {
return false;
}
if (charSize != op2.charSize || wideCharSize != op2.wideCharSize) {
return false;
}
if (defaultAlignment != op2.defaultAlignment) {
return false;
}
if (defaultPointerAlignment != op2.defaultPointerAlignment) {
return false;
}
if (doubleSize != op2.doubleSize || floatSize != op2.floatSize) {
return false;
}
if (integerSize != op2.integerSize || longLongSize != op2.longLongSize) {
return false;
}
if (shortSize != op2.shortSize) {
return false;
}
if (longSize != op2.longSize || longDoubleSize != op2.longDoubleSize) {
return false;
}
if (isSignedChar != op2.isSignedChar) {
return false;
}
if (machineAlignment != op2.machineAlignment) {
return false;
}
if (pointerSize != op2.pointerSize || pointerShift != op2.pointerShift) {
return false;
}
Set<Integer> keys = sizeAlignmentMap.keySet();
Set<Integer> op2keys = op2.sizeAlignmentMap.keySet();
if (keys.size() != op2keys.size()) {
return false;
}
for (int k : keys) {
if (!SystemUtilities.isEqual(sizeAlignmentMap.get(k), op2.sizeAlignmentMap.get(k))) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
int hash = bitFieldPacking.hashCode();
hash = 79 * hash + absoluteMaxAlignment;
hash = 79 * hash + (bigEndian ? 27 : 13);
hash = 79 * hash + charSize;
hash = 79 * hash + defaultAlignment;
hash = 79 * hash + defaultPointerAlignment;
hash = 79 * hash + doubleSize;
hash = 79 * hash + floatSize;
hash = 79 * hash + integerSize;
hash = 79 * hash + (isSignedChar ? 1 : 3);
hash = 79 * hash + longDoubleSize;
hash = 79 * hash + longLongSize;
hash = 79 * hash + longSize;
hash = 79 * hash + machineAlignment;
hash = 79 * hash + pointerShift;
hash = 79 * hash + pointerSize;
hash = 79 * hash + shortSize;
hash = 79 * hash + wideCharSize;
for (int k : sizeAlignmentMap.keySet()) {
hash = 79 * hash + sizeAlignmentMap.get(k);
}
return hash;
}
} }

View file

@ -302,16 +302,6 @@ public class BasicCompilerSpec implements CompilerSpec {
} }
} }
/**
* Convenience method to marshal this entire object, via saveXml, into a String object.
* @return a String containing this entire spec as an XML document.
*/
public String getXMLString() {
StringBuilder buffer = new StringBuilder();
saveXml(buffer);
return buffer.toString();
}
@Override @Override
public void applyContextSettings(DefaultProgramContext programContext) { public void applyContextSettings(DefaultProgramContext programContext) {
for (ContextSetting cs : ctxsetting) { for (ContextSetting cs : ctxsetting) {
@ -512,11 +502,7 @@ public class BasicCompilerSpec implements CompilerSpec {
} }
} }
/** @Override
* Marshal this entire specification to an XML stream. An XML document is written with
* root tag \<compiler_spec>.
* @param buffer is the XML stream
*/
public void saveXml(StringBuilder buffer) { public void saveXml(StringBuilder buffer) {
buffer.append("<compiler_spec>\n"); buffer.append("<compiler_spec>\n");
saveProperties(buffer); saveProperties(buffer);
@ -1125,111 +1111,114 @@ public class BasicCompilerSpec implements CompilerSpec {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(CompilerSpec obj) {
BasicCompilerSpec op2 = (BasicCompilerSpec) obj; if (getClass() != obj.getClass()) {
if (aggressiveTrim != op2.aggressiveTrim || copiedThisModel != op2.copiedThisModel) {
return false; return false;
} }
if (!dataOrganization.equals(op2.dataOrganization)) { BasicCompilerSpec other = (BasicCompilerSpec) obj;
if (aggressiveTrim != other.aggressiveTrim || copiedThisModel != other.copiedThisModel) {
return false; return false;
} }
if (!ctxsetting.equals(op2.ctxsetting)) { if (!dataOrganization.isEquivalent(other.dataOrganization)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(deadCodeDelay, op2.deadCodeDelay)) { if (ctxsetting.size() != other.ctxsetting.size()) {
return false;
}
for (int i = 0; i < ctxsetting.size(); ++i) {
if (!ctxsetting.get(i).isEquivalent(other.ctxsetting.get(i))) {
return false;
}
}
if (!SystemUtilities.isEqual(deadCodeDelay, other.deadCodeDelay)) {
return false; return false;
} }
if (defaultModel != null) { if (defaultModel != null) {
if (op2.defaultModel == null) { if (other.defaultModel == null) {
return false; return false;
} }
if (!defaultModel.name.equals(op2.defaultModel.name)) { if (!defaultModel.name.equals(other.defaultModel.name)) {
return false; return false;
} }
} }
else if (op2.defaultModel != null) { else if (other.defaultModel != null) {
return false; return false;
} }
if (evalCalledModel != null) { if (evalCalledModel != null) {
if (op2.evalCalledModel == null) { if (other.evalCalledModel == null) {
return false; return false;
} }
if (!evalCalledModel.name.equals(op2.evalCalledModel.name)) { if (!evalCalledModel.name.equals(other.evalCalledModel.name)) {
return false; return false;
} }
} }
else if (op2.evalCalledModel != null) { else if (other.evalCalledModel != null) {
return false; return false;
} }
if (evalCurrentModel != null) { if (evalCurrentModel != null) {
if (op2.evalCurrentModel == null) { if (other.evalCurrentModel == null) {
return false; return false;
} }
if (!evalCurrentModel.name.equals(op2.evalCurrentModel.name)) { if (!evalCurrentModel.name.equals(other.evalCurrentModel.name)) {
return false; return false;
} }
} }
else if (op2.evalCurrentModel != null) { else if (other.evalCurrentModel != null) {
return false; return false;
} }
if (allmodels.length != op2.allmodels.length) { if (allmodels.length != other.allmodels.length) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(allmodels, op2.allmodels)) { for (int i = 0; i < allmodels.length; ++i) {
if (!allmodels[i].isEquivalent(other.allmodels[i])) {
return false; return false;
} }
if (!SystemUtilities.isEqual(extraRanges, op2.extraRanges)) { }
if (!SystemUtilities.isEqual(extraRanges, other.extraRanges)) {
return false; return false;
} }
if (funcPtrAlign != op2.funcPtrAlign) { if (funcPtrAlign != other.funcPtrAlign) {
return false; return false;
} }
if (!globalSet.equals(op2.globalSet)) { if (!globalSet.equals(other.globalSet)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(inferPtrBounds, op2.inferPtrBounds)) { if (!SystemUtilities.isEqual(inferPtrBounds, other.inferPtrBounds)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(noHighPtr, op2.noHighPtr)) { if (!SystemUtilities.isEqual(noHighPtr, other.noHighPtr)) {
return false; return false;
} }
if (!pcodeInject.equals(op2.pcodeInject)) { if (!pcodeInject.isEquivalent(other.pcodeInject)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(preferSplit, op2.preferSplit)) { if (!SystemUtilities.isEqual(preferSplit, other.preferSplit)) {
return false; return false;
} }
if (!properties.equals(op2.properties)) { if (!properties.equals(other.properties)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(readOnlySet, op2.readOnlySet)) { if (!SystemUtilities.isEqual(readOnlySet, other.readOnlySet)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(returnAddress, op2.returnAddress)) { if (!SystemUtilities.isEqual(returnAddress, other.returnAddress)) {
return false; return false;
} }
if (reverseJustifyStack != op2.reverseJustifyStack) { if (reverseJustifyStack != other.reverseJustifyStack) {
return false; return false;
} }
if (!SystemUtilities.isEqual(spaceBases, op2.spaceBases)) { if (!SystemUtilities.isEqual(spaceBases, other.spaceBases)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(stackBaseSpace, op2.stackBaseSpace)) { if (!SystemUtilities.isEqual(stackBaseSpace, other.stackBaseSpace)) {
return false; return false;
} }
if (stackGrowsNegative != op2.stackGrowsNegative) { if (stackGrowsNegative != other.stackGrowsNegative) {
return false; return false;
} }
if (!SystemUtilities.isEqual(stackPointer, op2.stackPointer)) { if (!SystemUtilities.isEqual(stackPointer, other.stackPointer)) {
return false; return false;
} }
return true; return true;
} }
@Override
public int hashCode() {
int hash = language.getLanguageID().hashCode();
hash = 79 * description.getCompilerSpecID().hashCode() + hash;
return hash;
}
} }

View file

@ -237,4 +237,18 @@ public interface CompilerSpec {
* @return read-only set of property keys * @return read-only set of property keys
*/ */
public Set<String> getPropertyKeys(); public Set<String> getPropertyKeys();
/**
* Marshal this entire specification to an XML stream. An XML document is written with
* root tag \<compiler_spec>.
* @param buffer is the XML stream
*/
public void saveXml(StringBuilder buffer);
/**
* Determine if this CompilerSpec is equivalent to another specified instance
* @param obj is the other instance
* @return true if they are equivalent
*/
public boolean isEquivalent(CompilerSpec obj);
} }

View file

@ -29,7 +29,7 @@ import ghidra.xml.*;
* Class for context configuration information as * Class for context configuration information as
* part of the compiler configuration (CompilerSpec) * part of the compiler configuration (CompilerSpec)
*/ */
public class ContextSetting { public final class ContextSetting {
private Register register; // Register being set in default context private Register register; // Register being set in default context
private BigInteger value; // value being set in default context private BigInteger value; // value being set in default context
private Address startAddr; // Beginning address of context private Address startAddr; // Beginning address of context
@ -108,33 +108,27 @@ public class ContextSetting {
buffer.append("/>\n"); buffer.append("/>\n");
} }
@Override /**
public boolean equals(Object obj) { * Determine if this ContextSetting is equivalent to another specified instance
ContextSetting op2 = (ContextSetting) obj; * @param obj is the other instance
if (!startAddr.equals(op2.startAddr)) { * @return true if they are equivalent
*/
public boolean isEquivalent(ContextSetting obj) {
if (!startAddr.equals(obj.startAddr)) {
return false; return false;
} }
if (!endAddr.equals(op2.endAddr)) { if (!endAddr.equals(obj.endAddr)) {
return false; return false;
} }
if (!register.equals(op2.register)) { if (!register.equals(obj.register)) {
return false; return false;
} }
if (!value.equals(op2.value)) { if (!value.equals(obj.value)) {
return false; return false;
} }
return true; return true;
} }
@Override
public int hashCode() {
int hash = startAddr.hashCode();
hash = 79 * hash + endAddr.hashCode();
hash = 79 * hash + register.hashCode();
hash = 79 * hash + value.hashCode();
return hash;
}
public static void parseContextSet(List<ContextSetting> resList, XmlPullParser parser, public static void parseContextSet(List<ContextSetting> resList, XmlPullParser parser,
CompilerSpec cspec) throws XmlParseException { CompilerSpec cspec) throws XmlParseException {
XmlElement el = parser.start(); XmlElement el = parser.start();

View file

@ -62,25 +62,20 @@ public interface InjectPayload {
index = i; index = i;
} }
@Override /**
public boolean equals(Object obj) { * Determine if this InjectParameter and another instance are equivalent
InjectParameter op2 = (InjectParameter) obj; * @param obj is the other instance
if (index != op2.index || size != op2.size) { * @return true if they are equivalent
*/
public boolean isEquivalent(InjectParameter obj) {
if (!name.equals(obj.name)) {
return false; return false;
} }
if (!name.equals(op2.name)) { if (index != obj.index || size != obj.size) {
return false; return false;
} }
return true; return true;
} }
@Override
public int hashCode() {
int hash = name.hashCode();
hash = 79 * hash + index;
hash = 79 * hash + size;
return hash;
}
} }
/** /**
@ -160,4 +155,12 @@ public interface InjectPayload {
* @throws XmlParseException for badly formed XML * @throws XmlParseException for badly formed XML
*/ */
public void restoreXml(XmlPullParser parser, SleighLanguage language) throws XmlParseException; public void restoreXml(XmlPullParser parser, SleighLanguage language) throws XmlParseException;
/**
* Determine if this InjectPayload and another instance are equivalent
* (have the same name and generate the same p-code)
* @param obj is the other payload
* @return true if they are equivalent
*/
public boolean isEquivalent(InjectPayload obj);
} }

View file

@ -102,21 +102,14 @@ public class InjectPayloadCallfixup extends InjectPayloadSleigh {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(InjectPayload obj) {
if (getClass() != obj.getClass()) {
return false;
}
InjectPayloadCallfixup op2 = (InjectPayloadCallfixup) obj; InjectPayloadCallfixup op2 = (InjectPayloadCallfixup) obj;
if (!targetSymbolNames.equals(op2.targetSymbolNames)) { if (!targetSymbolNames.equals(op2.targetSymbolNames)) {
return false; return false;
} }
return super.equals(obj); return super.isEquivalent(obj);
}
@Override
public int hashCode() {
int hash = 13;
for (String target : targetSymbolNames) {
hash = 79 * hash + target.hashCode();
}
hash = 79 * hash + super.hashCode();
return hash;
} }
} }

View file

@ -45,4 +45,16 @@ public class InjectPayloadJumpAssist extends InjectPayloadSleigh {
} }
super.restoreXml(parser, language); super.restoreXml(parser, language);
} }
@Override
public boolean isEquivalent(InjectPayload obj) {
if (getClass() != obj.getClass()) {
return false;
}
InjectPayloadJumpAssist op2 = (InjectPayloadJumpAssist) obj;
if (!baseName.equals(op2.baseName)) {
return false;
}
return super.isEquivalent(obj);
}
} }

View file

@ -103,7 +103,10 @@ public class InjectPayloadSegment extends InjectPayloadSleigh {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(InjectPayload obj) {
if (getClass() != obj.getClass()) {
return false;
}
InjectPayloadSegment op2 = (InjectPayloadSegment) obj; InjectPayloadSegment op2 = (InjectPayloadSegment) obj;
if (constResolveOffset != op2.constResolveOffset) { if (constResolveOffset != op2.constResolveOffset) {
return false; return false;
@ -120,18 +123,6 @@ public class InjectPayloadSegment extends InjectPayloadSleigh {
if (supportsFarPointer != op2.supportsFarPointer) { if (supportsFarPointer != op2.supportsFarPointer) {
return false; return false;
} }
return true; return super.isEquivalent(obj);
}
@Override
public int hashCode() {
int hash = space.hashCode();
if (constResolveSpace != null) {
hash = 79 * hash + constResolveSpace.hashCode();
}
hash = 79 * hash + Long.hashCode(constResolveOffset);
hash = 79 * hash + constResolveSize;
hash = 79 * hash + (supportsFarPointer ? 1 : 13);
return hash;
} }
} }

View file

@ -26,7 +26,6 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
import ghidra.util.SystemUtilities;
import ghidra.util.xml.SpecXmlUtils; import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.*; import ghidra.xml.*;
@ -395,17 +394,30 @@ public class InjectPayloadSleigh implements InjectPayload {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(InjectPayload obj) {
if (getClass() != obj.getClass()) {
return false;
}
InjectPayloadSleigh op2 = (InjectPayloadSleigh) obj; InjectPayloadSleigh op2 = (InjectPayloadSleigh) obj;
if (!name.equals(op2.name)) { if (!name.equals(op2.name)) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(inputlist, op2.inputlist)) { if (inputlist.length != op2.inputlist.length) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(output, op2.output)) { for (int i = 0; i < inputlist.length; ++i) {
if (!inputlist[i].isEquivalent(op2.inputlist[i])) {
return false; return false;
} }
}
if (output.length != op2.output.length) {
return false;
}
for (int i = 0; i < output.length; ++i) {
if (!output[i].isEquivalent(op2.output[i])) {
return false;
}
}
if (incidentalCopy != op2.incidentalCopy) { if (incidentalCopy != op2.incidentalCopy) {
return false; return false;
} }
@ -423,22 +435,6 @@ public class InjectPayloadSleigh implements InjectPayload {
return true; return true;
} }
@Override
public int hashCode() {
int hash = (incidentalCopy ? 1 : 13);
hash = 79 * hash + name.hashCode();
hash = 79 * hash + type;
hash = 79 * hash + subType;
hash = 79 * hash + paramShift;
for (InjectParameter param : inputlist) {
hash = 79 * hash + param.hashCode();
}
for (InjectParameter param : output) {
hash = 79 * hash + param.hashCode();
}
return hash;
}
/** /**
* Build a dummy p-code sequence to use in place of a normal parsed payload. * Build a dummy p-code sequence to use in place of a normal parsed payload.
* A ConstructTpl is built out of Varnode and PcodeOp templates that can * A ConstructTpl is built out of Varnode and PcodeOp templates that can

View file

@ -494,50 +494,33 @@ public class ParamEntry {
parser.end(el); parser.end(el);
} }
@Override /**
public boolean equals(Object obj) { * Determine if this ParamEntry is equivalent to another instance
ParamEntry op2 = (ParamEntry) obj; * @param obj is the other instance
if (!spaceid.equals(op2.spaceid) || addressbase != op2.addressbase) { * @return true if they are equivalent
*/
public boolean isEquivalent(ParamEntry obj) {
if (!spaceid.equals(obj.spaceid) || addressbase != obj.addressbase) {
return false; return false;
} }
if (size != op2.size || minsize != op2.minsize || alignment != op2.alignment) { if (size != obj.size || minsize != obj.minsize || alignment != obj.alignment) {
return false; return false;
} }
if (type != op2.type || flags != op2.flags) { if (type != obj.type || flags != obj.flags) {
return false; return false;
} }
if (numslots != op2.numslots) { if (numslots != obj.numslots) {
return false; return false;
} }
if (group != op2.group || groupsize != op2.groupsize) { if (group != obj.group || groupsize != obj.groupsize) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(joinrec, op2.joinrec)) { if (!SystemUtilities.isArrayEqual(joinrec, obj.joinrec)) {
return false; return false;
} }
return true; return true;
} }
@Override
public int hashCode() {
int hash = spaceid.hashCode();
hash = 79 * hash + Long.hashCode(addressbase);
hash = 79 * hash + alignment;
hash = 79 * hash + flags;
hash = 79 * hash + group;
hash = 79 * hash + groupsize;
hash = 79 * hash + minsize;
hash = 79 * hash + numslots;
hash = 79 * hash + size;
hash = 79 * hash + type;
if (joinrec != null) {
for (Varnode vn : joinrec) {
hash = 79 * hash + vn.hashCode();
}
}
return hash;
}
/** /**
* Unsigned less-than operation * Unsigned less-than operation
* @param a is the first operand * @param a is the first operand

View file

@ -79,4 +79,11 @@ public interface ParamList {
public boolean possibleParamWithSlot(Address loc, int size, WithSlotRec res); public boolean possibleParamWithSlot(Address loc, int size, WithSlotRec res);
public boolean isThisBeforeRetPointer(); public boolean isThisBeforeRetPointer();
/**
* Determine if this ParmList is equivalent to another instance
* @param obj is the other instance
* @return true if they are equivalent
*/
public boolean isEquivalent(ParamList obj);
} }

View file

@ -381,11 +381,19 @@ public class ParamListStandard implements ParamList {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(ParamList obj) {
ParamListStandard op2 = (ParamListStandard) obj; if (this.getClass() != obj.getClass()) {
if (!SystemUtilities.isArrayEqual(entry, op2.entry)) {
return false; return false;
} }
ParamListStandard op2 = (ParamListStandard) obj;
if (entry.length != op2.entry.length) {
return false;
}
for (int i = 0; i < entry.length; ++i) {
if (!entry[i].isEquivalent(op2.entry[i])) {
return false;
}
}
if (numgroup != op2.numgroup || pointermax != op2.pointermax) { if (numgroup != op2.numgroup || pointermax != op2.pointermax) {
return false; return false;
} }
@ -398,20 +406,6 @@ public class ParamListStandard implements ParamList {
return true; return true;
} }
@Override
public int hashCode() {
int hash = numgroup;
hash = 79 * hash + pointermax;
hash = 79 * hash + (thisbeforeret ? 27 : 19);
for (ParamEntry param : entry) {
hash = 79 * hash + param.hashCode();
}
if (spacebase == null) {
hash = 79 * hash + spacebase.hashCode();
}
return hash;
}
@Override @Override
public boolean isThisBeforeRetPointer() { public boolean isThisBeforeRetPointer() {
return thisbeforeret; return thisbeforeret;

View file

@ -25,7 +25,6 @@ import ghidra.program.model.lang.InjectPayload.InjectParameter;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.sleigh.grammar.Location; import ghidra.sleigh.grammar.Location;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.xml.XmlParseException; import ghidra.xml.XmlParseException;
import ghidra.xml.XmlPullParser; import ghidra.xml.XmlPullParser;
@ -423,59 +422,93 @@ public class PcodeInjectLibrary {
return uniqueBase; return uniqueBase;
} }
@Override /**
public boolean equals(Object obj) { * Compare that this and the other library contain all equivalent payloads
PcodeInjectLibrary op2 = (PcodeInjectLibrary) obj; * @param obj is the other library
* @return true if all payloads are equivalent
*/
public boolean isEquivalent(PcodeInjectLibrary obj) {
if (getClass() != obj.getClass()) {
return false;
}
// Cannot compare uniqueBase as one side may not have parsed p-code // Cannot compare uniqueBase as one side may not have parsed p-code
// if (uniqueBase != op2.uniqueBase) { // if (uniqueBase != op2.uniqueBase) {
// return false; // return false;
// } // }
if (!callFixupMap.equals(op2.callFixupMap)) { if (callFixupMap.size() != obj.callFixupMap.size()) {
return false; return false;
} }
if (!callMechFixupMap.equals(op2.callMechFixupMap)) { for (Entry<String, InjectPayload> entry : callFixupMap.entrySet()) {
InjectPayload op2payload = obj.callFixupMap.get(entry.getKey());
if (!entry.getValue().isEquivalent(op2payload)) {
return false; return false;
} }
if (!callOtherFixupMap.equals(op2.callOtherFixupMap)) { }
if (callMechFixupMap.size() != obj.callMechFixupMap.size()) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(callOtherOverride, op2.callOtherOverride)) { for (Entry<String, InjectPayload> entry : callMechFixupMap.entrySet()) {
InjectPayload op2payload = obj.callMechFixupMap.get(entry.getKey());
if (!entry.getValue().isEquivalent(op2payload)) {
return false; return false;
} }
if (!exePcodeMap.equals(op2.exePcodeMap)) { }
if (callOtherFixupMap.size() != obj.callOtherFixupMap.size()) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(programPayload, op2.programPayload)) { for (Entry<String, InjectPayload> entry : callOtherFixupMap.entrySet()) {
InjectPayload op2payload = obj.callOtherFixupMap.get(entry.getKey());
if (entry.getValue() != null && op2payload != null) {
if (!entry.getValue().isEquivalent(op2payload)) {
return false;
}
}
else if (entry.getValue() != null || op2payload != null) {
return false;
}
}
if (callOtherOverride != null && obj.callOtherOverride != null) {
if (callOtherOverride.length != obj.callOtherOverride.length) {
return false;
}
for (int i = 0; i < callOtherOverride.length; ++i) {
if (!callOtherOverride[i].isEquivalent(obj.callOtherOverride[i])) {
return false;
}
}
}
else if (callOtherOverride == null && obj.callOtherOverride == null) {
// continue
}
else {
return false;
}
if (exePcodeMap.size() != obj.exePcodeMap.size()) {
return false;
}
for (Entry<String, InjectPayload> entry : exePcodeMap.entrySet()) {
InjectPayload op2payload = obj.exePcodeMap.get(entry.getKey());
if (!entry.getValue().isEquivalent(op2payload)) {
return false;
}
}
if (programPayload != null && obj.programPayload != null) {
if (programPayload.length != obj.programPayload.length) {
return false;
}
for (int i = 0; i < programPayload.length; ++i) {
if (!programPayload[i].isEquivalent(obj.programPayload[i])) {
return false;
}
}
}
else if (programPayload == null && obj.programPayload == null) {
// continue
}
else {
return false; return false;
} }
return true; return true;
} }
@Override
public int hashCode() {
int hash = 111;
for (InjectPayload payload : callFixupMap.values()) {
hash = 79 * hash + payload.hashCode();
}
for (InjectPayload payload : callMechFixupMap.values()) {
hash = 79 * hash + payload.hashCode();
}
for (InjectPayload payload : callOtherFixupMap.values()) {
hash = 79 * hash + payload.hashCode();
}
for (InjectPayload payload : exePcodeMap.values()) {
hash = 79 * hash + payload.hashCode();
}
if (programPayload != null) {
for (InjectPayloadSleigh payload : programPayload) {
hash = 79 * hash + payload.hashCode();
}
}
if (callOtherOverride != null) {
for (InjectPayload payload : callOtherOverride) {
hash = 79 * hash + payload.hashCode();
}
}
return hash;
}
} }

View file

@ -617,59 +617,60 @@ public class PrototypeModel {
return inputParams.getPotentialRegisterStorage(prog); return inputParams.getPotentialRegisterStorage(prog);
} }
@Override /**
public boolean equals(Object obj) { * Determine if this PrototypeModel is equivalent to another instance
PrototypeModel op2 = (PrototypeModel) obj; * @param obj is the other instance
if (!name.equals(op2.name)) { * @return true if they are equivalent
*/
public boolean isEquivalent(PrototypeModel obj) {
if (getClass() != obj.getClass()) {
return false; return false;
} }
if (extrapop != op2.extrapop || stackshift != op2.stackshift) { if (!name.equals(obj.name)) {
return false; return false;
} }
if (genericCallingConvention != op2.genericCallingConvention) { if (extrapop != obj.extrapop || stackshift != obj.stackshift) {
return false; return false;
} }
if (hasThis != op2.hasThis || isConstruct != op2.isConstruct) { if (genericCallingConvention != obj.genericCallingConvention) {
return false; return false;
} }
if (hasUponEntry != op2.hasUponEntry || hasUponReturn != op2.hasUponReturn) { if (hasThis != obj.hasThis || isConstruct != obj.isConstruct) {
return false; return false;
} }
if (inputListType != op2.inputListType) { if (hasUponEntry != obj.hasUponEntry || hasUponReturn != obj.hasUponReturn) {
return false; return false;
} }
if (!inputParams.equals(op2.inputParams)) { if (inputListType != obj.inputListType) {
return false; return false;
} }
if (!outputParams.equals(op2.outputParams)) { if (!inputParams.isEquivalent(obj.inputParams)) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(unaffected, op2.unaffected)) { if (!outputParams.isEquivalent(obj.outputParams)) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(killedbycall, op2.killedbycall)) { if (!SystemUtilities.isArrayEqual(unaffected, obj.unaffected)) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(likelytrash, op2.likelytrash)) { if (!SystemUtilities.isArrayEqual(killedbycall, obj.killedbycall)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(localRange, op2.localRange)) { if (!SystemUtilities.isArrayEqual(likelytrash, obj.likelytrash)) {
return false; return false;
} }
if (!SystemUtilities.isEqual(paramRange, op2.paramRange)) { if (!SystemUtilities.isEqual(localRange, obj.localRange)) {
return false; return false;
} }
if (!SystemUtilities.isArrayEqual(returnaddress, op2.returnaddress)) { if (!SystemUtilities.isEqual(paramRange, obj.paramRange)) {
return false;
}
if (!SystemUtilities.isArrayEqual(returnaddress, obj.returnaddress)) {
return false; return false;
} }
return true; return true;
} }
@Override
public int hashCode() {
return name.hashCode();
}
@Override @Override
public String toString() { public String toString() {
return getName(); return getName();

View file

@ -20,7 +20,6 @@ import java.util.*;
import ghidra.app.plugin.processors.sleigh.SleighException; import ghidra.app.plugin.processors.sleigh.SleighException;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Parameter; import ghidra.program.model.listing.Parameter;
import ghidra.util.SystemUtilities;
import ghidra.util.xml.SpecXmlUtils; import ghidra.util.xml.SpecXmlUtils;
import ghidra.xml.*; import ghidra.xml.*;
@ -215,20 +214,19 @@ public class PrototypeModelMerged extends PrototypeModel {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(PrototypeModel obj) {
PrototypeModelMerged op2 = (PrototypeModelMerged) obj; if (getClass() != obj.getClass()) {
if (!name.equals(op2.name)) {
return false; return false;
} }
return SystemUtilities.isArrayEqual(modellist, op2.modellist); PrototypeModelMerged op2 = (PrototypeModelMerged) obj;
if (modellist.length != op2.modellist.length) {
return false;
} }
for (int i = 0; i < modellist.length; ++i) {
@Override if (!modellist[i].getName().equals(op2.modellist[i].getName())) {
public int hashCode() { return false;
int hash = name.hashCode(); }
for (PrototypeModel model : modellist) { }
hash = 79 * hash + model.hashCode(); return true;
}
return hash;
} }
} }

View file

@ -679,4 +679,14 @@ class TemporaryCompilerSpec implements CompilerSpec {
public PcodeInjectLibrary getPcodeInjectLibrary() { public PcodeInjectLibrary getPcodeInjectLibrary() {
return newCompilerSpec.getPcodeInjectLibrary(); return newCompilerSpec.getPcodeInjectLibrary();
} }
@Override
public void saveXml(StringBuilder buffer) {
throw new UnsupportedOperationException();
}
@Override
public boolean isEquivalent(CompilerSpec obj) {
return (this == obj);
}
} }

View file

@ -201,12 +201,17 @@ public class InjectPayloadDexParameters implements InjectPayload {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(InjectPayload obj) {
return (obj instanceof InjectPayloadDexParameters); // All instances are equal if (getClass() != obj.getClass()) {
return false;
} }
InjectPayloadDexParameters op2 = (InjectPayloadDexParameters) obj;
@Override if (!name.equals(op2.name)) {
public int hashCode() { return false;
return 123474219; // All instances are equal }
if (!sourceName.equals(op2.sourceName)) {
return false;
}
return true;
} }
} }

View file

@ -21,6 +21,7 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.javaclass.format.ClassFileAnalysisState; import ghidra.javaclass.format.ClassFileAnalysisState;
import ghidra.javaclass.format.ClassFileJava; import ghidra.javaclass.format.ClassFileJava;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.program.model.lang.InjectPayload;
import ghidra.program.model.lang.InjectPayloadCallother; import ghidra.program.model.lang.InjectPayloadCallother;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
@ -51,4 +52,16 @@ public abstract class InjectPayloadJava extends InjectPayloadCallother {
ClassFileJava classFile = analysisState.getClassFile(); ClassFileJava classFile = analysisState.getClassFile();
return classFile.getConstantPool(); return classFile.getConstantPool();
} }
@Override
public boolean isEquivalent(InjectPayload obj) {
if (this.getClass() != obj.getClass()) {
return false;
}
InjectPayloadJava op2 = (InjectPayloadJava) obj;
if (uniqueBase != op2.uniqueBase) {
return false;
}
return super.isEquivalent(obj);
}
} }

View file

@ -110,6 +110,15 @@ public class InjectPayloadJavaParameters implements InjectPayload {
return false; return false;
} }
@Override
public void saveXml(StringBuilder buffer) {
// Provide a minimal tag so decompiler can call-back
buffer.append("<pcode");
SpecXmlUtils.encodeStringAttribute(buffer, "inject", "uponentry");
SpecXmlUtils.encodeBooleanAttribute(buffer, "dynamic", true);
buffer.append("/>\n");
}
@Override @Override
public void inject(InjectContext context, PcodeEmit emit) { public void inject(InjectContext context, PcodeEmit emit) {
//not used //not used
@ -203,15 +212,6 @@ public class InjectPayloadJavaParameters implements InjectPayload {
return false; return false;
} }
@Override
public void saveXml(StringBuilder buffer) {
// Provide a minimal tag so decompiler can call-back
buffer.append("<pcode");
SpecXmlUtils.encodeStringAttribute(buffer, "inject", "uponentry");
SpecXmlUtils.encodeBooleanAttribute(buffer, "dynamic", true);
buffer.append("/>\n");
}
@Override @Override
public void restoreXml(XmlPullParser parser, SleighLanguage language) throws XmlParseException { public void restoreXml(XmlPullParser parser, SleighLanguage language) throws XmlParseException {
XmlElement el = parser.start(); XmlElement el = parser.start();
@ -227,12 +227,22 @@ public class InjectPayloadJavaParameters implements InjectPayload {
} }
@Override @Override
public boolean equals(Object obj) { public boolean isEquivalent(InjectPayload obj) {
return (obj instanceof InjectPayloadJavaParameters); // All instances are equal if (getClass() != obj.getClass()) {
return false;
} }
InjectPayloadJavaParameters op2 = (InjectPayloadJavaParameters) obj;
@Override if (!name.equals(op2.name)) {
public int hashCode() { return false;
return 123474217; // All instances are equal }
if (!sourceName.equals(op2.sourceName)) {
return false;
}
// Compare temp4 to determine if the uniqBase passed in was equivalent.
// Otherwise we don't need to compare the other internal Varnodes
if (!temp4.equals(op2.temp4)) {
return false;
}
return true;
} }
} }