GP-1421 - Version Tracking - Converted 'command' to a 'task' and updated

the progress monitor to show continuous progress; fixed slow test

Closes #3221
This commit is contained in:
dragonmacher 2021-11-16 13:14:46 -05:00
parent e55550edfd
commit c3375b6b88
8 changed files with 334 additions and 246 deletions

View file

@ -31,10 +31,4 @@ dependencies {
testImplementation "org.jmockit:jmockit:1.44" testImplementation "org.jmockit:jmockit:1.44"
testImplementation project(path: ':Project', configuration: 'testArtifacts') testImplementation project(path: ':Project', configuration: 'testArtifacts')
} }
integrationTest {
// tests to slow to run during automated testing
excludes = [
'**/VTAutoVersionTrackingTest*',
]
}

View file

@ -23,12 +23,13 @@ import java.util.List;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.feature.vt.api.db.VTSessionDB; import ghidra.feature.vt.api.db.VTSessionDB;
import ghidra.feature.vt.api.main.VTSession; import ghidra.feature.vt.api.main.VTSession;
import ghidra.feature.vt.gui.actions.AutoVersionTrackingCommand; import ghidra.feature.vt.gui.actions.AutoVersionTrackingTask;
import ghidra.feature.vt.gui.plugin.*; import ghidra.feature.vt.gui.plugin.*;
import ghidra.framework.model.DomainFolder; import ghidra.framework.model.DomainFolder;
import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.task.TaskLauncher;
public class AutoVersionTrackingScript extends GhidraScript { public class AutoVersionTrackingScript extends GhidraScript {
@Override @Override
@ -72,15 +73,10 @@ public class AutoVersionTrackingScript extends GhidraScript {
//String description = "AutoVTScript"; //String description = "AutoVTScript";
AutoVersionTrackingCommand autoVTcmd = AutoVersionTrackingTask autoVtTask =
new AutoVersionTrackingCommand(controller, session, 1.0, 10.0); new AutoVersionTrackingTask(controller, session, 1.0, 10.0);
controller.getTool().executeBackgroundCommand(autoVTcmd, session);
//destinationProgram.save(description, monitor);
//session.save(description, monitor);
//session.release(this);
TaskLauncher.launch(autoVtTask);
} }
public static <T extends Plugin> T getPlugin(PluginTool tool, Class<T> c) { public static <T extends Plugin> T getPlugin(PluginTool tool, Class<T> c) {

View file

@ -25,10 +25,11 @@ import ghidra.feature.vt.gui.plugin.VTController;
import ghidra.feature.vt.gui.plugin.VTPlugin; import ghidra.feature.vt.gui.plugin.VTPlugin;
import ghidra.util.HTMLUtilities; import ghidra.util.HTMLUtilities;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.task.TaskLauncher;
import resources.ResourceManager; import resources.ResourceManager;
/** /**
* This action runs the {@link AutoVersionTrackingCommand} * This action runs the {@link AutoVersionTrackingTask}
*/ */
public class AutoVersionTrackingAction extends DockingAction { public class AutoVersionTrackingAction extends DockingAction {
public static Icon AUTO_VT_ICON = ResourceManager.loadImage("images/wizard.png"); public static Icon AUTO_VT_ICON = ResourceManager.loadImage("images/wizard.png");
@ -59,18 +60,16 @@ public class AutoVersionTrackingAction extends DockingAction {
VTSession session = controller.getSession(); VTSession session = controller.getSession();
// In the future we might want to make these user options so the user can change them // In the future we might want to make these user options so the user can change them.
// I don't want to make this change until the confidence option in the reference // We don't want to make this change until the confidence option in the reference
// correlators is changed to make more sense to the user - currently the confidence has // correlators is changed to make more sense to the user - currently the confidence has
// to be entered as the value before the log 10 is computed but the table shows log 10 value // to be entered as the value before the log 10 is computed but the table shows log 10 value.
//
// The current passed values for score and confidence (.95 and 10.0) // The current passed values for score and confidence (.95 and 10.0)
// get you accepted matches with similarity scores >= .95 and // get you accepted matches with similarity scores >= .95 and
// confidence (log 10) scores 2.0 and up // confidence (log 10) scores 2.0 and up
AutoVersionTrackingCommand command = AutoVersionTrackingTask task = new AutoVersionTrackingTask(controller, session, 0.95, 10.0);
new AutoVersionTrackingCommand(controller, session, 0.95, 10.0); TaskLauncher.launch(task);
controller.getTool().executeBackgroundCommand(command, session);
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,6 +17,8 @@ package ghidra.feature.vt.gui.actions;
import java.util.*; import java.util.*;
import javax.swing.SwingConstants;
import ghidra.feature.vt.api.correlator.program.*; import ghidra.feature.vt.api.correlator.program.*;
import ghidra.feature.vt.api.main.*; import ghidra.feature.vt.api.main.*;
import ghidra.feature.vt.api.util.VTAssociationStatusException; import ghidra.feature.vt.api.util.VTAssociationStatusException;
@ -24,8 +26,6 @@ import ghidra.feature.vt.api.util.VTOptions;
import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTController;
import ghidra.feature.vt.gui.task.ApplyMarkupItemTask; import ghidra.feature.vt.gui.task.ApplyMarkupItemTask;
import ghidra.feature.vt.gui.util.MatchInfo; import ghidra.feature.vt.gui.util.MatchInfo;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.framework.options.ToolOptions; import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
@ -36,12 +36,12 @@ import ghidra.program.util.ListingDiff;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.*;
import util.CollectionUtils; 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): * unique matches (i.e., only one of each match is found in each program):
* <ol> * <ol>
* <li> Exact Symbol Name correlator </li> * <li> Exact Symbol Name correlator </li>
* <li> Exact Data correlator </li> * <li> Exact Data correlator </li>
@ -65,8 +65,9 @@ import util.CollectionUtils;
* <P> As more techniques get developed, more automation will be added to this command. * <P> As more techniques get developed, more automation will be added to this command.
* *
*/ */
public class AutoVersionTrackingCommand extends BackgroundCommand { public class AutoVersionTrackingTask extends Task {
private static final String NAME = "Auto Version Tracking Command";
private VTSession session; private VTSession session;
private Program sourceProgram; private Program sourceProgram;
private Program destinationProgram; private Program destinationProgram;
@ -78,7 +79,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
private double minCombinedReferenceCorrelatorConfidence; private double minCombinedReferenceCorrelatorConfidence;
private final ToolOptions applyOptions; private final ToolOptions applyOptions;
private String statusMsg = null; private String statusMsg = null;
private static int NUM_CORRELATORS = 7; private static int NUM_CORRELATORS = 8;
/** /**
* Constructor for AutoVersionTrackingCommand * Constructor for AutoVersionTrackingCommand
@ -92,9 +93,10 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
* @param minCombinedReferenceCorrelatorConfidence The minimum confidence used to limit matches * @param minCombinedReferenceCorrelatorConfidence The minimum confidence used to limit matches
* created by the Combined Reference Correlator. * created by the Combined Reference Correlator.
*/ */
public AutoVersionTrackingCommand(VTController controller, VTSession session, public AutoVersionTrackingTask(VTController controller, VTSession session,
double minCombinedReferenceCorrelatorScore, double minCombinedReferenceCorrelatorScore,
double minCombinedReferenceCorrelatorConfidence) { double minCombinedReferenceCorrelatorConfidence) {
super(NAME, true, true, true);
this.session = session; this.session = session;
this.sourceProgram = session.getSourceProgram(); this.sourceProgram = session.getSourceProgram();
this.destinationProgram = session.getDestinationProgram(); this.destinationProgram = session.getDestinationProgram();
@ -103,119 +105,160 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
this.minCombinedReferenceCorrelatorScore = minCombinedReferenceCorrelatorScore; this.minCombinedReferenceCorrelatorScore = minCombinedReferenceCorrelatorScore;
this.minCombinedReferenceCorrelatorConfidence = minCombinedReferenceCorrelatorConfidence; this.minCombinedReferenceCorrelatorConfidence = minCombinedReferenceCorrelatorConfidence;
this.applyOptions = controller.getOptions(); this.applyOptions = controller.getOptions();
} }
@Override @Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) { public int getStatusTextAlignment() {
return SwingConstants.LEADING;
}
@Override
public void run(TaskMonitor monitor) throws CancelledException {
boolean error = true;
int id = session.startTransaction(NAME);
try {
session.setEventsEnabled(false);
doRun(monitor);
error = false;
}
catch (CancelledException e) {
error = false; // allow work performed so far to be saved
}
finally {
session.setEventsEnabled(true);
session.endTransaction(id, !error);
}
}
private void doRun(TaskMonitor realMonitor) throws CancelledException {
SubTaskMonitor monitor = new SubTaskMonitor(realMonitor);
boolean hasApplyErrors = false; boolean hasApplyErrors = false;
sourceAddressSet = sourceProgram.getMemory().getLoadedAndInitializedAddressSet(); sourceAddressSet = sourceProgram.getMemory().getLoadedAndInitializedAddressSet();
destinationAddressSet = destinationProgram.getMemory().getLoadedAndInitializedAddressSet(); destinationAddressSet = destinationProgram.getMemory().getLoadedAndInitializedAddressSet();
try {
monitor.setMessage("Running Auto Version Tracking");
monitor.setCancelEnabled(true);
monitor.initialize(NUM_CORRELATORS);
// Use default options for all of the "exact" correlators and passed in options for int count = 0;
// the others. monitor.doInitialize(NUM_CORRELATORS);
VTOptions options;
// Run the correlators in the following order: // Use default options for all of the "exact" correlators; passed in options for the others
// Do this one first because we don't want it to find ones that get markup VTOptions options;
// applied by later correlators
VTProgramCorrelatorFactory factory = new SymbolNameProgramCorrelatorFactory(); // 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();
String prefix = "%s correlation (%d of " + NUM_CORRELATORS + ") - ";
monitor.setPrefix(String.format(prefix, "Symbol Name", ++count));
hasApplyErrors = correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
factory = new ExactDataMatchProgramCorrelatorFactory();
options = factory.createDefaultOptions();
monitor.setPrefix(String.format(prefix, "Exact Data", ++count));
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
factory = new ExactMatchBytesProgramCorrelatorFactory();
options = factory.createDefaultOptions();
monitor.setPrefix(String.format(prefix, "Exact Bytes", ++count));
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
factory = new ExactMatchInstructionsProgramCorrelatorFactory();
options = factory.createDefaultOptions();
monitor.setPrefix(String.format(prefix, "Exact Instructions", ++count));
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
factory = new ExactMatchMnemonicsProgramCorrelatorFactory();
options = factory.createDefaultOptions();
monitor.setPrefix(String.format(prefix, "Exact Mnemonic", ++count));
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
// 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
// finding the correct match is very accurate.
factory = new DuplicateFunctionMatchProgramCorrelatorFactory();
options = factory.createDefaultOptions();
monitor.setPrefix(String.format(prefix, "Duplicate Function", ++count));
hasApplyErrors |= correlateAndPossiblyApplyDuplicateFunctions(factory, options, monitor);
monitor.doIncrementProgress();
// 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
// further on more programs and possibly add options for users to give their own thresholds.
// Get the names of the confidence and similarity score thresholds that
// are used by all of the "reference" correlators
String confidenceOption = VTAbstractReferenceProgramCorrelatorFactory.CONFIDENCE_THRESHOLD;
String scoreOption = VTAbstractReferenceProgramCorrelatorFactory.SIMILARITY_THRESHOLD;
// Get the number of data and function matches
int numDataMatches = getNumberOfDataMatches(monitor);
int numFunctionMatches = getNumberOfFunctionMatches(monitor);
// Run the DataReferenceCorrelator if there are accepted data matches but no accepted
// function matches
if (numDataMatches > 0 && numFunctionMatches == 0) {
factory = new DataReferenceProgramCorrelatorFactory();
options = factory.createDefaultOptions(); options = factory.createDefaultOptions();
hasApplyErrors = correlateAndPossiblyApply(factory, options, monitor); options.setDouble(confidenceOption, minCombinedReferenceCorrelatorConfidence);
options.setDouble(scoreOption, minCombinedReferenceCorrelatorScore);
factory = new ExactDataMatchProgramCorrelatorFactory(); monitor.setPrefix(String.format(prefix, "Data Reference", ++count));
options = factory.createDefaultOptions(); hasApplyErrors = hasApplyErrors | correlateAndPossiblyApply(factory, options, monitor);
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor); monitor.doIncrementProgress();
factory = new ExactMatchBytesProgramCorrelatorFactory(); // Get the number of data and function matches again if this correlator ran
options = factory.createDefaultOptions(); numDataMatches = getNumberOfDataMatches(monitor);
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor); numFunctionMatches = getNumberOfFunctionMatches(monitor);
factory = new ExactMatchInstructionsProgramCorrelatorFactory();
options = factory.createDefaultOptions();
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor);
factory = new ExactMatchMnemonicsProgramCorrelatorFactory();
options = factory.createDefaultOptions();
hasApplyErrors |= correlateAndPossiblyApply(factory, options, monitor);
// 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
// finding the correct match is very accurate.
factory = new DuplicateFunctionMatchProgramCorrelatorFactory();
options = factory.createDefaultOptions();
hasApplyErrors |=
correlateAndPossiblyApplyDuplicateFunctions(factory, options, monitor);
// 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
// further on more programs and possibly add options for users to
// give their own thresholds.
// Get the names of the confidence and similarity score thresholds that
// are used by all of the "reference" correlators
String confidenceOption =
VTAbstractReferenceProgramCorrelatorFactory.CONFIDENCE_THRESHOLD;
String scoreOption = VTAbstractReferenceProgramCorrelatorFactory.SIMILARITY_THRESHOLD;
// Get the number of data and function matches
int numDataMatches = getNumberOfDataMatches(monitor);
int numFunctionMatches = getNumberOfFunctionMatches(monitor);
// Run the DataReferenceCorrelator if there are accepted data matches but no accepted
// function matches
if (numDataMatches > 0 && numFunctionMatches == 0) {
factory = new DataReferenceProgramCorrelatorFactory();
options = factory.createDefaultOptions();
options.setDouble(confidenceOption, minCombinedReferenceCorrelatorConfidence);
options.setDouble(scoreOption, minCombinedReferenceCorrelatorScore);
hasApplyErrors =
hasApplyErrors | correlateAndPossiblyApply(factory, options, monitor);
// Get the number of data and function matches again if this correlator ran
numDataMatches = getNumberOfDataMatches(monitor);
numFunctionMatches = getNumberOfFunctionMatches(monitor);
}
// Run the FunctionReferenceCorrelator if there are accepted function matches but
// no accepted data matches
if (numDataMatches > 0 && numFunctionMatches == 0) {
factory = new FunctionReferenceProgramCorrelatorFactory();
options = factory.createDefaultOptions();
options.setDouble(confidenceOption, minCombinedReferenceCorrelatorConfidence);
options.setDouble(scoreOption, minCombinedReferenceCorrelatorScore);
factory = new FunctionReferenceProgramCorrelatorFactory();
hasApplyErrors =
hasApplyErrors | correlateAndPossiblyApply(factory, options, monitor);
// Get the number of data and function matches again if this correlator ran
numDataMatches = getNumberOfDataMatches(monitor);
numFunctionMatches = getNumberOfFunctionMatches(monitor);
}
// Run the CombinedDataAndFunctionReferenceCorrelator if there are both accepted function matches but
// and data matches
if (numDataMatches > 0 && numFunctionMatches > 0) {
factory = new CombinedFunctionAndDataReferenceProgramCorrelatorFactory();
options = factory.createDefaultOptions();
options.setDouble(confidenceOption, minCombinedReferenceCorrelatorConfidence);
options.setDouble(scoreOption, minCombinedReferenceCorrelatorScore);
hasApplyErrors =
hasApplyErrors | correlateAndPossiblyApply(factory, options, monitor);
}
} }
catch (CancelledException e) {
statusMsg = getName() + " was cancelled."; // Run the FunctionReferenceCorrelator if there are accepted function matches but no
return false; // accepted data matches
if (numDataMatches > 0 && numFunctionMatches == 0) {
factory = new FunctionReferenceProgramCorrelatorFactory();
options = factory.createDefaultOptions();
options.setDouble(confidenceOption, minCombinedReferenceCorrelatorConfidence);
options.setDouble(scoreOption, minCombinedReferenceCorrelatorScore);
factory = new FunctionReferenceProgramCorrelatorFactory();
monitor.setPrefix(String.format(prefix, "Function Reference", ++count));
hasApplyErrors = hasApplyErrors | correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
// Get the number of data and function matches again if this correlator ran
numDataMatches = getNumberOfDataMatches(monitor);
numFunctionMatches = getNumberOfFunctionMatches(monitor);
}
// Run the CombinedDataAndFunctionReferenceCorrelator if there are both accepted function
// matches but and data matches
if (numDataMatches > 0 && numFunctionMatches > 0) {
factory = new CombinedFunctionAndDataReferenceProgramCorrelatorFactory();
options = factory.createDefaultOptions();
options.setDouble(confidenceOption, minCombinedReferenceCorrelatorConfidence);
options.setDouble(scoreOption, minCombinedReferenceCorrelatorScore);
monitor.setPrefix(String.format(prefix, "Function and Data", ++count));
hasApplyErrors = hasApplyErrors | correlateAndPossiblyApply(factory, options, monitor);
monitor.doIncrementProgress();
} }
String applyMarkupStatus = " with no apply markup errors."; String applyMarkupStatus = " with no apply markup errors.";
@ -223,13 +266,9 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
applyMarkupStatus = applyMarkupStatus =
" with some apply markup errors. See the log or the markup table for more details"; " with some apply markup errors. See the log or the markup table for more details";
} }
statusMsg = statusMsg = NAME + " completed successfully" + applyMarkupStatus;
getName() + " completed successfully" + applyMarkupStatus;
controller.getTool().setStatusInfo(statusMsg); controller.getTool().setStatusInfo(statusMsg);
return true;
} }
private int getNumberOfDataMatches(TaskMonitor monitor) throws CancelledException { private int getNumberOfDataMatches(TaskMonitor monitor) throws CancelledException {
@ -288,7 +327,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
sourceAddressSet, destinationProgram, destinationAddressSet, options); sourceAddressSet, destinationProgram, destinationAddressSet, options);
VTMatchSet results = correlator.correlate(session, monitor); VTMatchSet results = correlator.correlate(session, monitor);
monitor.initialize(results.getMatchCount());
boolean hasMarkupErrors = applyMatches(results.getMatches(), correlator.getName(), monitor); boolean hasMarkupErrors = applyMatches(results.getMatches(), correlator.getName(), monitor);
monitor.incrementProgress(1); monitor.incrementProgress(1);
@ -318,6 +357,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
sourceAddressSet, destinationProgram, destinationAddressSet, options); sourceAddressSet, destinationProgram, destinationAddressSet, options);
VTMatchSet results = correlator.correlate(session, monitor); VTMatchSet results = correlator.correlate(session, monitor);
monitor.initialize(results.getMatchCount());
boolean hasMarkupErrors = applyDuplicateFunctionMatches(results.getMatches(), monitor); boolean hasMarkupErrors = applyDuplicateFunctionMatches(results.getMatches(), monitor);
monitor.incrementProgress(1); monitor.incrementProgress(1);
@ -363,6 +403,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
ApplyMarkupItemTask markupTask = ApplyMarkupItemTask markupTask =
new ApplyMarkupItemTask(controller.getSession(), markupItems, applyOptions); new ApplyMarkupItemTask(controller.getSession(), markupItems, applyOptions);
markupTask.run(monitor); markupTask.run(monitor);
boolean currentMatchHasErrors = markupTask.hasErrors(); boolean currentMatchHasErrors = markupTask.hasErrors();
if (currentMatchHasErrors) { if (currentMatchHasErrors) {
@ -387,19 +428,19 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
return true; return true;
} }
catch (VTAssociationStatusException e) { catch (VTAssociationStatusException e) {
Msg.warn(AutoVersionTrackingCommand.class, Msg.warn(AutoVersionTrackingTask.class,
"Could not set match accepted for " + association, e); "Could not set match accepted for " + association, e);
return false; return false;
} }
} }
/** /**
* 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
* if they are a unique match within their associated set. * operands if they are a unique match within their associated set.
* @param matches A collection of version tracking matches from the duplicate instruction * @param matches A collection of version tracking matches from the duplicate instruction
* matcher. * matcher
* @param monitor Allows user to cancel * @param monitor Allows user to cancel
* @return true if any markup errors, false if no markup errors. * @return true if any markup errors, false if no markup errors
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
private boolean applyDuplicateFunctionMatches(Collection<VTMatch> matches, TaskMonitor monitor) private boolean applyDuplicateFunctionMatches(Collection<VTMatch> matches, TaskMonitor monitor)
@ -409,19 +450,22 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
boolean someMatchesHaveMarkupErrors = false; boolean someMatchesHaveMarkupErrors = false;
Set<VTMatch> copyOfMatches = new HashSet<>(matches); Set<VTMatch> copyOfMatches = new HashSet<>(matches);
// Process matches in related sets of matches String message = "Processing match %d of %d...";
for (VTMatch match : matches) { int n = matches.size();
Iterator<VTMatch> it = matches.iterator();
for (int i = 0; it.hasNext(); i++) {
monitor.checkCanceled(); monitor.checkCanceled();
monitor.setMessage(String.format(message, i, n));
// if match has already been removed (ie it was in a set that was already processed) VTMatch match = it.next();
// then skip it
// skip if match has already been removed (it was in a set that was already processed)
if (!copyOfMatches.contains(match)) { if (!copyOfMatches.contains(match)) {
continue; continue;
} }
// get a set of related matches from the set of all matches // Get a set of related matches from the set of all matches. These all have the same
// ie these all have the same instructions as each other but not necessarily // instructions as each other but not necessarily the same operands.
// the same operands.
Set<VTMatch> relatedMatches = getRelatedMatches(match, matches, monitor); Set<VTMatch> relatedMatches = getRelatedMatches(match, matches, monitor);
// remove related matches from the set of matches to process next time // remove related matches from the set of matches to process next time
@ -440,19 +484,19 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
Set<Address> uniqueDestFunctionAddresses = Set<Address> uniqueDestFunctionAddresses =
dedupMatchingFunctions(destinationProgram, destAddresses, monitor); dedupMatchingFunctions(destinationProgram, destAddresses, monitor);
// Keep only matches containing the unique sources and destination functions determined above // Keep only matches containing unique source and destination functions from above
Set<VTMatch> dedupedMatches = getMatches(relatedMatches, uniqueSourceFunctionAddresses, Set<VTMatch> dedupedMatches = getMatches(relatedMatches, uniqueSourceFunctionAddresses,
uniqueDestFunctionAddresses, monitor); uniqueDestFunctionAddresses, monitor);
// Loop through all the source functions // loop through all the source functions
for (Address sourceAddress : uniqueSourceFunctionAddresses) { for (Address sourceAddress : uniqueSourceFunctionAddresses) {
monitor.checkCanceled(); monitor.checkCanceled();
// Find all destination functions with equivalent operands to current source function // find all destination functions with equivalent operands to source function
Set<VTMatch> matchesWithEquivalentOperands = getMatchesWithEquivalentOperands( Set<VTMatch> matchesWithEquivalentOperands = getMatchesWithEquivalentOperands(
dedupedMatches, sourceAddress, uniqueDestFunctionAddresses, monitor); 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) { if (matchesWithEquivalentOperands.size() == 1) {
VTMatch theMatch = CollectionUtils.any(matchesWithEquivalentOperands); VTMatch theMatch = CollectionUtils.any(matchesWithEquivalentOperands);
someMatchesHaveMarkupErrors |= someMatchesHaveMarkupErrors |=
@ -814,7 +858,7 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
* @return Set of addresses of deduped function bytes * @return Set of addresses of deduped function bytes
* @throws CancelledException if cancelled * @throws CancelledException if cancelled
*/ */
public Set<Address> dedupMatchingFunctions(Program program, Set<Address> addresses, private Set<Address> dedupMatchingFunctions(Program program, Set<Address> addresses,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
FunctionManager functionManager = program.getFunctionManager(); FunctionManager functionManager = program.getFunctionManager();
@ -859,13 +903,54 @@ public class AutoVersionTrackingCommand extends BackgroundCommand {
return uniqueFunctionAddresses; return uniqueFunctionAddresses;
} }
@Override
public String getStatusMsg() { public String getStatusMsg() {
return statusMsg; return statusMsg;
} }
@Override /** A task monitor that allows us to control the message content and the progress */
public String getName() { private class SubTaskMonitor extends WrappingTaskMonitor {
return "Auto Version Tracking Command";
private String prefix;
SubTaskMonitor(TaskMonitor delegate) {
super(delegate);
}
void setPrefix(String prefix) {
this.prefix = prefix;
}
void doIncrementProgress() {
super.incrementProgress(1);
}
void doInitialize(long max) {
super.initialize(max);
}
@Override
public void setMessage(String message) {
super.setMessage(prefix + message);
}
@Override
public void initialize(long max) {
// we control the max value
}
@Override
public synchronized void setMaximum(long max) {
// we control the max value
}
@Override
public void setProgress(long value) {
// we control the progress
}
@Override
public void incrementProgress(long incrementAmount) {
// we control progress
}
} }
} }

