From 4bfade4cd8b72ef60b609e81def6b7e004249d59 Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Fri, 7 Jan 2022 19:54:07 -0500 Subject: [PATCH] GP-1647 equivalence check --- .../app/decompiler/DecompInterface.java | 8 +- .../program/model/data/BitFieldPacking.java | 18 +++ .../model/data/BitFieldPackingImpl.java | 20 ---- .../program/model/data/DataOrganization.java | 65 +++++++++++ .../model/data/DataOrganizationImpl.java | 84 +------------- .../program/model/lang/BasicCompilerSpec.java | 101 ++++++++-------- .../program/model/lang/CompilerSpec.java | 14 +++ .../program/model/lang/ContextSetting.java | 28 ++--- .../program/model/lang/InjectPayload.java | 29 ++--- .../model/lang/InjectPayloadCallfixup.java | 17 +-- .../model/lang/InjectPayloadJumpAssist.java | 12 ++ .../model/lang/InjectPayloadSegment.java | 19 +-- .../model/lang/InjectPayloadSleigh.java | 36 +++--- .../ghidra/program/model/lang/ParamEntry.java | 41 ++----- .../ghidra/program/model/lang/ParamList.java | 7 ++ .../program/model/lang/ParamListStandard.java | 28 ++--- .../model/lang/PcodeInjectLibrary.java | 109 ++++++++++++------ .../program/model/lang/PrototypeModel.java | 45 ++++---- .../model/lang/PrototypeModelMerged.java | 24 ++-- .../util/LanguageTranslatorAdapter.java | 10 ++ .../inject/InjectPayloadDexParameters.java | 19 +-- .../util/pcodeInject/InjectPayloadJava.java | 13 +++ .../InjectPayloadJavaParameters.java | 42 ++++--- 23 files changed, 409 insertions(+), 380 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java index dc2e2ae6f6..ef77169b63 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompInterface.java @@ -86,7 +86,7 @@ public class DecompInterface { // Last warning messages from the decompiler // or other error message protected String decompileMessage; - protected BasicCompilerSpec compilerSpec; + protected CompilerSpec compilerSpec; protected DecompileProcess decompProcess; protected DecompileCallback decompCallback; private DecompileDebug debug; @@ -221,7 +221,9 @@ public class DecompInterface { (SleighLanguageDescription) pcodelanguage.getLanguageDescription(); ResourceFile pspecfile = sleighdescription.getSpecFile(); String pspecxml = fileToString(pspecfile); - String cspecxml = compilerSpec.getXMLString(); + StringBuilder buffer = new StringBuilder(); + compilerSpec.saveXml(buffer); + String cspecxml = buffer.toString(); decompCallback.setNativeMessage(null); decompProcess.registerProgram(decompCallback, pspecxml, cspecxml, tspec, coretypes); @@ -313,7 +315,7 @@ public class DecompInterface { "Language has unsupported compiler spec: " + spec.getClass().getName(); return false; } - compilerSpec = (BasicCompilerSpec) spec; + compilerSpec = spec; dtmanage = new PcodeDataTypeManager(prog); try { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPacking.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPacking.java index b6e3981220..cd663de3d0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPacking.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPacking.java @@ -42,4 +42,22 @@ public interface BitFieldPacking { * a zero-length bit-field */ 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; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java index 3c1cff9a55..222da71e45 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldPackingImpl.java @@ -118,24 +118,4 @@ public class BitFieldPackingImpl implements BitFieldPacking { } 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; - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java index d3c4bacc23..fea8581459 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganization.java @@ -172,4 +172,69 @@ public interface DataOrganization { // * @return the aligned offset for the data type // */ // 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; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java index efc8d0cd22..14a8b2cdbd 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataOrganizationImpl.java @@ -18,7 +18,6 @@ package ghidra.program.model.data; import java.util.*; import ghidra.program.model.lang.Language; -import ghidra.util.SystemUtilities; import ghidra.util.exception.NoValueException; import ghidra.util.xml.SpecXmlUtils; import ghidra.xml.XmlElement; @@ -509,7 +508,7 @@ public class DataOrganizationImpl implements DataOrganization { // Otherwise just assume the default alignment. return getDefaultAlignment(); } - + /** * Determines the first offset that is equal to or greater than the minimum offset which * has the specified alignment. If a non-positive alignment is specified the origina @@ -736,85 +735,4 @@ public class DataOrganizationImpl implements DataOrganization { 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 keys = sizeAlignmentMap.keySet(); - Set 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; - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java index c93c9e41a8..2d6bffc6d2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/BasicCompilerSpec.java @@ -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 public void applyContextSettings(DefaultProgramContext programContext) { for (ContextSetting cs : ctxsetting) { @@ -512,11 +502,7 @@ public class BasicCompilerSpec implements CompilerSpec { } } - /** - * Marshal this entire specification to an XML stream. An XML document is written with - * root tag \. - * @param buffer is the XML stream - */ + @Override public void saveXml(StringBuilder buffer) { buffer.append("\n"); saveProperties(buffer); @@ -1125,111 +1111,114 @@ public class BasicCompilerSpec implements CompilerSpec { } @Override - public boolean equals(Object obj) { - BasicCompilerSpec op2 = (BasicCompilerSpec) obj; - if (aggressiveTrim != op2.aggressiveTrim || copiedThisModel != op2.copiedThisModel) { + public boolean isEquivalent(CompilerSpec obj) { + if (getClass() != obj.getClass()) { return false; } - if (!dataOrganization.equals(op2.dataOrganization)) { + BasicCompilerSpec other = (BasicCompilerSpec) obj; + if (aggressiveTrim != other.aggressiveTrim || copiedThisModel != other.copiedThisModel) { return false; } - if (!ctxsetting.equals(op2.ctxsetting)) { + if (!dataOrganization.isEquivalent(other.dataOrganization)) { 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; } if (defaultModel != null) { - if (op2.defaultModel == null) { + if (other.defaultModel == null) { return false; } - if (!defaultModel.name.equals(op2.defaultModel.name)) { + if (!defaultModel.name.equals(other.defaultModel.name)) { return false; } } - else if (op2.defaultModel != null) { + else if (other.defaultModel != null) { return false; } if (evalCalledModel != null) { - if (op2.evalCalledModel == null) { + if (other.evalCalledModel == null) { return false; } - if (!evalCalledModel.name.equals(op2.evalCalledModel.name)) { + if (!evalCalledModel.name.equals(other.evalCalledModel.name)) { return false; } } - else if (op2.evalCalledModel != null) { + else if (other.evalCalledModel != null) { return false; } if (evalCurrentModel != null) { - if (op2.evalCurrentModel == null) { + if (other.evalCurrentModel == null) { return false; } - if (!evalCurrentModel.name.equals(op2.evalCurrentModel.name)) { + if (!evalCurrentModel.name.equals(other.evalCurrentModel.name)) { return false; } } - else if (op2.evalCurrentModel != null) { + else if (other.evalCurrentModel != null) { return false; } - if (allmodels.length != op2.allmodels.length) { + if (allmodels.length != other.allmodels.length) { 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; + } + } + if (!SystemUtilities.isEqual(extraRanges, other.extraRanges)) { return false; } - if (!SystemUtilities.isEqual(extraRanges, op2.extraRanges)) { + if (funcPtrAlign != other.funcPtrAlign) { return false; } - if (funcPtrAlign != op2.funcPtrAlign) { + if (!globalSet.equals(other.globalSet)) { return false; } - if (!globalSet.equals(op2.globalSet)) { + if (!SystemUtilities.isEqual(inferPtrBounds, other.inferPtrBounds)) { return false; } - if (!SystemUtilities.isEqual(inferPtrBounds, op2.inferPtrBounds)) { + if (!SystemUtilities.isEqual(noHighPtr, other.noHighPtr)) { return false; } - if (!SystemUtilities.isEqual(noHighPtr, op2.noHighPtr)) { + if (!pcodeInject.isEquivalent(other.pcodeInject)) { return false; } - if (!pcodeInject.equals(op2.pcodeInject)) { + if (!SystemUtilities.isEqual(preferSplit, other.preferSplit)) { return false; } - if (!SystemUtilities.isEqual(preferSplit, op2.preferSplit)) { + if (!properties.equals(other.properties)) { return false; } - if (!properties.equals(op2.properties)) { + if (!SystemUtilities.isEqual(readOnlySet, other.readOnlySet)) { return false; } - if (!SystemUtilities.isEqual(readOnlySet, op2.readOnlySet)) { + if (!SystemUtilities.isEqual(returnAddress, other.returnAddress)) { return false; } - if (!SystemUtilities.isEqual(returnAddress, op2.returnAddress)) { + if (reverseJustifyStack != other.reverseJustifyStack) { return false; } - if (reverseJustifyStack != op2.reverseJustifyStack) { + if (!SystemUtilities.isEqual(spaceBases, other.spaceBases)) { return false; } - if (!SystemUtilities.isEqual(spaceBases, op2.spaceBases)) { + if (!SystemUtilities.isEqual(stackBaseSpace, other.stackBaseSpace)) { return false; } - if (!SystemUtilities.isEqual(stackBaseSpace, op2.stackBaseSpace)) { + if (stackGrowsNegative != other.stackGrowsNegative) { return false; } - if (stackGrowsNegative != op2.stackGrowsNegative) { - return false; - } - if (!SystemUtilities.isEqual(stackPointer, op2.stackPointer)) { + if (!SystemUtilities.isEqual(stackPointer, other.stackPointer)) { return false; } return true; } - - @Override - public int hashCode() { - int hash = language.getLanguageID().hashCode(); - hash = 79 * description.getCompilerSpecID().hashCode() + hash; - return hash; - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java index 8a7aa14ae9..c85b9ac7f4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/CompilerSpec.java @@ -237,4 +237,18 @@ public interface CompilerSpec { * @return read-only set of property keys */ public Set getPropertyKeys(); + + /** + * Marshal this entire specification to an XML stream. An XML document is written with + * root tag \. + * @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); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ContextSetting.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ContextSetting.java index f2cf712ffb..c8a8aa60b4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ContextSetting.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ContextSetting.java @@ -29,7 +29,7 @@ import ghidra.xml.*; * Class for context configuration information as * part of the compiler configuration (CompilerSpec) */ -public class ContextSetting { +public final class ContextSetting { private Register register; // Register being set in default context private BigInteger value; // value being set in default context private Address startAddr; // Beginning address of context @@ -108,33 +108,27 @@ public class ContextSetting { buffer.append("/>\n"); } - @Override - public boolean equals(Object obj) { - ContextSetting op2 = (ContextSetting) obj; - if (!startAddr.equals(op2.startAddr)) { + /** + * Determine if this ContextSetting is equivalent to another specified instance + * @param obj is the other instance + * @return true if they are equivalent + */ + public boolean isEquivalent(ContextSetting obj) { + if (!startAddr.equals(obj.startAddr)) { return false; } - if (!endAddr.equals(op2.endAddr)) { + if (!endAddr.equals(obj.endAddr)) { return false; } - if (!register.equals(op2.register)) { + if (!register.equals(obj.register)) { return false; } - if (!value.equals(op2.value)) { + if (!value.equals(obj.value)) { return false; } 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 resList, XmlPullParser parser, CompilerSpec cspec) throws XmlParseException { XmlElement el = parser.start(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayload.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayload.java index 805a182e2c..a2cb8bb498 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayload.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayload.java @@ -62,25 +62,20 @@ public interface InjectPayload { index = i; } - @Override - public boolean equals(Object obj) { - InjectParameter op2 = (InjectParameter) obj; - if (index != op2.index || size != op2.size) { + /** + * Determine if this InjectParameter and another instance are equivalent + * @param obj is the other instance + * @return true if they are equivalent + */ + public boolean isEquivalent(InjectParameter obj) { + if (!name.equals(obj.name)) { return false; } - if (!name.equals(op2.name)) { + if (index != obj.index || size != obj.size) { return false; } 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 */ 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); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadCallfixup.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadCallfixup.java index ed03cca12a..cecd3e51fb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadCallfixup.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadCallfixup.java @@ -102,21 +102,14 @@ public class InjectPayloadCallfixup extends InjectPayloadSleigh { } @Override - public boolean equals(Object obj) { + public boolean isEquivalent(InjectPayload obj) { + if (getClass() != obj.getClass()) { + return false; + } InjectPayloadCallfixup op2 = (InjectPayloadCallfixup) obj; if (!targetSymbolNames.equals(op2.targetSymbolNames)) { return false; } - return super.equals(obj); - } - - @Override - public int hashCode() { - int hash = 13; - for (String target : targetSymbolNames) { - hash = 79 * hash + target.hashCode(); - } - hash = 79 * hash + super.hashCode(); - return hash; + return super.isEquivalent(obj); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadJumpAssist.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadJumpAssist.java index d438d84dc3..8c85513882 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadJumpAssist.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadJumpAssist.java @@ -45,4 +45,16 @@ public class InjectPayloadJumpAssist extends InjectPayloadSleigh { } 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); + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSegment.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSegment.java index 84b3b73d81..970e50a977 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSegment.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSegment.java @@ -103,7 +103,10 @@ public class InjectPayloadSegment extends InjectPayloadSleigh { } @Override - public boolean equals(Object obj) { + public boolean isEquivalent(InjectPayload obj) { + if (getClass() != obj.getClass()) { + return false; + } InjectPayloadSegment op2 = (InjectPayloadSegment) obj; if (constResolveOffset != op2.constResolveOffset) { return false; @@ -120,18 +123,6 @@ public class InjectPayloadSegment extends InjectPayloadSleigh { if (supportsFarPointer != op2.supportsFarPointer) { return false; } - return true; - } - - @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; + return super.isEquivalent(obj); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSleigh.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSleigh.java index 776ed48509..6ae28981d7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSleigh.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InjectPayloadSleigh.java @@ -26,7 +26,6 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.Varnode; -import ghidra.util.SystemUtilities; import ghidra.util.xml.SpecXmlUtils; import ghidra.xml.*; @@ -395,17 +394,30 @@ public class InjectPayloadSleigh implements InjectPayload { } @Override - public boolean equals(Object obj) { + public boolean isEquivalent(InjectPayload obj) { + if (getClass() != obj.getClass()) { + return false; + } InjectPayloadSleigh op2 = (InjectPayloadSleigh) obj; if (!name.equals(op2.name)) { return false; } - if (!SystemUtilities.isArrayEqual(inputlist, op2.inputlist)) { + if (inputlist.length != op2.inputlist.length) { 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; + } + } + 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) { return false; } @@ -423,22 +435,6 @@ public class InjectPayloadSleigh implements InjectPayload { 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. * A ConstructTpl is built out of Varnode and PcodeOp templates that can diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java index d6b73eee87..eb9aebd14e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamEntry.java @@ -494,50 +494,33 @@ public class ParamEntry { parser.end(el); } - @Override - public boolean equals(Object obj) { - ParamEntry op2 = (ParamEntry) obj; - if (!spaceid.equals(op2.spaceid) || addressbase != op2.addressbase) { + /** + * Determine if this ParamEntry is equivalent to another instance + * @param obj is the other instance + * @return true if they are equivalent + */ + public boolean isEquivalent(ParamEntry obj) { + if (!spaceid.equals(obj.spaceid) || addressbase != obj.addressbase) { return false; } - if (size != op2.size || minsize != op2.minsize || alignment != op2.alignment) { + if (size != obj.size || minsize != obj.minsize || alignment != obj.alignment) { return false; } - if (type != op2.type || flags != op2.flags) { + if (type != obj.type || flags != obj.flags) { return false; } - if (numslots != op2.numslots) { + if (numslots != obj.numslots) { return false; } - if (group != op2.group || groupsize != op2.groupsize) { + if (group != obj.group || groupsize != obj.groupsize) { return false; } - if (!SystemUtilities.isArrayEqual(joinrec, op2.joinrec)) { + if (!SystemUtilities.isArrayEqual(joinrec, obj.joinrec)) { return false; } 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 * @param a is the first operand diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamList.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamList.java index 4a311ef65d..7ba013089d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamList.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamList.java @@ -79,4 +79,11 @@ public interface ParamList { public boolean possibleParamWithSlot(Address loc, int size, WithSlotRec res); 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); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java index 462eb493c5..03654072b6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java @@ -381,11 +381,19 @@ public class ParamListStandard implements ParamList { } @Override - public boolean equals(Object obj) { - ParamListStandard op2 = (ParamListStandard) obj; - if (!SystemUtilities.isArrayEqual(entry, op2.entry)) { + public boolean isEquivalent(ParamList obj) { + if (this.getClass() != obj.getClass()) { 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) { return false; } @@ -398,20 +406,6 @@ public class ParamListStandard implements ParamList { 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 public boolean isThisBeforeRetPointer() { return thisbeforeret; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeInjectLibrary.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeInjectLibrary.java index d706b76d2a..9f667772de 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeInjectLibrary.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PcodeInjectLibrary.java @@ -25,7 +25,6 @@ import ghidra.program.model.lang.InjectPayload.InjectParameter; import ghidra.program.model.listing.Program; import ghidra.sleigh.grammar.Location; import ghidra.util.Msg; -import ghidra.util.SystemUtilities; import ghidra.xml.XmlParseException; import ghidra.xml.XmlPullParser; @@ -423,59 +422,93 @@ public class PcodeInjectLibrary { return uniqueBase; } - @Override - public boolean equals(Object obj) { - PcodeInjectLibrary op2 = (PcodeInjectLibrary) obj; + /** + * Compare that this and the other library contain all equivalent payloads + * @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 // if (uniqueBase != op2.uniqueBase) { // return false; // } - if (!callFixupMap.equals(op2.callFixupMap)) { + if (callFixupMap.size() != obj.callFixupMap.size()) { return false; } - if (!callMechFixupMap.equals(op2.callMechFixupMap)) { + for (Entry entry : callFixupMap.entrySet()) { + InjectPayload op2payload = obj.callFixupMap.get(entry.getKey()); + if (!entry.getValue().isEquivalent(op2payload)) { + return false; + } + } + if (callMechFixupMap.size() != obj.callMechFixupMap.size()) { return false; } - if (!callOtherFixupMap.equals(op2.callOtherFixupMap)) { + for (Entry entry : callMechFixupMap.entrySet()) { + InjectPayload op2payload = obj.callMechFixupMap.get(entry.getKey()); + if (!entry.getValue().isEquivalent(op2payload)) { + return false; + } + } + if (callOtherFixupMap.size() != obj.callOtherFixupMap.size()) { return false; } - if (!SystemUtilities.isArrayEqual(callOtherOverride, op2.callOtherOverride)) { + for (Entry 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.equals(op2.exePcodeMap)) { + + if (exePcodeMap.size() != obj.exePcodeMap.size()) { return false; } - if (!SystemUtilities.isArrayEqual(programPayload, op2.programPayload)) { + for (Entry 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 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; - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java index d6fda3962c..766e09456e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModel.java @@ -617,59 +617,60 @@ public class PrototypeModel { return inputParams.getPotentialRegisterStorage(prog); } - @Override - public boolean equals(Object obj) { - PrototypeModel op2 = (PrototypeModel) obj; - if (!name.equals(op2.name)) { + /** + * Determine if this PrototypeModel is equivalent to another instance + * @param obj is the other instance + * @return true if they are equivalent + */ + public boolean isEquivalent(PrototypeModel obj) { + if (getClass() != obj.getClass()) { return false; } - if (extrapop != op2.extrapop || stackshift != op2.stackshift) { + if (!name.equals(obj.name)) { return false; } - if (genericCallingConvention != op2.genericCallingConvention) { + if (extrapop != obj.extrapop || stackshift != obj.stackshift) { return false; } - if (hasThis != op2.hasThis || isConstruct != op2.isConstruct) { + if (genericCallingConvention != obj.genericCallingConvention) { return false; } - if (hasUponEntry != op2.hasUponEntry || hasUponReturn != op2.hasUponReturn) { + if (hasThis != obj.hasThis || isConstruct != obj.isConstruct) { return false; } - if (inputListType != op2.inputListType) { + if (hasUponEntry != obj.hasUponEntry || hasUponReturn != obj.hasUponReturn) { return false; } - if (!inputParams.equals(op2.inputParams)) { + if (inputListType != obj.inputListType) { return false; } - if (!outputParams.equals(op2.outputParams)) { + if (!inputParams.isEquivalent(obj.inputParams)) { return false; } - if (!SystemUtilities.isArrayEqual(unaffected, op2.unaffected)) { + if (!outputParams.isEquivalent(obj.outputParams)) { return false; } - if (!SystemUtilities.isArrayEqual(killedbycall, op2.killedbycall)) { + if (!SystemUtilities.isArrayEqual(unaffected, obj.unaffected)) { return false; } - if (!SystemUtilities.isArrayEqual(likelytrash, op2.likelytrash)) { + if (!SystemUtilities.isArrayEqual(killedbycall, obj.killedbycall)) { return false; } - if (!SystemUtilities.isEqual(localRange, op2.localRange)) { + if (!SystemUtilities.isArrayEqual(likelytrash, obj.likelytrash)) { return false; } - if (!SystemUtilities.isEqual(paramRange, op2.paramRange)) { + if (!SystemUtilities.isEqual(localRange, obj.localRange)) { 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 true; } - @Override - public int hashCode() { - return name.hashCode(); - } - @Override public String toString() { return getName(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java index 93642bf7e0..3f94f8d8bb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/PrototypeModelMerged.java @@ -20,7 +20,6 @@ import java.util.*; import ghidra.app.plugin.processors.sleigh.SleighException; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Parameter; -import ghidra.util.SystemUtilities; import ghidra.util.xml.SpecXmlUtils; import ghidra.xml.*; @@ -215,20 +214,19 @@ public class PrototypeModelMerged extends PrototypeModel { } @Override - public boolean equals(Object obj) { - PrototypeModelMerged op2 = (PrototypeModelMerged) obj; - if (!name.equals(op2.name)) { + public boolean isEquivalent(PrototypeModel obj) { + if (getClass() != obj.getClass()) { return false; } - return SystemUtilities.isArrayEqual(modellist, op2.modellist); - } - - @Override - public int hashCode() { - int hash = name.hashCode(); - for (PrototypeModel model : modellist) { - hash = 79 * hash + model.hashCode(); + PrototypeModelMerged op2 = (PrototypeModelMerged) obj; + if (modellist.length != op2.modellist.length) { + return false; } - return hash; + for (int i = 0; i < modellist.length; ++i) { + if (!modellist[i].getName().equals(op2.modellist[i].getName())) { + return false; + } + } + return true; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java index fd9b6d0ff3..5910e401b5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/LanguageTranslatorAdapter.java @@ -679,4 +679,14 @@ class TemporaryCompilerSpec implements CompilerSpec { public PcodeInjectLibrary getPcodeInjectLibrary() { return newCompilerSpec.getPcodeInjectLibrary(); } + + @Override + public void saveXml(StringBuilder buffer) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEquivalent(CompilerSpec obj) { + return (this == obj); + } } diff --git a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/InjectPayloadDexParameters.java b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/InjectPayloadDexParameters.java index 16574b2801..ab5533718f 100644 --- a/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/InjectPayloadDexParameters.java +++ b/Ghidra/Processors/Dalvik/src/main/java/ghidra/dalvik/dex/inject/InjectPayloadDexParameters.java @@ -201,12 +201,17 @@ public class InjectPayloadDexParameters implements InjectPayload { } @Override - public boolean equals(Object obj) { - return (obj instanceof InjectPayloadDexParameters); // All instances are equal - } - - @Override - public int hashCode() { - return 123474219; // All instances are equal + public boolean isEquivalent(InjectPayload obj) { + if (getClass() != obj.getClass()) { + return false; + } + InjectPayloadDexParameters op2 = (InjectPayloadDexParameters) obj; + if (!name.equals(op2.name)) { + return false; + } + if (!sourceName.equals(op2.sourceName)) { + return false; + } + return true; } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJava.java index 6b380344a1..6c3f6a7416 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJava.java @@ -21,6 +21,7 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.javaclass.format.ClassFileAnalysisState; import ghidra.javaclass.format.ClassFileJava; import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; +import ghidra.program.model.lang.InjectPayload; import ghidra.program.model.lang.InjectPayloadCallother; import ghidra.program.model.listing.Program; @@ -51,4 +52,16 @@ public abstract class InjectPayloadJava extends InjectPayloadCallother { ClassFileJava classFile = analysisState.getClassFile(); 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); + } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJavaParameters.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJavaParameters.java index 4d48a5fa44..7f9c6c7472 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJavaParameters.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectPayloadJavaParameters.java @@ -110,6 +110,15 @@ public class InjectPayloadJavaParameters implements InjectPayload { return false; } + @Override + public void saveXml(StringBuilder buffer) { + // Provide a minimal tag so decompiler can call-back + buffer.append("\n"); + } + @Override public void inject(InjectContext context, PcodeEmit emit) { //not used @@ -203,15 +212,6 @@ public class InjectPayloadJavaParameters implements InjectPayload { return false; } - @Override - public void saveXml(StringBuilder buffer) { - // Provide a minimal tag so decompiler can call-back - buffer.append("\n"); - } - @Override public void restoreXml(XmlPullParser parser, SleighLanguage language) throws XmlParseException { XmlElement el = parser.start(); @@ -227,12 +227,22 @@ public class InjectPayloadJavaParameters implements InjectPayload { } @Override - public boolean equals(Object obj) { - return (obj instanceof InjectPayloadJavaParameters); // All instances are equal - } - - @Override - public int hashCode() { - return 123474217; // All instances are equal + public boolean isEquivalent(InjectPayload obj) { + if (getClass() != obj.getClass()) { + return false; + } + InjectPayloadJavaParameters op2 = (InjectPayloadJavaParameters) obj; + if (!name.equals(op2.name)) { + return false; + } + 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; } }