diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalFunctionMerger.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalFunctionMerger.java index ad4976124f..b3441faa4a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalFunctionMerger.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/ExternalFunctionMerger.java @@ -556,7 +556,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li Symbol originalSymbol = symbolTables[ORIGINAL].getSymbol(originalID); Address originalAddress = originalSymbol.getAddress(); Symbol latestSymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[ORIGINAL], - originalSymbol, programs[LATEST], latestAddIDs); + originalSymbol, programs[LATEST], false, latestAddIDs); if (latestSymbol != null) { Address latestAddress = latestSymbol.getAddress(); // Check the external space addresses to ensure they are the same. @@ -577,7 +577,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li Symbol originalSymbol = symbolTables[ORIGINAL].getSymbol(originalID); Address originalAddress = originalSymbol.getAddress(); Symbol mySymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[ORIGINAL], - originalSymbol, programs[MY], myAddIDs); + originalSymbol, programs[MY], false, myAddIDs); if (mySymbol != null) { Address myAddress = mySymbol.getAddress(); // Check the external space addresses to ensure they are the same. @@ -1560,7 +1560,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li // Get the external symbol in LATEST that we think most likely matches MY external. // Only try to match it with externals that were also added in LATEST. Symbol latestSymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[MY], - mySymbol, programs[LATEST], latestAddIDs); + mySymbol, programs[LATEST], false, latestAddIDs); ExternalLocation latestExternalLocation = null; if (latestSymbol != null) { // We have a possible matching external from LATEST. @@ -4045,7 +4045,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li */ private void removeExternal(Program sourceProgram, ExternalLocation sourceExternalLocation) { ExternalLocation resultExternalLocation = SimpleDiffUtility.getMatchingExternalLocation( - sourceProgram, sourceExternalLocation, programs[RESULT]); + sourceProgram, sourceExternalLocation, programs[RESULT], false); if (resultExternalLocation == null) { return; } @@ -4054,7 +4054,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li functionManagers[RESULT].removeFunction(externalSpaceAddress); // See if the location is now just a label. resultExternalLocation = SimpleDiffUtility.getMatchingExternalLocation(sourceProgram, - sourceExternalLocation, programs[RESULT]); + sourceExternalLocation, programs[RESULT], false); if (resultExternalLocation == null) { return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionMerger.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionMerger.java index d6b58dc067..c7e4f8f3ef 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionMerger.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/FunctionMerger.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -212,12 +212,12 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger { public void autoMerge(int progressMin, int progressMax, TaskMonitor monitor) throws ProgramConflictException, MemoryAccessException, CancelledException { - latestResolvedDts = (Map) mergeManager.getResolveInformation( - MergeConstants.RESOLVED_LATEST_DTS); - myResolvedDts = (Map) mergeManager.getResolveInformation( - MergeConstants.RESOLVED_MY_DTS); - origResolvedDts = (Map) mergeManager.getResolveInformation( - MergeConstants.RESOLVED_ORIGINAL_DTS); + latestResolvedDts = (Map) mergeManager + .getResolveInformation(MergeConstants.RESOLVED_LATEST_DTS); + myResolvedDts = (Map) mergeManager + .getResolveInformation(MergeConstants.RESOLVED_MY_DTS); + origResolvedDts = (Map) mergeManager + .getResolveInformation(MergeConstants.RESOLVED_ORIGINAL_DTS); initializeAutoMerge("Auto-merging Functions and determining conflicts.", progressMin, progressMax, monitor); @@ -450,8 +450,8 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger { conflictingMyEntries.add(latestOnly.intersect(changeMy)); if (!conflictingMyEntries.isEmpty()) { entryConflictSet.add(latestBody); // Add Latest function's body. - entryConflictSet.add( - getBodies(functionManagers[MY], conflictingMyEntries)); // Add My conflicting function bodies. + entryConflictSet + .add(getBodies(functionManagers[MY], conflictingMyEntries)); // Add My conflicting function bodies. } newEntries.add(conflictingMyEntries); } @@ -613,7 +613,7 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger { Function myThunkedFunction = functions[MY].getThunkedFunction(false); Address myThunkedEntry = myThunkedFunction.getEntryPoint(); Address myThunkedEntryAsLatest = SimpleDiffUtility.getCompatibleAddress( - functions[MY].getProgram(), myThunkedEntry, functions[LATEST].getProgram()); + functions[MY].getProgram(), myThunkedEntry, functions[RESULT].getProgram()); if (!latestThunkedEntry.equals(myThunkedEntryAsLatest)) { // Save the thunk conflict saveThunkConflict(functions[RESULT]); @@ -1065,10 +1065,8 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger { mergeParamInfo(addr, paramInfoConflicts, parameterInfoChoice, monitor); } else if (askUser && mergeManager != null) { - Iterator iter = paramInfoConflicts.iterator(); - while (iter.hasNext()) { + for (ParamInfoConflict pc : paramInfoConflicts) { monitor.checkCancelled(); - ParamInfoConflict pc = iter.next(); boolean useForAll = (parameterInfoChoice != ASK_USER); if (useForAll) { mergeParamInfo(addr, pc, parameterInfoChoice, monitor); @@ -1356,11 +1354,9 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger { protected void mergeParameters(Address entryPtAddress, int chosenConflictOption, TaskMonitor monitor) { - Function resultFunction = - listingMergeManager.mergeLatest.getResultProgram() - .getFunctionManager() - .getFunctionAt( - entryPtAddress); + Function resultFunction = listingMergeManager.mergeLatest.getResultProgram() + .getFunctionManager() + .getFunctionAt(entryPtAddress); if (resultFunction == null) { return; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMerge.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMerge.java index dd414c77df..299b482ae0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMerge.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMerge.java @@ -1317,7 +1317,7 @@ public class ProgramMerge { Program fromPgm = fromExtLoc.getSymbol().getProgram(); Namespace toNamespace = DiffUtility.createNamespace(fromPgm, fromNamespace, toPgm); ExternalLocation toExternalLocation = - SimpleDiffUtility.getMatchingExternalLocation(fromPgm, fromExtLoc, toPgm); + SimpleDiffUtility.getMatchingExternalLocation(fromPgm, fromExtLoc, toPgm, false); if (toExternalLocation == null) { toExtMgr.addExtLocation(toNamespace, fromExtLabel, fromExtAddr, fromSourceType); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ExternalMergerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ExternalMergerTest.java index b4f160378e..22d2bcbd77 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ExternalMergerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/ExternalMergerTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -242,13 +242,16 @@ public class ExternalMergerTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", LATEST_BUTTON);// Add Conflict + // NOTE: Duplicate external program address is not treated as conflict, bot external + // locations will be added. + chooseButtonAndApply("Resolve Reference Conflict", LATEST_BUTTON);// Add Conflict waitForMergeCompletion(); ExternalManager externalManager = resultProgram.getExternalManager(); ExternalLocation extLocApples = externalManager.getUniqueExternalLocation("advapi32.dll", "apples"); - assertNull(extLocApples); + assertNotNull(extLocApples); + ExternalLocation extLocOranges = externalManager.getUniqueExternalLocation("advapi32.dll", "oranges"); assertNotNull(extLocOranges); @@ -303,16 +306,19 @@ public class ExternalMergerTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", MY_BUTTON);// Add Conflict + // NOTE: Duplicate external program address is not treated as conflict, bot external + // locations will be added. + chooseButtonAndApply("Resolve Reference Conflict", MY_BUTTON);// Add Conflict waitForMergeCompletion(); ExternalManager externalManager = resultProgram.getExternalManager(); ExternalLocation extLocApples = externalManager.getUniqueExternalLocation("advapi32.dll", "apples"); assertNotNull(extLocApples); + ExternalLocation extLocOranges = externalManager.getUniqueExternalLocation("advapi32.dll", "oranges"); - assertNull(extLocOranges); + assertNotNull(extLocOranges); ReferenceManager refMgr = resultProgram.getReferenceManager(); Reference[] refs; @@ -1406,7 +1412,7 @@ public class ExternalMergerTest extends AbstractExternalMergerTest { public void testExtLabelRefAddDiffAddressConflictPickMy() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { - + @Override public void modifyLatest(ProgramDB program) { try { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/FunctionMergerThunkTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/FunctionMergerThunkTest.java index f35d98eecc..01fd78ed99 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/FunctionMergerThunkTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/FunctionMergerThunkTest.java @@ -929,7 +929,9 @@ public class FunctionMergerThunkTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); + // Two diiferent external program addresses for the same external location (name match) chooseButtonAndApply("Resolve External Add Conflict", KEEP_BOTH_BUTTON); + chooseButtonAndApply("Resolve Thunk Function Conflict", LATEST_BUTTON); waitForMergeCompletion(); Function thunkFunction = getFunction(resultProgram, THUNK_A_ENTRY); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/RefMergerExtTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/RefMergerExtTest.java index c69907e185..f88d00fac1 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/RefMergerExtTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/RefMergerExtTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -147,7 +147,6 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { - @Override public void modifyLatest(ProgramDB program) { try { @@ -656,8 +655,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -678,8 +676,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -741,8 +738,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -828,8 +824,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -913,8 +908,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -949,7 +943,8 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", LATEST_BUTTON); + // The two external locations are not in conflict and can both exist + chooseButtonAndApply("Resolve Reference Conflict", LATEST_BUTTON); waitForMergeCompletion(); ReferenceManager refMgr = resultProgram.getReferenceManager(); @@ -999,8 +994,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -1035,7 +1029,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", MY_BUTTON); + chooseButtonAndApply("Resolve Reference Conflict", MY_BUTTON); waitForMergeCompletion(); ReferenceManager refMgr = resultProgram.getReferenceManager(); @@ -1084,8 +1078,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -1130,7 +1123,6 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", KEEP_BOTH_BUTTON); chooseRadioButton("Resolve Reference Conflict", LATEST_BUTTON);// Since kept both, now choose reference conflict. waitForMergeCompletion(); @@ -1188,8 +1180,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -1234,7 +1225,6 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", KEEP_BOTH_BUTTON); chooseRadioButton("Resolve Reference Conflict", MY_BUTTON);// Since kept both, now choose reference conflict. waitForMergeCompletion(); @@ -1280,8 +1270,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -1316,9 +1305,10 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", MERGE_BOTH_BUTTON); - chooseVariousOptionsForConflictType("Resolve External Detail Conflict", - new int[] { INFO_ROW, KEEP_LATEST, KEEP_MY });// Namespace, Name + chooseButtonAndApply("Resolve Reference Conflict", MY_BUTTON); + // NOTE: Locations are not considered conflicts since both get added +// chooseVariousOptionsForConflictType("Resolve External Detail Conflict", +// new int[] { INFO_ROW, KEEP_LATEST, KEEP_MY });// Namespace, Name waitForMergeCompletion(); ReferenceManager refMgr = resultProgram.getReferenceManager(); @@ -1333,11 +1323,10 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr("0x10013d8"), -1); assertEquals(1, refs.length); - assertEquals("ADVAPI32.DLL::getName", + assertEquals("USER32.DLL::getName", ((ExternalReference) refs[0]).getExternalLocation().toString()); - assertEquals("77db2233", - ((ExternalReference) refs[0]).getExternalLocation().getAddress().toString()); - assertEquals(SourceType.DEFAULT, refs[0].getSource()); + assertNull(((ExternalReference) refs[0]).getExternalLocation().getAddress()); + assertEquals(SourceType.USER_DEFINED, refs[0].getSource()); } @Test @@ -1357,8 +1346,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); assertEquals(0, refs.length); refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", - addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, - RefType.DATA); + addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); assertEquals(0, refs.length); @@ -1393,9 +1381,10 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { }); executeMerge(ASK_USER); - chooseButtonAndApply("Resolve External Add Conflict", MERGE_BOTH_BUTTON); - chooseVariousOptionsForConflictType("Resolve External Detail Conflict", - new int[] { INFO_ROW, KEEP_MY, KEEP_LATEST });// Namespace, Name + // NOTE: Locations are not considered conflicts since both get added + chooseButtonAndApply("Resolve Reference Conflict", LATEST_BUTTON); +// chooseVariousOptionsForConflictType("Resolve External Detail Conflict", +// new int[] { INFO_ROW, KEEP_MY, KEEP_LATEST });// Namespace, Name waitForMergeCompletion(); ReferenceManager refMgr = resultProgram.getReferenceManager(); @@ -1410,7 +1399,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest { refs = refMgr.getReferencesFrom(addr("0x10013d8"), -1); assertEquals(1, refs.length); - assertEquals("USER32.DLL::EXT_77db2233", + assertEquals("ADVAPI32.DLL::EXT_77db2233", ((ExternalReference) refs[0]).getExternalLocation().toString()); assertEquals("77db2233", ((ExternalReference) refs[0]).getExternalLocation().getAddress().toString()); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/SimpleDiffUtility.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/SimpleDiffUtility.java index 319584a6cc..ff98780b63 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/SimpleDiffUtility.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/SimpleDiffUtility.java @@ -190,7 +190,14 @@ public class SimpleDiffUtility { /** * Convert an address from the specified program to a comparable address in the - * specified otherProgram. + * specified otherProgram. + *
+ * For external locations the match-up is very fuzzy and + * will use correlated references. If an exact match is required for an external location + * the {@link #getMatchingExternalLocation(Program, ExternalLocation, Program, boolean)} or + * {@link #getMatchingExternalSymbol(Program, Symbol, Program, boolean, Set)} should be used + * directly. + * * @param program program which contains the specified address instance * @param addr address in program * @param otherProgram other program @@ -250,7 +257,7 @@ public class SimpleDiffUtility { else if (addr.isExternalAddress()) { Symbol s = program.getSymbolTable().getPrimarySymbol(addr); if (s != null && s.isExternal()) { - s = getMatchingExternalSymbol(program, s, otherProgram, null); + s = getMatchingExternalSymbol(program, s, otherProgram, true, null); if (s != null) { return s.getAddress(); } @@ -314,6 +321,10 @@ public class SimpleDiffUtility { /** * Given a symbol for a specified program, get the corresponding symbol from the * specified otherProgram. + *
+ * In the case of external locations this performs an exact match based upon symbol name, + * namespace and symbol type. + * * @param symbol symbol to look for * @param otherProgram other program * @return corresponding symbol for otherProgram or null if no such symbol exists. @@ -405,6 +416,12 @@ public class SimpleDiffUtility { ExternalLocation external = getExternalLocation(symbol); + // TODO: This match-up is exact based upon name and namespace and does not consider + // the original imported name or address, however these attributes must match. + + // TODO: It is rather confusing to have two sets of methods for finding external + // locations. This should be simplified. getOther... getMatchingExternal... + SymbolTable otherSymbolTable = otherProgram.getSymbolTable(); List otherSymbols = otherSymbolTable.getSymbols(symbol.getName(), otherNamespace); @@ -595,16 +612,24 @@ public class SimpleDiffUtility { /** * Given an external symbol for a specified program, get the corresponding symbol, * which has the same name and path, from the specified otherProgram.
- * Note: The type of the returned symbol may be different than the type of the symbol + * Note: In The type of the returned symbol may be different than the type of the symbol + * (i.e., Function vs Label). * @param program program which contains the specified symbol instance * @param symbol symbol to look for * @param otherProgram other program + * @param allowInferredMatch if true an inferred match may be performed using reference + * correlation (NOTE: reference correlation is only possible if the exact same binary + * is in use). This option is ignored if the two programs do not have the same + * original binary hash. * @param otherRestrictedSymbolIds an optional set of symbol ID's from the other program * which will be treated as the exclusive set of candidate symbols to consider. * @return corresponding external symbol for otherProgram or null if no such symbol exists. */ public static Symbol getMatchingExternalSymbol(Program program, Symbol symbol, - Program otherProgram, Set otherRestrictedSymbolIds) { + Program otherProgram, boolean allowInferredMatch, Set otherRestrictedSymbolIds) { + + // TODO: It is rather confusing to have two sets of methods for finding external + // locations. This should be simplified. getOther... getMatchingExternal... if (symbol == null) { return null; @@ -614,7 +639,13 @@ public class SimpleDiffUtility { return null; } - ReferenceManager refMgr = program.getReferenceManager(); + if (allowInferredMatch) { + // Inferred reference-based match only valid for the same program (i.e., multi-user merge) + if (program.getUniqueProgramID() != otherProgram.getUniqueProgramID()) { + allowInferredMatch = false; + } + } + ExternalManager extMgr = program.getExternalManager(); ExternalLocation extLoc = extMgr.getExternalLocation(symbol); @@ -626,80 +657,111 @@ public class SimpleDiffUtility { } Address targetAddr = extLoc.getAddress(); - ReferenceManager otherRefMgr = otherProgram.getReferenceManager(); SymbolTable otherSymbMgr = otherProgram.getSymbolTable(); ExternalManager otherExtMgr = otherProgram.getExternalManager(); - // Process references - ReferenceIterator refIter = refMgr.getReferencesTo(symbol.getAddress()); HashMap matchesMap = new HashMap<>(); - int totalMatchCnt = 0; - while (refIter.hasNext()) { - Reference ref = refIter.next(); - Reference otherRef = - otherRefMgr.getPrimaryReferenceFrom(ref.getFromAddress(), ref.getOperandIndex()); - if (otherRef == null || !otherRef.isExternalReference()) { - continue; - } - Address otherExtAddr = otherRef.getToAddress(); - ExternalReferenceCount refMatch = matchesMap.get(otherExtAddr); - if (refMatch == null) { - Symbol otherSym = otherSymbMgr.getPrimarySymbol(otherExtAddr); - if (otherRestrictedSymbolIds != null && - !otherRestrictedSymbolIds.contains(otherSym.getID())) { - continue; + + // Search by name + if (symbol.getSource() != SourceType.DEFAULT) { + + // TODO: Need to improve support for lookup based upon other fields + // Need separate Symbol DB indexing of ExternalLocation fields (address,originalImportName) + + Symbol otherParent = getSymbol(symbol.getParentSymbol(), otherProgram); + if (otherParent != null) { + SymbolIterator symbols = + otherProgram.getSymbolTable().getExternalSymbols(symbol.getName()); + for (Symbol otherSym : symbols) { + ExternalLocation otherExtLoc = otherExtMgr.getExternalLocation(otherSym); + if (otherExtLoc != null) { + ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc); + if (matchType == ExternalMatchType.NONE) { + continue; + } + ExternalReferenceCount refMatch = + new ExternalReferenceCount(otherExtLoc, matchType); + refMatch.setRelativeRank(targetAddr, targetNamespace, targetName, + targetOrigImportedName); + matchesMap.put(otherSym.getAddress(), refMatch); + } } - ExternalLocation otherExtLoc = otherExtMgr.getExternalLocation(otherSym); - ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc); - refMatch = new ExternalReferenceCount(otherExtLoc, matchType); - if (matchType != ExternalMatchType.NONE) { - refMatch.setRelativeRank(targetAddr, targetNamespace, targetName, - targetOrigImportedName); - } - matchesMap.put(otherExtAddr, refMatch); - } - else { - ++refMatch.refCount; - } - if (++totalMatchCnt == 20) { - break; } } - // Process thunk-references (include all) - if (extLoc.isFunction()) { - Address[] thunkAddrs = extLoc.getFunction().getFunctionThunkAddresses(); - if (thunkAddrs != null) { - for (Address thunkAddr : thunkAddrs) { - Symbol otherThunkSym = otherSymbMgr.getPrimarySymbol(thunkAddr); - if (otherThunkSym == null || - otherThunkSym.getSymbolType() != SymbolType.FUNCTION) { + if (allowInferredMatch && matchesMap.isEmpty()) { + // Process references + ReferenceManager refMgr = program.getReferenceManager(); + ReferenceManager otherRefMgr = otherProgram.getReferenceManager(); + ReferenceIterator refIter = refMgr.getReferencesTo(symbol.getAddress()); + int totalMatchCnt = 0; + while (refIter.hasNext()) { + Reference ref = refIter.next(); + Reference otherRef = otherRefMgr.getPrimaryReferenceFrom(ref.getFromAddress(), + ref.getOperandIndex()); + if (otherRef == null || !otherRef.isExternalReference()) { + continue; + } + Address otherExtAddr = otherRef.getToAddress(); + ExternalReferenceCount refMatch = matchesMap.get(otherExtAddr); + if (refMatch == null) { + Symbol otherSym = otherSymbMgr.getPrimarySymbol(otherExtAddr); + if (otherRestrictedSymbolIds != null && + !otherRestrictedSymbolIds.contains(otherSym.getID())) { continue; } - Function otherFunc = (Function) otherThunkSym.getObject(); - Function otherThunkedFunc = otherFunc.getThunkedFunction(false); - if (otherThunkedFunc == null || !otherThunkedFunc.isExternal()) { - continue; + ExternalLocation otherExtLoc = otherExtMgr.getExternalLocation(otherSym); + ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc); + refMatch = new ExternalReferenceCount(otherExtLoc, matchType); + if (matchType != ExternalMatchType.NONE) { + refMatch.setRelativeRank(targetAddr, targetNamespace, targetName, + targetOrigImportedName); } - ExternalReferenceCount refMatch = - matchesMap.get(otherThunkedFunc.getEntryPoint()); - if (refMatch == null) { - if (otherRestrictedSymbolIds != null && - !otherRestrictedSymbolIds.contains(otherThunkedFunc.getID())) { + matchesMap.put(otherExtAddr, refMatch); + } + else { + ++refMatch.refCount; + } + if (++totalMatchCnt == 20) { + break; + } + } + + // Process thunk-references (include all) + if (extLoc.isFunction()) { + Address[] thunkAddrs = extLoc.getFunction().getFunctionThunkAddresses(); + if (thunkAddrs != null) { + for (Address thunkAddr : thunkAddrs) { + Symbol otherThunkSym = otherSymbMgr.getPrimarySymbol(thunkAddr); + if (otherThunkSym == null || + otherThunkSym.getSymbolType() != SymbolType.FUNCTION) { continue; } - ExternalLocation otherExtLoc = - otherExtMgr.getExternalLocation(otherThunkedFunc.getSymbol()); - ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc); - refMatch = new ExternalReferenceCount(otherExtLoc, matchType); - if (matchType != ExternalMatchType.NONE) { - refMatch.setRelativeRank(targetAddr, targetNamespace, targetName, - targetOrigImportedName); + Function otherFunc = (Function) otherThunkSym.getObject(); + Function otherThunkedFunc = otherFunc.getThunkedFunction(false); + if (otherThunkedFunc == null || !otherThunkedFunc.isExternal()) { + continue; + } + ExternalReferenceCount refMatch = + matchesMap.get(otherThunkedFunc.getEntryPoint()); + if (refMatch == null) { + if (otherRestrictedSymbolIds != null && + !otherRestrictedSymbolIds.contains(otherThunkedFunc.getID())) { + continue; + } + ExternalLocation otherExtLoc = + otherExtMgr.getExternalLocation(otherThunkedFunc.getSymbol()); + ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc); + refMatch = new ExternalReferenceCount(otherExtLoc, matchType); + if (matchType != ExternalMatchType.NONE) { + refMatch.setRelativeRank(targetAddr, targetNamespace, targetName, + targetOrigImportedName); + } + matchesMap.put(otherThunkedFunc.getEntryPoint(), refMatch); + } + else { + ++refMatch.refCount; } - matchesMap.put(otherThunkedFunc.getEntryPoint(), refMatch); - } - else { - ++refMatch.refCount; } } } @@ -751,10 +813,14 @@ public class SimpleDiffUtility { * @param program program which contains the specified external location instance * @param externalLocation external location to look for * @param otherProgram other program + * @param allowInferredMatch if true an inferred match may be performed using reference + * correlation. NOTE: reference correlation is only possible if the exact same binary + * is in use. This option is ignored if the two programs do not have the same + * original binary hash and reference correlation will not be performed. * @return corresponding external location for otherProgram or null if no such external location exists. */ public static ExternalLocation getMatchingExternalLocation(Program program, - ExternalLocation externalLocation, Program otherProgram) { + ExternalLocation externalLocation, Program otherProgram, boolean allowInferredMatch) { if (externalLocation == null) { return null; } @@ -763,7 +829,7 @@ public class SimpleDiffUtility { return null; } Symbol matchingExternalSymbol = - getMatchingExternalSymbol(program, symbol, otherProgram, null); + getMatchingExternalSymbol(program, symbol, otherProgram, allowInferredMatch, null); if (matchingExternalSymbol == null) { return null; }