GP-3953 Updated the Auto Version Tracking action to apply implied matches if the number of votes and conflicts are good indicators of a good match.

This commit is contained in:
ghidra007 2023-10-23 23:02:28 +00:00
parent cf562e79b3
commit 81f2e5283f
2 changed files with 163 additions and 34 deletions

View file

@ -306,6 +306,12 @@ public class AutoVersionTrackingTask extends Task {
monitor.doIncrementProgress();
}
// if user had implied match option chosen then figure out implied matches now
// TODO: add option for applying good matches and num votes/conflicts
if (autoCreateImpliedMatches) {
hasApplyErrors = hasApplyErrors | createImpliedMatches(true, monitor);
}
String applyMarkupStatus = " with no apply markup errors.";
if (hasApplyErrors) {
applyMarkupStatus =
@ -313,62 +319,159 @@ public class AutoVersionTrackingTask extends Task {
}
statusMsg = NAME + " completed successfully" + applyMarkupStatus;
// if user had implied match option chosen then figure out implied matches now
if (autoCreateImpliedMatches) {
processImpliedMatches(monitor);
}
// reset auto implied match option to user choice
// TODO: make separate AutoVT implied match option
applyOptions.setBoolean(VTOptionDefines.AUTO_CREATE_IMPLIED_MATCH,
autoCreateImpliedMatches);
}
private void processImpliedMatches(TaskMonitor monitor) throws CancelledException {
/**
* Method to create implied matches for the existing applied matches in the current session
* @param applyGoodMatches if true, create applied matches for "good" implied matches based on
* votes/conflict information. For all the applied implied matches, rerun the creation of
* applied matches until no new ones found.
* @param monitor the task monitor
* @return true if there are any apply errors, false otherwise
* @throws CancelledException if cancelled
*/
private boolean createImpliedMatches(boolean applyGoodMatches, TaskMonitor monitor)
throws CancelledException {
Set<VTAssociation> processedSrcDestPairs = new HashSet<>();
List<VTMatchSet> matchSets = session.getMatchSets();
monitor.setMessage("Processing Implied Matches...");
//TODO: make these options
int minVoteCountNeeded = 2;
int maxConflictsAllowed = 0;
monitor.setMessage("Creating Implied Matches...");
monitor.initialize(matchSets.size());
// create implied matches for the existing matchSets (ie sets of results from various
// correlators
for (VTMatchSet matchSet : matchSets) {
monitor.checkCancelled();
Collection<VTMatch> matches = matchSet.getMatches();
for (VTMatch match : matches) {
createImpliedMatches(monitor, processedSrcDestPairs, matches);
monitor.incrementProgress();
}
// if user chose not to apply good implied matches then don't continue
if (!applyGoodMatches) {
return false;
}
// otherwise, try to find and apply good implied matches until no more to be found
boolean hasApplyErrors = false;
VTMatchSet impliedMatchSet = session.getImpliedMatchSet();
Set<VTMatch> goodImpliedMatches =
findGoodImpliedMatches(impliedMatchSet.getMatches(), minVoteCountNeeded,
maxConflictsAllowed, monitor);
while (goodImpliedMatches.size() > 0) {
monitor.checkCancelled();
// apply the "good" implied matches
hasApplyErrors |= applyMatches(goodImpliedMatches, monitor);
// possibly create more implied matches from the newly applied matches
createImpliedMatches(monitor, processedSrcDestPairs, goodImpliedMatches);
// possibly find more "good" implied matches from any new implied matches found
impliedMatchSet = session.getImpliedMatchSet();
goodImpliedMatches = findGoodImpliedMatches(impliedMatchSet.getMatches(),
minVoteCountNeeded, maxConflictsAllowed, monitor);
}
return hasApplyErrors;
}
private void createImpliedMatches(TaskMonitor monitor, Set<VTAssociation> processedSrcDestPairs,
Collection<VTMatch> matches) throws CancelledException {
for (VTMatch match : matches) {
monitor.checkCancelled();
VTAssociation association = match.getAssociation();
// Implied matches currently only created for functions so skip matches that are
// data matches
if (association.getType() == VTAssociationType.DATA) {
continue;
}
// Implied matches should only be created for matches that user has accepted as
// good matches
if (association.getStatus() != VTAssociationStatus.ACCEPTED) {
continue;
}
// only process the same match pair once so implied vote counts are not overinflated
if (processedSrcDestPairs.contains(association)) {
continue;
}
MatchInfo matchInfo = matchInfoFactory.getMatchInfo(match, addressCorrelator);
ImpliedMatchUtils.updateImpliedMatchForAcceptedAssocation(
matchInfo.getSourceFunction(),
matchInfo.getDestinationFunction(), session,
addressCorrelator, monitor);
processedSrcDestPairs.add(association);
}
}
/**
* Method to find good implied matches based on number of votes and conflicts
* @param matchesToProcess the set of matches to process for good implied matches
* @param minVoteCountNeeded the minimum vote count needed for a "good" implied match
* @param maxConflictsAllowed the maximum number of conflicts allowed for a "good" implied match
* @param monitor the monitor
* @return a set of good implied matches based on the minVoteCountNeeded needed and
* maxConfictsAllowed
* @throws CancelledException if cancelled
*/
private Set<VTMatch> findGoodImpliedMatches(Collection<VTMatch> matchesToProcess,
int minVoteCountNeeded, int maxConflictsAllowed,
TaskMonitor monitor) throws CancelledException {
Set<VTMatch> goodImpliedMatches = new HashSet<>();
for (VTMatch match : matchesToProcess) {
monitor.checkCancelled();
VTAssociation association = match.getAssociation();
// Implied matches currently only created for functions so skip matches that are
// data matches
if (association.getType() == VTAssociationType.DATA) {
// skip if already accepted or blocked match
if (association.getStatus() != VTAssociationStatus.AVAILABLE) {
continue;
}
// Implied matches should only be created for matches that user has accepted as
// good matches
if (association.getStatus() != VTAssociationStatus.ACCEPTED) {
continue;
}
// only process the same match pair once so implied vote counts are not overinflated
if (processedSrcDestPairs.contains(association)) {
// skip if there are any conflicting associations
int numConflicts = association.getRelatedAssociations().size() - 1;
if (numConflicts > maxConflictsAllowed) {
continue;
}
MatchInfo matchInfo = matchInfoFactory.getMatchInfo(match, addressCorrelator);
int voteCount = association.getVoteCount();
ImpliedMatchUtils.updateImpliedMatchForAcceptedAssocation(
matchInfo.getSourceFunction(),
matchInfo.getDestinationFunction(), session,
addressCorrelator, monitor);
if (voteCount >= minVoteCountNeeded) {
goodImpliedMatches.add(match);
}
processedSrcDestPairs.add(association);
}
monitor.incrementProgress();
monitor.incrementProgress();
}
return goodImpliedMatches;
}
private int getNumberOfDataMatches(TaskMonitor monitor) throws CancelledException {
@ -428,7 +531,7 @@ public class AutoVersionTrackingTask extends Task {
VTMatchSet results = correlator.correlate(session, monitor);
monitor.initialize(results.getMatchCount());
boolean hasMarkupErrors = applyMatches(results.getMatches(), correlator.getName(), monitor);
boolean hasMarkupErrors = applyMatches(results.getMatches(), monitor);
monitor.incrementProgress(1);
@ -468,15 +571,13 @@ public class AutoVersionTrackingTask extends Task {
/**
* 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.
* @param matches The set of matches to try to accept
* @param monitor the task monitor
* @return true if some matches have markup errors and false if none have markup errors
* @throws CancelledException if cancelled
*/
private boolean applyMatches(Collection<VTMatch> matches, String correlatorName,
TaskMonitor monitor) throws CancelledException {
private boolean applyMatches(Collection<VTMatch> matches, TaskMonitor monitor)
throws CancelledException {
// If this value gets set to true then there are some markup errors in the whole set of
// matches.

View file

@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@ -31,6 +32,7 @@ import org.junit.Test;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.feature.vt.api.db.VTSessionDB;
import ghidra.feature.vt.api.main.VTAssociation;
import ghidra.feature.vt.api.main.VTAssociationStatus;
import ghidra.feature.vt.api.main.VTAssociationType;
import ghidra.feature.vt.api.main.VTMatch;
@ -818,7 +820,33 @@ public class VTAutoVersionTrackingTest extends AbstractGhidraHeadedIntegrationTe
// Score .999999 and confidence 10.0 (log10 confidence 2.0) and up
runAutoVTCommand(0.999999999, 10.0);
assertTrue(session.getImpliedMatchSet().getMatchCount() > 0);
VTMatchSet impliedMatchSet = session.getImpliedMatchSet();
assertTrue(impliedMatchSet.getMatchCount() > 0);
// test whether good implied matches were accepted
Collection<VTMatch> matches = impliedMatchSet.getMatches();
for (VTMatch match : matches) {
VTAssociationStatus matchStatus = getMatchStatus(session, "Implied Match",
match.getSourceAddress(), match.getDestinationAddress());
if (matchStatus == VTAssociationStatus.BLOCKED) {
continue;
}
VTAssociation association = match.getAssociation();
int numConflicts = association.getRelatedAssociations().size() - 1;
// TODO: use options once options created
// if not min vote count or has conflicts - make sure not accepted match
if (association.getVoteCount() < 2 || numConflicts > 0) {
assertEquals(VTAssociationStatus.AVAILABLE, matchStatus);
continue;
}
// else make sure the match was accepted
assertEquals(VTAssociationStatus.ACCEPTED, matchStatus);
}
}
/*