From b4308f76f80d8ae570d88ef1c150623fee9b1eec Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 12 Jun 2024 15:18:33 -0400 Subject: [PATCH] GP-3921 Improved Diff data instance settings support --- .../java/ghidra/program/util/ProgramDiff.java | 28 + .../program/util/ProgramDiffDetails.java | 59 ++- .../ghidra/program/util/ProgramDiff1Test.java | 139 +++-- .../program/util/ProgramMerge3Test.java | 482 ++++++++++-------- .../data/ProgramBasedDataTypeManagerDB.java | 17 +- 5 files changed, 455 insertions(+), 270 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiff.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiff.java index 90bae950e1..5e09d2dace 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiff.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiff.java @@ -17,8 +17,12 @@ package ghidra.program.util; import java.util.*; +import javax.help.UnsupportedOperationException; + +import ghidra.program.database.data.ProgramBasedDataTypeManagerDB; import ghidra.program.database.properties.UnsupportedMapDB; import ghidra.program.model.address.*; +import ghidra.program.model.data.ProgramBasedDataTypeManager; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.listing.*; @@ -2966,6 +2970,30 @@ public class ProgramDiff { return false; } + // assume only top-level data code units are compared + // we should not be a DataComponent (i.e., no parent) + if (d1.getParent() != null || d2.getParent() != null) { + throw new UnsupportedOperationException("Expecting top-level Data only"); + } + + // Only top-level Data instance Settings are supported + + String[] settingNames1 = d1.getNames(); + Arrays.sort(settingNames1); + String[] settingNames2 = d2.getNames(); + Arrays.sort(settingNames2); + if (!Arrays.equals(settingNames1, settingNames2)) { + return false; + } + + for (int i = 0; i < settingNames1.length; i++) { + Object v1 = d1.getValue(settingNames1[i]); + Object v2 = d2.getValue(settingNames2[i]); + if (!Objects.equals(v1, v2)) { + return false; + } + } + return true; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java index 489ab24a10..536bbca498 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramDiffDetails.java @@ -22,6 +22,8 @@ import java.util.*; import javax.swing.text.*; import generic.theme.GColor; +import ghidra.docking.settings.EnumSettingsDefinition; +import ghidra.docking.settings.SettingsDefinition; import ghidra.program.database.properties.UnsupportedMapDB; import ghidra.program.model.address.*; import ghidra.program.model.data.*; @@ -972,8 +974,8 @@ public class ProgramDiffDetails { Address max = cu.getMaxAddress(); String addrRangeStr = min + ((min.equals(max)) ? "" : " - " + max); String cuRep; - if (cu instanceof Data) { - cuRep = ((Data) cu).getDataType().getPathName(); + if (cu instanceof Data data) { + cuRep = data.getDataType().getPathName(); } else if (cu instanceof Instruction) { Instruction inst = (Instruction) cu; @@ -1018,6 +1020,35 @@ public class ProgramDiffDetails { cuRep = cu.toString(); } buf.append(indent + addrRangeStr + " " + cuRep + newLine); + + if (cu instanceof Data data) { + // NOTE: Diff operates on the outmost code-unit only and not data components + String[] settingNames = data.getNames(); + if (settingNames.length != 0) { + Map defMap = new HashMap<>(); + for (SettingsDefinition settingsDef : data.getDataType().getSettingsDefinitions()) { + defMap.put(settingsDef.getStorageKey(), settingsDef); + } + buf.append(indent + indent + "Data Settings: "); + int count = 0; + Arrays.sort(settingNames); + for (String settingName : settingNames) { + Object value = data.getValue(settingName); + SettingsDefinition def = defMap.get(settingName); + if (def != null) { + settingName = def.getName(); + } + if (value instanceof Long && def instanceof EnumSettingsDefinition eDef) { + value = eDef.getValueString(data); + } + if (count++ != 0) { + buf.append(", "); + } + buf.append(settingName + "=" + value); + } + buf.append(newLine); + } + } return min; } @@ -2364,6 +2395,30 @@ public class ProgramDiffDetails { return false; } + // assume only top-level data code units are compared + // we should not be a DataComponent (i.e., no parent) + if (d1.getParent() != null || d2.getParent() != null) { + throw new UnsupportedOperationException("Expecting top-level Data only"); + } + + // Only top-level Data instance Settings are supported + + String[] settingNames1 = d1.getNames(); + Arrays.sort(settingNames1); + String[] settingNames2 = d2.getNames(); + Arrays.sort(settingNames2); + if (!Arrays.equals(settingNames1, settingNames2)) { + return false; + } + + for (int i = 0; i < settingNames1.length; i++) { + Object v1 = d1.getValue(settingNames1[i]); + Object v2 = d2.getValue(settingNames2[i]); + if (!Objects.equals(v1, v2)) { + return false; + } + } + return true; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramDiff1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramDiff1Test.java index a1485c318c..8c1cb5e64f 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramDiff1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramDiff1Test.java @@ -24,10 +24,14 @@ package ghidra.program.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import java.util.Arrays; +import java.util.Objects; + import org.junit.*; import ghidra.program.model.address.*; import ghidra.program.model.data.*; +import ghidra.program.model.data.DataUtilities.ClearDataMode; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Namespace; @@ -88,7 +92,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * Test that ProgramDiff correctly returns program1 and program2. */ @Test - public void testGetPrograms() throws Exception { + public void testGetPrograms() throws Exception { programDiff = new ProgramDiff(p1, p2); assertEquals(p1, programDiff.getProgramOne()); assertEquals(p2, programDiff.getProgramTwo()); @@ -99,7 +103,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * in Program1 and Program2. */ @Test - public void testGetCombinedAddresses() throws Exception { + public void testGetCombinedAddresses() throws Exception { programBuilder1.createMemory("d1", "0x100", 0x100, null, (byte) 0xAC); programBuilder1.createMemory("d2", "0x200", 0x100); @@ -126,7 +130,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * in common between Program1 and Program2. */ @Test - public void testGetAddressesInCommon() throws Exception { + public void testGetAddressesInCommon() throws Exception { programBuilder1.createMemory("d1", "0x100", 0x100, null, (byte) 0xAC); programBuilder1.createMemory("d2", "0x200", 0x100); @@ -150,7 +154,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * initialized data are in common between Program1 and Program2. */ @Test - public void testGetInitializedInCommon() throws Exception { + public void testGetInitializedInCommon() throws Exception { programBuilder1.createMemory("d1", "0x100", 0x100, null, (byte) 0xAC); programBuilder1.createMemory("d2", "0x200", 0x100); @@ -175,7 +179,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * and Program2. */ @Test - public void testGetByteDifferences() throws Exception { + public void testGetByteDifferences() throws Exception { programBuilder1.createMemory("d1", "0x100", 0x100, null, (byte) 0xAC); programBuilder1.createMemory("d2", "0x200", 0x100); programBuilder1.createLabel("0x01006420", "Function1"); @@ -209,7 +213,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * and Program2 when the bytes differ for an instruction but its prototype doesn't. */ @Test - public void testGetByteDifferencesSamePrototype() throws Exception { + public void testGetByteDifferencesSamePrototype() throws Exception { programBuilder1.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder1.setBytes("0x01002cf8", "3b 74 24 08", true); @@ -230,7 +234,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * and Program2 when the bytes differ for an instruction but its prototype doesn't. */ @Test - public void testGetCodeUnitDifferencesSamePrototypeDiffByte() throws Exception { + public void testGetCodeUnitDifferencesSamePrototypeDiffByte() throws Exception { programBuilder1.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder1.setBytes("0x01002cf8", "3b 74 24 08", true); @@ -272,7 +276,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * Program1 and Program2. */ @Test - public void testGetCodeUnitDifferences() throws Exception { + public void testGetCodeUnitDifferences() throws Exception { programBuilder1.createMemory("d1", "0x100", 0x100, null, (byte) 0xAC); programBuilder1.createMemory("d2", "0x200", 0x100); programBuilder1.createLabel("0x01006420", "Function1"); @@ -315,8 +319,53 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(addrSet, diffAs); } + /** + * Test that ProgramDiff can determine the code unit differences between + * Program1 and Program2 where Data Settings differ. + */ @Test - public void testGetCommentDifference1() throws Exception { + public void testGetCodeUnitSettingsDifferences() throws Exception { + + p1.withTransaction("Apply p1 Data", () -> { + + // NOTE: unknown settings will be dropped + + Data d1 = DataUtilities.createData(p1, addr(p1, 0x1008014), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + CharsetSettingsDefinition.CHARSET.setChoice(d1, 2); // differs from p2 + + d1 = DataUtilities.createData(p1, addr(p1, 0x1008028), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + CharsetSettingsDefinition.CHARSET.setChoice(d1, 3); // same as p2 + + }); + + p2.withTransaction("Apply p2 Data", () -> { + + DataUtilities.createData(p2, addr(p2, 0x1008014), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + + Data d2 = DataUtilities.createData(p2, addr(p2, 0x1008028), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + CharsetSettingsDefinition.CHARSET.setChoice(d2, 3); // same as p1 + + }); + + AddressSet as = new AddressSet(); + as.addRange(addr(p1, 0x1008000), addr(p1, 0x10085ff)); + programDiff = new ProgramDiff(p1, p2, as); + programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.CODE_UNIT_DIFFS)); + + AddressSetView diffAs = programDiff.getDifferences(programDiff.getFilter(), null); + + AddressSet addrSet = new AddressSet(); + addrSet.addRange(addr(p1, 0x1008014), addr(p1, 0x1008015)); + + assertEquals(addrSet, diffAs); + } + + @Test + public void testGetCommentDifference1() throws Exception { // 0x1002040: p1 has Plate, Pre, EOL, Post, & Repeatable comment. programBuilder1.createComment("0x1002040", "My Plate Comment", CodeUnit.PLATE_COMMENT); programBuilder1.createComment("0x1002040", "My Pre Comment", CodeUnit.PRE_COMMENT); @@ -329,7 +378,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference2() throws Exception { + public void testGetCommentDifference2() throws Exception { // 0x100204c: p2 has Plate, Pre, EOL, Post, & Repeatable comment. programBuilder2.createComment("0x100204c", "Other Plate Comment", CodeUnit.PLATE_COMMENT); programBuilder2.createComment("0x100204c", "Other Pre Comment", CodeUnit.PRE_COMMENT); @@ -342,7 +391,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference3() throws Exception { + public void testGetCommentDifference3() throws Exception { // 0x1002304: p1 has EOL comment. programBuilder1.createComment("0x1002304", "My EOL Comment", CodeUnit.EOL_COMMENT); @@ -350,7 +399,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference4() throws Exception { + public void testGetCommentDifference4() throws Exception { // 0x1002306: p1 has pre-comment. programBuilder1.createComment("0x1002306", "My Pre Comment", CodeUnit.PRE_COMMENT); @@ -358,7 +407,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference5() throws Exception { + public void testGetCommentDifference5() throws Exception { // 0x100230b: p1 has plate and post comments. programBuilder1.createComment("0x100230b", "My Plate Comment", CodeUnit.PLATE_COMMENT); programBuilder1.createComment("0x100230b", "My Post Comment", CodeUnit.POST_COMMENT); @@ -367,7 +416,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference6() throws Exception { + public void testGetCommentDifference6() throws Exception { // p2 plate comments contain the p1 comment string. programBuilder1.createComment("0x100230d", "Plate Comment", CodeUnit.PLATE_COMMENT); programBuilder2.createComment("0x100230d", "Other Plate Comment", CodeUnit.PLATE_COMMENT); @@ -376,7 +425,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference7() throws Exception { + public void testGetCommentDifference7() throws Exception { // p2 pre comments contain the p1 comment string. programBuilder1.createComment("0x100230d", "Pre Comment", CodeUnit.PRE_COMMENT); programBuilder2.createComment("0x100230d", "Other Pre Comment", CodeUnit.PRE_COMMENT); @@ -385,7 +434,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference8() throws Exception { + public void testGetCommentDifference8() throws Exception { // p2 eol comments contain the p1 comment string. programBuilder1.createComment("0x100230d", "EOL Comment", CodeUnit.EOL_COMMENT); programBuilder2.createComment("0x100230d", "Other EOL Comment", CodeUnit.EOL_COMMENT); @@ -394,7 +443,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference9() throws Exception { + public void testGetCommentDifference9() throws Exception { // p2 post comments contain the p1 comment string. programBuilder1.createComment("0x100230d", "Post Comment", CodeUnit.POST_COMMENT); programBuilder2.createComment("0x100230d", "Other Post Comment", CodeUnit.POST_COMMENT); @@ -403,7 +452,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference10() throws Exception { + public void testGetCommentDifference10() throws Exception { // p2 repeatable comments contain the p1 comment string. programBuilder1.createComment("0x100230d", "Repeatable Comment", CodeUnit.REPEATABLE_COMMENT); @@ -414,7 +463,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference11() throws Exception { + public void testGetCommentDifference11() throws Exception { // 0x1002336: Different Repeatable comments. programBuilder1.createComment("0x1002336", "Once upon a time,", CodeUnit.REPEATABLE_COMMENT); @@ -425,7 +474,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference12() throws Exception { + public void testGetCommentDifference12() throws Exception { // 0x1002346: P1 Repeatable comment contains P2 Repeatable comment. programBuilder1.createComment("0x1002346", "This is a sample comment.", CodeUnit.REPEATABLE_COMMENT); @@ -435,7 +484,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference13() throws Exception { + public void testGetCommentDifference13() throws Exception { // 0x1002350: P1 Repeatable comment contained within P2 Repeatable comment. programBuilder1.createComment("0x1002350", "This is a sample", CodeUnit.REPEATABLE_COMMENT); programBuilder2.createComment("0x1002350", "This is a sample comment.", @@ -445,7 +494,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference14() throws Exception { + public void testGetCommentDifference14() throws Exception { // 0x100238f: Different EOL comments. programBuilder1.createComment("0x100238f", "Once upon a time,", CodeUnit.EOL_COMMENT); programBuilder2.createComment("0x100238f", "This is a sample comment.", @@ -455,7 +504,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference15() throws Exception { + public void testGetCommentDifference15() throws Exception { // 0x1002395: Different Pre comments. programBuilder1.createComment("0x1002395", "Once upon a time,", CodeUnit.PRE_COMMENT); programBuilder2.createComment("0x1002395", "This is a sample comment.", @@ -465,7 +514,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference16() throws Exception { + public void testGetCommentDifference16() throws Exception { // 0x100239d: Different Plate comments. programBuilder1.createComment("0x100239d", "Once upon a time,", CodeUnit.PLATE_COMMENT); programBuilder2.createComment("0x100239d", "This is a sample comment.", @@ -475,7 +524,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference17() throws Exception { + public void testGetCommentDifference17() throws Exception { // 0x100239d: Different Post comments. programBuilder1.createComment("0x100239d", "Once upon a time,", CodeUnit.POST_COMMENT); programBuilder2.createComment("0x100239d", "This is a sample comment.", @@ -485,7 +534,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference18() throws Exception { + public void testGetCommentDifference18() throws Exception { // 0x1002a91: p2 has a plate comment. programBuilder2.createComment("0x1002a91", "This is a sample comment.", CodeUnit.PLATE_COMMENT); @@ -494,7 +543,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference19() throws Exception { + public void testGetCommentDifference19() throws Exception { // 0x100248f: p1 has function comment. programBuilder1.createFunctionComment("0x100248f", "Sample function comment."); @@ -502,7 +551,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference20() throws Exception { + public void testGetCommentDifference20() throws Exception { // 0x100248f: p2 has function comment. programBuilder2.createFunctionComment("0x100248f", "Other function comment."); @@ -510,7 +559,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference21() throws Exception { + public void testGetCommentDifference21() throws Exception { // 0x100248f: p1 and p2 have same function comment. programBuilder1.createFunctionComment("0x100248f", "Sample function comment."); programBuilder2.createFunctionComment("0x100248f", "Sample function comment."); @@ -519,7 +568,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetCommentDifference22() throws Exception { + public void testGetCommentDifference22() throws Exception { // 0x100248f: p1 and p2 have different function comments. programBuilder1.createFunctionComment("0x100248f", "Sample function comment."); programBuilder2.createFunctionComment("0x100248f", "Other function comment."); @@ -545,7 +594,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference1() throws Exception { + public void testGetBookmarkDifference1() throws Exception { // 0x1002306: p1 and p2 have same bookmarks. programBuilder1.createBookmark("0x1002306", BookmarkType.INFO, "Cat1", "My bookmark"); programBuilder2.createBookmark("0x1002306", BookmarkType.INFO, "Cat1", "My bookmark"); @@ -556,7 +605,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference2() throws Exception { + public void testGetBookmarkDifference2() throws Exception { // 0x100230b: p1 and p2 have bookmarks with different categories. programBuilder1.createBookmark("0x100230b", BookmarkType.INFO, "Cat1", "My bookmark"); programBuilder2.createBookmark("0x100230b", BookmarkType.INFO, "Stuff", "My bookmark"); @@ -567,7 +616,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference3() throws Exception { + public void testGetBookmarkDifference3() throws Exception { // 0x100230c: p1 has bookmark, p2 doesn't. programBuilder1.createBookmark("0x100230c", BookmarkType.INFO, "", "Something different"); @@ -577,7 +626,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference4() throws Exception { + public void testGetBookmarkDifference4() throws Exception { // 0x100230d: p2 has bookmark, p1 doesn't. programBuilder2.createBookmark("0x100230d", BookmarkType.INFO, "", "My bookmark"); @@ -587,7 +636,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference5() throws Exception { + public void testGetBookmarkDifference5() throws Exception { // 0x1002312: p1 and p2 have bookmarks with no category and different descriptions. programBuilder1.createBookmark("0x1002312", BookmarkType.INFO, "", "Something different"); programBuilder2.createBookmark("0x1002312", BookmarkType.INFO, "", "My bookmark"); @@ -598,7 +647,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference6() throws Exception { + public void testGetBookmarkDifference6() throws Exception { // 0x1002318: p1 and p2 have bookmarks with same category and different descriptions. programBuilder1.createBookmark("0x1002318", BookmarkType.INFO, "stuff", "Something different"); @@ -610,7 +659,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference7() throws Exception { + public void testGetBookmarkDifference7() throws Exception { // 0x100231d: p1 and p2 have same NOTE bookmarks. programBuilder1.createBookmark("0x100231d", BookmarkType.NOTE, "stuff", "My bookmark"); programBuilder2.createBookmark("0x100231d", BookmarkType.NOTE, "stuff", "My bookmark"); @@ -621,7 +670,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetBookmarkDifference8() throws Exception { + public void testGetBookmarkDifference8() throws Exception { // 0x1002323: p1 and p2 have same INFO bookmarks. programBuilder1.createBookmark("0x1002323", BookmarkType.INFO, "stuff", "My bookmark"); programBuilder2.createBookmark("0x1002323", BookmarkType.INFO, "stuff", "My bookmark"); @@ -647,7 +696,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testGetUserDefinedPropertyDifferences() throws Exception { + public void testGetUserDefinedPropertyDifferences() throws Exception { // SPACE property // 0x10018ae: p1 has space=1. // 0x10018ba: p1 and p2 have space=1. @@ -696,7 +745,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * Program1 and Program2. */ @Test - public void testGetSymbolDifferences() throws Exception { + public void testGetSymbolDifferences() throws Exception { // p1 and p2 have same default label 1002d11-1002d13 LAB... // p1 and p2 have same symbols and same primary. 1002d14-1002d15 bar, baz, bam @@ -755,7 +804,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * Program1 and Program2. */ @Test - public void testGetEquateDifferences() throws Exception { + public void testGetEquateDifferences() throws Exception { // 0x100650e: Both have same equates. op2 is 0x22. @@ -791,14 +840,14 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * are the same in Program1 and Program2. */ @Test - public void testFunctionsSame() throws Exception { + public void testFunctionsSame() throws Exception { programDiff = new ProgramDiff(p1, p2, new AddressSet(addr(0x1002239), addr(0x100248c))); programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.FUNCTION_DIFFS)); assertEquals(new AddressSet(), programDiff.getDifferences(programDiff.getFilter(), null)); } @Test - public void testFunctionRegParamDiff9() throws Exception { + public void testFunctionRegParamDiff9() throws Exception { // added register param in program2 @@ -818,7 +867,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * different. */ @Test - public void testFunctionReturnDiff() throws Exception { + public void testFunctionReturnDiff() throws Exception { // 0x010048a3: p1 returns DWord, p2 returns Float. // 0x010059a3: p1 returns Byte, p2 returns Undefined. @@ -863,7 +912,7 @@ public class ProgramDiff1Test extends AbstractGhidraHeadedIntegrationTest { * between Program1 and Program2. */ @Test - public void testGetProgramContextDifferences() throws Exception { + public void testGetProgramContextDifferences() throws Exception { // C0 is 1 bit // AH is 8 bits diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramMerge3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramMerge3Test.java index 951c448aac..270796c0b6 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramMerge3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/ProgramMerge3Test.java @@ -19,8 +19,10 @@ import static org.junit.Assert.*; import org.junit.*; +import ghidra.docking.settings.FormatSettingsDefinition; import ghidra.program.model.address.*; import ghidra.program.model.data.*; +import ghidra.program.model.data.DataUtilities.ClearDataMode; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.symbol.*; @@ -93,10 +95,10 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { // 0x100248c: p2 has format line indicating function exit. // 0x1002428: p1 and p2 both have a format line. programBuilder1.setIntProperty("0x1002428", "Space", 1); - + programBuilder2.setIntProperty("0x100248c", "Space", 1); programBuilder2.setIntProperty("0x1002428", "Space", 1); - + AddressSet addrSet = new AddressSet(addr(0x1002488), addr(0x1002492)); addrSet.addRange(addr(0x01002428), addr(0x0100242c)); programMerge = new ProgramMergeManager(p1, p2, addrSet, TaskMonitor.DUMMY); @@ -113,51 +115,51 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { * Test that programMerge can determine the bookmark user defined property * differences between Program1 and Program2. */ - @Test - public void testApplyBookmarkDifferences() throws Exception { - // 0x1002306: p1 and p2 have same bookmarks. - programBuilder1.createBookmark("0x1002306", BookmarkType.INFO, "Cat1", "My bookmark"); - programBuilder2.createBookmark("0x1002306", BookmarkType.INFO, "Cat1", "My bookmark"); - - // 0x100230b: p1 and p2 have bookmarks with different categories. - programBuilder1.createBookmark("0x100230b", BookmarkType.INFO, "Cat1", "My bookmark"); - programBuilder2.createBookmark("0x100230b", BookmarkType.INFO, "Stuff", "My bookmark"); - - // 0x100230c: p1 has bookmark, p2 doesn't. - programBuilder1.createBookmark("0x100230c", BookmarkType.INFO, "", "Something different"); - - // 0x100230d: p2 has bookmark, p1 doesn't. - programBuilder2.createBookmark("0x100230d", BookmarkType.INFO, "", "My bookmark"); - - // 0x1002312: p1 and p2 have bookmarks with no category and different descriptions. - programBuilder1.createBookmark("0x1002312", BookmarkType.INFO, "", "Something different"); - programBuilder2.createBookmark("0x1002312", BookmarkType.INFO, "", "My bookmark"); - - // 0x1002318: p1 and p2 have bookmarks with same category and different descriptions. - programBuilder1.createBookmark("0x1002318", BookmarkType.INFO, "stuff", - "Something different"); - programBuilder2.createBookmark("0x1002318", BookmarkType.INFO, "stuff", "My bookmark"); - - // 0x100231d: p1 and p2 have same NOTE bookmarks. - programBuilder1.createBookmark("0x100231d", BookmarkType.NOTE, "stuff", "My bookmark"); - programBuilder2.createBookmark("0x100231d", BookmarkType.NOTE, "stuff", "My bookmark"); - - // 0x1002323: p1 and p2 have same INFO bookmarks. - programBuilder1.createBookmark("0x1002323", BookmarkType.INFO, "stuff", "My bookmark"); - programBuilder2.createBookmark("0x1002323", BookmarkType.INFO, "stuff", "My bookmark"); - - programMerge = new ProgramMergeManager(p1, p2, - new AddressSet(addr(0x1002306), addr(0x100232f)), TaskMonitor.DUMMY); - AddressSet as = new AddressSet(addr(0x100230b), addr(0x100231c)); - programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.BOOKMARK_DIFFS)); - programMerge.setMergeFilter( - new ProgramMergeFilter(ProgramMergeFilter.BOOKMARKS, ProgramMergeFilter.REPLACE)); - // printAddressSet(as); - // printAddressSet(programMerge.getFilteredDifferences()); - assertEquals(as, programMerge.getFilteredDifferences()); - programMerge.merge(as, TaskMonitor.DUMMY); - assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); - } + @Test + public void testApplyBookmarkDifferences() throws Exception { + // 0x1002306: p1 and p2 have same bookmarks. + programBuilder1.createBookmark("0x1002306", BookmarkType.INFO, "Cat1", "My bookmark"); + programBuilder2.createBookmark("0x1002306", BookmarkType.INFO, "Cat1", "My bookmark"); + + // 0x100230b: p1 and p2 have bookmarks with different categories. + programBuilder1.createBookmark("0x100230b", BookmarkType.INFO, "Cat1", "My bookmark"); + programBuilder2.createBookmark("0x100230b", BookmarkType.INFO, "Stuff", "My bookmark"); + + // 0x100230c: p1 has bookmark, p2 doesn't. + programBuilder1.createBookmark("0x100230c", BookmarkType.INFO, "", "Something different"); + + // 0x100230d: p2 has bookmark, p1 doesn't. + programBuilder2.createBookmark("0x100230d", BookmarkType.INFO, "", "My bookmark"); + + // 0x1002312: p1 and p2 have bookmarks with no category and different descriptions. + programBuilder1.createBookmark("0x1002312", BookmarkType.INFO, "", "Something different"); + programBuilder2.createBookmark("0x1002312", BookmarkType.INFO, "", "My bookmark"); + + // 0x1002318: p1 and p2 have bookmarks with same category and different descriptions. + programBuilder1.createBookmark("0x1002318", BookmarkType.INFO, "stuff", + "Something different"); + programBuilder2.createBookmark("0x1002318", BookmarkType.INFO, "stuff", "My bookmark"); + + // 0x100231d: p1 and p2 have same NOTE bookmarks. + programBuilder1.createBookmark("0x100231d", BookmarkType.NOTE, "stuff", "My bookmark"); + programBuilder2.createBookmark("0x100231d", BookmarkType.NOTE, "stuff", "My bookmark"); + + // 0x1002323: p1 and p2 have same INFO bookmarks. + programBuilder1.createBookmark("0x1002323", BookmarkType.INFO, "stuff", "My bookmark"); + programBuilder2.createBookmark("0x1002323", BookmarkType.INFO, "stuff", "My bookmark"); + + programMerge = new ProgramMergeManager(p1, p2, + new AddressSet(addr(0x1002306), addr(0x100232f)), TaskMonitor.DUMMY); + AddressSet as = new AddressSet(addr(0x100230b), addr(0x100231c)); + programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.BOOKMARK_DIFFS)); + programMerge.setMergeFilter( + new ProgramMergeFilter(ProgramMergeFilter.BOOKMARKS, ProgramMergeFilter.REPLACE)); + // printAddressSet(as); + // printAddressSet(programMerge.getFilteredDifferences()); + assertEquals(as, programMerge.getFilteredDifferences()); + programMerge.merge(as, TaskMonitor.DUMMY); + assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); + } /** * Test that ProgramMerge can apply the byte differences between Program1 @@ -166,13 +168,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyByteAndCodeUnitDifferencesSamePrototypeDiffByte() throws Exception { - + programBuilder1.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder1.setBytes("0x01002cf8", "3b 74 24 08", true); - + programBuilder2.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder2.setBytes("0x01002cf8", "3b 74 24 0c", true); - + // p1 & p2 differ at byte at 0x01002cfb. programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); programMerge.setDiffFilter(new ProgramDiffFilter( @@ -183,7 +185,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { as.addRange(addr(0x01002cf8), addr(0x01002cfb)); assertEquals(as, programMerge.getFilteredDifferences()); programMerge.merge(as, TaskMonitor.DUMMY); - + AddressSet unMergableByteAddresses = new AddressSet();// None that can't merge. assertEquals(unMergableByteAddresses, programMerge.getFilteredDifferences()); } @@ -194,23 +196,23 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyByteDifferences() throws Exception { - + programBuilder1.createMemory("d1", "0x100", 0x100, null, (byte) 0xAC); programBuilder1.createMemory("d2", "0x200", 0x100); - + programBuilder2.createMemory("d1", "0x100", 0x100, null, (byte) 0xAF); programBuilder2.createMemory("d4", "0x400", 0x100); - + // p1 has 0x100 to 0x1ff with byte values of 0xCF, but in p2 of 0xAF. // p1 has changed byte at 0x1002b45 from 0x8b to 0xee. // p2 has changed byte at 0x1002b49 from 0x57 to 0xee. - + programBuilder1.setBytes("0x1002b45", "ee"); programBuilder1.setBytes("0x1002b49", "ee"); - + programBuilder2.setBytes("0x1002b45", "8b"); programBuilder2.setBytes("0x1002b49", "57"); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.BYTE_DIFFS)); programMerge.setMergeFilter( @@ -225,7 +227,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { as.addRange(addr(0x00000400), addr(0x000004ff)); assertEquals(as, programMerge.getFilteredDifferences()); programMerge.merge(as, TaskMonitor.DUMMY); - + AddressSet unMergableByteAddresses = new AddressSet(); // Add the bytes for the blocks that are in program1 and not in program2. unMergableByteAddresses.addRange(addr(0x00000200), addr(0x000002ff)); @@ -248,7 +250,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { programBuilder1.setBytes("0x01002b49", "57", true); programBuilder1.clearCodeUnits("0x01002cf5", "0x01002d6d", true); programBuilder1.setBytes("0x01002951", "45 10 83 e8 00 74 12", true); - + programBuilder2.createMemory("d1", "0x100", 0x100, null, (byte) 0xAF); programBuilder2.createMemory("d4", "0x400", 0x100); programBuilder2.createLabel("0x01006420", "Function2"); @@ -258,7 +260,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { programBuilder2.clearCodeUnits("0x01002239", "0x0100248e", true); programBuilder2.disassemble("0x10024b8", 19); programBuilder2.setBytes("0x01002950", "8b 45 10 83 e8 00 74 12", true); - + // p2 has code units cleared from 0x1005887 to 0x1005fbd. // p1 has code unit at 0x1005912 cleared only. // p1 & p2 have different bytes causing different instructions at 0x01002b49. @@ -277,7 +279,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { addrSet.addRange(addr(p1, 0x01002950), addr(p1, 0x01002957)); AddressSetView diffAs = programMerge.getFilteredDifferences(); assertEquals(addrSet, diffAs); - + programMerge.merge(as, TaskMonitor.DUMMY); assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); } @@ -288,32 +290,32 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyConflictingDataTypeDifferences() throws Exception { - + // 0x01003b02: different unions with differing structures inside. - + Structure struct_b1 = new StructureDataType("struct_a", 0); struct_b1.add(new ByteDataType()); struct_b1.add(new PointerDataType(new DWordDataType())); - + Union union_a1 = new UnionDataType("union_1"); union_a1.add(new ByteDataType()); union_a1.add(struct_b1); programBuilder1.applyDataType("0x01003b02", union_a1, 1); - + Structure struct_b2 = new StructureDataType("struct_a", 0); struct_b2.add(new ByteDataType()); struct_b2.add(new PointerDataType(new CharDataType())); - + Union union_a2 = new UnionDataType("union_1"); union_a2.add(new CharDataType()); union_a2.add(struct_b1); programBuilder2.applyDataType("0x01003b02", union_a2, 1); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.CODE_UNIT_DIFFS)); programMerge.setMergeFilter( new ProgramMergeFilter(ProgramMergeFilter.CODE_UNITS, ProgramMergeFilter.REPLACE)); - + AddressSet as = new AddressSet(); as.addRange(addr(0x01003b02), addr(0x01003b06)); assertEquals(as, programMerge.getFilteredDifferences()); @@ -332,9 +334,9 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertEquals("union_1", u1.getName()); assertEquals("union_1", u2.getName()); assertEquals(false, u1.isEquivalent(u2)); - + programMerge.merge(as, TaskMonitor.DUMMY); - + assertEquals(as, programMerge.getFilteredDifferences()); cu1 = p1.getListing().getCodeUnitAt(addr(0x01003b02)); cu2 = p2.getListing().getCodeUnitAt(addr(0x01003b02)); @@ -353,10 +355,10 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertTrue(u1.isEquivalent(u2)); assertEquals(stripConflictDtSuffixes(u1.getPathName()), stripConflictDtSuffixes(u2.getPathName())); - + // Try to apply it again. Should get same result. programMerge.merge(as, TaskMonitor.DUMMY); - + assertEquals(as, programMerge.getFilteredDifferences()); cu1 = p1.getListing().getCodeUnitAt(addr(0x01003b02)); cu2 = p2.getListing().getCodeUnitAt(addr(0x01003b02)); @@ -379,19 +381,19 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference1() throws Exception { - + // 0x01003ac8: same size and named struct with different components. - + Structure struct_a1 = new StructureDataType("struct_a", 0); struct_a1.add(new ByteDataType()); struct_a1.add(new DWordDataType()); programBuilder1.applyDataType("0x01003ac8", struct_a1, 1); - + Structure struct_a2 = new StructureDataType("struct_a", 0); struct_a2.add(new CharDataType()); struct_a2.add(new DWordDataType()); programBuilder2.applyDataType("0x01003ac8", struct_a2, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003ac8), addr(0x01003acc)), programMerge.getFilteredDifferences()); @@ -403,13 +405,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference10() throws Exception { - + // 0x01003b29: different type of pointers. - + programBuilder1.applyDataType("0x01003b29", new PointerDataType(new WordDataType()), 1); - + programBuilder2.applyDataType("0x01003b29", new PointerDataType(new ByteDataType()), 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b29), addr(0x01003b2c)), programMerge.getFilteredDifferences()); @@ -419,17 +421,17 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference11() throws Exception { - + // 0x01003b31: 5 bytes vs an array of 5 bytes. - + programBuilder1.applyDataType("0x01003b31", new WordDataType(), 1); programBuilder1.applyDataType("0x01003b31", new WordDataType(), 1); programBuilder1.applyDataType("0x01003b31", new WordDataType(), 1); programBuilder1.applyDataType("0x01003b31", new WordDataType(), 1); programBuilder1.applyDataType("0x01003b31", new WordDataType(), 1); - + programBuilder2.applyDataType("0x01003b31", new ArrayDataType(new ByteDataType(), 5, 1), 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b31), addr(0x01003b35)), programMerge.getFilteredDifferences()); @@ -439,11 +441,11 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference12() throws Exception { - + // 0x01003b3a: p2 has a double. - + programBuilder2.applyDataType("0x1003b3a", new DoubleDataType(), 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b3a), addr(0x01003b41)), programMerge.getFilteredDifferences()); @@ -453,39 +455,39 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference13() throws Exception { - + // 0x01003b45: p1 and p2 have the same nested structure. - + Structure inner = new StructureDataType("inner", 0); inner.add(new ByteDataType()); inner.add(new PointerDataType(new DWordDataType())); - + Structure outer = new StructureDataType("outer", 0); outer.add(new ByteDataType()); outer.add(inner); - + programBuilder1.applyDataType("0x01003b45", outer, 1); - + programBuilder2.applyDataType("0x01003b45", outer, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); } @Test public void testApplyDataDifference14() throws Exception { - + // 0x01003b5e - 0x01003b62: p1 has instructions and p2 has structure - + programBuilder1.setBytes("0x01003b5e", "75 12 39 75 08", true); - + programBuilder2.setBytes("0x01003b5e", "75 12 39 75 08", false); - + Structure struct_a2 = new StructureDataType("struct_a", 0); struct_a2.add(new CharDataType()); struct_a2.add(new DWordDataType()); programBuilder2.applyDataType("0x01003b5e", struct_a2, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b5e), addr(0x01003b62)), programMerge.getFilteredDifferences()); @@ -493,21 +495,63 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); } + @Test + public void testApplyDataDifference15() throws Exception { + + p1.withTransaction("Apply p1 Data", () -> { + + Data d1 = DataUtilities.createData(p1, addr(p1, 0x1008014), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + CharsetSettingsDefinition.CHARSET.setChoice(d1, 2); + + d1 = DataUtilities.createData(p1, addr(p1, 0x1008028), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + CharsetSettingsDefinition.CHARSET.setChoice(d1, 2); + + }); + + p2.withTransaction("Apply p2 Data", () -> { + + Data d2 = DataUtilities.createData(p2, addr(p2, 0x1008014), ByteDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + FormatSettingsDefinition.DEF.setChoice(d2, FormatSettingsDefinition.DECIMAL); + + d2 = DataUtilities.createData(p2, addr(p2, 0x1008028), StringDataType.dataType, -1, + ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA); + CharsetSettingsDefinition.CHARSET.setChoice(d2, 3); + + }); + + // NOTE: unknown settings will be dropped during merge + + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); + + AddressSet addrSet = new AddressSet(); + addrSet.addRange(addr(p1, 0x1008014), addr(p1, 0x1008015)); + addrSet.add(addr(p1, 0x1008028)); + + assertEquals(addrSet, programMerge.getFilteredDifferences()); + + mergeCodeUnitDifference(addrSet); + + assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); + } + @Test public void testApplyDataDifference2() throws Exception { - + // 0x01003ad5: same structs except different pointer type component. - + Structure struct_b1 = new StructureDataType("struct_a", 0); struct_b1.add(new ByteDataType()); struct_b1.add(new PointerDataType(new DWordDataType())); programBuilder1.applyDataType("0x01003ad5", struct_b1, 1); - + Structure struct_b2 = new StructureDataType("struct_a", 0); struct_b2.add(new ByteDataType()); struct_b2.add(new PointerDataType(new CharDataType())); programBuilder2.applyDataType("0x01003ad5", struct_b2, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003ad5), addr(0x01003ad9)), programMerge.getFilteredDifferences()); @@ -519,20 +563,20 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference3() throws Exception { - + // 0x01003ae1: struct vs union - + Structure struct_c1 = new StructureDataType("struct_c", 0); struct_c1.add(new WordDataType()); struct_c1.add(new FloatDataType()); programBuilder1.applyDataType("0x01003ae1", struct_c1, 1); - + Union union_c2 = new UnionDataType("union_c"); union_c2.add(new ByteDataType()); union_c2.add(new PointerDataType(new DWordDataType())); union_c2.add(new DWordDataType()); programBuilder2.applyDataType("0x01003ae1", union_c2, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003ae1), addr(0x01003ae6)), programMerge.getFilteredDifferences()); @@ -542,16 +586,16 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference4() throws Exception { - + // 0x01003aec & 0x1003aed: same struct positioned 0ne byte address different. Structure struct_a1 = new StructureDataType("struct_a", 0); struct_a1.add(new ByteDataType()); struct_a1.add(new DWordDataType()); - + programBuilder1.applyDataType("0x01003aec", struct_a1, 1); - + programBuilder2.applyDataType("0x1003aed", struct_a1, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003aec), addr(0x01003af1)), programMerge.getFilteredDifferences()); @@ -561,20 +605,20 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference5() throws Exception { - + // 0x01003af7: same struct with different names. - + Structure struct_a1 = new StructureDataType("struct_a", 0); struct_a1.add(new ByteDataType()); struct_a1.add(new DWordDataType()); - + programBuilder1.applyDataType("0x01003af7", struct_a1, 1); - + Structure struct_altName_a1 = new StructureDataType("my_struct_a", 0); struct_altName_a1.add(new ByteDataType()); struct_altName_a1.add(new DWordDataType()); programBuilder2.applyDataType("0x1003af7", struct_altName_a1, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003af7), addr(0x01003afb)), programMerge.getFilteredDifferences()); @@ -584,19 +628,19 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference6() throws Exception { - + // 0x01003b02: same struct, different category - + Structure struct_a1 = new StructureDataType("struct_a", 0); struct_a1.add(new ByteDataType()); struct_a1.add(new DWordDataType()); programBuilder1.applyDataType("0x01003b02", struct_a1, 1); - + Structure struct_sub1_a1 = new StructureDataType(new CategoryPath("/sub1"), "struct_a", 0); struct_sub1_a1.add(new ByteDataType()); struct_sub1_a1.add(new DWordDataType()); programBuilder2.applyDataType("0x1003b02", struct_sub1_a1, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b02), addr(0x01003b06)), programMerge.getFilteredDifferences()); @@ -606,13 +650,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference7() throws Exception { - + // 0x01003b0d: different data type with different size - + programBuilder1.applyDataType("0x01003b0d", new WordDataType(), 1); - + programBuilder2.applyDataType("0x1003b0d", new ByteDataType(), 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b0d), addr(0x01003b0e)), programMerge.getFilteredDifferences()); @@ -622,13 +666,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference8() throws Exception { - + // 0x01003b14: different data type, same size - + programBuilder1.applyDataType("0x01003b14", new CharDataType(), 1); - + programBuilder2.applyDataType("0x1003b14", new ByteDataType(), 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b14), addr(0x01003b14)), programMerge.getFilteredDifferences()); @@ -638,13 +682,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyDataDifference9() throws Exception { - + // 0x01003b1c: different variable length data types, same size - + programBuilder1.applyDataType("0x01003b1c", new StringDataType(), 1); - + programBuilder2.applyDataType("0x1003b1c", new UnicodeDataType(), 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); assertEquals(new AddressSet(addr(0x01003b1c), addr(0x01003b1d)), programMerge.getFilteredDifferences()); @@ -658,25 +702,25 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyEquateDifferences() throws Exception { - + // 0x100650e: Both have same equates. op2 is 0x22. - + // 0x100643d: p1 has an equate op 2 is -0x68. p2 doesn't. // 0x100644d: p2 has an equate op 1 is 0x2. p1 doesn't. // 0x1006455: Both have different named equates. op2 is 0x4. // 0x10064c5: p1 has MY_EQUATE. op2 is 0x8. // 0x10064ee: p2 has MY_EQUATE. op2 is 0x14. - + programBuilder1.createEquate("0x100650e", "Pos22", 0x22, 2); programBuilder1.createEquate("0x100643d", "Minus68", -0x68, 2); programBuilder1.createEquate("0x1006455", "Pos4", 0x4, 2); programBuilder1.createEquate("0x10064c5", "MY_EQUATE", 0x8, 2); - + programBuilder2.createEquate("0x100650e", "Pos22", 0x22, 2); programBuilder2.createEquate("0x100644d", "Two", 0x2, 2); programBuilder2.createEquate("0x100643d", "Four", 0x4, 2); programBuilder2.createEquate("0x10064ee", "MY_EQUATE", 0x14, 2); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(); as.addRange(addr(0x100643d), addr(0x100643d)); @@ -695,18 +739,18 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyExtRefDiff1() throws Exception { // 0x1001028: p2 changed external ref to mem ref on operand 0. - + programBuilder1.applyDataType("0x01001028", new Pointer32DataType(), 1); programBuilder1.createExternalReference("0x01001028", "ADVAPI32.dll", "IsTextUnicode", 0); - + programBuilder2.applyDataType("0x01001028", new Pointer32DataType(), 1); programBuilder2.createMemoryReference("0x01001028", "0x01001000", RefType.INDIRECTION, SourceType.DEFAULT); - + programMerge = new ProgramMergeManager(p1, p2, new AddressSet(addr(0x01001000), addr(0x010017ff)), TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x01001028), addr(0x0100102b)); - + programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.REFERENCE_DIFFS)); programMerge.setMergeFilter( new ProgramMergeFilter(ProgramMergeFilter.REFERENCES, ProgramMergeFilter.REPLACE)); @@ -724,7 +768,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { Function function2 = p2.getFunctionManager().getFunctionAt(addr(0x100299e)); function2.setBody(new AddressSet(addr(0x100299e), addr(0x1002a89))); p2.endTransaction(transactionID, true); - + programMerge = new ProgramMergeManager(p1, p2, new AddressSet(addr(0x0100299e), addr(0x01002a90)), TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x0100299e), addr(0x0100299e)); @@ -742,12 +786,12 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionDefaultStackLocalDiff() throws Exception { - + // 0x010048a3: created default stack local_1 in p2. - + Function function2 = p2.getFunctionManager().getFunctionAt(addr(p2, 0x010048a3)); programBuilder2.createLocalVariable(function2, null, DataType.DEFAULT, 0x1); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x010048a3), addr(0x010048a3)); @@ -765,14 +809,14 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionDefaultStackParamDiff() throws Exception { - + // 0x1002cf5: created default stack param in p2. int transactionID = p2.startTransaction("Test Transaction"); Function function = p2.getFunctionManager().getFunctionAt(addr(p2, 0x1002cf5)); Variable var = new ParameterImpl("variable", DataType.DEFAULT, 0x1c, p2); function.addParameter(var, SourceType.USER_DEFINED); p2.endTransaction(transactionID, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x1002cf5), addr(0x1002cf5)); @@ -790,9 +834,9 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionLocalNameDiff() throws Exception { - + // 0x10059a3: renamed local_18 to numAvailable in p1. - + int transactionID1 = p1.startTransaction("Test Transaction"); Function function1 = p1.getFunctionManager().getFunctionAt(addr(p1, 0x10059a3)); Variable[] localVariables = function1.getLocalVariables(); @@ -800,7 +844,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(-0x18, localVariables[4].getStackOffset()); localVariables[4].setName("numAvailable", SourceType.USER_DEFINED); p1.endTransaction(transactionID1, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x10059a3), addr(0x10059a3)); @@ -818,9 +862,9 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionLocalsDiff() throws Exception { - + // 0x10059a3: removed local_18 in p1. - + int transactionID1 = p1.startTransaction("Test Transaction"); Function function1 = p1.getFunctionManager().getFunctionAt(addr(p1, 0x10059a3)); Variable[] localVariables = function1.getLocalVariables(); @@ -828,7 +872,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(-0x18, localVariables[4].getStackOffset()); function1.removeVariable(localVariables[4]); p1.endTransaction(transactionID1, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x10059a3), addr(0x10059a3)); @@ -846,9 +890,9 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionLocalTypeDiff() throws Exception { - + // 0x10059a3: in p1 local_8 is a Undefined, in p2 it's Pointer. - + int transactionID1 = p1.startTransaction("Test Transaction"); Function function1 = p1.getFunctionManager().getFunctionAt(addr(p1, 0x10059a3)); Variable[] localVariables = function1.getLocalVariables(); @@ -856,7 +900,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(-0x8, localVariables[0].getStackOffset()); localVariables[0].setDataType(DataType.DEFAULT, SourceType.DEFAULT); p1.endTransaction(transactionID1, true); - + int transactionID2 = p2.startTransaction("Test Transaction"); Function function2 = p2.getFunctionManager().getFunctionAt(addr(p2, 0x10059a3)); Variable[] localVariables2 = function2.getLocalVariables(); @@ -864,7 +908,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertEquals(-0x8, localVariables2[0].getStackOffset()); localVariables2[0].setDataType(new PointerDataType(), SourceType.DEFAULT); p2.endTransaction(transactionID2, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x10059a3), addr(0x10059a3)); @@ -881,7 +925,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionNameDiff() throws Exception { - + // 0x010048a3: function names differ. // 0x01002239: function names same. int transactionID = p1.startTransaction("Test Transaction"); @@ -893,7 +937,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertNotNull(function1); function1.setName("Function2239", SourceType.USER_DEFINED); p1.endTransaction(transactionID, true); - + int transactionID2 = p2.startTransaction("Test Transaction"); FunctionManager functionManager2 = p2.getFunctionManager(); Function function2 = functionManager2.getFunctionAt(addr(0x010048a3)); @@ -903,7 +947,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertNotNull(function2); function2.setName("Function2239", SourceType.USER_DEFINED); p2.endTransaction(transactionID2, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x10048a3), addr(0x10048a3)); @@ -926,7 +970,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { int transactionID = p2.startTransaction("Test Transaction"); p2.getFunctionManager().removeFunction(addr(0x10030d2)); p2.endTransaction(transactionID, true); - + programMerge = new ProgramMergeManager(p1, p2, new AddressSet(addr(0x10030d2), addr(0x10030d7)), TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x10030d2), addr(0x10030d2)); @@ -948,7 +992,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { int transactionID = p1.startTransaction("Test Transaction"); p1.getFunctionManager().removeFunction(addr(0x10030d2)); p1.endTransaction(transactionID, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x10030d2), addr(0x10030d2)); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.FUNCTION_DIFFS)); @@ -965,13 +1009,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionParamNameDiff() throws Exception { - + // 0x01002cf5: renamed parm_2 to value in p1. int transactionID = p1.startTransaction("Test Transaction"); Function function = p1.getFunctionManager().getFunctionAt(addr(p1, 0x1002cf5)); function.getParameter(0).setName("value", SourceType.USER_DEFINED); p1.endTransaction(transactionID, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x01002cf5), addr(0x01002cf5)); @@ -987,24 +1031,24 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { * Test that programMerge can determine that function param offsets are * different. */ - @Test - public void testApplyFunctionParamOffsetDiff() throws Exception { - - // 0x010032d5: changed param offset from 0x8 to 0x4 in p2. - - AddressSet as = new AddressSet(); - as.addRange(addr(0x010032d5), addr(0x010033f5)); - programMerge = new ProgramMergeManager(p1, p2, as, TaskMonitor.DUMMY); - AddressSet diffAs = new AddressSet(); - // For now, we are not allowing you to set the parameter offset or local size outright. - // diffAs.addRange(addr(0x010032d5), addr(0x010032d5)); - programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.FUNCTION_DIFFS)); - programMerge.setMergeFilter( - new ProgramMergeFilter(ProgramMergeFilter.FUNCTIONS, ProgramMergeFilter.REPLACE)); - assertEquals(diffAs, programMerge.getFilteredDifferences()); - programMerge.merge(as, TaskMonitor.DUMMY); - assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); - } + @Test + public void testApplyFunctionParamOffsetDiff() throws Exception { + + // 0x010032d5: changed param offset from 0x8 to 0x4 in p2. + + AddressSet as = new AddressSet(); + as.addRange(addr(0x010032d5), addr(0x010033f5)); + programMerge = new ProgramMergeManager(p1, p2, as, TaskMonitor.DUMMY); + AddressSet diffAs = new AddressSet(); + // For now, we are not allowing you to set the parameter offset or local size outright. + // diffAs.addRange(addr(0x010032d5), addr(0x010032d5)); + programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.FUNCTION_DIFFS)); + programMerge.setMergeFilter( + new ProgramMergeFilter(ProgramMergeFilter.FUNCTIONS, ProgramMergeFilter.REPLACE)); + assertEquals(diffAs, programMerge.getFilteredDifferences()); + programMerge.merge(as, TaskMonitor.DUMMY); + assertEquals(new AddressSet(), programMerge.getFilteredDifferences()); + } /** * Test that programMerge can determine that function parameters are @@ -1012,13 +1056,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionParamsDiff() throws Exception { - + // 0x01002cf5: removed parm_2 from p1. int transactionID = p1.startTransaction("Test Transaction"); Function function = p1.getFunctionManager().getFunctionAt(addr(p1, 0x1002cf5)); function.removeParameter(0); p1.endTransaction(transactionID, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x01002cf5), addr(0x01002cf5)); @@ -1036,7 +1080,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionParamTypeDiff() throws Exception { - + // 0x010059a3: in p1 parm_2 is a Word, in p2 it's Undefined. int transactionID = p1.startTransaction("Test Transaction"); FunctionManager functionManager1 = p1.getFunctionManager(); @@ -1045,7 +1089,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { Parameter f1p0 = function1.getParameter(0); f1p0.setDataType(new WordDataType(), SourceType.USER_DEFINED); p1.endTransaction(transactionID, true); - + int transactionID2 = p2.startTransaction("Test Transaction"); FunctionManager functionManager2 = p2.getFunctionManager(); Function function2 = functionManager2.getFunctionAt(addr(0x010059a3)); @@ -1053,7 +1097,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { Parameter f2p0 = function2.getParameter(0); f2p0.setDataType(DataType.DEFAULT, SourceType.USER_DEFINED); p2.endTransaction(transactionID2, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x010059a3), addr(0x010059a3)); @@ -1071,11 +1115,11 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyFunctionReturnDiff() throws Exception { - + // 0x010048a3: p1 returns DWord, p2 returns Float. // 0x010059a3: p1 returns Byte, p2 returns Word. // 0x01002239: functions are the same, both return Ascii. - + int transactionID = p1.startTransaction("Test Transaction"); FunctionManager functionManager1 = p1.getFunctionManager(); Function function1 = functionManager1.getFunctionAt(addr(0x010048a3)); @@ -1088,7 +1132,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertNotNull(function1); function1.setReturnType(new CharDataType(), SourceType.USER_DEFINED); p1.endTransaction(transactionID, true); - + int transactionID2 = p2.startTransaction("Test Transaction"); FunctionManager functionManager2 = p2.getFunctionManager(); Function function2 = functionManager2.getFunctionAt(addr(0x010048a3)); @@ -1101,7 +1145,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { assertNotNull(function2); function2.setReturnType(new CharDataType(), SourceType.USER_DEFINED); p2.endTransaction(transactionID2, true); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr(0x010048a3), addr(0x010048a3)); @@ -1123,7 +1167,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyLabelsInCycle() throws Exception { // Diff/Merge symbols from 1002950 to 100299b - + SymbolTable symtab1 = p1.getSymbolTable(); symtab1.createLabel(addr(0x100295d), "ONE", SourceType.USER_DEFINED); symtab1.createLabel(addr(0x1002969), "TWO", SourceType.USER_DEFINED); @@ -1134,9 +1178,8 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { symtab2.createLabel(addr(0x1002973), "TWO", SourceType.USER_DEFINED); AddressSet as; AddressSet limitedAddrSet = new AddressSet(addr(0x1002950), addr(0x100299b)); - programMerge = - new ProgramMergeManager(p1, p2, limitedAddrSet, TaskMonitor.DUMMY); - + programMerge = new ProgramMergeManager(p1, p2, limitedAddrSet, TaskMonitor.DUMMY); + as = new AddressSet(); as.addRange(addr(0x100295d), addr(0x100295d)); as.addRange(addr(0x1002969), addr(0x1002969)); @@ -1157,13 +1200,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyMemRefOpIndexDiff() throws Exception { // 0x1002d0f: p1 and p2 have mem refs on different op indices. - + programBuilder1.createMemoryReference("0x1002d0f", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 0); - + programBuilder2.createMemoryReference("0x1002d0f", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 1); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(); as.addRange(addr(0x1002d0f), addr(0x1002d10)); @@ -1183,12 +1226,12 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { public void testApplyMemRefP1MnemonicDiff() throws Exception { // 0x1002cfc: p1 has mem ref on mnemonic and p2 doesn't. // 0x1002d03: p2 has mem ref on mnemonic and p1 doesn't. - + programBuilder1.createMemoryReference("0x1002cfc", "0x1006488", RefType.READ, SourceType.USER_DEFINED, -1); programBuilder2.createMemoryReference("0x1002d03", "0x1006488", RefType.READ, SourceType.USER_DEFINED, -1); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x1002cfc), addr(0x1002cfc)); as.add(addr(0x1002d03), addr(0x1002d03)); @@ -1207,10 +1250,10 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyMemRefP2OpDiff() throws Exception { // 0x1002d25: p2 has operand 1 mem ref and p1 doesn't. - + programBuilder2.createMemoryReference("0x1002d25", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 1); - + programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x1002d25), addr(0x1002d26)); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.REFERENCE_DIFFS)); @@ -1229,7 +1272,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyMemRefPrimaryDiff() throws Exception { // 0x1002cfc: p1 and p2 have mem refs, but different ref is primary. - + programBuilder1.createMemoryReference("0x1002cfc", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 0); programBuilder1.createMemoryReference("0x1002cfc", "0x10064a0", RefType.READ, @@ -1238,7 +1281,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { SourceType.USER_DEFINED, 0); programBuilder2.createMemoryReference("0x1002cfc", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 0); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x1002cfc), addr(0x1002cfc)); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.REFERENCE_DIFFS)); @@ -1257,12 +1300,12 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyMemRefToAddrDiff() throws Exception { // 0x1002cfc: p1 and p2 have mem refs to different addresses. - + programBuilder1.createMemoryReference("0x1002cfc", "0x10064a0", RefType.READ, SourceType.USER_DEFINED, 0); programBuilder2.createMemoryReference("0x1002cfc", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 0); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x1002cfc), addr(0x1002cfc)); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.REFERENCE_DIFFS)); @@ -1280,12 +1323,12 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { @Test public void testApplyOffsetRefDiff() throws Exception { // 0x1002cfc: p1 and p2 have mem refs, but p1 has offset. - + programBuilder1.createOffsetMemReference("0x1002cfc", "0x1006488", 2, RefType.READ, SourceType.USER_DEFINED, 0); programBuilder2.createMemoryReference("0x1002cfc", "0x1006488", RefType.READ, SourceType.USER_DEFINED, 0); - + programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); AddressSet as = new AddressSet(addr(0x1002cfc), addr(0x1002cfc)); programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.REFERENCE_DIFFS)); @@ -1302,13 +1345,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyOnlyByteDifferencesSamePrototype() throws Exception { - + programBuilder1.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder1.setBytes("0x01002cf8", "3b 74 24 08", true); - + programBuilder2.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder2.setBytes("0x01002cf8", "3b 74 24 0c", true); - + // p1 & p2 differ at byte at 0x01002cfb. programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); programMerge.setDiffFilter(new ProgramDiffFilter( @@ -1319,7 +1362,7 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { as.addRange(addr(0x01002cf8), addr(0x01002cfb)); assertEquals(as, programMerge.getFilteredDifferences()); programMerge.merge(as, TaskMonitor.DUMMY); - + AddressSet unMergableByteAddresses = new AddressSet();// None that can't merge. assertEquals(unMergableByteAddresses, programMerge.getFilteredDifferences()); } @@ -1331,13 +1374,13 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { */ @Test public void testApplyOnlyCodeUnitDifferencesSamePrototypeDiffByte() throws Exception { - + programBuilder1.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder1.setBytes("0x01002cf8", "3b 74 24 08", true); - + programBuilder2.clearCodeUnits("0x01002cf8", "0x01002cfb", false); programBuilder2.setBytes("0x01002cf8", "3b 74 24 0c", true); - + // p1 & p2 differ at byte at 0x01002cfb. programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY); programMerge.setDiffFilter(new ProgramDiffFilter( @@ -1348,12 +1391,12 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { as.addRange(addr(0x01002cf8), addr(0x01002cfb)); assertEquals(as, programMerge.getFilteredDifferences()); programMerge.merge(as, TaskMonitor.DUMMY); - + AddressSet unMergableByteAddresses = new AddressSet();// None that can't merge. assertEquals(unMergableByteAddresses, programMerge.getFilteredDifferences()); } - private Address addr(Program program, int offset) { + private Address addr(Program program, long offset) { return program.getAddressFactory().getDefaultAddressSpace().getAddress(offset); } @@ -1373,10 +1416,15 @@ public class ProgramMerge3Test extends AbstractGhidraHeadedIntegrationTest { return pathName; } - private void mergeCodeUnitDifference(int diffStart, int diffEnd) + private void mergeCodeUnitDifference(long diffStart, long diffEnd) throws CancelledException, MemoryAccessException { AddressSet addrSet = new AddressSet(); addrSet.addRange(addr(p1, diffStart), addr(p1, diffEnd)); + mergeCodeUnitDifference(addrSet); + } + + private void mergeCodeUnitDifference(AddressSet addrSet) + throws CancelledException, MemoryAccessException { programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.CODE_UNIT_DIFFS)); programMerge.setMergeFilter( diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java index 97bb9fad28..0435f42ef3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/ProgramBasedDataTypeManagerDB.java @@ -310,6 +310,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB if (instanceSettingsAdapter == null) { throw new UnsupportedOperationException(); } + lock.acquire(); try { Address dataAddr = getDataSettingsAddress(data); return instanceSettingsAdapter @@ -318,6 +319,9 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB catch (IOException e) { errHandler.dbError(e); } + finally { + lock.release(); + } return true; } @@ -427,14 +431,15 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB } } - private static Address getDataSettingsAddress(Data data) { - Data parent = data.getParent(); - if (parent != null) { + public static Address getDataSettingsAddress(Data data) { + Address addr = data.getAddress(); + for (Data parent = data.getParent(); parent != null; parent = parent.getParent()) { DataType dataType = parent.getDataType(); - if (dataType instanceof Array) { - return getDataSettingsAddress(parent); + if (!(dataType instanceof Array a)) { + break; } + addr = parent.getAddress(); } - return data.getAddress(); + return addr; } }