From e55550edfd720af361dd58aa679a623e60d2324f Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Wed, 10 Nov 2021 15:16:12 -0500 Subject: [PATCH] GP-1421 - Version Tracking - Updated API code to use the current in-use task monitor to allow for the cancelling of slow implied match finding. Closes #3221 --- .../DebuggerMemoryBytesProviderTest.java | 38 ++-- .../model/DebuggerModelServiceTest.java | 13 +- .../util/table/GhidraProgramTableModel.java | 12 +- Ghidra/Features/VersionTracking/build.gradle | 6 + .../vt/api/db/AssociationDatabaseManager.java | 109 ++++++++--- .../api/db/VTAssociationTableDBAdapter.java | 9 +- .../api/db/VTAssociationTableDBAdapterV0.java | 16 +- .../ghidra/feature/vt/api/db/VTSessionDB.java | 25 ++- .../vt/api/impl/VTSessionContentHandler.java | 47 +++-- .../feature/vt/api/main/AssociationHook.java | 5 +- .../feature/vt/api/main/VTAssociation.java | 44 +++-- .../vt/api/main/VTAssociationManager.java | 12 +- .../actions/AutoVersionTrackingCommand.java | 176 +++++++++--------- .../gui/plugin/AddressCorrelatorManager.java | 2 +- .../vt/gui/plugin/VTControllerImpl.java | 122 +++++++----- .../feature/vt/gui/plugin/VTTaskMonitor.java | 50 +++++ .../VTFunctionAssociationTableModel.java | 40 ++-- .../ImpliedMatchAssociationHook.java | 43 +++-- .../onetomany/VTMatchSourceTableModel.java | 38 ++-- .../ghidra/feature/vt/gui/task/VtTask.java | 5 +- .../gui/util/AbstractVTMatchTableModel.java | 9 +- .../vt/api/VTAutoVersionTrackingTest.java | 107 +++++------ .../src/main/java/ghidra/util/task/Task.java | 14 +- 23 files changed, 541 insertions(+), 401 deletions(-) create mode 100644 Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTTaskMonitor.java diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java index 1078c1b838..b2032f5619 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.debug.gui.memory; -import static ghidra.lifecycle.Unfinished.TODO; +import static ghidra.lifecycle.Unfinished.*; import static org.junit.Assert.*; import java.awt.*; @@ -28,6 +28,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import org.junit.*; +import org.junit.experimental.categories.Category; import com.google.common.collect.Range; @@ -35,6 +36,7 @@ import docking.action.DockingActionIf; import docking.menu.ActionState; import docking.menu.MultiStateDockingAction; import docking.widgets.EventTrigger; +import generic.test.category.NightlyCategory; import ghidra.GhidraOptions; import ghidra.app.plugin.core.byteviewer.ByteViewerComponent; import ghidra.app.plugin.core.byteviewer.ByteViewerPanel; @@ -62,6 +64,7 @@ import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.time.TraceSnapshot; import ghidra.util.database.UndoableTransaction; +@Category(NightlyCategory.class) public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebuggerGUITest { static LocationTrackingSpec getLocationTrackingSpec(String name) { return LocationTrackingSpec.fromConfigName(name); @@ -78,8 +81,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge final LocationTrackingSpec trackSp = getLocationTrackingSpec(SPLocationTrackingSpec.CONFIG_NAME); - final AutoReadMemorySpec readNone = - getAutoReadMemorySpec(NoneAutoReadMemorySpec.CONFIG_NAME); + final AutoReadMemorySpec readNone = getAutoReadMemorySpec(NoneAutoReadMemorySpec.CONFIG_NAME); final AutoReadMemorySpec readVisible = getAutoReadMemorySpec(VisibleAutoReadMemorySpec.CONFIG_NAME); final AutoReadMemorySpec readVisROOnce = @@ -254,8 +256,9 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge createAndOpenTrace(); TraceThread thread1; TraceThread thread2; - DebuggerMemoryBytesProvider extraProvider = SwingExecutorService.INSTANCE.submit( - () -> memBytesPlugin.createViewerIfMissing(trackPc, true)).get(); + DebuggerMemoryBytesProvider extraProvider = SwingExecutorService.INSTANCE + .submit(() -> memBytesPlugin.createViewerIfMissing(trackPc, true)) + .get(); try (UndoableTransaction tid = tb.startTransaction()) { DBTraceMemoryManager memory = tb.trace.getMemoryManager(); memory.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff), @@ -322,8 +325,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge } @Test - public void testFollowsCurrentTraceOnTraceChangeWithoutRegisterTracking() - throws Exception { + public void testFollowsCurrentTraceOnTraceChangeWithoutRegisterTracking() throws Exception { memBytesProvider.setTrackingSpec(trackNone); try ( // ToyDBTraceBuilder b1 = @@ -374,8 +376,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge } @Test - public void testFollowsCurrentThreadOnThreadChangeWithoutRegisterTracking() - throws Exception { + public void testFollowsCurrentThreadOnThreadChangeWithoutRegisterTracking() throws Exception { memBytesProvider.setTrackingSpec(trackNone); try ( // ToyDBTraceBuilder b1 = @@ -426,8 +427,8 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge } } - protected void assertViewerBackgroundAt(Color expected, ByteViewerPanel panel, - Address addr) throws AWTException, InterruptedException { + protected void assertViewerBackgroundAt(Color expected, ByteViewerPanel panel, Address addr) + throws AWTException, InterruptedException { goToDyn(addr); waitForPass(() -> { Rectangle r = panel.getBounds(); @@ -577,8 +578,8 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge assertEquals(traceManager.getCurrentView(), memBytesProvider.getProgram()); assertEquals("(nowhere)", memBytesProvider.locationLabel.getText()); - DebuggerMemoryBytesProvider extraProvider = runSwing( - () -> memBytesPlugin.createViewerIfMissing(trackNone, false)); + DebuggerMemoryBytesProvider extraProvider = + runSwing(() -> memBytesPlugin.createViewerIfMissing(trackNone, false)); waitForSwing(); assertEquals(traceManager.getCurrentView(), extraProvider.getProgram()); assertEquals("(nowhere)", extraProvider.locationLabel.getText()); @@ -716,8 +717,8 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge traceManager.activateThread(thread1); // NOTE: Action does not exist for main dynamic listing - DebuggerMemoryBytesProvider extraProvider = runSwing( - () -> memBytesPlugin.createViewerIfMissing(trackNone, true)); + DebuggerMemoryBytesProvider extraProvider = + runSwing(() -> memBytesPlugin.createViewerIfMissing(trackNone, true)); waitForSwing(); assertTrue(extraProvider.actionFollowsCurrentThread.isEnabled()); assertTrue(extraProvider.actionFollowsCurrentThread.isSelected()); @@ -844,8 +845,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge assertEquals(readVisROOnce, memBytesProvider.getAutoReadMemorySpec()); assertEquals(readVisROOnce, memBytesProvider.actionAutoReadMemory.getCurrentUserData()); - memBytesProvider.actionAutoReadMemory - .setCurrentActionStateByUserData(readNone); + memBytesProvider.actionAutoReadMemory.setCurrentActionStateByUserData(readNone); waitForSwing(); assertEquals(readNone, memBytesProvider.getAutoReadMemorySpec()); assertEquals(readNone, memBytesProvider.actionAutoReadMemory.getCurrentUserData()); @@ -886,8 +886,8 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge TraceModule modExe; try (UndoableTransaction tid = tb.startTransaction()) { modExe = tb.trace.getModuleManager() - .addModule("modExe", "modExe", - tb.range(0x55550000, 0x555501ff), Range.atLeast(0L)); + .addModule("modExe", "modExe", tb.range(0x55550000, 0x555501ff), + Range.atLeast(0L)); } waitForDomainObject(tb.trace); waitForPass(() -> assertEquals("modExe", memBytesProvider.locationLabel.getText())); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java index 7240283b84..d7092243fd 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java @@ -27,8 +27,10 @@ import javax.swing.JLabel; import javax.swing.JTextField; import org.junit.Test; +import org.junit.experimental.categories.Category; import generic.Unique; +import generic.test.category.NightlyCategory; import ghidra.app.plugin.core.debug.event.ModelObjectFocusedPluginEvent; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractConnectAction; @@ -53,10 +55,11 @@ import mockit.VerificationsInOrder; /** * TODO: Cover the error cases, and cases where {@code null} is expected - * + * *

