GP-5480 Additinal improvement/fixes for ExternalLocation merge support

to address test failures.
This commit is contained in:
ghidra1 2025-03-18 11:13:10 -04:00
parent 6cc201b572
commit 5aec479fb2
7 changed files with 196 additions and 137 deletions

View file

@ -556,7 +556,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
Symbol originalSymbol = symbolTables[ORIGINAL].getSymbol(originalID); Symbol originalSymbol = symbolTables[ORIGINAL].getSymbol(originalID);
Address originalAddress = originalSymbol.getAddress(); Address originalAddress = originalSymbol.getAddress();
Symbol latestSymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[ORIGINAL], Symbol latestSymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[ORIGINAL],
originalSymbol, programs[LATEST], latestAddIDs); originalSymbol, programs[LATEST], false, latestAddIDs);
if (latestSymbol != null) { if (latestSymbol != null) {
Address latestAddress = latestSymbol.getAddress(); Address latestAddress = latestSymbol.getAddress();
// Check the external space addresses to ensure they are the same. // 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); Symbol originalSymbol = symbolTables[ORIGINAL].getSymbol(originalID);
Address originalAddress = originalSymbol.getAddress(); Address originalAddress = originalSymbol.getAddress();
Symbol mySymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[ORIGINAL], Symbol mySymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[ORIGINAL],
originalSymbol, programs[MY], myAddIDs); originalSymbol, programs[MY], false, myAddIDs);
if (mySymbol != null) { if (mySymbol != null) {
Address myAddress = mySymbol.getAddress(); Address myAddress = mySymbol.getAddress();
// Check the external space addresses to ensure they are the same. // 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. // 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. // Only try to match it with externals that were also added in LATEST.
Symbol latestSymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[MY], Symbol latestSymbol = SimpleDiffUtility.getMatchingExternalSymbol(programs[MY],
mySymbol, programs[LATEST], latestAddIDs); mySymbol, programs[LATEST], false, latestAddIDs);
ExternalLocation latestExternalLocation = null; ExternalLocation latestExternalLocation = null;
if (latestSymbol != null) { if (latestSymbol != null) {
// We have a possible matching external from LATEST. // 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) { private void removeExternal(Program sourceProgram, ExternalLocation sourceExternalLocation) {
ExternalLocation resultExternalLocation = SimpleDiffUtility.getMatchingExternalLocation( ExternalLocation resultExternalLocation = SimpleDiffUtility.getMatchingExternalLocation(
sourceProgram, sourceExternalLocation, programs[RESULT]); sourceProgram, sourceExternalLocation, programs[RESULT], false);
if (resultExternalLocation == null) { if (resultExternalLocation == null) {
return; return;
} }
@ -4054,7 +4054,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
functionManagers[RESULT].removeFunction(externalSpaceAddress); functionManagers[RESULT].removeFunction(externalSpaceAddress);
// See if the location is now just a label. // See if the location is now just a label.
resultExternalLocation = SimpleDiffUtility.getMatchingExternalLocation(sourceProgram, resultExternalLocation = SimpleDiffUtility.getMatchingExternalLocation(sourceProgram,
sourceExternalLocation, programs[RESULT]); sourceExternalLocation, programs[RESULT], false);
if (resultExternalLocation == null) { if (resultExternalLocation == null) {
return; return;
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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) public void autoMerge(int progressMin, int progressMax, TaskMonitor monitor)
throws ProgramConflictException, MemoryAccessException, CancelledException { throws ProgramConflictException, MemoryAccessException, CancelledException {
latestResolvedDts = (Map<Long, DataType>) mergeManager.getResolveInformation( latestResolvedDts = (Map<Long, DataType>) mergeManager
MergeConstants.RESOLVED_LATEST_DTS); .getResolveInformation(MergeConstants.RESOLVED_LATEST_DTS);
myResolvedDts = (Map<Long, DataType>) mergeManager.getResolveInformation( myResolvedDts = (Map<Long, DataType>) mergeManager
MergeConstants.RESOLVED_MY_DTS); .getResolveInformation(MergeConstants.RESOLVED_MY_DTS);
origResolvedDts = (Map<Long, DataType>) mergeManager.getResolveInformation( origResolvedDts = (Map<Long, DataType>) mergeManager
MergeConstants.RESOLVED_ORIGINAL_DTS); .getResolveInformation(MergeConstants.RESOLVED_ORIGINAL_DTS);
initializeAutoMerge("Auto-merging Functions and determining conflicts.", progressMin, initializeAutoMerge("Auto-merging Functions and determining conflicts.", progressMin,
progressMax, monitor); progressMax, monitor);
@ -450,8 +450,8 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
conflictingMyEntries.add(latestOnly.intersect(changeMy)); conflictingMyEntries.add(latestOnly.intersect(changeMy));
if (!conflictingMyEntries.isEmpty()) { if (!conflictingMyEntries.isEmpty()) {
entryConflictSet.add(latestBody); // Add Latest function's body. entryConflictSet.add(latestBody); // Add Latest function's body.
entryConflictSet.add( entryConflictSet
getBodies(functionManagers[MY], conflictingMyEntries)); // Add My conflicting function bodies. .add(getBodies(functionManagers[MY], conflictingMyEntries)); // Add My conflicting function bodies.
} }
newEntries.add(conflictingMyEntries); newEntries.add(conflictingMyEntries);
} }
@ -613,7 +613,7 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
Function myThunkedFunction = functions[MY].getThunkedFunction(false); Function myThunkedFunction = functions[MY].getThunkedFunction(false);
Address myThunkedEntry = myThunkedFunction.getEntryPoint(); Address myThunkedEntry = myThunkedFunction.getEntryPoint();
Address myThunkedEntryAsLatest = SimpleDiffUtility.getCompatibleAddress( Address myThunkedEntryAsLatest = SimpleDiffUtility.getCompatibleAddress(
functions[MY].getProgram(), myThunkedEntry, functions[LATEST].getProgram()); functions[MY].getProgram(), myThunkedEntry, functions[RESULT].getProgram());
if (!latestThunkedEntry.equals(myThunkedEntryAsLatest)) { if (!latestThunkedEntry.equals(myThunkedEntryAsLatest)) {
// Save the thunk conflict // Save the thunk conflict
saveThunkConflict(functions[RESULT]); saveThunkConflict(functions[RESULT]);
@ -1065,10 +1065,8 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
mergeParamInfo(addr, paramInfoConflicts, parameterInfoChoice, monitor); mergeParamInfo(addr, paramInfoConflicts, parameterInfoChoice, monitor);
} }
else if (askUser && mergeManager != null) { else if (askUser && mergeManager != null) {
Iterator<ParamInfoConflict> iter = paramInfoConflicts.iterator(); for (ParamInfoConflict pc : paramInfoConflicts) {
while (iter.hasNext()) {
monitor.checkCancelled(); monitor.checkCancelled();
ParamInfoConflict pc = iter.next();
boolean useForAll = (parameterInfoChoice != ASK_USER); boolean useForAll = (parameterInfoChoice != ASK_USER);
if (useForAll) { if (useForAll) {
mergeParamInfo(addr, pc, parameterInfoChoice, monitor); mergeParamInfo(addr, pc, parameterInfoChoice, monitor);
@ -1356,11 +1354,9 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
protected void mergeParameters(Address entryPtAddress, int chosenConflictOption, protected void mergeParameters(Address entryPtAddress, int chosenConflictOption,
TaskMonitor monitor) { TaskMonitor monitor) {
Function resultFunction = Function resultFunction = listingMergeManager.mergeLatest.getResultProgram()
listingMergeManager.mergeLatest.getResultProgram() .getFunctionManager()
.getFunctionManager() .getFunctionAt(entryPtAddress);
.getFunctionAt(
entryPtAddress);
if (resultFunction == null) { if (resultFunction == null) {
return; return;
} }

View file

@ -1317,7 +1317,7 @@ public class ProgramMerge {
Program fromPgm = fromExtLoc.getSymbol().getProgram(); Program fromPgm = fromExtLoc.getSymbol().getProgram();
Namespace toNamespace = DiffUtility.createNamespace(fromPgm, fromNamespace, toPgm); Namespace toNamespace = DiffUtility.createNamespace(fromPgm, fromNamespace, toPgm);
ExternalLocation toExternalLocation = ExternalLocation toExternalLocation =
SimpleDiffUtility.getMatchingExternalLocation(fromPgm, fromExtLoc, toPgm); SimpleDiffUtility.getMatchingExternalLocation(fromPgm, fromExtLoc, toPgm, false);
if (toExternalLocation == null) { if (toExternalLocation == null) {
toExtMgr.addExtLocation(toNamespace, fromExtLabel, fromExtAddr, fromSourceType); toExtMgr.addExtLocation(toNamespace, fromExtLabel, fromExtAddr, fromSourceType);
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -242,13 +242,16 @@ public class ExternalMergerTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); 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(); waitForMergeCompletion();
ExternalManager externalManager = resultProgram.getExternalManager(); ExternalManager externalManager = resultProgram.getExternalManager();
ExternalLocation extLocApples = ExternalLocation extLocApples =
externalManager.getUniqueExternalLocation("advapi32.dll", "apples"); externalManager.getUniqueExternalLocation("advapi32.dll", "apples");
assertNull(extLocApples); assertNotNull(extLocApples);
ExternalLocation extLocOranges = ExternalLocation extLocOranges =
externalManager.getUniqueExternalLocation("advapi32.dll", "oranges"); externalManager.getUniqueExternalLocation("advapi32.dll", "oranges");
assertNotNull(extLocOranges); assertNotNull(extLocOranges);
@ -303,16 +306,19 @@ public class ExternalMergerTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); 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(); waitForMergeCompletion();
ExternalManager externalManager = resultProgram.getExternalManager(); ExternalManager externalManager = resultProgram.getExternalManager();
ExternalLocation extLocApples = ExternalLocation extLocApples =
externalManager.getUniqueExternalLocation("advapi32.dll", "apples"); externalManager.getUniqueExternalLocation("advapi32.dll", "apples");
assertNotNull(extLocApples); assertNotNull(extLocApples);
ExternalLocation extLocOranges = ExternalLocation extLocOranges =
externalManager.getUniqueExternalLocation("advapi32.dll", "oranges"); externalManager.getUniqueExternalLocation("advapi32.dll", "oranges");
assertNull(extLocOranges); assertNotNull(extLocOranges);
ReferenceManager refMgr = resultProgram.getReferenceManager(); ReferenceManager refMgr = resultProgram.getReferenceManager();
Reference[] refs; Reference[] refs;
@ -1406,7 +1412,7 @@ public class ExternalMergerTest extends AbstractExternalMergerTest {
public void testExtLabelRefAddDiffAddressConflictPickMy() throws Exception { public void testExtLabelRefAddDiffAddressConflictPickMy() throws Exception {
mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() {
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
try { try {

View file

@ -929,7 +929,9 @@ public class FunctionMergerThunkTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); 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 External Add Conflict", KEEP_BOTH_BUTTON);
chooseButtonAndApply("Resolve Thunk Function Conflict", LATEST_BUTTON);
waitForMergeCompletion(); waitForMergeCompletion();
Function thunkFunction = getFunction(resultProgram, THUNK_A_ENTRY); Function thunkFunction = getFunction(resultProgram, THUNK_A_ENTRY);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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() { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() {
@Override @Override
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
try { try {
@ -656,8 +655,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -678,8 +676,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -741,8 +738,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -828,8 +824,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -913,8 +908,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -949,7 +943,8 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); 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(); waitForMergeCompletion();
ReferenceManager refMgr = resultProgram.getReferenceManager(); ReferenceManager refMgr = resultProgram.getReferenceManager();
@ -999,8 +994,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -1035,7 +1029,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); executeMerge(ASK_USER);
chooseButtonAndApply("Resolve External Add Conflict", MY_BUTTON); chooseButtonAndApply("Resolve Reference Conflict", MY_BUTTON);
waitForMergeCompletion(); waitForMergeCompletion();
ReferenceManager refMgr = resultProgram.getReferenceManager(); ReferenceManager refMgr = resultProgram.getReferenceManager();
@ -1084,8 +1078,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -1130,7 +1123,6 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); executeMerge(ASK_USER);
chooseButtonAndApply("Resolve External Add Conflict", KEEP_BOTH_BUTTON);
chooseRadioButton("Resolve Reference Conflict", LATEST_BUTTON);// Since kept both, now choose reference conflict. chooseRadioButton("Resolve Reference Conflict", LATEST_BUTTON);// Since kept both, now choose reference conflict.
waitForMergeCompletion(); waitForMergeCompletion();
@ -1188,8 +1180,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -1234,7 +1225,6 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); executeMerge(ASK_USER);
chooseButtonAndApply("Resolve External Add Conflict", KEEP_BOTH_BUTTON);
chooseRadioButton("Resolve Reference Conflict", MY_BUTTON);// Since kept both, now choose reference conflict. chooseRadioButton("Resolve Reference Conflict", MY_BUTTON);// Since kept both, now choose reference conflict.
waitForMergeCompletion(); waitForMergeCompletion();
@ -1280,8 +1270,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -1316,9 +1305,10 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); executeMerge(ASK_USER);
chooseButtonAndApply("Resolve External Add Conflict", MERGE_BOTH_BUTTON); chooseButtonAndApply("Resolve Reference Conflict", MY_BUTTON);
chooseVariousOptionsForConflictType("Resolve External Detail Conflict", // NOTE: Locations are not considered conflicts since both get added
new int[] { INFO_ROW, KEEP_LATEST, KEEP_MY });// Namespace, Name // chooseVariousOptionsForConflictType("Resolve External Detail Conflict",
// new int[] { INFO_ROW, KEEP_LATEST, KEEP_MY });// Namespace, Name
waitForMergeCompletion(); waitForMergeCompletion();
ReferenceManager refMgr = resultProgram.getReferenceManager(); ReferenceManager refMgr = resultProgram.getReferenceManager();
@ -1333,11 +1323,10 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr("0x10013d8"), -1); refs = refMgr.getReferencesFrom(addr("0x10013d8"), -1);
assertEquals(1, refs.length); assertEquals(1, refs.length);
assertEquals("ADVAPI32.DLL::getName", assertEquals("USER32.DLL::getName",
((ExternalReference) refs[0]).getExternalLocation().toString()); ((ExternalReference) refs[0]).getExternalLocation().toString());
assertEquals("77db2233", assertNull(((ExternalReference) refs[0]).getExternalLocation().getAddress());
((ExternalReference) refs[0]).getExternalLocation().getAddress().toString()); assertEquals(SourceType.USER_DEFINED, refs[0].getSource());
assertEquals(SourceType.DEFAULT, refs[0].getSource());
} }
@Test @Test
@ -1357,8 +1346,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013cc"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf", refMgr.addExternalReference(addr(program, "0x10013cc"), "USER32.DLL", "printf",
addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, addr(program, "0x01234567"), SourceType.USER_DEFINED, 0, RefType.DATA);
RefType.DATA);
refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0); refs = refMgr.getReferencesFrom(addr(program, "0x10013d8"), 0);
assertEquals(0, refs.length); assertEquals(0, refs.length);
@ -1393,9 +1381,10 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
}); });
executeMerge(ASK_USER); executeMerge(ASK_USER);
chooseButtonAndApply("Resolve External Add Conflict", MERGE_BOTH_BUTTON); // NOTE: Locations are not considered conflicts since both get added
chooseVariousOptionsForConflictType("Resolve External Detail Conflict", chooseButtonAndApply("Resolve Reference Conflict", LATEST_BUTTON);
new int[] { INFO_ROW, KEEP_MY, KEEP_LATEST });// Namespace, Name // chooseVariousOptionsForConflictType("Resolve External Detail Conflict",
// new int[] { INFO_ROW, KEEP_MY, KEEP_LATEST });// Namespace, Name
waitForMergeCompletion(); waitForMergeCompletion();
ReferenceManager refMgr = resultProgram.getReferenceManager(); ReferenceManager refMgr = resultProgram.getReferenceManager();
@ -1410,7 +1399,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
refs = refMgr.getReferencesFrom(addr("0x10013d8"), -1); refs = refMgr.getReferencesFrom(addr("0x10013d8"), -1);
assertEquals(1, refs.length); assertEquals(1, refs.length);
assertEquals("USER32.DLL::EXT_77db2233", assertEquals("ADVAPI32.DLL::EXT_77db2233",
((ExternalReference) refs[0]).getExternalLocation().toString()); ((ExternalReference) refs[0]).getExternalLocation().toString());
assertEquals("77db2233", assertEquals("77db2233",
((ExternalReference) refs[0]).getExternalLocation().getAddress().toString()); ((ExternalReference) refs[0]).getExternalLocation().getAddress().toString());

View file

@ -190,7 +190,14 @@ public class SimpleDiffUtility {
/** /**
* Convert an address from the specified program to a comparable address in the * Convert an address from the specified program to a comparable address in the
* specified otherProgram. * specified otherProgram.
* <br>
* 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 program program which contains the specified address instance
* @param addr address in program * @param addr address in program
* @param otherProgram other program * @param otherProgram other program
@ -250,7 +257,7 @@ public class SimpleDiffUtility {
else if (addr.isExternalAddress()) { else if (addr.isExternalAddress()) {
Symbol s = program.getSymbolTable().getPrimarySymbol(addr); Symbol s = program.getSymbolTable().getPrimarySymbol(addr);
if (s != null && s.isExternal()) { if (s != null && s.isExternal()) {
s = getMatchingExternalSymbol(program, s, otherProgram, null); s = getMatchingExternalSymbol(program, s, otherProgram, true, null);
if (s != null) { if (s != null) {
return s.getAddress(); return s.getAddress();
} }
@ -314,6 +321,10 @@ public class SimpleDiffUtility {
/** /**
* Given a symbol for a specified program, get the corresponding symbol from the * Given a symbol for a specified program, get the corresponding symbol from the
* specified otherProgram. * specified otherProgram.
* <br>
* 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 symbol symbol to look for
* @param otherProgram other program * @param otherProgram other program
* @return corresponding symbol for otherProgram or null if no such symbol exists. * @return corresponding symbol for otherProgram or null if no such symbol exists.
@ -405,6 +416,12 @@ public class SimpleDiffUtility {
ExternalLocation external = getExternalLocation(symbol); 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(); SymbolTable otherSymbolTable = otherProgram.getSymbolTable();
List<Symbol> otherSymbols = otherSymbolTable.getSymbols(symbol.getName(), otherNamespace); List<Symbol> 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, * Given an external symbol for a specified program, get the corresponding symbol,
* which has the same name and path, from the specified otherProgram.<br> * which has the same name and path, from the specified otherProgram.<br>
* 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 program program which contains the specified symbol instance
* @param symbol symbol to look for * @param symbol symbol to look for
* @param otherProgram other program * @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 * @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. * 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. * @return corresponding external symbol for otherProgram or null if no such symbol exists.
*/ */
public static Symbol getMatchingExternalSymbol(Program program, Symbol symbol, public static Symbol getMatchingExternalSymbol(Program program, Symbol symbol,
Program otherProgram, Set<Long> otherRestrictedSymbolIds) { Program otherProgram, boolean allowInferredMatch, Set<Long> 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) { if (symbol == null) {
return null; return null;
@ -614,7 +639,13 @@ public class SimpleDiffUtility {
return null; 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(); ExternalManager extMgr = program.getExternalManager();
ExternalLocation extLoc = extMgr.getExternalLocation(symbol); ExternalLocation extLoc = extMgr.getExternalLocation(symbol);
@ -626,80 +657,111 @@ public class SimpleDiffUtility {
} }
Address targetAddr = extLoc.getAddress(); Address targetAddr = extLoc.getAddress();
ReferenceManager otherRefMgr = otherProgram.getReferenceManager();
SymbolTable otherSymbMgr = otherProgram.getSymbolTable(); SymbolTable otherSymbMgr = otherProgram.getSymbolTable();
ExternalManager otherExtMgr = otherProgram.getExternalManager(); ExternalManager otherExtMgr = otherProgram.getExternalManager();
// Process references
ReferenceIterator refIter = refMgr.getReferencesTo(symbol.getAddress());
HashMap<Address, ExternalReferenceCount> matchesMap = new HashMap<>(); HashMap<Address, ExternalReferenceCount> matchesMap = new HashMap<>();
int totalMatchCnt = 0;
while (refIter.hasNext()) { // Search by name
Reference ref = refIter.next(); if (symbol.getSource() != SourceType.DEFAULT) {
Reference otherRef =
otherRefMgr.getPrimaryReferenceFrom(ref.getFromAddress(), ref.getOperandIndex()); // TODO: Need to improve support for lookup based upon other fields
if (otherRef == null || !otherRef.isExternalReference()) { // Need separate Symbol DB indexing of ExternalLocation fields (address,originalImportName)
continue;
} Symbol otherParent = getSymbol(symbol.getParentSymbol(), otherProgram);
Address otherExtAddr = otherRef.getToAddress(); if (otherParent != null) {
ExternalReferenceCount refMatch = matchesMap.get(otherExtAddr); SymbolIterator symbols =
if (refMatch == null) { otherProgram.getSymbolTable().getExternalSymbols(symbol.getName());
Symbol otherSym = otherSymbMgr.getPrimarySymbol(otherExtAddr); for (Symbol otherSym : symbols) {
if (otherRestrictedSymbolIds != null && ExternalLocation otherExtLoc = otherExtMgr.getExternalLocation(otherSym);
!otherRestrictedSymbolIds.contains(otherSym.getID())) { if (otherExtLoc != null) {
continue; 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 (allowInferredMatch && matchesMap.isEmpty()) {
if (extLoc.isFunction()) { // Process references
Address[] thunkAddrs = extLoc.getFunction().getFunctionThunkAddresses(); ReferenceManager refMgr = program.getReferenceManager();
if (thunkAddrs != null) { ReferenceManager otherRefMgr = otherProgram.getReferenceManager();
for (Address thunkAddr : thunkAddrs) { ReferenceIterator refIter = refMgr.getReferencesTo(symbol.getAddress());
Symbol otherThunkSym = otherSymbMgr.getPrimarySymbol(thunkAddr); int totalMatchCnt = 0;
if (otherThunkSym == null || while (refIter.hasNext()) {
otherThunkSym.getSymbolType() != SymbolType.FUNCTION) { 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; continue;
} }
Function otherFunc = (Function) otherThunkSym.getObject(); ExternalLocation otherExtLoc = otherExtMgr.getExternalLocation(otherSym);
Function otherThunkedFunc = otherFunc.getThunkedFunction(false); ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc);
if (otherThunkedFunc == null || !otherThunkedFunc.isExternal()) { refMatch = new ExternalReferenceCount(otherExtLoc, matchType);
continue; if (matchType != ExternalMatchType.NONE) {
refMatch.setRelativeRank(targetAddr, targetNamespace, targetName,
targetOrigImportedName);
} }
ExternalReferenceCount refMatch = matchesMap.put(otherExtAddr, refMatch);
matchesMap.get(otherThunkedFunc.getEntryPoint()); }
if (refMatch == null) { else {
if (otherRestrictedSymbolIds != null && ++refMatch.refCount;
!otherRestrictedSymbolIds.contains(otherThunkedFunc.getID())) { }
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; continue;
} }
ExternalLocation otherExtLoc = Function otherFunc = (Function) otherThunkSym.getObject();
otherExtMgr.getExternalLocation(otherThunkedFunc.getSymbol()); Function otherThunkedFunc = otherFunc.getThunkedFunction(false);
ExternalMatchType matchType = testExternalMatch(otherExtLoc, extLoc); if (otherThunkedFunc == null || !otherThunkedFunc.isExternal()) {
refMatch = new ExternalReferenceCount(otherExtLoc, matchType); continue;
if (matchType != ExternalMatchType.NONE) { }
refMatch.setRelativeRank(targetAddr, targetNamespace, targetName, ExternalReferenceCount refMatch =
targetOrigImportedName); 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 program program which contains the specified external location instance
* @param externalLocation external location to look for * @param externalLocation external location to look for
* @param otherProgram other program * @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. * @return corresponding external location for otherProgram or null if no such external location exists.
*/ */
public static ExternalLocation getMatchingExternalLocation(Program program, public static ExternalLocation getMatchingExternalLocation(Program program,
ExternalLocation externalLocation, Program otherProgram) { ExternalLocation externalLocation, Program otherProgram, boolean allowInferredMatch) {
if (externalLocation == null) { if (externalLocation == null) {
return null; return null;
} }
@ -763,7 +829,7 @@ public class SimpleDiffUtility {
return null; return null;
} }
Symbol matchingExternalSymbol = Symbol matchingExternalSymbol =
getMatchingExternalSymbol(program, symbol, otherProgram, null); getMatchingExternalSymbol(program, symbol, otherProgram, allowInferredMatch, null);
if (matchingExternalSymbol == null) { if (matchingExternalSymbol == null) {
return null; return null;
} }