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
This commit is contained in:
dragonmacher 2021-11-10 15:16:12 -05:00
parent 53e4f2ff9b
commit e55550edfd
23 changed files with 541 additions and 401 deletions

View File

@ -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()));

View File

@ -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
*
*
* <p>
* 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?
*
*
* <p>
* 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));

View File

@ -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<ROW_TYPE> extends
ThreadedTableModel<ROW_TYPE, Program> implements ProgramTableModel {
public abstract class GhidraProgramTableModel<ROW_TYPE>
extends ThreadedTableModel<ROW_TYPE, Program> implements ProgramTableModel {
protected Program program;
@ -47,9 +46,10 @@ public abstract class GhidraProgramTableModel<ROW_TYPE> 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();

View File

@ -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*',
]
}

View File

@ -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<Address> acceptedSourceAssociations = new HashSet<>();
private Set<Address> acceptedDestinationAssociations = new HashSet<>();
private VTMatchMarkupItemTableDBAdapter markupItemTableAdapter;
private DBObjectCache<MarkupItemStorageDB> markupItemCache;
private List<AssociationHook> 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<MarkupItemStorageDB> 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<DBRecord> 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<VTAssociation> getRelatedAssociationsBySourceAddress(Address sourceAddress) {
lock.acquire();
try {
long sourceID = session.getLongFromSourceAddress(sourceAddress);
long sourceId = session.getLongFromSourceAddress(sourceAddress);
Set<DBRecord> relatedRecords =
associationTableAdapter.getRelatedAssociationRecordsBySourceAddress(sourceID);
associationTableAdapter.getRelatedAssociationRecordsBySourceAddress(sourceId);
List<VTAssociation> 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<DBRecord> relatedRecords =
associationTableAdapter.getRelatedAssociationRecordsByDestinationAddress(
destinationID);
long destinationId = session.getLongFromDestinationAddress(destinationAddress);
Set<DBRecord> relatedRecords = associationTableAdapter
.getRelatedAssociationRecordsByDestinationAddress(destinationId);
List<VTAssociation> 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<DBRecord> relatedRecords =
associationTableAdapter.getRelatedAssociationRecordsBySourceAndDestinationAddress(
sourceID, destinationID);
sourceId, destinationId);
List<VTAssociation> associations = new ArrayList<>();
for (DBRecord record : relatedRecords) {
associations.add(getAssociationForRecord(record));
@ -566,15 +598,15 @@ public class AssociationDatabaseManager implements VTAssociationManager {
}
private Set<VTAssociationDB> getRelatedAssociations(VTAssociationDB association) {
long sourceID = session.getLongFromSourceAddress(association.getSourceAddress());
long destinationID =
long sourceId = session.getLongFromSourceAddress(association.getSourceAddress());
long destinationId =
session.getLongFromDestinationAddress(association.getDestinationAddress());
Set<VTAssociationDB> relatedAssociaitons = new HashSet<>();
try {
Set<DBRecord> 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();
}
}

View File

@ -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<DBRecord> getRelatedAssociationRecordsBySourceAddress(long sourceAddressID)
throws IOException;
abstract Set<DBRecord> getRelatedAssociationRecordsByDestinationAddress(long destinationAddressID)
throws IOException;
abstract Set<DBRecord> getRelatedAssociationRecordsByDestinationAddress(
long destinationAddressID) throws IOException;
abstract void updateRecord(DBRecord record) throws IOException;

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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);

View File

@ -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<VTAssociation> 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}
* <b>or</b> 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}
* <b>or</b> 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();

View File

@ -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<VTAssociation> 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<VTAssociation> getRelatedAssociationsBySourceAndDestinationAddress(
Address sourceAddress, Address destinationAddress);
}

View File