* TODO: Cover cases where multiple recorders are present */ +@Category(NightlyCategory.class) public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITest implements DebuggerModelTestUtils { protected static final long TIMEOUT_MILLIS = @@ -67,7 +70,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes * CollectionChangeListener.of() if I try to mock one of those or a subclass directly. I'm * guessing the version we're using (1.44 as of this writing) is utterly ignorant of static * interface methods. What was the latest version of Java at the time? - * + * *

* TODO: Check if a later version fixes this issue. If so, consider upgrading. If not, submit an * issue. @@ -582,8 +585,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes public void testRecordBestOfferUnrecognized() throws Exception { createTestModel(); mb.testModel.session.environment.changeAttributes(List.of(), - Map.of(TargetEnvironment.ARCH_ATTRIBUTE_NAME, "test-bogus-arch"), - "Testing"); + Map.of(TargetEnvironment.ARCH_ATTRIBUTE_NAME, "test-bogus-arch"), "Testing"); mb.createTestProcessesAndThreads(); modelService.recordTargetBestOffer(mb.testProcess1); @@ -609,8 +611,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes public void testRecordPromptOffersUnrecognized() throws Exception { createTestModel(); mb.testModel.session.environment.changeAttributes(List.of(), - Map.of(TargetEnvironment.ARCH_ATTRIBUTE_NAME, "test-bogus-arch"), - "Testing"); + Map.of(TargetEnvironment.ARCH_ATTRIBUTE_NAME, "test-bogus-arch"), "Testing"); mb.createTestProcessesAndThreads(); runSwingLater(() -> modelService.recordTargetPromptOffers(mb.testProcess1)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java index 58ec474c18..3289ea913b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/GhidraProgramTableModel.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +15,13 @@ */ package ghidra.util.table; +import docking.widgets.table.threaded.ThreadedTableModel; import ghidra.framework.plugintool.ServiceProvider; import ghidra.program.model.listing.Program; import ghidra.util.task.TaskMonitor; -import docking.widgets.table.threaded.ThreadedTableModel; -public abstract class GhidraProgramTableModel extends - ThreadedTableModel implements ProgramTableModel { +public abstract class GhidraProgramTableModel + extends ThreadedTableModel implements ProgramTableModel { protected Program program; @@ -47,9 +46,10 @@ public abstract class GhidraProgramTableModel extends } /** - * Extension point for getting a row-specific program. Most models don't need this - * capability. + * Extension point for getting a row-specific program. Most models don't need this + * capability. * @param t The ROW_TYPE row object + * @return the program */ protected Program getProgramForRow(ROW_TYPE t) { return getProgram(); diff --git a/Ghidra/Features/VersionTracking/build.gradle b/Ghidra/Features/VersionTracking/build.gradle index 9786f07f23..05d0966b84 100644 --- a/Ghidra/Features/VersionTracking/build.gradle +++ b/Ghidra/Features/VersionTracking/build.gradle @@ -32,3 +32,9 @@ dependencies { testImplementation "org.jmockit:jmockit:1.44" testImplementation project(path: ':Project', configuration: 'testArtifacts') } +integrationTest { + // tests to slow to run during automated testing + excludes = [ + '**/VTAutoVersionTrackingTest*', + ] +} diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/AssociationDatabaseManager.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/AssociationDatabaseManager.java index 98555898e9..cc88a5c5ef 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/AssociationDatabaseManager.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/AssociationDatabaseManager.java @@ -29,12 +29,20 @@ import ghidra.program.database.DBObjectCache; import ghidra.program.model.address.Address; import ghidra.util.Lock; import ghidra.util.exception.*; +import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; public class AssociationDatabaseManager implements VTAssociationManager { - private VTAssociationTableDBAdapter associationTableAdapter; + private final VTSessionDB session; + private VTAssociationTableDBAdapter associationTableAdapter; + + // A cache of accepted associations that allow this class to check isBlocked() quickly. This + // was added to fix a major performance bottleneck. + private Set

acceptedSourceAssociations = new HashSet<>(); + private Set
acceptedDestinationAssociations = new HashSet<>(); + private VTMatchMarkupItemTableDBAdapter markupItemTableAdapter; private DBObjectCache markupItemCache; private List associationHooks = new ArrayList<>(); @@ -56,6 +64,7 @@ public class AssociationDatabaseManager implements VTAssociationManager { VTAssociationTableDBAdapter.getAdapter(dbHandle, openMode, monitor); manager.markupItemTableAdapter = VTMatchMarkupItemTableDBAdapter.getAdapter(dbHandle, openMode, monitor); + return manager; } @@ -66,6 +75,39 @@ public class AssociationDatabaseManager implements VTAssociationManager { markupItemCache = new DBObjectCache<>(10); } + /** + * Called when an existing session has been initialized with its programs. This is not called + * when a new session is created. + */ + void sessionInitialized() { + TaskLauncher.launchModal("Loading Associations", + monitor -> loadAcceptedAssociations(monitor)); + } + + private void loadAcceptedAssociations(TaskMonitor monitor) { + + monitor.setMessage("Loading accepted associations..."); + + try { + RecordIterator it = associationTableAdapter.getRecords(); + while (it.hasNext() && !monitor.isCancelled()) { + DBRecord record = it.next(); + VTAssociationDB associationDB = getAssociationForRecord(record); + VTAssociationStatus status = associationDB.getStatus(); + if (status == ACCEPTED) { + Address sourceAddress = associationDB.getSourceAddress(); + Address destinationAddress = associationDB.getDestinationAddress(); + acceptedSourceAssociations.add(sourceAddress); + acceptedDestinationAssociations.add(destinationAddress); + } + } + monitor.setMessage("Finished loading accepted associations"); + } + catch (IOException e) { + session.dbError(e); + } + } + public Collection getAppliedMarkupItems(TaskMonitor monitor, VTAssociation association) throws CancelledException { @@ -222,8 +264,8 @@ public class AssociationDatabaseManager implements VTAssociationManager { VTAssociationDB newAssociation = null; try { lock.acquire(); - DBRecord record = associationTableAdapter.insertRecord(sourceLong, destinationLong, type, - isBlocked ? BLOCKED : AVAILABLE, 0); + DBRecord record = associationTableAdapter.insertRecord(sourceLong, destinationLong, + type, isBlocked ? BLOCKED : AVAILABLE, 0); newAssociation = new VTAssociationDB(this, associationCache, record); } catch (IOException e) { @@ -257,22 +299,13 @@ public class AssociationDatabaseManager implements VTAssociationManager { } private boolean isBlocked(Address sourceAddress, Address destinationAddress) { - long sourceID = session.getLongFromSourceAddress(sourceAddress); - long destinationID = session.getLongFromDestinationAddress(destinationAddress); - try { - Set relatedRecords = - associationTableAdapter.getRelatedAssociationRecordsBySourceAndDestinationAddress( - sourceID, destinationID); - for (DBRecord record : relatedRecords) { - VTAssociationDB associationDB = getAssociationForRecord(record); - VTAssociationStatus status = associationDB.getStatus(); - if (status == ACCEPTED) { - return true; - } - } + + if (acceptedSourceAssociations.contains(sourceAddress)) { + return true; } - catch (IOException e) { - session.dbError(e); + + if (acceptedDestinationAssociations.contains(destinationAddress)) { + return true; } return false; @@ -396,9 +429,9 @@ public class AssociationDatabaseManager implements VTAssociationManager { public Collection getRelatedAssociationsBySourceAddress(Address sourceAddress) { lock.acquire(); try { - long sourceID = session.getLongFromSourceAddress(sourceAddress); + long sourceId = session.getLongFromSourceAddress(sourceAddress); Set relatedRecords = - associationTableAdapter.getRelatedAssociationRecordsBySourceAddress(sourceID); + associationTableAdapter.getRelatedAssociationRecordsBySourceAddress(sourceId); List associations = new ArrayList<>(); for (DBRecord record : relatedRecords) { associations.add(getAssociationForRecord(record)); @@ -419,10 +452,9 @@ public class AssociationDatabaseManager implements VTAssociationManager { Address destinationAddress) { lock.acquire(); try { - long destinationID = session.getLongFromDestinationAddress(destinationAddress); - Set relatedRecords = - associationTableAdapter.getRelatedAssociationRecordsByDestinationAddress( - destinationID); + long destinationId = session.getLongFromDestinationAddress(destinationAddress); + Set relatedRecords = associationTableAdapter + .getRelatedAssociationRecordsByDestinationAddress(destinationId); List associations = new ArrayList<>(); for (DBRecord record : relatedRecords) { associations.add(getAssociationForRecord(record)); @@ -443,11 +475,11 @@ public class AssociationDatabaseManager implements VTAssociationManager { Address sourceAddress, Address destinationAddress) { lock.acquire(); try { - long sourceID = session.getLongFromSourceAddress(sourceAddress); - long destinationID = session.getLongFromDestinationAddress(destinationAddress); + long sourceId = session.getLongFromSourceAddress(sourceAddress); + long destinationId = session.getLongFromDestinationAddress(destinationAddress); Set relatedRecords = associationTableAdapter.getRelatedAssociationRecordsBySourceAndDestinationAddress( - sourceID, destinationID); + sourceId, destinationId); List associations = new ArrayList<>(); for (DBRecord record : relatedRecords) { associations.add(getAssociationForRecord(record)); @@ -566,15 +598,15 @@ public class AssociationDatabaseManager implements VTAssociationManager { } private Set getRelatedAssociations(VTAssociationDB association) { - long sourceID = session.getLongFromSourceAddress(association.getSourceAddress()); - long destinationID = + long sourceId = session.getLongFromSourceAddress(association.getSourceAddress()); + long destinationId = session.getLongFromDestinationAddress(association.getDestinationAddress()); Set relatedAssociaitons = new HashSet<>(); try { Set relatedRecords = associationTableAdapter.getRelatedAssociationRecordsBySourceAndDestinationAddress( - sourceID, destinationID); + sourceId, destinationId); relatedRecords.remove(association.getRecord()); // don't change the given association for (DBRecord record : relatedRecords) { relatedAssociaitons.add(getAssociationForRecord(record)); @@ -593,6 +625,19 @@ public class AssociationDatabaseManager implements VTAssociationManager { catch (IOException e) { session.dbError(e); } + + VTAssociationDB association = getAssociationForRecord(record); + Address sourceAddress = association.getSourceAddress(); + Address destinationAddress = association.getDestinationAddress(); + VTAssociationStatus status = association.getStatus(); + if (status == ACCEPTED) { + acceptedSourceAssociations.add(sourceAddress); + acceptedDestinationAssociations.add(destinationAddress); + } + else { + acceptedSourceAssociations.remove(sourceAddress); + acceptedDestinationAssociations.remove(destinationAddress); + } } void updateMarkupRecord(DBRecord record) { @@ -632,4 +677,8 @@ public class AssociationDatabaseManager implements VTAssociationManager { } } + void dispose() { + acceptedSourceAssociations.clear(); + acceptedDestinationAssociations.clear(); + } } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapter.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapter.java index f9594ca669..2cb927cddf 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapter.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapter.java @@ -61,10 +61,9 @@ public abstract class VTAssociationTableDBAdapter { abstract void deleteRecord(long sourceAddressID) throws IOException; - abstract RecordIterator getRecordsForSourceAddress(long sourceAddressID) throws IOException; + abstract RecordIterator getRecordsForSourceAddress(long addressID) throws IOException; - abstract RecordIterator getRecordsForDestinationAddress(long destinationAddressID) - throws IOException; + abstract RecordIterator getRecordsForDestinationAddress(long addressID) throws IOException; abstract int getRecordCount(); @@ -78,8 +77,8 @@ public abstract class VTAssociationTableDBAdapter { abstract Set getRelatedAssociationRecordsBySourceAddress(long sourceAddressID) throws IOException; - abstract Set getRelatedAssociationRecordsByDestinationAddress(long destinationAddressID) - throws IOException; + abstract Set getRelatedAssociationRecordsByDestinationAddress( + long destinationAddressID) throws IOException; abstract void updateRecord(DBRecord record) throws IOException; diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapterV0.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapterV0.java index 2d325f6e33..f799849c58 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapterV0.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTAssociationTableDBAdapterV0.java @@ -16,16 +16,16 @@ package ghidra.feature.vt.api.db; import static ghidra.feature.vt.api.db.VTAssociationTableDBAdapter.AssociationTableDescriptor.*; -import ghidra.feature.vt.api.main.VTAssociationStatus; -import ghidra.feature.vt.api.main.VTAssociationType; -import ghidra.util.exception.VersionException; -import ghidra.util.task.TaskMonitor; import java.io.IOException; import java.util.HashSet; import java.util.Set; import db.*; +import ghidra.feature.vt.api.main.VTAssociationStatus; +import ghidra.feature.vt.api.main.VTAssociationType; +import ghidra.util.exception.VersionException; +import ghidra.util.task.TaskMonitor; public class VTAssociationTableDBAdapterV0 extends VTAssociationTableDBAdapter { @@ -81,14 +81,14 @@ public class VTAssociationTableDBAdapterV0 extends VTAssociationTableDBAdapter { } @Override - RecordIterator getRecordsForDestinationAddress(long addressID) throws IOException { - LongField longField = new LongField(addressID); + RecordIterator getRecordsForDestinationAddress(long addressId) throws IOException { + LongField longField = new LongField(addressId); return table.indexIterator(DESTINATION_ADDRESS_COL.column(), longField, longField, true); } @Override - RecordIterator getRecordsForSourceAddress(long addressID) throws IOException { - LongField longField = new LongField(addressID); + RecordIterator getRecordsForSourceAddress(long addressId) throws IOException { + LongField longField = new LongField(addressId); return table.indexIterator(SOURCE_ADDRESS_COL.column(), longField, longField, true); } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java index c0ba332e46..55545d5cdc 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/db/VTSessionDB.java @@ -36,7 +36,8 @@ import ghidra.program.model.address.AddressSet; import ghidra.program.model.listing.Program; import ghidra.util.Msg; import ghidra.util.exception.*; -import ghidra.util.task.*; +import ghidra.util.task.TaskLauncher; +import ghidra.util.task.TaskMonitor; public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTChangeManager { private final static Field[] COL_FIELDS = new Field[] { StringField.INSTANCE }; @@ -61,7 +62,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC * database schema associated with any of the adapters. * 14-Nov-2019 - version 2 - Corrected fixed length indexing implementation causing * change in index table low-level storage for newly - * created tables. + * created tables. */ private static final int DB_VERSION = 2; @@ -287,6 +288,8 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC throw new RuntimeException(buffer.toString()); } + associationManager.sessionInitialized(); + try { addSynchronizedDomainObject(destinationProgram); } @@ -324,9 +327,6 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC } } - /** - * @see ghidra.framework.data.DomainObjectAdapterDB#clearCache() - */ @Override protected void clearCache(boolean all) { lock.acquire(); @@ -354,7 +354,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC @Override public void save() throws IOException { try { - save(DESTINATION_PROGRAM_ID_PROPERTY_KEY, TaskMonitorAdapter.DUMMY_MONITOR); + save(DESTINATION_PROGRAM_ID_PROPERTY_KEY, TaskMonitor.DUMMY); } catch (CancelledException e) { // can't happen because we are using a dummy monitor @@ -476,7 +476,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC return associationManager; } - /** Package-level methods for accessing DB-related manager */ + /* Package-level methods for accessing DB-related manager */ public AssociationDatabaseManager getAssociationManagerDBM() { return associationManager; } @@ -508,9 +508,6 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC @Override public void setChanged(int type, Object oldValue, Object newValue) { -// if (recordChanges) { -// updateChangeSet(newstart, newend); -// } changed = true; fireEvent(new VersionTrackingChangeRecord(type, null, oldValue, newValue)); @@ -528,9 +525,6 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC @Override public void setObjectChanged(int type, Object affectedObject, Object oldValue, Object newValue) { -// if (recordChanges) { -// updateChangeSet(newstart, newend); -// } changed = true; fireEvent(new VersionTrackingChangeRecord(type, affectedObject, oldValue, newValue)); @@ -716,4 +710,9 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession, VTC associationManager.removeAssociationHook(hook); } + @Override + protected void close() { + associationManager.dispose(); + super.close(); + } } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java index af2bd8156f..513ce83b4b 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/impl/VTSessionContentHandler.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +15,14 @@ */ package ghidra.feature.vt.api.impl; +import java.io.IOException; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import db.DBHandle; +import db.OpenMode; +import db.buffers.BufferFile; import ghidra.feature.vt.api.db.VTSessionDB; import ghidra.framework.data.*; import ghidra.framework.model.ChangeSet; @@ -26,38 +33,30 @@ import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; import ghidra.util.task.TaskMonitor; - -import java.io.IOException; - -import javax.swing.Icon; -import javax.swing.ImageIcon; - import resources.ResourceManager; -import db.DBHandle; -import db.OpenMode; -import db.buffers.BufferFile; public class VTSessionContentHandler extends DBContentHandler { - private static ImageIcon ICON = ResourceManager.getScaledIcon( - ResourceManager.loadImage("images/start-here_16.png"), 16, 16); + private static ImageIcon ICON = ResourceManager + .getScaledIcon(ResourceManager.loadImage("images/start-here_16.png"), 16, 16); public final static String CONTENT_TYPE = "VersionTracking"; @Override public long createFile(FileSystem fs, FileSystem userfs, String path, String name, - DomainObject domainObject, TaskMonitor monitor) throws IOException, - InvalidNameException, CancelledException { + DomainObject domainObject, TaskMonitor monitor) + throws IOException, InvalidNameException, CancelledException { if (!(domainObject instanceof VTSessionDB)) { - throw new IOException("Unsupported domain object: " + domainObject.getClass().getName()); + throw new IOException( + "Unsupported domain object: " + domainObject.getClass().getName()); } return createFile((VTSessionDB) domainObject, CONTENT_TYPE, fs, path, name, monitor); } @Override - public ChangeSet getChangeSet(FolderItem versionedFolderItem, int olderVersion, int newerVersion) - throws VersionException, IOException { + public ChangeSet getChangeSet(FolderItem versionedFolderItem, int olderVersion, + int newerVersion) throws VersionException, IOException { return null; } @@ -133,8 +132,8 @@ public class VTSessionContentHandler extends DBContentHandler { @Override public DomainObjectAdapter getImmutableObject(FolderItem item, Object consumer, int version, - int minChangeVersion, TaskMonitor monitor) throws IOException, CancelledException, - VersionException { + int minChangeVersion, TaskMonitor monitor) + throws IOException, CancelledException, VersionException { String contentType = item.getContentType(); if (!contentType.equals(CONTENT_TYPE)) { @@ -145,16 +144,16 @@ public class VTSessionContentHandler extends DBContentHandler { } @Override - public DomainObjectMergeManager getMergeManager(DomainObject resultsObj, - DomainObject sourceObj, DomainObject originalObj, DomainObject latestObj) { + public DomainObjectMergeManager getMergeManager(DomainObject resultsObj, DomainObject sourceObj, + DomainObject originalObj, DomainObject latestObj) { return null; } @Override public DomainObjectAdapter getReadOnlyObject(FolderItem item, int version, boolean okToUpgrade, - Object consumer, TaskMonitor monitor) throws IOException, VersionException, - CancelledException { + Object consumer, TaskMonitor monitor) + throws IOException, VersionException, CancelledException { String contentType = item.getContentType(); if (contentType != null && !contentType.equals(CONTENT_TYPE)) { @@ -181,7 +180,7 @@ public class VTSessionContentHandler extends DBContentHandler { throw e; } catch (Throwable t) { - Msg.error(this, "getImmutableObject failed", t); + Msg.error(this, "Get read-only object failed", t); String msg = t.getMessage(); if (msg == null) { msg = t.toString(); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/AssociationHook.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/AssociationHook.java index c7ba6f3981..519331b055 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/AssociationHook.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/AssociationHook.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +16,7 @@ package ghidra.feature.vt.api.main; /** - * Interface used for a callback when associations are accepted or cleared. + * Interface used for a callback when associations are accepted or cleared. */ public interface AssociationHook { /** @@ -28,7 +27,7 @@ public interface AssociationHook { /** * Called whenever an association has been cleared from the accepted state. - * @param association the association that has been cleared from the accpeted state. + * @param association the association that has been cleared from the accepted state. */ public void associationCleared(VTAssociation association); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociation.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociation.java index f48a941121..dc07aeb7b7 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociation.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociation.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +15,15 @@ */ package ghidra.feature.vt.api.main; +import java.util.Collection; + import ghidra.feature.vt.api.util.VTAssociationStatusException; import ghidra.program.model.address.Address; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; -import java.util.Collection; - /** - * A VTAssociation is a possible equivalence between a function or data in one program to + * A VTAssociation is a possible equivalence between a function or data in one program to * a function or data in another program. VTAssociations can be "Accepted" indicating that * the user has agreed that the association is correct. */ @@ -72,23 +71,24 @@ public interface VTAssociation { /** * Returns a collection of VTAssociations that have either the same source address or the same - * destination address. + * destination address. * @return a collection of VTAssociations that have either the same source address or the same * destination address. */ public Collection getRelatedAssociations(); /** - * Sets the markup status of this association. This method is used by the + * Sets the markup status of this association. This method is used by the * {@link VTAssociationManager} to update the association with information about the state * of its markup items. + * @param markupItemsStatus the markup items */ public void setMarkupStatus(VTAssociationMarkupStatus markupItemsStatus); /** - * Returns the status of the markup items for this association. + * Returns the status of the markup items for this association. * See {@link VTAssociationMarkupStatus} for details. - * + * * @return the status of the markup items for this association. */ public VTAssociationMarkupStatus getMarkupStatus(); @@ -102,25 +102,23 @@ public interface VTAssociation { /** * A convenience method to accept the given association without actually performing an apply. - * - * @param association the association to accept - * @throws VTAssociationStatusException if the given association is + * + * @throws VTAssociationStatusException if the given association is * {@link VTAssociationStatus#BLOCKED} */ public void setAccepted() throws VTAssociationStatusException; /** * Clears the state of the given association from {@link VTAssociationStatus#ACCEPTED} - * or {@link VTAssociationStatus#REJECTED} to {@link VTAssociationStatus#AVAILABLE}. - * This method will throw an exception if called while the given assocation's markup items - * have been applied. That is, you must first unapply any applied markup items before - * calling this method. - * - * @param association the association whose state will be changed - * @throws VTAssociationStatusException if the given association's status is not - * {@link VTAssociationStatus#ACCEPTED}/{@link VTAssociationStatus#REJECTED} - * or if the given assocation's - * {@link VTMarkupItemManager} contains markup items that have been applied. + * or {@link VTAssociationStatus#REJECTED} to {@link VTAssociationStatus#AVAILABLE}. + * This method will throw an exception if called while the given assocation's markup items + * have been applied. That is, you must first unapply any applied markup items before + * calling this method. + * + * @throws VTAssociationStatusException if the given association's status is not + * {@link VTAssociationStatus#ACCEPTED}/{@link VTAssociationStatus#REJECTED} + * or if the given assocation's markup item manager contains markup items that + * have been applied. */ public void clearStatus() throws VTAssociationStatusException; @@ -132,9 +130,9 @@ public interface VTAssociation { /** * Returns the current vote count which is an application settable field which should generally - * be used to indicate a number of supporting facts. For example, other accepted assocations + * be used to indicate a number of supporting facts. For example, other accepted associations * may have matching call references to this association, each of those matching calls should - * have incremented the votes. + * have incremented the votes. * @return the current number of facts that support this association */ public int getVoteCount(); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociationManager.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociationManager.java index 110fa4da5f..66850a379b 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociationManager.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/api/main/VTAssociationManager.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +15,14 @@ */ package ghidra.feature.vt.api.main; -import ghidra.program.model.address.Address; - import java.util.Collection; import java.util.List; +import ghidra.program.model.address.Address; + /** * The interface for the association manager which manages the associations which are shared - * with similar matches within a session. + * with similar matches within a session. * */ public interface VTAssociationManager { @@ -60,7 +59,7 @@ public interface VTAssociationManager { /** * Returns a collection of all defined associations that have the given destination address. - * @param destinaitionAddress the source address to use to search for associations. + * @param destinationAddress the source address to use to search for associations. * @return a collection of all defined associations that have the given destination address. */ public Collection getRelatedAssociationsByDestinationAddress( @@ -70,11 +69,10 @@ public interface VTAssociationManager { * Returns a collection of all defined associations that have the either the given source * address or the given destination address * @param sourceAddress the source address to use to search for associations. - * @param destinaitionAddress the source address to use to search for associations. + * @param destinationAddress the source address to use to search for associations. * @return a collection of all defined associations that have either the given source * address or the given destination address. */ public Collection getRelatedAssociationsBySourceAndDestinationAddress( Address sourceAddress, Address destinationAddress); - } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingCommand.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingCommand.java index 13e42be3a8..92eed54d3d 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingCommand.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/actions/AutoVersionTrackingCommand.java @@ -40,30 +40,30 @@ import ghidra.util.task.TaskMonitor; import util.CollectionUtils; /** - * This command runs all of the exact {@link VTProgramCorrelator}s that return + * This command runs all of the exact {@link VTProgramCorrelator}s that return * unique matches (ie only one of each match is found in each program): *
    *
  1. Exact Symbol Name correlator
  2. *
  3. Exact Data correlator
  4. - *
  5. Exact Function Byte correlator
  6. + *
  7. Exact Function Byte correlator
  8. *
  9. Exact Function Instruction correlator
  10. *
  11. Exact Function Mnemonic correlator
  12. *
- * + * *

After running each correlator all matches are accepted since they are exact/unique matches * and all markup from the source program functions is applied to the matching destination program * functions. - * - *

Next, this command runs the Duplicate Function Instruction correlator to find any non-unique - * functions with exact instruction bytes then compares their operands to determine and accept - * correct matches with markup. - * - *

The command then gets a little more speculative by running the Combined Function and Data - * Reference correlator, which uses match information from the previous correlators to find more - * matches. - * + * + *

Next, this command runs the Duplicate Function Instruction correlator to find any non-unique + * functions with exact instruction bytes then compares their operands to determine and accept + * correct matches with markup. + * + *

The command then gets a little more speculative by running the Combined Function and Data + * Reference correlator, which uses match information from the previous correlators to find more + * matches. + * *

As more techniques get developed, more automation will be added to this command. - * + * */ public class AutoVersionTrackingCommand extends BackgroundCommand { @@ -82,14 +82,14 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * Constructor for AutoVersionTrackingCommand - * + * * @param controller The Version Tracking controller for this session containing option and * tool information needed for this command. - * @param session The Version Tracking session containing the source, destination, correlator - * and match information needed for this command. + * @param session The Version Tracking session containing the source, destination, correlator + * and match information needed for this command. * @param minCombinedReferenceCorrelatorScore The minimum score used to limit matches created by * the Combined Reference Correlator. - * @param minCombinedReferenceCorrelatorConfidence The minimum confidence used to limit matches + * @param minCombinedReferenceCorrelatorConfidence The minimum confidence used to limit matches * created by the Combined Reference Correlator. */ public AutoVersionTrackingCommand(VTController controller, VTSession session, @@ -117,11 +117,11 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { monitor.initialize(NUM_CORRELATORS); // Use default options for all of the "exact" correlators and passed in options for - // the others. + // the others. VTOptions options; - // Run the correlators in the following order: - // Do this one first because we don't want it to find ones that get markup + // Run the correlators in the following order: + // Do this one first because we don't want it to find ones that get markup // applied by later correlators VTProgramCorrelatorFactory factory = new SymbolNameProgramCorrelatorFactory(); options = factory.createDefaultOptions(); @@ -145,10 +145,10 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { // This is the first of the "speculative" post-correlator match algorithm. The correlator // returns all duplicate function instruction matches so there will always be more - // than one possible match for each function. The compare mechanism used by the - // function compare window determines matches based on matching operand values. - // Given that each function must contains the same instructions to even become a match, - // and the compare function mechanism has been very well tested, the mechanism for + // than one possible match for each function. The compare mechanism used by the + // function compare window determines matches based on matching operand values. + // Given that each function must contains the same instructions to even become a match, + // and the compare function mechanism has been very well tested, the mechanism for // finding the correct match is very accurate. factory = new DuplicateFunctionMatchProgramCorrelatorFactory(); options = factory.createDefaultOptions(); @@ -157,11 +157,11 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { // The rest are mores speculative matching algorithms because they depend on our // choosing the correct score/confidence pair to determine very probable matches. These - // values were chosen based on what has been seen so far but this needs to be tested + // values were chosen based on what has been seen so far but this needs to be tested // further on more programs and possibly add options for users to - // give their own thresholds. + // give their own thresholds. - // Get the names of the confidence and similarity score thresholds that + // Get the names of the confidence and similarity score thresholds that // are used by all of the "reference" correlators String confidenceOption = VTAbstractReferenceProgramCorrelatorFactory.CONFIDENCE_THRESHOLD; @@ -171,7 +171,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { int numDataMatches = getNumberOfDataMatches(monitor); int numFunctionMatches = getNumberOfFunctionMatches(monitor); - // Run the DataReferenceCorrelator if there are accepted data matches but no accepted + // Run the DataReferenceCorrelator if there are accepted data matches but no accepted // function matches if (numDataMatches > 0 && numFunctionMatches == 0) { factory = new DataReferenceProgramCorrelatorFactory(); @@ -269,12 +269,12 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } /** - * Runs the given version tracking (VT) correlator and applies the returned matches meeting the + * Runs the given version tracking (VT) correlator and applies the returned matches meeting the * given score and confidence thresholds and are not otherwise blocked. * @param factory The correlator factory used to create and run the desired VT correlator. * @param options The options to pass the correlator including score and confidence values. * @param monitor Checks to see if user has cancelled. - * @throws CancelledException + * @throws CancelledException if cancelled */ private boolean correlateAndPossiblyApply(VTProgramCorrelatorFactory factory, VTOptions options, TaskMonitor monitor) throws CancelledException { @@ -299,14 +299,14 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * Runs the Duplicate Exact Function match version tracking (VT) correlator then determines - * correct matches based on matching operand values. Those matches are accepted and other + * correct matches based on matching operand values. Those matches are accepted and other * possible matches for those functions are blocked. Markup from accepted source functions - * is applied to matching destination functions. + * is applied to matching destination functions. * - * @param factory The correlator factory used to create and run the desired VT correlator. In + * @param factory The correlator factory used to create and run the desired VT correlator. In * this case, the duplicate function instruction match correlator. * @param monitor Checks to see if user has cancelled. - * @throws CancelledException + * @throws CancelledException if cancelled */ private boolean correlateAndPossiblyApplyDuplicateFunctions(VTProgramCorrelatorFactory factory, VTOptions options, TaskMonitor monitor) throws CancelledException { @@ -326,14 +326,14 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } /** - * Called for all correlators that are run by this command except the duplicate function - * instruction match correlator. - * @param matches The set of matches to try to accept as matches. - * @param correlatorName The name of the Version Tracking correlator whose matches are being - * applied here. + * Called for all correlators that are run by this command except the duplicate function + * instruction match correlator. + * @param matches The set of matches to try to accept as matches. + * @param correlatorName The name of the Version Tracking correlator whose matches are being + * applied here. * @param monitor Checks to see if user has cancelled. * @return true if some matches have markup errors and false if none have markup errors. - * @throws CancelledException + * @throws CancelledException if cancelled */ private boolean applyMatches(Collection matches, String correlatorName, TaskMonitor monitor) throws CancelledException { @@ -341,7 +341,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { // If this value gets set to true then there are some markup errors in the whole set of // matches. boolean someMatchesHaveMarkupErrors = false; - // Note: no need to check score/confidence because they are passed into the correlator + // Note: no need to check score/confidence because they are passed into the correlator // ahead of time so correlator only returns matches higher than given score/threshold for (VTMatch match : matches) { monitor.checkCanceled(); @@ -376,7 +376,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * This method tries to set a match association as accepted. - * @param association The match association between two match items. + * @param association The match association between two match items. * @return true if match is accepted and false if an exception occurred and the match couldn't be * accepted. */ @@ -394,13 +394,13 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } /** - * Accept matches and apply markup for duplicate function instruction matches with matching operands + * Accept matches and apply markup for duplicate function instruction matches with matching operands * if they are a unique match within their associated set. - * @param matches A collection of version tracking matches from the duplicate instruction - * matcher. + * @param matches A collection of version tracking matches from the duplicate instruction + * matcher. * @param monitor Allows user to cancel * @return true if any markup errors, false if no markup errors. - * @throws CancelledException + * @throws CancelledException if cancelled */ private boolean applyDuplicateFunctionMatches(Collection matches, TaskMonitor monitor) throws CancelledException { @@ -413,34 +413,34 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { for (VTMatch match : matches) { monitor.checkCanceled(); - // if match has already been removed (ie it was in a set that was already processed) + // if match has already been removed (ie it was in a set that was already processed) // then skip it if (!copyOfMatches.contains(match)) { continue; } // get a set of related matches from the set of all matches - // ie these all have the same instructions as each other but not necessarily + // ie these all have the same instructions as each other but not necessarily // the same operands. Set relatedMatches = getRelatedMatches(match, matches, monitor); // remove related matches from the set of matches to process next time removeMatches(copyOfMatches, relatedMatches); - // remove any matches that have identical source functions - if more than one + // remove any matches that have identical source functions - if more than one // with exactly the same instructions and operands then cannot determine a unique match Set

sourceAddresses = getSourceAddressesFromMatches(relatedMatches, monitor); Set
uniqueSourceFunctionAddresses = - dedupeMatchingFunctions(sourceProgram, sourceAddresses, monitor); + dedupMatchingFunctions(sourceProgram, sourceAddresses, monitor); - // remove any matches that have identical destination functions - if more than one + // remove any matches that have identical destination functions - if more than one // with exactly the same instructions and operands then cannot determine a unique match Set
destAddresses = getDestinationAddressesFromMatches(relatedMatches, monitor); Set
uniqueDestFunctionAddresses = - dedupeMatchingFunctions(destinationProgram, destAddresses, monitor); + dedupMatchingFunctions(destinationProgram, destAddresses, monitor); - //Keep only matches containing the unique sources and destination functions determined above + // Keep only matches containing the unique sources and destination functions determined above Set dedupedMatches = getMatches(relatedMatches, uniqueSourceFunctionAddresses, uniqueDestFunctionAddresses, monitor); @@ -448,14 +448,15 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { for (Address sourceAddress : uniqueSourceFunctionAddresses) { monitor.checkCanceled(); - //Find all destination functions with equivalent operands to current source function + // Find all destination functions with equivalent operands to current source function Set matchesWithEquivalentOperands = getMatchesWithEquivalentOperands( dedupedMatches, sourceAddress, uniqueDestFunctionAddresses, monitor); - // If there is just one equivalent match try to accept the match and apply markup + // If there is just one equivalent match try to accept the match and apply markup if (matchesWithEquivalentOperands.size() == 1) { VTMatch theMatch = CollectionUtils.any(matchesWithEquivalentOperands); - someMatchesHaveMarkupErrors = tryToAcceptMatchAndApplyMarkup(theMatch, monitor); + someMatchesHaveMarkupErrors |= + tryToAcceptMatchAndApplyMarkup(theMatch, monitor); } } } @@ -505,7 +506,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { * @param destAddresses Addresses of destination functions to compare with source function * @param monitor Allows user to cancel * @return Set of all matches with equivalent operands. - * @throws CancelledException + * @throws CancelledException if cancelled */ private Set getMatchesWithEquivalentOperands(Set matches, Address sourceAddress, Set
destAddresses, TaskMonitor monitor) @@ -526,13 +527,13 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } /** - * Determine which matches from a collection of matches are related to the given match, ie - * have the same source or destination address as the current match. + * Determine which matches from a collection of matches are related to the given match, ie + * have the same source or destination address as the current match. * @param match Current version tracking match * @param matches Collection version tracking matches * @param monitor Allows user to cancel * @return Set of matches related to the given match - * @throws CancelledException + * @throws CancelledException if cancelled */ private Set getRelatedMatches(VTMatch match, Collection matches, TaskMonitor monitor) throws CancelledException { @@ -562,7 +563,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * Remove given matches from a set of matches. - * @param matchSet Set of matches. + * @param matchSet Set of matches. * @param matchesToRemove Set of matches to remove from matches set. */ private void removeMatches(Set matchSet, Set matchesToRemove) { @@ -581,7 +582,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { * @param matches Set of version tracking matches * @param monitor Allows user to cancel * @return A set of source addresses from the given set of version tracking matches. - * @throws CancelledException + * @throws CancelledException if cancelled */ private Set
getSourceAddressesFromMatches(Set matches, TaskMonitor monitor) throws CancelledException { @@ -599,7 +600,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { * @param matches Set of version tracking matches * @param monitor Allows user to cancel * @return A set of destination addresses from the given set of version tracking matches. - * @throws CancelledException + * @throws CancelledException if cancelled */ private Set
getDestinationAddressesFromMatches(Set matches, TaskMonitor monitor) throws CancelledException { @@ -632,13 +633,13 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } /** - * From a set of matches get the subset that contains the given source and destination addresses. + * From a set of matches get the subset that contains the given source and destination addresses. * @param matches Set of matches * @param sourceAddresses Set of source addresses * @param destAddresses Set of destination addresses * @param monitor Allows user to cancel * @return Set of matches containing given source and destination addresses. - * @throws CancelledException + * @throws CancelledException if cancelled */ private Set getMatches(Set matches, Set
sourceAddresses, Set
destAddresses, TaskMonitor monitor) throws CancelledException { @@ -656,18 +657,18 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * * This method is only called to compare functions with identical instruction - * bytes, identical operand lengths, but possibly different operand values. It returns true - * if the two functions in the match have potentially equivalent operands. It returns false if - * any of the operands do not match. + * bytes, identical operand lengths, but possibly different operand values. It returns true + * if the two functions in the match have potentially equivalent operands. It returns false if + * any of the operands do not match. * Potentially equivalent means corresponding scalar operands match, corresponding other operands have - * the same type of operand (ie code, data,register) + * the same type of operand (i.e., code, data,register) * @param program1 Program containing function1 - * @param function1 Function to compare with function2 + * @param address1 Function to compare with function2 * @param program2 Program containing function2 - * @param function2 Function to compare with function1 + * @param address2 Function to compare with function1 * @param monitor Allows user to cancel * @return true if all operands between the two functions match and false otherwise. - * @throws CancelledException + * @throws CancelledException if cancelled */ private boolean haveEquivalentOperands(Program program1, Address address1, Program program2, Address address2, TaskMonitor monitor) throws CancelledException { @@ -703,7 +704,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } // This should never happen but if it does then throw an error because that means something - // weird is happening like the action updating the source and destination match lengths + // weird is happening like the action updating the source and destination match lengths // didn't do it correctly. if (func1InstIter.hasNext() || func2InstIter.hasNext()) { throw new AssertException( @@ -716,11 +717,11 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * Determine if the given instructions which have at least one differing operand, have equivalent - * operand types. If operand type is a scalar, is it the same scalar. + * operand types. If operand type is a scalar, is it the same scalar. * @param inst1 Instruction 1 * @param inst2 Instruction 2 * @param operandsThatDiffer Array of indexes of operands that differ - * @return true if all operands in the two instructions are equivalent types and scalars are equal, + * @return true if all operands in the two instructions are equivalent types and scalars are equal, * else return false */ private boolean haveEquivalentOperands(Instruction inst1, Instruction inst2, @@ -761,14 +762,14 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * Method to determine if two functions with exactly the same instructions also have exactly the - * same operands. + * same operands. * @param program1 Program that contains function1 * @param function1 Function to compare with function2 - * @param program2 Program that contains function2 (can be same or different than program1) + * @param program2 Program that contains function2 (can be same or different than program1) * @param function2 Function to compare with function1 - * @param monitor + * @param monitor the monitor * @return true if two functions have no operand differences, else returns false - * @throws CancelledException + * @throws CancelledException if cancelled */ private boolean haveSameOperands(Program program1, Function function1, Program program2, Function function2, TaskMonitor monitor) throws CancelledException { @@ -795,7 +796,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { } } // This should never happen but if it does then throw an error because that means something - // weird is happening like the action updating the source and destination match lengths + // weird is happening like the action updating the source and destination match lengths // didn't do it correctly. if (sourceFuncCodeUnitIter.hasNext() || destFuncCodeUnitIter.hasNext()) { throw new AssertException( @@ -807,14 +808,13 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { /** * Remove addresses from a set of function starting addresses if any functions have all matching * operands. - * @param program Program containing functions we are interested in deduping. - * @param addresses Set of function start addresses. - * @param functionManager Function manager to get functions using their start addresses. - * @param monitor - * @return Set of addresses of deduped function bytes. - * @throws CancelledException + * @param program the program + * @param addresses Set of function start addresses + * @param monitor the monitor + * @return Set of addresses of deduped function bytes + * @throws CancelledException if cancelled */ - public Set
dedupeMatchingFunctions(Program program, Set
addresses, + public Set
dedupMatchingFunctions(Program program, Set
addresses, TaskMonitor monitor) throws CancelledException { FunctionManager functionManager = program.getFunctionManager(); @@ -824,7 +824,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand { List
list = new ArrayList<>(addresses); - // Compare 0 to 1, 0 to 2, ... 0 to j-1, 1 to 2, 1 to 3, ... 1- j-1, .... i-2 to j-1 + // Compare 0 to 1, 0 to 2, ... 0 to j-1, 1 to 2, 1 to 3, ... 1- j-1, .... i-2 to j-1 for (int i = 0; i < list.size(); i++) { Address address1 = list.get(i); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/AddressCorrelatorManager.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/AddressCorrelatorManager.java index caa305b403..14eb803346 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/AddressCorrelatorManager.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/AddressCorrelatorManager.java @@ -54,7 +54,7 @@ public class AddressCorrelatorManager { } private void initializeAddressCorrelators(VTController controller) { - // Put the CodeCompare address correlator that uses match info to handle exact matches + // Put the CodeCompare address correlator that uses match info to handle exact matches // so it is first in the list. correlatorList.add(new ExactMatchAddressCorrelator(controller)); correlatorList.addAll(initializeAddressCorrelators()); diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTControllerImpl.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTControllerImpl.java index 8400d00557..e8bcdbd358 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTControllerImpl.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTControllerImpl.java @@ -73,8 +73,10 @@ public class VTControllerImpl vtOptions = plugin.getTool().getOptions(VERSION_TRACKING_OPTIONS_NAME); vtOptions.addOptionsChangeListener(this); folderListener = new MyFolderListener(); - plugin.getTool().getProject().getProjectData().addDomainFolderChangeListener( - folderListener); + plugin.getTool() + .getProject() + .getProjectData() + .addDomainFolderChangeListener(folderListener); } @Override @@ -98,8 +100,8 @@ public class VTControllerImpl return; } try { - VTSessionDB newSession = (VTSessionDB) domainFile.getDomainObject(this, true, true, - TaskMonitorAdapter.DUMMY_MONITOR); + VTSessionDB newSession = + (VTSessionDB) domainFile.getDomainObject(this, true, true, TaskMonitor.DUMMY); doOpenSession(newSession); } catch (VersionException e) { @@ -476,9 +478,11 @@ public class VTControllerImpl return; } + WrapperTask wrappedTask = new WrapperTask(task); + int matchSetTransactionID = session.startTransaction(task.getTaskTitle()); try { - new TaskLauncher(task, getParentComponent()); + new TaskLauncher(wrappedTask, getParentComponent()); } finally { session.endTransaction(matchSetTransactionID, task.wasSuccessfull()); @@ -486,7 +490,6 @@ public class VTControllerImpl if (task.hasErrors()) { task.showErrors(); } - } private boolean hasTransactionsOpen(Program program, VtTask task) { @@ -527,9 +530,45 @@ public class VTControllerImpl plugin.setSelectionInDestinationTool(destinationSet); } -//================================================================================================== -// Inner Classes -//================================================================================================== + @Override + public Symbol getDestinationSymbol(VTAssociation association) { + if (session == null) { + return null; + } + Address address = association.getDestinationAddress(); + Symbol symbol = destinationSymbolCache.get(address); + if (symbol == null) { + Program program = session.getDestinationProgram(); + symbol = program.getSymbolTable().getPrimarySymbol(address); + destinationSymbolCache.put(address, symbol); + } + return symbol; + } + + @Override + public Symbol getSourceSymbol(VTAssociation association) { + if (session == null) { + return null; + } + Address address = association.getSourceAddress(); + Symbol symbol = sourceSymbolCache.get(address); + if (symbol == null) { + Program program = session.getSourceProgram(); + symbol = program.getSymbolTable().getPrimarySymbol(address); + sourceSymbolCache.put(address, symbol); + } + return symbol; + } + + @Override + public ColorizingService getSourceColorizingService() { + return plugin.getSourceColorizingService(); + } + + @Override + public ColorizingService getDestinationColorizingService() { + return plugin.getDestinationColorizingService(); + } @Override public void transactionEnded(DomainObjectAdapterDB domainObj) { @@ -552,6 +591,10 @@ public class VTControllerImpl // don't care } +//================================================================================================== +// Inner Classes +//================================================================================================== + private class MyFolderListener extends DomainFolderListenerAdapter { @Override @@ -571,8 +614,7 @@ public class VTControllerImpl } Program newProgram; try { - newProgram = (Program) file.getDomainObject(this, false, false, - TaskMonitorAdapter.DUMMY_MONITOR); + newProgram = (Program) file.getDomainObject(this, false, false, TaskMonitor.DUMMY); } catch (Exception e) { Msg.showError(this, getParentComponent(), "Error opening program " + file, e); @@ -630,43 +672,31 @@ public class VTControllerImpl } } - @Override - public Symbol getDestinationSymbol(VTAssociation association) { - if (session == null) { - return null; - } - Address address = association.getDestinationAddress(); - Symbol symbol = destinationSymbolCache.get(address); - if (symbol == null) { - Program program = session.getDestinationProgram(); - symbol = program.getSymbolTable().getPrimarySymbol(address); - destinationSymbolCache.put(address, symbol); - } - return symbol; - } + /** + * A task wrapper that allows us to set the currently in-use task monitor for VT APIs to use + * when they are not explicitly passed a task monitor. + */ + private class WrapperTask extends Task { - @Override - public Symbol getSourceSymbol(VTAssociation association) { - if (session == null) { - return null; - } - Address address = association.getSourceAddress(); - Symbol symbol = sourceSymbolCache.get(address); - if (symbol == null) { - Program program = session.getSourceProgram(); - symbol = program.getSymbolTable().getPrimarySymbol(address); - sourceSymbolCache.put(address, symbol); - } - return symbol; - } + private final Task delegate; - @Override - public ColorizingService getSourceColorizingService() { - return plugin.getSourceColorizingService(); - } + WrapperTask(Task t) { + super(t.getTaskTitle(), t.canCancel(), t.hasProgress(), t.isModal(), + t.getWaitForTaskCompleted()); + this.delegate = t; + } + + @Override + public void run(TaskMonitor monitor) throws CancelledException { + + VTTaskMonitor.setTaskMonitor(monitor); + try { + delegate.run(monitor); + } + finally { + VTTaskMonitor.setTaskMonitor(null); + } + } - @Override - public ColorizingService getDestinationColorizingService() { - return plugin.getDestinationColorizingService(); } } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTTaskMonitor.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTTaskMonitor.java new file mode 100644 index 0000000000..b6f7a1a94e --- /dev/null +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/plugin/VTTaskMonitor.java @@ -0,0 +1,50 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.feature.vt.gui.plugin; + +import ghidra.util.task.TaskMonitor; + +/** + * A class that allows the VT application to track the currently in-use task monitor. The + * {@link VTController} will set this value each time it runs a VT task via + * {@link VTController#runVTTask(ghidra.feature.vt.gui.task.VtTask)}. + * + *

In general, all background tasks should take a task monitor. However, some parts of the + * VT API perform time-consuming work that does not require a task monitor. This exposes a + * design flaw of the API. However, rather than add the task monitor to most API interfaces of + * VT, we use this class to allow these poorly designed APIs to use the currently running task + * monitor. + * + *

When using this monitor, it is expected that the client uses it only to check the state + * of the cancelled flag. Other monitor operations, such as updating progress and setting + * messages, are discouraged. + */ +public class VTTaskMonitor { + + private static TaskMonitor monitor = TaskMonitor.DUMMY; + + static void setTaskMonitor(TaskMonitor m) { + monitor = TaskMonitor.dummyIfNull(m); + } + + /** + * Returns the current in-use task monitor or a dummy monitor if there is no task running + * @return the monitor + */ + public static TaskMonitor getTaskMonitor() { + return monitor; + } +} diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationTableModel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationTableModel.java index d8e23c403c..682a1125b0 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationTableModel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/functionassociation/VTFunctionAssociationTableModel.java @@ -116,7 +116,7 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel accumulator, TaskMonitor monitor) throws CancelledException { - LongIterator it = LongIterator.EMPTY; - if (getProgram() != null) { - FunctionManager functionManager = getProgram().getFunctionManager(); - it = new FunctionKeyIterator(functionManager); - - monitor.initialize(getKeyCount()); - while (it.hasNext()) { - monitor.incrementProgress(1); - monitor.checkCanceled(); - long key = it.next(); - - Function f = functionManager.getFunction(key); - if (!f.isThunk()) { - accumulator.add(new VTFunctionRowObject(new FunctionAssociationInfo(key))); - } - } + if (program == null) { + return; } + monitor.initialize(getKeyCount()); + FunctionManager functionManager = getProgram().getFunctionManager(); + LongIterator it = new FunctionKeyIterator(functionManager); + while (it.hasNext()) { + monitor.incrementProgress(1); + monitor.checkCanceled(); + long key = it.next(); + Function f = functionManager.getFunction(key); + if (!f.isThunk()) { + accumulator.add(new VTFunctionRowObject(new FunctionAssociationInfo(key))); + } + } } @Override @@ -377,10 +374,9 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel impliedMatches = - ImpliedMatchUtils.findImpliedMatches(controller, source, destination, session, - correlator, TaskMonitorAdapter.DUMMY_MONITOR); - processAssociationAccepted(impliedMatches); - } - catch (Exception e) { - Msg.error(this, "Error auto-creating implied matches for association: " + - association); - } + if (!autoCreateImpliedMatches) { + return; + } + + try { + TaskMonitor monitor = VTTaskMonitor.getTaskMonitor(); + Set impliedMatches = ImpliedMatchUtils.findImpliedMatches( + controller, source, destination, session, correlator, monitor); + processAssociationAccepted(impliedMatches); + } + catch (CancelledException e) { + Msg.info(this, "User cancelled finding implied matches when accepting an assocation"); } } /** * When a match is accepted either create associated implied matches or if a match already * exists, increase the vote count - * @param impliedMatches The implied matches set to either create or increase vote count + * @param impliedMatches The implied matches set to either create or increase vote count */ private void processAssociationAccepted(Set impliedMatches) { for (VTImpliedMatchInfo impliedMatch : impliedMatches) { @@ -112,15 +114,20 @@ public class ImpliedMatchAssociationHook implements AssociationHook, VTControlle if (source == null || destination == null) { return; } + + if (!autoCreateImpliedMatches) { + return; + } + AddressCorrelatorManager correlator = controller.getCorrelator(); try { - Set impliedMatches = - ImpliedMatchUtils.findImpliedMatches(controller, source, destination, session, - correlator, TaskMonitorAdapter.DUMMY_MONITOR); + TaskMonitor monitor = VTTaskMonitor.getTaskMonitor(); + Set impliedMatches = ImpliedMatchUtils.findImpliedMatches( + controller, source, destination, session, correlator, monitor); processAssociationCleared(impliedMatches); } catch (CancelledException e) { - // can't happen - using dummy monitor + Msg.info(this, "User cancelled finding implied matches when clearing an assocation"); } } @@ -182,7 +189,7 @@ public class ImpliedMatchAssociationHook implements AssociationHook, VTControlle @Override public void sessionUpdated(DomainObjectChangedEvent ev) { - // don't care + // don't care } } diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchSourceTableModel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchSourceTableModel.java index 17abbb24d0..482b3e83bd 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchSourceTableModel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/provider/onetomany/VTMatchSourceTableModel.java @@ -74,20 +74,22 @@ public class VTMatchSourceTableModel extends VTMatchOneToManyTableModel { throws CancelledException { List matchSets = session.getMatchSets(); VTAssociationManager associationManager = session.getAssociationManager(); - if (address != null && associationManager != null) { - Collection associations = - associationManager.getRelatedAssociationsBySourceAddress(address); - monitor.initialize(associations.size()); - for (VTAssociation vtAssociation : associations) { + if (address == null || associationManager == null) { + return; + } + + Collection associations = + associationManager.getRelatedAssociationsBySourceAddress(address); + monitor.initialize(associations.size()); + for (VTAssociation vtAssociation : associations) { + monitor.checkCanceled(); + monitor.incrementProgress(1); + for (VTMatchSet matchSet : matchSets) { monitor.checkCanceled(); - monitor.incrementProgress(1); - for (VTMatchSet matchSet : matchSets) { + Collection matches = matchSet.getMatches(vtAssociation); + for (VTMatch match : matches) { monitor.checkCanceled(); - Collection matches = matchSet.getMatches(vtAssociation); - for (VTMatch match : matches) { - monitor.checkCanceled(); - accumulator.add(match); - } + accumulator.add(match); } } } @@ -96,14 +98,14 @@ public class VTMatchSourceTableModel extends VTMatchOneToManyTableModel { @Override protected Comparator createSortComparator(int columnIndex) { - // - // Unusual Code Alert!: since we define some of our columns for this table model as - // off/hidden by default, we cannot rely on the ordinal of the - // ColumnDescriptor to match the 'columnIndex' parameter. Instead, + // + // Unusual Code Alert!: since we define some of our columns for this table model as + // off/hidden by default, we cannot rely on the ordinal of the + // ColumnDescriptor to match the 'columnIndex' parameter. Instead, // we have to lookup the model's index for the given ColumnDescriptor - // and test that value against the index parameter (which is the + // and test that value against the index parameter (which is the // value used by the column model. - // + // int destinationAddressColumnIndex = getColumnIndex(DestinationAddressTableColumn.class); if (destinationAddressColumnIndex == columnIndex) { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/task/VtTask.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/task/VtTask.java index ece6c85d1a..7c8ffcf136 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/task/VtTask.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/task/VtTask.java @@ -64,8 +64,8 @@ public abstract class VtTask extends Task { /** * Determine if session events should be suspended during task execution. - * This can improve performance during task execution at the expense of bulk - * table updates at task completion. Method return false by default. + * This can improve performance during task execution at the expense of bulk + * table updates at task completion. Method return false by default. * If not constructed with a session this method is not used. * @return true if events should be suspended */ @@ -143,7 +143,6 @@ public abstract class VtTask extends Task { /** * Returns an HTML formated error message - * @param messagePrefix the error message header * @return an HTML formatted error message */ public String getErrorDetails() { diff --git a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java index 81eb4fb7d3..adb8b489a7 100644 --- a/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java +++ b/Ghidra/Features/VersionTracking/src/main/java/ghidra/feature/vt/gui/util/AbstractVTMatchTableModel.java @@ -16,8 +16,7 @@ */ package ghidra.feature.vt.gui.util; -import static ghidra.feature.vt.gui.provider.matchtable.MultipleLabelsRenderer.MultipleLabelsRendererType.DESTINATION; -import static ghidra.feature.vt.gui.provider.matchtable.MultipleLabelsRenderer.MultipleLabelsRendererType.SOURCE; +import static ghidra.feature.vt.gui.provider.matchtable.MultipleLabelsRenderer.MultipleLabelsRendererType.*; import static ghidra.feature.vt.gui.util.MungedAssocationAndMarkupItemStatus.*; import java.awt.Color; @@ -102,7 +101,7 @@ public abstract class AbstractVTMatchTableModel extends AddressBasedTableModel identicalSourceAddrs = new ArrayList<>(); @@ -457,7 +452,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe String correlator = "Duplicate Function Instructions Match"; - // Checks that the duplicate identical ones are available matches + // Checks that the duplicate identical ones are available matches for (Address sourceAddr : identicalSourceAddrs) { for (Address destAddr : identicalDestAddrs) { assertAvailableMatch(session, correlator, sourceAddr.toString(), @@ -516,7 +511,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe sourceProgram = env.getProgram(TEST_SOURCE_PROGRAM_NAME); destinationProgram = env.getProgram(TEST_DESTINATION_PROGRAM_NAME); - // Create three functions in both the source and destination program with matching + // Create three functions in both the source and destination program with matching // instructions but different constant operands and a call with different offset so that // the exact bytes matcher doesn't find it first but it still has the same instructions @@ -563,7 +558,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe env.showTool(); controller = env.getVTController(); - // run auto VT + // run auto VT runAutoVTCommand(1.0, 10.0); // Test to make sure that they weren't matched by something else first so we can @@ -585,8 +580,8 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe /* * This tests whether the markup from a function gets applied to the destination function - * for the case where all instructions line up exactly between both functions. It tests - * the apply markup path for unique matches. + * for the case where all instructions line up exactly between both functions. It tests + * the apply markup path for unique matches. */ @Test public void testMarkup_AllMarkupShouldApply_UniqueMatch() throws Exception { @@ -642,8 +637,8 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe /* * This tests whether the markup from a function gets applied to the destination function - * for the case where all instructions line up exactly between both functions. It tests - * the apply markup path for duplicate matches. + * for the case where all instructions line up exactly between both functions. It tests + * the apply markup path for duplicate matches. */ @Test public void testMarkup_AllMarkupShouldApply_DuplicateMatch() throws Exception { @@ -708,13 +703,13 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe // Override the setup to switch the source and destination programs. // This is because the destination program has a sample match where the length - // of a matching function is greater than the one in the source program and + // of a matching function is greater than the one in the source program and // it is needed to test this case. sourceProgram = env.getProgram(TEST_DESTINATION_PROGRAM_NAME); destinationProgram = env.getProgram(TEST_SOURCE_PROGRAM_NAME); - // Now put some markup in the new source function to test such that there is a + // Now put some markup in the new source function to test such that there is a // comment at each code unit called Test Comment "n" where n is a one up value starting // at 0 Listing sourceListing = sourceProgram.getListing(); @@ -738,7 +733,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe env.showTool(); controller = env.getVTController(); - // Now run the AutoVT command with lower confidence thresholds to allow the match we want to + // Now run the AutoVT command with lower confidence thresholds to allow the match we want to // test in as a match boolean success = runAutoVTCommand(0.5, 1.0); assertTrue("Auto Version Tracking Command failed to run", success); @@ -748,15 +743,16 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe assertAcceptedMatch(session, correlator, "0x4118c0", "0x4118f0"); // Check that the expected comments were moved over - // The case we have is where the source function has a chunk of five code units in the - // middle that isn't in the destination function. We need to test that the top set of code + // The case we have is where the source function has a chunk of five code units in the + // middle that isn't in the destination function. We need to test that the top set of code // units have comments Test Comment 0-n and then skip the five then test the rest that // should match until the end of the function Listing destListing = destinationProgram.getListing(); // Get the first set of comments that should line up and test them first - AddressSet topAddressSet = destinationProgram.getAddressFactory().getAddressSet( - addr("0x4118f0", destinationProgram), addr("0x4119ad", destinationProgram)); + AddressSet topAddressSet = destinationProgram.getAddressFactory() + .getAddressSet(addr("0x4118f0", destinationProgram), + addr("0x4119ad", destinationProgram)); CodeUnitIterator codeUnitsDestTop = destListing.getCodeUnits(topAddressSet, true); numComments = 0; @@ -771,9 +767,10 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe assertEquals(null, destListing.getComment(CodeUnit.EOL_COMMENT, addr("0x4119af", destinationProgram))); - // Now get the bottom section - AddressSet bottomAddressSet = destinationProgram.getAddressFactory().getAddressSet( - addr("0x4119b1", destinationProgram), addr("0x4119e9", destinationProgram)); + // Now get the bottom section + AddressSet bottomAddressSet = destinationProgram.getAddressFactory() + .getAddressSet(addr("0x4119b1", destinationProgram), + addr("0x4119e9", destinationProgram)); CodeUnitIterator codeUnitsDestBottom = destListing.getCodeUnits(bottomAddressSet, true); // The five comments from the source should not get moved over so skip those and test that @@ -805,10 +802,14 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe info.setConfidenceScore(confidence); VTScore score = new VTScore(1.0); info.setSimilarityScore(score); - long sourceLen = sourceProgram.getFunctionManager().getFunctionAt( - sourceAddress).getBody().getNumAddresses(); - long destLen = destinationProgram.getFunctionManager().getFunctionAt( - destinationAddress).getBody().getNumAddresses(); + long sourceLen = sourceProgram.getFunctionManager() + .getFunctionAt(sourceAddress) + .getBody() + .getNumAddresses(); + long destLen = destinationProgram.getFunctionManager() + .getFunctionAt(destinationAddress) + .getBody() + .getNumAddresses(); info.setSourceLength((int) sourceLen); info.setDestinationLength((int) destLen); matchSet.addMatch(info); @@ -934,7 +935,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe List matchSets = vtSession.getMatchSets(); for (VTMatchSet matchSet : matchSets) { - // Ignore the matchSet with the given correlator name + // Ignore the matchSet with the given correlator name if (matchSet.getProgramCorrelatorInfo().getName().equals(correlatorName)) { continue; } @@ -994,7 +995,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe assertBlockedMatch(vtSession, correlator, "0x412330", "0x4122e0"); } - // These are the matches when score is .999999999 and log 10 conf threshold is 2.0 + // These are the matches when score is .999999999 and log 10 conf threshold is 2.0 private void assertCombinedReferenceMatchStatusesHigherScoreAndConfidence(VTSession vtSession) { String correlator = "Combined Function and Data Reference Match"; diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/Task.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/Task.java index 10141b8be1..afb6a5c11f 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/Task.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/task/Task.java @@ -108,11 +108,19 @@ public abstract class Task implements MonitoredRunnable { return SwingConstants.CENTER; } + /** + * Returns the value of the 'wait for completed task' boolean that was passed into this class + * @return the value + */ + public boolean getWaitForTaskCompleted() { + return waitForTaskCompleted; + } + /** * When an object implementing interface Runnable is used to create a thread, * starting the thread causes the object's run method to be called in that * separately executing thread. - * + * * @param monitor the task monitor */ @Override @@ -176,13 +184,13 @@ public abstract class Task implements MonitoredRunnable { /** * This is the method that will be called to do the work - * + * *

Note: The run(TaskMonitor) method should not make any calls directly * on Swing components, as these calls are not thread safe. Place Swing * calls in a Runnable, then call {@link Swing#runLater(Runnable)} or * {@link Swing#runNow(Runnable)}to schedule the Runnable inside of * the AWT Event Thread. - * + * * @param monitor The TaskMonitor that will monitor the executing Task * @throws CancelledException if the task is cancelled. Subclasses can trigger this exception * by calling {@link TaskMonitor#checkCanceled()}. This allows