View file

@ -82,7 +82,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
private SelectionOverrideMemento selectionMemento; private SelectionOverrideMemento selectionMemento;
private boolean filteringFrozen; private boolean filteringFrozen;
// a selection we may have to set later, after the table has finished loading // a selection we may have to set later, after the table has finished loading
private VTMatch pendingMatchSelection; private VTMatch pendingMatchSelection;
private SwingUpdateManager selectMatchUpdateManager; private SwingUpdateManager selectMatchUpdateManager;
private MatchTableSelectionAction tableSelectionStateAction; private MatchTableSelectionAction tableSelectionStateAction;
@ -182,8 +182,8 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
int filteredCount = matchesTableModel.getRowCount(); int filteredCount = matchesTableModel.getRowCount();
int unfilteredCount = matchesTableModel.getUnfilteredRowCount(); int unfilteredCount = matchesTableModel.getUnfilteredRowCount();
int filteredOutCount = unfilteredCount - filteredCount; int filteredOutCount = unfilteredCount - filteredCount;
ancillaryFilterButton.setToolTipText( ancillaryFilterButton
"More Filters - " + filteredOutCount + " item(s) hidden"); .setToolTipText("More Filters - " + filteredOutCount + " item(s) hidden");
} }
else { else {
ancillaryFilterButton.setToolTipText("More Filters - no active filters"); ancillaryFilterButton.setToolTipText("More Filters - no active filters");
@ -233,9 +233,9 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
int unfilteredCount = matchesTableModel.getUnfilteredRowCount(); int unfilteredCount = matchesTableModel.getUnfilteredRowCount();
String sessionName = controller.getVersionTrackingSessionName(); String sessionName = controller.getVersionTrackingSessionName();
StringBuffer buffy = new StringBuffer(); StringBuilder buffy = new StringBuilder();
buffy.append("[Session: ").append(sessionName).append("] "); buffy.append("[Session: ").append(sessionName).append("] - ");
buffy.append('-').append(filteredCount).append(" matches"); buffy.append(filteredCount).append(" matches");
if (filteredCount != unfilteredCount) { if (filteredCount != unfilteredCount) {
buffy.append(" (of ").append(unfilteredCount).append(')'); buffy.append(" (of ").append(unfilteredCount).append(')');
} }
@ -289,7 +289,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
selectMatchUpdateManager.updateLater(); selectMatchUpdateManager.updateLater();
} }
else { else {
// for any selection that is not handled by the match changing we want to // for any selection that is not handled by the match changing we want to
// notify that context has changed so that actions properly update // notify that context has changed so that actions properly update
notifyContextChanged(); notifyContextChanged();
} }
@ -307,14 +307,14 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
int sourceLabelColumnIndex = matchesTableModel.getColumnIndex(SourceLabelTableColumn.class); int sourceLabelColumnIndex = matchesTableModel.getColumnIndex(SourceLabelTableColumn.class);
TableColumn sourceLabelColumn = columnModel.getColumn(sourceLabelColumnIndex); TableColumn sourceLabelColumn = columnModel.getColumn(sourceLabelColumnIndex);
sourceLabelColumn.setCellRenderer( sourceLabelColumn
new VTSymbolRenderer(controller.getServiceProvider(), table)); .setCellRenderer(new VTSymbolRenderer(controller.getServiceProvider(), table));
int destinationLabelColumnIndex = int destinationLabelColumnIndex =
matchesTableModel.getColumnIndex(DestinationLabelTableColumn.class); matchesTableModel.getColumnIndex(DestinationLabelTableColumn.class);
TableColumn destinationLabelColumn = columnModel.getColumn(destinationLabelColumnIndex); TableColumn destinationLabelColumn = columnModel.getColumn(destinationLabelColumnIndex);
destinationLabelColumn.setCellRenderer( destinationLabelColumn
new VTSymbolRenderer(controller.getServiceProvider(), table)); .setCellRenderer(new VTSymbolRenderer(controller.getServiceProvider(), table));
int statusColumnIndex = matchesTableModel.getColumnIndex(StatusTableColumn.class); int statusColumnIndex = matchesTableModel.getColumnIndex(StatusTableColumn.class);
TableColumn statusColumn = columnModel.getColumn(statusColumnIndex); TableColumn statusColumn = columnModel.getColumn(statusColumnIndex);
@ -352,8 +352,8 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
innerPanel.add(lengthFilterPanel); innerPanel.add(lengthFilterPanel);
ancillaryFilterButton = new JButton(UNFILTERED_ICON); ancillaryFilterButton = new JButton(UNFILTERED_ICON);
ancillaryFilterButton.addActionListener( ancillaryFilterButton
e -> tool.showDialog(ancillaryFilterDialog, component)); .addActionListener(e -> tool.showDialog(ancillaryFilterDialog, component));
ancillaryFilterButton.setToolTipText("Filters Dialog"); ancillaryFilterButton.setToolTipText("Filters Dialog");
HelpService helpService = DockingWindowManager.getHelpService(); HelpService helpService = DockingWindowManager.getHelpService();
HelpLocation filterHelpLocation = HelpLocation filterHelpLocation =
@ -405,7 +405,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
int row = matchesTableModel.getRowIndex(match); int row = matchesTableModel.getRowIndex(match);
if (row < 0) { if (row < 0) {
pendingMatchSelection = match; pendingMatchSelection = match;
// this happen while reloading. If so, save the match and listen for // this happen while reloading. If so, save the match and listen for
// the table data changed and restore the selection at that point // the table data changed and restore the selection at that point
return; return;
} }
@ -517,7 +517,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
} }
if (matchesContextChanged) { if (matchesContextChanged) {
// Now that all records have been processed, // Now that all records have been processed,
// since the match table changed perform a reload to apply filters. // since the match table changed perform a reload to apply filters.
reload(); reload();
@ -695,8 +695,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
"should become ignored by applying a match."); "should become ignored by applying a match.");
vtOptions.getOptions(APPLY_MARKUP_OPTIONS_NAME) vtOptions.getOptions(APPLY_MARKUP_OPTIONS_NAME)
.registerOptionsEditor( .registerOptionsEditor(new ApplyMarkupPropertyEditor(controller));
new ApplyMarkupPropertyEditor(controller));
vtOptions.getOptions(DISPLAY_APPLY_MARKUP_OPTIONS) vtOptions.getOptions(DISPLAY_APPLY_MARKUP_OPTIONS)
.setOptionsHelpLocation( .setOptionsHelpLocation(
new HelpLocation("VersionTracking", "Apply Markup Options")); new HelpLocation("VersionTracking", "Apply Markup Options"));
@ -709,17 +708,15 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
vtOptions.setOptionsHelpLocation(applyOptionsHelpLocation); vtOptions.setOptionsHelpLocation(applyOptionsHelpLocation);
vtOptions.getOptions(ACCEPT_MATCH_OPTIONS_NAME) vtOptions.getOptions(ACCEPT_MATCH_OPTIONS_NAME)
.setOptionsHelpLocation( .setOptionsHelpLocation(applyMatchOptionsHelpLocation);
applyMatchOptionsHelpLocation);
vtOptions.getOptions(APPLY_MARKUP_OPTIONS_NAME) vtOptions.getOptions(APPLY_MARKUP_OPTIONS_NAME)
.setOptionsHelpLocation( .setOptionsHelpLocation(applyMatchOptionsHelpLocation);
applyMatchOptionsHelpLocation);
} }
//================================================================================================== //==================================================================================================
// FilterDialogModel Methods // FilterDialogModel Methods
//================================================================================================== //==================================================================================================
@Override @Override
public void addFilter(Filter<VTMatch> filter) { public void addFilter(Filter<VTMatch> filter) {
@ -728,7 +725,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
matchesTableModel.addFilter(filter); matchesTableModel.addFilter(filter);
} }
/** /**
* Forces a refilter, even though filtering operations may be disabled. The reload * Forces a refilter, even though filtering operations may be disabled. The reload
* is necessary since the model contents may have changed * is necessary since the model contents may have changed
*/ */
@ -794,11 +791,11 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
/** /**
* A class meant to override the default table selection behavior <b>in special situations</b>. * A class meant to override the default table selection behavior <b>in special situations</b>.
* <p> * <p>
* <u>Issue 1:</u> Accepting or applying a match can trigger the match to be filtered out * <u>Issue 1:</u> Accepting or applying a match can trigger the match to be filtered out
* of the table. The default SelectionManager does not restore the selection for that item, * of the table. The default SelectionManager does not restore the selection for that item,
* as it knows that the item is gone. * as it knows that the item is gone.
* <p> * <p>
* <u>Issue 2:</u> Accepting or applying a match can trigger the match to be moved due to a * <u>Issue 2:</u> Accepting or applying a match can trigger the match to be moved due to a
* sort operation after the edit. * sort operation after the edit.
* <p> * <p>
* <u>Desired Behavior:</u> Have the selection restored to the previous location, even if the * <u>Desired Behavior:</u> Have the selection restored to the previous location, even if the
@ -847,18 +844,18 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
ListSelectionModel selectionModel = matchesTable.getSelectionModel(); ListSelectionModel selectionModel = matchesTable.getSelectionModel();
int rowToSelect = row; int rowToSelect = row;
if (row > matchesTableModel.getRowCount()) { if (row > matchesTableModel.getRowCount()) {
// The model has shrunk. Not sure what the best action is? // The model has shrunk. Not sure what the best action is?
tryToSelectMatch(selectionModel);// this only works if we are tracking by match and not index tryToSelectMatch(selectionModel);// this only works if we are tracking by match and not index
return; return;
} }
// At this point the selection model may still believe that its selection is the // At this point the selection model may still believe that its selection is the
// value we are setting. Calling clearSelection() will kick the model. Without the // value we are setting. Calling clearSelection() will kick the model. Without the
// kick, the setSelectionInterval() call we make may ultimately have no effect. // kick, the setSelectionInterval() call we make may ultimately have no effect.
selectionModel.clearSelection(); selectionModel.clearSelection();
if (tableSelectionState == MAINTAIN_SELECTED_ROW_INDEX) { if (tableSelectionState == MAINTAIN_SELECTED_ROW_INDEX) {
// In this state we are tracking row selection, so just select the previously // In this state we are tracking row selection, so just select the previously
// selected row. // selected row.
selectionModel.setSelectionInterval(rowToSelect, rowToSelect); selectionModel.setSelectionInterval(rowToSelect, rowToSelect);
matchesTable.scrollToSelectedRow(); matchesTable.scrollToSelectedRow();
@ -874,7 +871,7 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
} }
private void tryToSelectMatch(ListSelectionModel selectionModel) { private void tryToSelectMatch(ListSelectionModel selectionModel) {
// In this state we are tracking the value that was selected and we want to // In this state we are tracking the value that was selected and we want to
// reselect that value. // reselect that value.
int matchRow = matchesTableModel.getRowIndex(match); int matchRow = matchesTableModel.getRowIndex(match);
if (matchRow >= 0 && matchRow < matchesTableModel.getRowCount()) { if (matchRow >= 0 && matchRow < matchesTableModel.getRowCount()) {
@ -890,8 +887,8 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
} }
/** /**
* Override the built-in SelectionManager so that we can respond to the current table * Override the built-in SelectionManager so that we can respond to the current table
* selection mode. * selection mode.
*/ */
private class VTMatchTableSelectionManager extends RowObjectSelectionManager<VTMatch> { private class VTMatchTableSelectionManager extends RowObjectSelectionManager<VTMatch> {
VTMatchTableSelectionManager(JTable table, AbstractSortedTableModel<VTMatch> tableModel) { VTMatchTableSelectionManager(JTable table, AbstractSortedTableModel<VTMatch> tableModel) {

View file

@ -41,11 +41,8 @@ public abstract class VtTask extends Task {
@Override @Override
public final void run(TaskMonitor monitor) { public final void run(TaskMonitor monitor) {
boolean restoreEvents = false; boolean restoreEvents = suspendEvents();
if (session != null && shouldSuspendSessionEvents()) {
session.setEventsEnabled(false);
restoreEvents = true;
}
try { try {
success = doWork(monitor); success = doWork(monitor);
} }
@ -62,6 +59,24 @@ public abstract class VtTask extends Task {
} }
} }
private boolean suspendEvents() {
if (session == null) {
return false; // no events to suspend
}
if (!shouldSuspendSessionEvents()) {
return false; // this task has chosen not to suspend events
}
if (!session.isSendingEvents()) {
return false; // someone external to this task is managing events
}
session.setEventsEnabled(false);
return true;
}
/** /**
* Determine if session events should be suspended during task execution. * Determine if session events should be suspended during task execution.
* This can improve performance during task execution at the expense of bulk * This can improve performance during task execution at the expense of bulk

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,7 +19,6 @@ import static ghidra.feature.vt.db.VTTestUtils.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.*; import org.junit.*;
@ -29,7 +28,7 @@ import ghidra.feature.vt.api.main.*;
import ghidra.feature.vt.api.util.VTAssociationStatusException; import ghidra.feature.vt.api.util.VTAssociationStatusException;
import ghidra.feature.vt.db.VTTestUtils; import ghidra.feature.vt.db.VTTestUtils;
import ghidra.feature.vt.gui.VTTestEnv; import ghidra.feature.vt.gui.VTTestEnv;
import ghidra.feature.vt.gui.actions.AutoVersionTrackingCommand; import ghidra.feature.vt.gui.actions.AutoVersionTrackingTask;
import ghidra.feature.vt.gui.plugin.VTController; import ghidra.feature.vt.gui.plugin.VTController;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
@ -42,7 +41,7 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskLauncher;
public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTest { public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTest {
@ -84,8 +83,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
controller = env.getVTController(); controller = env.getVTController();
// Score .999999 and confidence 10.0 (log10 confidence 2.0) and up // Score .999999 and confidence 10.0 (log10 confidence 2.0) and up
boolean success = runAutoVTCommand(0.999999999, 10.0); runAutoVTCommand(0.999999999, 10.0);
assertTrue("Auto Version Tracking Command failed to run", success);
// verify that the default options are what we expect // 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
@ -146,8 +144,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
// 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 // reference correlator and 1.0 and higher for the log 10 confidence score
boolean success = runAutoVTCommand(0.5, 1.0); runAutoVTCommand(0.5, 1.0);
assertTrue("Auto Version Tracking Command failed to run", success);
// verify that the default options are what we expect // 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
@ -613,8 +610,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
sourceProgram.endTransaction(startTransaction, true); sourceProgram.endTransaction(startTransaction, true);
// run Auto VT // run Auto VT
boolean success = runAutoVTCommand(1.0, 10.0); runAutoVTCommand(1.0, 10.0);
assertTrue("Auto Version Tracking Command failed to run", success);
// Check that the match we are interested in got accepted // Check that the match we are interested in got accepted
String correlator = "Combined Function and Data Reference Match"; String correlator = "Combined Function and Data Reference Match";
@ -670,8 +666,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
sourceProgram.endTransaction(startTransaction, true); sourceProgram.endTransaction(startTransaction, true);
// run Auto VT // run Auto VT
boolean success = runAutoVTCommand(1.0, 10.0); runAutoVTCommand(1.0, 10.0);
assertTrue("Auto Version Tracking Command failed to run", success);
// Check that the match we are interested in got accepted // Check that the match we are interested in got accepted
String correlator = "Duplicate Function Instructions Match"; String correlator = "Duplicate Function Instructions Match";
@ -735,8 +730,7 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
// 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 // test in as a match
boolean success = runAutoVTCommand(0.5, 1.0); runAutoVTCommand(0.5, 1.0);
assertTrue("Auto Version Tracking Command failed to run", success);
// Check that the match we are interested in got accepted // Check that the match we are interested in got accepted
String correlator = "Combined Function and Data Reference Match"; String correlator = "Combined Function and Data Reference Match";
@ -829,20 +823,18 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
assertEquals(expectedAcceptedMatchCount, getNumAcceptedMatches(vtSession, correlatorName)); assertEquals(expectedAcceptedMatchCount, getNumAcceptedMatches(vtSession, correlatorName));
} }
private boolean runAutoVTCommand(double minReferenceCorrelatorScore, private void runAutoVTCommand(double minReferenceCorrelatorScore,
double minReferenceCorrelatorConfidence) { double minReferenceCorrelatorConfidence) {
AtomicBoolean result = new AtomicBoolean();
runSwing(() -> {
String transactionName = "Auto Version Tracking Test";
int startTransaction = session.startTransaction(transactionName);
AutoVersionTrackingCommand vtCommand = new AutoVersionTrackingCommand(controller, AutoVersionTrackingTask task = new AutoVersionTrackingTask(controller, session,
session, minReferenceCorrelatorScore, minReferenceCorrelatorConfidence); minReferenceCorrelatorScore, minReferenceCorrelatorConfidence);
result.set(vtCommand.applyTo(session, TaskMonitor.DUMMY)); TaskLauncher.launch(task);
waitForSession();
}
session.endTransaction(startTransaction, result.get()); private void waitForSession() {
}); session.flushEvents();
return result.get(); waitForSwing();
} }
private VTMatchSet getVTMatchSet(VTSession vtSession, String correlatorName) { private VTMatchSet getVTMatchSet(VTSession vtSession, String correlatorName) {

View file

@ -74,6 +74,7 @@ public interface DomainObject {
/** /**
* Returns whether the object has changed. * Returns whether the object has changed.
* @return whether the object has changed.
*/ */
public boolean isChanged(); public boolean isChanged();
@ -87,17 +88,19 @@ public interface DomainObject {
/** /**
* Returns true if this object has been marked as Temporary. * Returns true if this object has been marked as Temporary.
* @return true if this object has been marked as Temporary.
*/ */
public boolean isTemporary(); public boolean isTemporary();
/** /**
* Returns true if changes are permitted. * Returns true if changes are permitted.
* @return true if changes are permitted.
*/ */
public boolean isChangeable(); public boolean isChangeable();
/** /**
* Returns true if this object can be saved; a read-only file * Returns true if this object can be saved; a read-only file cannot be saved.
* cannot be saved. * @return true if this object can be saved
*/ */
public boolean canSave(); public boolean canSave();
@ -118,8 +121,8 @@ public interface DomainObject {
* Saves (i.e., serializes) the current content to a packed file. * Saves (i.e., serializes) the current content to a packed file.
* @param outputFile packed output file * @param outputFile packed output file
* @param monitor progress monitor * @param monitor progress monitor
* @throws IOException * @throws IOException if an exception occurs
* @throws CancelledException * @throws CancelledException if the user cancels
* @throws UnsupportedOperationException if not supported by object implementation * @throws UnsupportedOperationException if not supported by object implementation
*/ */
public void saveToPackedFile(File outputFile, TaskMonitor monitor) public void saveToPackedFile(File outputFile, TaskMonitor monitor)
@ -127,9 +130,9 @@ public interface DomainObject {
/** /**
* Notify the domain object that the specified consumer is no longer using it. * Notify the domain object that the specified consumer is no longer using it.
* When the last consumer invokes this method, the domain object will be closed * When the last consumer invokes this method, the domain object will be closed
* and will become invalid. * and will become invalid.
* @param consumer the consumer (e.g., tool, plugin, etc) of the domain object * @param consumer the consumer (e.g., tool, plugin, etc) of the domain object
* previously established with the addConsumer method. * previously established with the addConsumer method.
*/ */
public void release(Object consumer); public void release(Object consumer);
@ -149,14 +152,14 @@ public interface DomainObject {
/** /**
* Adds a listener that will be notified when this DomainObject is closed. This is meant * Adds a listener that will be notified when this DomainObject is closed. This is meant
* for clients to have a chance to cleanup, such as reference removal. * for clients to have a chance to cleanup, such as reference removal.
* *
* @param listener the reference to add * @param listener the reference to add
*/ */
public void addCloseListener(DomainObjectClosedListener listener); public void addCloseListener(DomainObjectClosedListener listener);
/** /**
* Removes the given close listener. * Removes the given close listener.
* *
* @param listener the listener to remove. * @param listener the listener to remove.
*/ */
public void removeCloseListener(DomainObjectClosedListener listener); public void removeCloseListener(DomainObjectClosedListener listener);
@ -179,11 +182,13 @@ public interface DomainObject {
/** /**
* Returns a word or short phrase that best describes or categorizes * Returns a word or short phrase that best describes or categorizes
* the object in terms that a user will understand. * the object in terms that a user will understand.
* @return the description
*/ */
public String getDescription(); public String getDescription();
/** /**
* Get the name of this domain object. * Get the name of this domain object.
* @return the name
*/ */
public String getName(); public String getName();
@ -195,7 +200,7 @@ public interface DomainObject {
/** /**
* Get the domain file for this domain object. * Get the domain file for this domain object.
* @return the associated domain file * @return the associated domain file
*/ */
public DomainFile getDomainFile(); public DomainFile getDomainFile();
@ -207,13 +212,13 @@ public interface DomainObject {
*/ */
public boolean addConsumer(Object consumer); public boolean addConsumer(Object consumer);
/** /**
* Returns the list of consumers on this domainObject * Returns the list of consumers on this domainObject
* @return the list of consumers. * @return the list of consumers.
*/ */
public ArrayList<Object> getConsumerList(); public ArrayList<Object> getConsumerList();
/** /**
* Returns true if the given consumer is using (has open) this domain object. * Returns true if the given consumer is using (has open) this domain object.
* @param consumer the object to test to see if it is a consumer of this domain object. * @param consumer the object to test to see if it is a consumer of this domain object.
* @return true if the given consumer is using (has open) this domain object; * @return true if the given consumer is using (has open) this domain object;
@ -229,8 +234,8 @@ public interface DomainObject {
* <p> * <p>
* NOTE: when re-enabling events, an event will be sent to the system to signal that * NOTE: when re-enabling events, an event will be sent to the system to signal that
* every listener should update. * every listener should update.
* *
* *
* @param enabled true means to enable events * @param enabled true means to enable events
*/ */
public void setEventsEnabled(boolean enabled); public void setEventsEnabled(boolean enabled);
@ -238,7 +243,8 @@ public interface DomainObject {
/** /**
* Returns true if this object is sending out events as it is changed. The default is * Returns true if this object is sending out events as it is changed. The default is
* true. You can change this value by calling {@link #setEventsEnabled(boolean)}. * true. You can change this value by calling {@link #setEventsEnabled(boolean)}.
* *
* @return true if sending events
* @see #setEventsEnabled(boolean) * @see #setEventsEnabled(boolean)
*/ */
public boolean isSendingEvents(); public boolean isSendingEvents();
@ -258,26 +264,27 @@ public interface DomainObject {
* Returns true if a modification lock can be obtained on this * Returns true if a modification lock can be obtained on this
* domain object. Care should be taken with using this method since * domain object. Care should be taken with using this method since
* this will not prevent another thread from modifying the domain object. * this will not prevent another thread from modifying the domain object.
* @return true if can lock
*/ */
public boolean canLock(); public boolean canLock();
/** /**
* Returns true if the domain object currenly has a modification lock enabled. * Returns true if the domain object currently has a modification lock enabled.
* @return true if locked
*/ */
public boolean isLocked(); public boolean isLocked();
/** /**
* Attempt to obtain a modification lock on the domain object. Multiple locks * Attempt to obtain a modification lock on the domain object. Multiple locks may be granted
* may be granted on this domain object, although all lock owners must release their * on this domain object, although all lock owners must release their lock in a timely fashion.
* lock in a timely fashion.
* @param reason very short reason for requesting lock * @param reason very short reason for requesting lock
* @return true if lock obtained successfully, else false which indicates that a * @return true if lock obtained successfully, else false which indicates that a modification
* modification is in process. * is in process.
*/ */
public boolean lock(String reason); public boolean lock(String reason);
/** /**
* Cancels any previous lock and aquires it. * Cancels any previous lock and acquires it.
* @param rollback if true, any changes in made with the previous lock should be discarded. * @param rollback if true, any changes in made with the previous lock should be discarded.
* @param reason very short reason for requesting lock * @param reason very short reason for requesting lock
*/ */
@ -290,7 +297,7 @@ public interface DomainObject {
/** /**
* Returns all properties lists contained by this domain object. * Returns all properties lists contained by this domain object.
* *
* @return all property lists contained by this domain object. * @return all property lists contained by this domain object.
*/ */
public List<String> getOptionsNames(); public List<String> getOptionsNames();
@ -298,17 +305,20 @@ public interface DomainObject {
/** /**
* Get the property list for the given name. * Get the property list for the given name.
* @param propertyListName name of property list * @param propertyListName name of property list
* @return the options
*/ */
public Options getOptions(String propertyListName); public Options getOptions(String propertyListName);
/** /**
* Returns true if this domain object has been closed as a result of the last release * Returns true if this domain object has been closed as a result of the last release
* @return true if closed
*/ */
public boolean isClosed(); public boolean isClosed();
/** /**
* Returns true if the user has exclusive access to the domain object. Exclusive access means * Returns true if the user has exclusive access to the domain object. Exclusive access means
* either the object is not shared or the user has an exclusive checkout on the object. * either the object is not shared or the user has an exclusive checkout on the object.
* @return true if has exclusive access
*/ */
public boolean hasExclusiveAccess(); public boolean hasExclusiveAccess();