@ -40,30 +40,30 @@ import ghidra.util.task.TaskMonitor;
import util.CollectionUtils;
/**
* This command runs all of the <b>exact</b> {@link VTProgramCorrelator}s that return
* This command runs all of the <b>exact</b> {@link VTProgramCorrelator}s that return
* unique matches (ie only one of each match is found in each program):
* <ol>
* <li> Exact Symbol Name correlator </li>
* <li> Exact Data correlator </li>
* <li> Exact Function Byte correlator </li>
* <li> Exact Function Byte correlator </li>
* <li> Exact Function Instruction correlator </li>
* <li> Exact Function Mnemonic correlator </li>
* </ol>
*
*
* <P> 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.
*
* <P> 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.
*
* <P> 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.
*
*
* <P> 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.
*
* <P> 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.
*
* <P> 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<VTMatch> 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<VTMatch> 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<VTMatch> 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<Address> sourceAddresses = getSourceAddressesFromMatches(relatedMatches, monitor);
Set<Address> 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<Address> destAddresses =
getDestinationAddressesFromMatches(relatedMatches, monitor);
Set<Address> 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<VTMatch> 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<VTMatch> 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<VTMatch> getMatchesWithEquivalentOperands(Set<VTMatch> matches,
Address sourceAddress, Set<Address> 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<VTMatch> getRelatedMatches(VTMatch match, Collection<VTMatch> 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<VTMatch> matchSet, Set<VTMatch> 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<Address> getSourceAddressesFromMatches(Set<VTMatch> 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<Address> getDestinationAddressesFromMatches(Set<VTMatch> 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<VTMatch> getMatches(Set<VTMatch> matches, Set<Address> sourceAddresses,
Set<Address> 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<Address> dedupeMatchingFunctions(Program program, Set<Address> addresses,
public Set<Address> dedupMatchingFunctions(Program program, Set<Address> addresses,
TaskMonitor monitor) throws CancelledException {
FunctionManager functionManager = program.getFunctionManager();
@ -824,7 +824,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
List<Address> 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);

View File

@ -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());

View File

@ -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();
}
}

View File

@ -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)}.
*
* <p>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.
*
* <p>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;
}
}

View File

@ -116,7 +116,7 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel<VTFunctionR
addObject(new VTFunctionRowObject(getInitializedFunctionInfo(function)));
// assumption: added functions did not exist and thus could not have been the basis for
// a match. Thus, we don't have to add the new function to the
// a match. Thus, we don't have to add the new function to the
// collection of matched functions.
}
@ -129,8 +129,8 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel<VTFunctionR
associationManager.getRelatedAssociationsBySourceAddress(function.getEntryPoint());
}
else {
associations = associationManager.getRelatedAssociationsByDestinationAddress(
function.getEntryPoint());
associations = associationManager
.getRelatedAssociationsByDestinationAddress(function.getEntryPoint());
}
boolean isInAssociation = !associations.isEmpty();
@ -245,7 +245,6 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel<VTFunctionR
Function getFunction(int row) {
VTFunctionRowObject rowObject = getRowObject(row);
FunctionAssociationInfo info = rowObject.getInfo();
Program program = getProgram();
FunctionManager manager = program.getFunctionManager();
return manager.getFunction(info.getFunctionID());
}
@ -264,25 +263,23 @@ class VTFunctionAssociationTableModel extends AddressBasedTableModel<VTFunctionR
@Override
protected void doLoad(Accumulator<VTFunctionRowObject> 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<VTFunctionR
}
monitor.setMessage("Setting filter data...");
monitor.initialize(data.size());
for (int row = 0; row < data.size(); row++) {
for (VTFunctionRowObject rowObject : data) {
monitor.checkCanceled();
monitor.incrementProgress(1);
VTFunctionRowObject rowObject = data.get(row);
FunctionAssociationInfo info = rowObject.getInfo();
Long functionID = info.getFunctionID();
info.setFilterData(matchSet.contains(functionID), acceptedSet.contains(functionID));

View File

@ -27,7 +27,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitorAdapter;
import ghidra.util.task.TaskMonitor;
public class ImpliedMatchAssociationHook implements AssociationHook, VTControllerListener {
private VTSession session;
@ -66,25 +66,27 @@ public class ImpliedMatchAssociationHook implements AssociationHook, VTControlle
if (source == null || destination == null) {
return;
}
AddressCorrelatorManager correlator = controller.getCorrelator();
if (autoCreateImpliedMatches) {
try {
Set<VTImpliedMatchInfo> 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<VTImpliedMatchInfo> 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<VTImpliedMatchInfo> 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<VTImpliedMatchInfo> impliedMatches =
ImpliedMatchUtils.findImpliedMatches(controller, source, destination, session,
correlator, TaskMonitorAdapter.DUMMY_MONITOR);
TaskMonitor monitor = VTTaskMonitor.getTaskMonitor();
Set<VTImpliedMatchInfo> 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
}
}

View File

@ -74,20 +74,22 @@ public class VTMatchSourceTableModel extends VTMatchOneToManyTableModel {
throws CancelledException {
List<VTMatchSet> matchSets = session.getMatchSets();
VTAssociationManager associationManager = session.getAssociationManager();
if (address != null && associationManager != null) {
Collection<VTAssociation> associations =
associationManager.getRelatedAssociationsBySourceAddress(address);
monitor.initialize(associations.size());
for (VTAssociation vtAssociation : associations) {
if (address == null || associationManager == null) {
return;
}
Collection<VTAssociation> 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<VTMatch> matches = matchSet.getMatches(vtAssociation);
for (VTMatch match : matches) {
monitor.checkCanceled();
Collection<VTMatch> 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<VTMatch> 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) {

View File

@ -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() {

View File

@ -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<V
FilterShortcutState state = filter.getFilterShortcutState();
if (state == FilterShortcutState.NEVER_PASSES) {
// we have found a filter that will never pass; signal that all filtering will
// fail by returning null (the client of this code must know that: null is a
// fail by returning null (the client of this code must know that: null is a
// special case and that no filtering is required; all items will fail the filter)
return null;
}
@ -212,8 +211,8 @@ public abstract class AbstractVTMatchTableModel extends AddressBasedTableModel<V
@Override
public boolean equals(Object obj) {
// For now we don't support equals(); if this filter gets re-created,
// then the table must be re-filtered. If we decide to implement this method, then
// For now we don't support equals(); if this filter gets re-created,
// then the table must be re-filtered. If we decide to implement this method, then
// we must also implement equals() on the filters used by this filter.
return this == obj;
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -47,8 +47,7 @@ import ghidra.util.task.TaskMonitor;
public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTest {
private static final String TEST_SOURCE_PROGRAM_NAME = "VersionTracking/WallaceSrc";
private static final String TEST_DESTINATION_PROGRAM_NAME =
"VersionTracking/WallaceVersion2";
private static final String TEST_DESTINATION_PROGRAM_NAME = "VersionTracking/WallaceVersion2";
private VTTestEnv env;
private VTController controller;
@ -56,10 +55,6 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
private ProgramDB destinationProgram;
private VTSessionDB session;
public VTAutoVersionTrackingTest() {
super();
}
@Before
public void setUp() throws Exception {
@ -93,17 +88,17 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
assertTrue("Auto Version Tracking Command failed to run", success);
// verify that the default options are what we expect
// if this assert fails then the follow-on tests will probably fail
// if this assert fails then the follow-on tests will probably fail
assertCorrectOptionValues(session, "0.999999999", "10.0");
// verify that given the above verified conditions the
// verify that given the above verified conditions the
// exact unique correlators (which have their own tests to verify which matches are
// correct) return the expected number of possible matches and accepted matches
// since they are exact and unique and this number is already known based on other tests
// this is just verifying that what we expect to happen is happening for debug purposes
// this is just verifying that what we expect to happen is happening for debug purposes
// in case something is changed in the future that would alter these numbers.
// We need to know that these are as expected before testing the non-exact/unique correlator
// results that depend on these answers.
// results that depend on these answers.
assertCorrectMatchCountAndAcceptedMatchCount(session, "Exact Symbol Name Match", 203, 203);
assertCorrectMatchCountAndAcceptedMatchCount(session, "Exact Data Match", 125, 125);
assertCorrectMatchCountAndAcceptedMatchCount(session, "Exact Function Bytes Match", 18, 18);
@ -135,7 +130,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
/*
* This tests auto version tracking with the default score/confidence values so some of the
* matches are probably not good matches. This was just to make sure that the expected
* matches are probably not good matches. This was just to make sure that the expected
* results happen in this case and to show difference between this and the more cautious ones.
*/
@Test
@ -149,23 +144,23 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
env.showTool();
controller = env.getVTController();
// Score 0.5 and conf threshold 1.0 allow similarity scores of higher than 0.5 for combined
// Score 0.5 and conf threshold 1.0 allow similarity scores of higher than 0.5 for combined
// reference correlator and 1.0 and higher for the log 10 confidence score
boolean success = runAutoVTCommand(0.5, 1.0);
assertTrue("Auto Version Tracking Command failed to run", success);
// verify that the default options are what we expect
// if this assert fails then the follow-on tests will probably fail
// if this assert fails then the follow-on tests will probably fail
assertCorrectOptionValues(session, "0.5", "1.0");
// verify that given the above verified conditions the
// verify that given the above verified conditions the
// exact unique correlators (which have their own tests to verify which matches are
// correct) return the expected number of possible matches and accepted matches
// since they are exact and unique and this number is already known based on other tests
// this is just verifying that what we expect to happen is happening for debug purposes
// this is just verifying that what we expect to happen is happening for debug purposes
// in case something is changed in the future that would alter these numbers.
// We need to know that these are as expected before testing the non-exact/unique correlator
// results that depend on these answers.
// results that depend on these answers.
assertCorrectMatchCountAndAcceptedMatchCount(session, "Exact Symbol Name Match", 203, 203);
assertCorrectMatchCountAndAcceptedMatchCount(session, "Exact Data Match", 125, 125);
assertCorrectMatchCountAndAcceptedMatchCount(session, "Exact Function Bytes Match", 18, 18);
@ -208,7 +203,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
VTMatch match = createMatch(addr("0x000411860", sourceProgram),
addr("0x00411830", destinationProgram), false);
//make a second match that conflicts with first match and accept it which will cause the
//make a second match that conflicts with first match and accept it which will cause the
// first match to be blocked
VTMatch match2 = createMatch(addr("0x4117c0", sourceProgram),
addr("0x00411830", destinationProgram), true);
@ -236,7 +231,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 register operands
byte[] bytes1 = { (byte) 0x8b, (byte) 0xff, (byte) 0x55, (byte) 0x8b, (byte) 0xec,
(byte) 0x33, (byte) 0xc0, (byte) 0x5d, (byte) 0x90, (byte) 0xc3 }; //XOR EAX,EAX;
@ -258,10 +253,10 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
env.showTool();
controller = env.getVTController();
// run auto VT
// run auto VT
runAutoVTCommand(1.0, 10.0);
// Now test that the correct matches were created based on the duplicate functions we created
// Now test that the correct matches were created based on the duplicate functions we created
String correlator = "Duplicate Function Instructions Match";
assertAcceptedMatch(session, correlator, "0x414c00", "0x414c00");
@ -276,7 +271,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 register operands
byte[] bytes1 = { (byte) 0x8b, (byte) 0xff, (byte) 0x55, (byte) 0x8b, (byte) 0xec,
(byte) 0x33, (byte) 0xc0, (byte) 0x5d, (byte) 0x90, (byte) 0xc3 }; //XOR EAX,EAX;
@ -304,10 +299,10 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
env.showTool();
controller = env.getVTController();
// run auto VT
// run auto VT
runAutoVTCommand(1.0, 10.0);
// Now test that the correct matches were created based on the duplicate functions we created
// Now test that the correct matches were created based on the duplicate functions we created
String correlator = "Duplicate Function Instructions Match";
assertAcceptedMatch(session, correlator, "0x414c00", "0x414c00");
@ -340,7 +335,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
@ -383,7 +378,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
createFunction(sourceProgram, bytes, addr("0x414e00", sourceProgram));
createFunction(destinationProgram, bytes, addr("0x414f00", destinationProgram));
// Create three functions in each program with same instructions as the above functions but
// Create three functions in each program with same instructions as the above functions but
// replace the XOR EAX, 1 with XOR EAX, 2, XOR EAX, 2, XOR EAX, 3 respectively
byte[] bytes2 = { (byte) 0x8b, (byte) 0xff, (byte) 0x55, (byte) 0x8b, (byte) 0xec,
@ -409,7 +404,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
@ -439,11 +434,11 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
}
}
// 40 = four for the 2x2 matches that already existed and 36 for the 6x6 matches just created
// 5 = 2 matches that already existed + 3 valid matches from the ones just created
// 5 = 2 matches that already existed + 3 valid matches from the ones just created
assertCorrectMatchCountAndAcceptedMatchCount(session,
"Duplicate Function Instructions Match", 40, 5);
// Now test that the Auto VT duplicate matcher did not accept any matches between the three
// Now test that the Auto VT duplicate matcher did not accept any matches between the three
// identical ones but did accept the unique ones and blocked the ones between the unique ones
// and the rest
List<Address> 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<VTMatchSet> 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";

View File

@ -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 <code>Runnable</code> is used to create a thread,
* starting the thread causes the object's <code>run</code> 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
*
*
* <P>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