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):
*
* - Exact Symbol Name correlator
* - Exact Data correlator
- * - Exact Function Byte correlator
+ * - Exact Function Byte correlator
* - Exact Function Instruction correlator
* - Exact Function Mnemonic correlator
*
- *
+ *
* 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