mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-4251: Added Function Compare action to the Version Tracking main
match table and associated match tables.
This commit is contained in:
parent
77aa79caf1
commit
f982e9bba5
12 changed files with 494 additions and 67 deletions
|
@ -19,13 +19,19 @@ import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.events.*;
|
import ghidra.app.events.ProgramActivatedPluginEvent;
|
||||||
|
import ghidra.app.events.ProgramClosedPluginEvent;
|
||||||
|
import ghidra.app.events.ProgramSelectionPluginEvent;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.ProgramPlugin;
|
import ghidra.app.plugin.ProgramPlugin;
|
||||||
import ghidra.app.plugin.core.functioncompare.actions.CompareFunctionsAction;
|
import ghidra.app.plugin.core.functioncompare.actions.CompareFunctionsAction;
|
||||||
import ghidra.app.plugin.core.functioncompare.actions.CompareFunctionsFromListingAction;
|
import ghidra.app.plugin.core.functioncompare.actions.CompareFunctionsFromListingAction;
|
||||||
import ghidra.app.services.FunctionComparisonService;
|
import ghidra.app.services.FunctionComparisonService;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||||
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
|
import ghidra.framework.model.DomainObjectEvent;
|
||||||
|
import ghidra.framework.model.DomainObjectListener;
|
||||||
|
import ghidra.framework.model.EventType;
|
||||||
import ghidra.framework.plugintool.PluginInfo;
|
import ghidra.framework.plugintool.PluginInfo;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
@ -170,6 +176,13 @@ public class FunctionComparisonPlugin extends ProgramPlugin
|
||||||
return getFromSwingBlocking(() -> functionComparisonManager.compareFunctions(functions));
|
return getFromSwingBlocking(() -> functionComparisonManager.compareFunctions(functions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FunctionComparisonProvider compareFunctions(Set<Function> sourceFunctions,
|
||||||
|
Set<Function> destinationFunctions) {
|
||||||
|
return getFromSwingBlocking(() -> functionComparisonManager
|
||||||
|
.compareFunctions(sourceFunctions, destinationFunctions));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void compareFunctions(Set<Function> functions, FunctionComparisonProvider provider) {
|
public void compareFunctions(Set<Function> functions, FunctionComparisonProvider provider) {
|
||||||
runOnSwingNonBlocking(
|
runOnSwingNonBlocking(
|
||||||
|
|
|
@ -20,7 +20,10 @@ import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
import docking.ComponentProviderActivationListener;
|
import docking.ComponentProviderActivationListener;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||||
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
|
import ghidra.framework.model.DomainObjectEvent;
|
||||||
|
import ghidra.framework.model.EventType;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
@ -81,6 +84,23 @@ public class FunctionComparisonProviderManager implements FunctionComparisonProv
|
||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new comparison between two given sets of functions
|
||||||
|
*
|
||||||
|
* @param sourceFunctions
|
||||||
|
* @param destinationFunctions
|
||||||
|
* @return the new comparison provider
|
||||||
|
*/
|
||||||
|
public FunctionComparisonProvider compareFunctions(Set<Function> sourceFunctions,
|
||||||
|
Set<Function> destinationFunctions) {
|
||||||
|
if (sourceFunctions.isEmpty() || destinationFunctions.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FunctionComparisonProvider provider = createProvider();
|
||||||
|
provider.getModel().compareFunctions(sourceFunctions, destinationFunctions);
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new comparison comparison between two functions
|
* Creates a new comparison comparison between two functions
|
||||||
*
|
*
|
||||||
|
|
|
@ -18,12 +18,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.services;
|
package ghidra.app.services;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
|
||||||
import ghidra.app.plugin.core.functioncompare.*;
|
import ghidra.app.plugin.core.functioncompare.FunctionComparison;
|
||||||
|
import ghidra.app.plugin.core.functioncompare.FunctionComparisonModelListener;
|
||||||
|
import ghidra.app.plugin.core.functioncompare.FunctionComparisonProvider;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
@ -128,6 +136,35 @@ public class FunctionComparisonModel {
|
||||||
fireModelChanged();
|
fireModelChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the model with two sets of functions to compare. This will add the
|
||||||
|
* functions to any existing {@link FunctionComparison comparisons} in the
|
||||||
|
* model and create new comparisons for functions not represented.
|
||||||
|
* <p>
|
||||||
|
* Note: It is assumed that when using this method, all source functions can be
|
||||||
|
* compared to all destination functions; meaning all functions in the source function set will
|
||||||
|
* be added as sources, and all functions in the destination function set will be added as targets.
|
||||||
|
*
|
||||||
|
* @param sourceFunctions
|
||||||
|
* @param destinationFunctions
|
||||||
|
*/
|
||||||
|
public void compareFunctions(Set<Function> sourceFunctions,
|
||||||
|
Set<Function> destinationFunctions) {
|
||||||
|
if (CollectionUtils.isEmpty(sourceFunctions) ||
|
||||||
|
CollectionUtils.isEmpty(destinationFunctions)) {
|
||||||
|
return; // not an error, just return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Function f : sourceFunctions) {
|
||||||
|
FunctionComparison comparison = new FunctionComparison();
|
||||||
|
|
||||||
|
comparison.setSource(f);
|
||||||
|
comparison.addTargets(destinationFunctions);
|
||||||
|
comparisons.add(comparison);
|
||||||
|
}
|
||||||
|
fireModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two functions. If a comparison already exists in the model for
|
* Compares two functions. If a comparison already exists in the model for
|
||||||
* the given source, the target will simply be added to it; otherwise a
|
* the given source, the target will simply be added to it; otherwise a
|
||||||
|
|
|
@ -63,6 +63,19 @@ public interface FunctionComparisonService {
|
||||||
*/
|
*/
|
||||||
public FunctionComparisonProvider compareFunctions(Set<Function> functions);
|
public FunctionComparisonProvider compareFunctions(Set<Function> functions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a comparison between two sets of functions, where all the functions in source list can
|
||||||
|
* be compared against all functions in the destination list.
|
||||||
|
* <p>
|
||||||
|
* Note that this method will always create a new provider.
|
||||||
|
*
|
||||||
|
* @param sourceFunctions
|
||||||
|
* @param destinationFunctions
|
||||||
|
* @return the new comparison provider
|
||||||
|
*/
|
||||||
|
public FunctionComparisonProvider compareFunctions(Set<Function> sourceFunctions,
|
||||||
|
Set<Function> destinationFunctions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a comparison between two functions, where the source function
|
* Creates a comparison between two functions, where the source function
|
||||||
* will be shown on the left side of the comparison dialog and the target
|
* will be shown on the left side of the comparison dialog and the target
|
||||||
|
|
|
@ -383,11 +383,19 @@
|
||||||
<BR>
|
<BR>
|
||||||
<BR>
|
<BR>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<P align="left"><A name="Match_Table_Settings"></A>The <b>Settings</b> <IMG src="images/settings16.gif" border="0">
|
<P align="left"><A name="Match_Table_Settings"></A>The <b>Settings</b> <IMG src="images/settings16.gif" border="0">
|
||||||
action will bring up the version tracking accept and apply options.</P>
|
action will bring up the version tracking accept and apply options.</P>
|
||||||
|
|
||||||
|
<P align="left"><A name="Match_Table_Compare_Functions"></A>The <b>Compare Functions</b>
|
||||||
|
action allows users to visually compare selected matched functions. To initiate this action,
|
||||||
|
select one or more matches from the Version Tracking Matches Table, then choose
|
||||||
|
<b>Compare Functions</b> from the pop up menu. This will open a new
|
||||||
|
<A href="help/topics/FunctionComparison/FunctionComparison.htm">Function Comparison</A>
|
||||||
|
table containing a list of source functions and a list of destination functions.
|
||||||
|
The user can choose one from each list at a time to visually compare to each other.
|
||||||
|
Note: You cannot compare Data matches or External Functions using this action, so
|
||||||
|
if you select either of these as matches they will not be populated in the table.</P>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H2><A name="Match_Filters"></A>Match Filters</H2>
|
<H2><A name="Match_Filters"></A>Match Filters</H2>
|
||||||
|
|
|
@ -110,6 +110,24 @@
|
||||||
|
|
||||||
<H2><A name="Related_Match_Actions"></A>Actions</H2>
|
<H2><A name="Related_Match_Actions"></A>Actions</H2>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<H3><A name="Compare_Functions">Compare Functions</A></H3>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>To initiate this action, navigate to the <B>Related Matches</B> table in either the
|
||||||
|
Destination Tool or the Source Tool. Select one or more matches in the table, then choose
|
||||||
|
<B>Compare Functions</B> from the right-mouse menu. This action will open a new
|
||||||
|
<A HREF="help/topics/FunctionComparison/FunctionComparison.htm">Function Comparison</A>
|
||||||
|
table. The left side of the window will display the function in the current tool location.
|
||||||
|
The right side of the window will contain a pull-down list with the selected matched
|
||||||
|
function(s) from the other program. This allows a user to visually compare the function at
|
||||||
|
the current tool location with the selected matched function(s) from the other program.</P>
|
||||||
|
|
||||||
|
<P>Note: You cannot compare Data matches or External Functions using this action, so
|
||||||
|
if you select either of these as matches they will not be populated in the table.</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<H3><A name="Select_Same_Match_In_Version_Tracking_Matches_Table">Select Match in VT
|
<H3><A name="Select_Same_Match_In_Version_Tracking_Matches_Table">Select Match in VT
|
||||||
Matches Table</A> <IMG alt="" border="0" src="Icons.MAKE_SELECTION_ICON"></H3>
|
Matches Table</A> <IMG alt="" border="0" src="Icons.MAKE_SELECTION_ICON"></H3>
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
package ghidra.feature.vt.gui.plugin;
|
package ghidra.feature.vt.gui.plugin;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
@ -42,6 +42,7 @@ import ghidra.framework.model.*;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
|
import ghidra.framework.plugintool.util.PluginException;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.framework.preferences.Preferences;
|
import ghidra.framework.preferences.Preferences;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
|
@ -119,6 +120,7 @@ public class VTPlugin extends Plugin {
|
||||||
new ImpliedMatchAssociationHook(controller);
|
new ImpliedMatchAssociationHook(controller);
|
||||||
|
|
||||||
initializeOptions();
|
initializeOptions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DockingActionIf getToolAction(String actionName) {
|
private DockingActionIf getToolAction(String actionName) {
|
||||||
|
@ -141,9 +143,37 @@ public class VTPlugin extends Plugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
|
addCustomPlugins();
|
||||||
|
|
||||||
maybeShowHelp();
|
maybeShowHelp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addCustomPlugins() {
|
||||||
|
|
||||||
|
List<String> names = new ArrayList<>(
|
||||||
|
List.of("ghidra.app.plugin.core.functioncompare.FunctionComparisonPlugin"));
|
||||||
|
List<Plugin> plugins = tool.getManagedPlugins();
|
||||||
|
Set<String> existingNames =
|
||||||
|
plugins.stream().map(c -> c.getName()).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
// Note: we check to see if the plugins we want to add have already been added to the tool.
|
||||||
|
// We should not needed to do this, but once the tool has been saved with the plugins added,
|
||||||
|
// they will get added again the next time the tool is loaded. Adding this check here seems
|
||||||
|
// easier than modifying the default to file to load the plugins, since the amount of xml
|
||||||
|
// required for that is non-trivial.
|
||||||
|
try {
|
||||||
|
for (String className : names) {
|
||||||
|
if (!existingNames.contains(className)) {
|
||||||
|
tool.addPlugin(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (PluginException e) {
|
||||||
|
Msg.error(this, "Unable to load plugin", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void maybeShowHelp() {
|
private void maybeShowHelp() {
|
||||||
if (SystemUtilities.isInDevelopmentMode() || SystemUtilities.isInTestingMode()) {
|
if (SystemUtilities.isInDevelopmentMode() || SystemUtilities.isInTestingMode()) {
|
||||||
return; // don't show help for dev mode
|
return; // don't show help for dev mode
|
||||||
|
|
|
@ -658,7 +658,7 @@ public class VTSubToolManager implements VTControllerListener, OptionsChangeList
|
||||||
*
|
*
|
||||||
* @return The source tool from the VT session.
|
* @return The source tool from the VT session.
|
||||||
*/
|
*/
|
||||||
PluginTool getSourceTool() {
|
public PluginTool getSourceTool() {
|
||||||
return sourceTool;
|
return sourceTool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.provider.matchtable;
|
package ghidra.feature.vt.gui.provider.matchtable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import docking.DefaultActionContext;
|
import docking.DefaultActionContext;
|
||||||
|
import ghidra.feature.vt.api.main.VTAssociation;
|
||||||
|
import ghidra.feature.vt.api.main.VTAssociationType;
|
||||||
import ghidra.feature.vt.api.main.VTMatch;
|
import ghidra.feature.vt.api.main.VTMatch;
|
||||||
import ghidra.feature.vt.api.main.VTSession;
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
|
||||||
|
@ -37,7 +40,25 @@ public class VTMatchContext extends DefaultActionContext {
|
||||||
return selectedMatches;
|
return selectedMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelectedRowCount() {
|
||||||
|
return selectedMatches.size();
|
||||||
|
}
|
||||||
|
|
||||||
public VTSession getSession() {
|
public VTSession getSession() {
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<VTMatch> getFunctionMatches() {
|
||||||
|
List<VTMatch> functionMatches = new ArrayList<>();
|
||||||
|
|
||||||
|
for (VTMatch match : selectedMatches) {
|
||||||
|
VTAssociation association = match.getAssociation();
|
||||||
|
if (association.getType() != VTAssociationType.FUNCTION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
functionMatches.add(match);
|
||||||
|
}
|
||||||
|
return functionMatches;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,39 +15,170 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.provider.matchtable;
|
package ghidra.feature.vt.gui.provider.matchtable;
|
||||||
|
|
||||||
import static ghidra.feature.vt.api.impl.VTEvent.*;
|
import static ghidra.feature.vt.api.impl.VTEvent.ASSOCIATION_STATUS_CHANGED;
|
||||||
import static ghidra.feature.vt.gui.actions.TableSelectionTrackingState.*;
|
import static ghidra.feature.vt.api.impl.VTEvent.MATCH_SET_ADDED;
|
||||||
import static ghidra.feature.vt.gui.plugin.VTPlugin.*;
|
import static ghidra.feature.vt.gui.actions.TableSelectionTrackingState.MAINTAIN_SELECTED_ROW_INDEX;
|
||||||
import static ghidra.feature.vt.gui.util.VTOptionDefines.*;
|
import static ghidra.feature.vt.gui.actions.TableSelectionTrackingState.MAINTAIN_SELECTED_ROW_VALUE;
|
||||||
import static ghidra.framework.model.DomainObjectEvent.*;
|
import static ghidra.feature.vt.gui.actions.TableSelectionTrackingState.NO_SELECTION_TRACKING;
|
||||||
|
import static ghidra.feature.vt.gui.plugin.VTPlugin.FILTERED_ICON;
|
||||||
|
import static ghidra.feature.vt.gui.plugin.VTPlugin.UNFILTERED_ICON;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.ACCEPT_MATCH_OPTIONS_NAME;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.APPLY_DATA_NAME_ON_ACCEPT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.APPLY_FUNCTION_NAME_ON_ACCEPT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.APPLY_IMPLIED_MATCHES_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.APPLY_MARKUP_OPTIONS_NAME;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_CREATE_IMPLIED_MATCH;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_DATA_CORRELATOR;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_DUPLICATE_FUNCTION_CORRELATOR;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_EXACT_FUNCTION_CORRELATORS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_IMPLIED_MATCH_CORRELATOR;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_OPTIONS_NAME;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_REFERENCE_CORRELATORS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.AUTO_VT_SYMBOL_CORRELATOR;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.CALLING_CONVENTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.CALL_FIXUP;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.CREATE_IMPLIED_MATCHES_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DATA_CORRELATOR_MIN_LEN_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DATA_MATCH_DATA_TYPE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_CALLING_CONVENTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_CALL_FIXUP;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_DATA_MATCH_DATA_TYPE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_EOL_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_FUNCTION_NAME;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_FUNCTION_RETURN_TYPE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_FUNCTION_SIGNATURE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_HIGHEST_NAME_PRIORITY;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_IGNORE_EXCLUDED_MARKUP_ITEMS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_IGNORE_INCOMPLETE_MARKUP_ITEMS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_INLINE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_LABELS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_NO_RETURN;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_DATA_TYPES;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_NAMES;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PARAMETER_NAMES_REPLACE_IF_SAME_PRIORITY;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PLATE_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_POST_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_PRE_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_REPEATABLE_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DEFAULT_OPTION_FOR_VAR_ARGS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DISPLAY_APPLY_MARKUP_OPTIONS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.DUPE_FUNCTION_CORRELATOR_MIN_LEN_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.END_OF_LINE_COMMENT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.FUNCTION_CORRELATOR_MIN_LEN_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.FUNCTION_NAME;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.FUNCTION_RETURN_TYPE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.FUNCTION_SIGNATURE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.HIGHEST_NAME_PRIORITY;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.IGNORE_EXCLUDED_MARKUP_ITEMS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.IGNORE_INCOMPLETE_MARKUP_ITEMS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.INLINE;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.LABELS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.MAX_CONFLICTS_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.MIN_VOTES_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.NO_RETURN;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.PARAMETER_COMMENTS;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.PARAMETER_DATA_TYPES;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.PARAMETER_NAMES;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.PARAMETER_NAMES_REPLACE_IF_SAME_PRIORITY;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.PLATE_COMMENT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.POST_COMMENT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.PRE_COMMENT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.REF_CORRELATOR_MIN_CONF_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.REF_CORRELATOR_MIN_SCORE_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.REPEATABLE_COMMENT;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.RUN_DUPE_FUNCTION_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.RUN_EXACT_DATA_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.RUN_EXACT_FUNCTION_BYTES_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.RUN_EXACT_FUNCTION_INST_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.RUN_EXACT_SYMBOL_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.RUN_REF_CORRELATORS_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.SYMBOL_CORRELATOR_MIN_LEN_OPTION;
|
||||||
|
import static ghidra.feature.vt.gui.util.VTOptionDefines.VAR_ARGS;
|
||||||
|
import static ghidra.framework.model.DomainObjectEvent.RESTORED;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Adjustable;
|
||||||
import java.awt.event.*;
|
import java.awt.BorderLayout;
|
||||||
import java.util.*;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.event.FocusAdapter;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollBar;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.table.*;
|
import javax.swing.table.TableCellRenderer;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import javax.swing.table.TableColumnModel;
|
||||||
|
|
||||||
import docking.*;
|
import docking.ActionContext;
|
||||||
import docking.widgets.table.*;
|
import docking.DockingWindowManager;
|
||||||
|
import docking.WindowPosition;
|
||||||
|
import docking.action.builder.ActionBuilder;
|
||||||
|
import docking.widgets.table.AbstractSortedTableModel;
|
||||||
|
import docking.widgets.table.GTable;
|
||||||
|
import docking.widgets.table.RowObjectSelectionManager;
|
||||||
|
import docking.widgets.table.RowObjectTableModel;
|
||||||
|
import docking.widgets.table.SelectionManager;
|
||||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||||
|
import generic.theme.GIcon;
|
||||||
|
import ghidra.app.services.FunctionComparisonService;
|
||||||
import ghidra.feature.vt.api.impl.VTEvent;
|
import ghidra.feature.vt.api.impl.VTEvent;
|
||||||
import ghidra.feature.vt.api.impl.VersionTrackingChangeRecord;
|
import ghidra.feature.vt.api.impl.VersionTrackingChangeRecord;
|
||||||
import ghidra.feature.vt.api.main.*;
|
import ghidra.feature.vt.api.main.VTMarkupItem;
|
||||||
import ghidra.feature.vt.gui.actions.*;
|
import ghidra.feature.vt.api.main.VTMatch;
|
||||||
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
import ghidra.feature.vt.gui.actions.AcceptMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.ApplyBlockedMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.ApplyMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.ChooseMatchTagAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.ClearMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.CreateSelectionAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.EditAllTagsAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.MatchTableSelectionAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.RejectMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.RemoveMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.RemoveMatchTagAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.TableSelectionTrackingState;
|
||||||
import ghidra.feature.vt.gui.editors.MatchTagCellEditor;
|
import ghidra.feature.vt.gui.editors.MatchTagCellEditor;
|
||||||
import ghidra.feature.vt.gui.filters.*;
|
import ghidra.feature.vt.gui.filters.AncillaryFilterDialogComponentProvider;
|
||||||
|
import ghidra.feature.vt.gui.filters.Filter;
|
||||||
import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
|
import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
|
||||||
import ghidra.feature.vt.gui.plugin.*;
|
import ghidra.feature.vt.gui.filters.FilterDialogModel;
|
||||||
import ghidra.feature.vt.gui.util.*;
|
import ghidra.feature.vt.gui.filters.FilterStatusListener;
|
||||||
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.*;
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.feature.vt.gui.plugin.VTControllerListener;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTPlugin;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VersionTrackingPluginPackage;
|
||||||
|
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.DestinationLabelTableColumn;
|
||||||
|
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.SourceLabelTableColumn;
|
||||||
|
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.StatusTableColumn;
|
||||||
|
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.TagTableColumn;
|
||||||
|
import ghidra.feature.vt.gui.util.AllTextFilter;
|
||||||
|
import ghidra.feature.vt.gui.util.FilterIconFlashTimer;
|
||||||
|
import ghidra.feature.vt.gui.util.MatchInfo;
|
||||||
|
import ghidra.feature.vt.gui.util.MatchStatusRenderer;
|
||||||
|
import ghidra.feature.vt.gui.util.VTSymbolRenderer;
|
||||||
|
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||||
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
|
import ghidra.framework.model.EventType;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
@ -60,6 +191,8 @@ import help.HelpService;
|
||||||
public class VTMatchTableProvider extends ComponentProviderAdapter
|
public class VTMatchTableProvider extends ComponentProviderAdapter
|
||||||
implements FilterDialogModel<VTMatch>, VTControllerListener {
|
implements FilterDialogModel<VTMatch>, VTControllerListener {
|
||||||
|
|
||||||
|
private static final Icon COMPARISON_ICON = new GIcon("icon.plugin.functioncompare.new");
|
||||||
|
|
||||||
private static final String TITLE = "Version Tracking Matches";
|
private static final String TITLE = "Version Tracking Matches";
|
||||||
private static final String TABLE_SELECTION_STATE = "TABLE_SELECTION_STATE";
|
private static final String TABLE_SELECTION_STATE = "TABLE_SELECTION_STATE";
|
||||||
|
|
||||||
|
@ -128,6 +261,42 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
|
||||||
addLocalAction(new CreateSelectionAction(controller));
|
addLocalAction(new CreateSelectionAction(controller));
|
||||||
tableSelectionStateAction = new MatchTableSelectionAction(this);
|
tableSelectionStateAction = new MatchTableSelectionAction(this);
|
||||||
addLocalAction(tableSelectionStateAction);
|
addLocalAction(tableSelectionStateAction);
|
||||||
|
|
||||||
|
new ActionBuilder("Compare Functions", getName()).popupMenuPath("Compare Functions")
|
||||||
|
.popupMenuGroup("Selection")
|
||||||
|
.popupMenuIcon(COMPARISON_ICON)
|
||||||
|
.keyBinding("shift c")
|
||||||
|
.sharedKeyBinding()
|
||||||
|
.description("Compares the Function(s) with its remote match")
|
||||||
|
.helpLocation(
|
||||||
|
new HelpLocation("VersionTrackingPlugin", "Match_Table_Compare_Functions"))
|
||||||
|
.withContext(VTMatchContext.class)
|
||||||
|
.enabledWhen(this::isValidFunctionComparison)
|
||||||
|
.onAction(this::compareFunctions)
|
||||||
|
.buildAndInstallLocal(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidFunctionComparison(VTMatchContext context) {
|
||||||
|
List<VTMatch> functionMatches = context.getFunctionMatches();
|
||||||
|
return !functionMatches.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compareFunctions(VTMatchContext c) {
|
||||||
|
Set<Function> sourceFunctions = new HashSet<>();
|
||||||
|
Set<Function> destinationFunctions = new HashSet<>();
|
||||||
|
List<VTMatch> matches = c.getFunctionMatches();
|
||||||
|
|
||||||
|
for (VTMatch match : matches) {
|
||||||
|
MatchInfo matchInfo = controller.getMatchInfo(match);
|
||||||
|
|
||||||
|
Function sourceFunction = matchInfo.getSourceFunction();
|
||||||
|
sourceFunctions.add(sourceFunction);
|
||||||
|
Function destinationFunction = matchInfo.getDestinationFunction();
|
||||||
|
destinationFunctions.add(destinationFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionComparisonService service = tool.getService(FunctionComparisonService.class);
|
||||||
|
service.compareFunctions(sourceFunctions, destinationFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback method from the MatchTableSelectionAction
|
// callback method from the MatchTableSelectionAction
|
||||||
|
@ -601,12 +770,14 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(Options options) {
|
public void optionsChanged(Options options) {
|
||||||
// implemented as ControllerListener. Don't care about options changed right now.
|
// implemented as ControllerListener. Don't care about options changed right
|
||||||
|
// now.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void markupItemSelected(VTMarkupItem markupItem) {
|
public void markupItemSelected(VTMarkupItem markupItem) {
|
||||||
// Do nothing since the matches table doesn't need to respond to the mark-up that is selected.
|
// Do nothing since the matches table doesn't need to respond to the mark-up
|
||||||
|
// that is selected.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeOptions() {
|
private void initializeOptions() {
|
||||||
|
@ -828,8 +999,8 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces a refilter, even though filtering operations may be disabled. The reload
|
* Forces a refilter, even though filtering operations may be disabled. The
|
||||||
* is necessary since the model contents may have changed
|
* reload is necessary since the model contents may have changed
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void forceRefilter() {
|
public void forceRefilter() {
|
||||||
|
@ -891,20 +1062,22 @@ 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
|
||||||
* of the table. The default SelectionManager does not restore the selection for that item,
|
* filtered out of the table. The default SelectionManager does not restore the
|
||||||
* as it knows that the item is gone.
|
* selection for that item, 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
|
||||||
* sort operation after the edit.
|
* moved due to a 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
|
||||||
* item is moved or removed.
|
* location, even if the item is moved or removed.
|
||||||
* <p>
|
* <p>
|
||||||
* Creating this object will cancel the default behavior. Calling <tt>restoreSelection</tt>
|
* Creating this object will cancel the default behavior. Calling
|
||||||
* will set the new selection, depending upon the conditions described above.
|
* <tt>restoreSelection</tt> will set the new selection, depending upon the
|
||||||
|
* conditions described above.
|
||||||
*/
|
*/
|
||||||
private class SelectionOverrideMemento {
|
private class SelectionOverrideMemento {
|
||||||
private final int row;
|
private final int row;
|
||||||
|
@ -952,7 +1125,8 @@ public class VTMatchTableProvider extends ComponentProviderAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
||||||
|
|
||||||
|
@ -989,8 +1163,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
|
||||||
* selection mode.
|
* table 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) {
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.provider.onetomany;
|
package ghidra.feature.vt.gui.provider.onetomany;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import docking.DefaultActionContext;
|
import docking.DefaultActionContext;
|
||||||
|
import ghidra.feature.vt.api.main.VTAssociation;
|
||||||
|
import ghidra.feature.vt.api.main.VTAssociationType;
|
||||||
import ghidra.feature.vt.api.main.VTMatch;
|
import ghidra.feature.vt.api.main.VTMatch;
|
||||||
|
|
||||||
public class VTMatchOneToManyContext extends DefaultActionContext {
|
public class VTMatchOneToManyContext extends DefaultActionContext {
|
||||||
|
@ -32,4 +35,23 @@ public class VTMatchOneToManyContext extends DefaultActionContext {
|
||||||
public List<VTMatch> getSelectedMatches() {
|
public List<VTMatch> getSelectedMatches() {
|
||||||
return selectedItems;
|
return selectedItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelectedRowCount() {
|
||||||
|
return selectedItems.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VTMatch> getFunctionMatches() {
|
||||||
|
List<VTMatch> functionMatches = new ArrayList<>();
|
||||||
|
|
||||||
|
for (VTMatch match : selectedItems) {
|
||||||
|
VTAssociation association = match.getAssociation();
|
||||||
|
if (association.getType() != VTAssociationType.FUNCTION) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
functionMatches.add(match);
|
||||||
|
}
|
||||||
|
return functionMatches;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,39 +15,70 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.feature.vt.gui.provider.onetomany;
|
package ghidra.feature.vt.gui.provider.onetomany;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Adjustable;
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollBar;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JToggleButton;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.table.*;
|
import javax.swing.table.TableCellRenderer;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import javax.swing.table.TableColumnModel;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
|
import docking.action.builder.ActionBuilder;
|
||||||
import docking.widgets.label.GDLabel;
|
import docking.widgets.label.GDLabel;
|
||||||
import docking.widgets.table.GTable;
|
import docking.widgets.table.GTable;
|
||||||
import docking.widgets.table.RowObjectTableModel;
|
import docking.widgets.table.RowObjectTableModel;
|
||||||
import docking.widgets.table.threaded.ThreadedTableModel;
|
import docking.widgets.table.threaded.ThreadedTableModel;
|
||||||
import generic.theme.GColor;
|
import generic.theme.GColor;
|
||||||
import generic.theme.GIcon;
|
import generic.theme.GIcon;
|
||||||
|
import ghidra.app.services.FunctionComparisonService;
|
||||||
import ghidra.feature.vt.api.impl.VTEvent;
|
import ghidra.feature.vt.api.impl.VTEvent;
|
||||||
import ghidra.feature.vt.api.main.*;
|
import ghidra.feature.vt.api.main.VTMarkupItem;
|
||||||
import ghidra.feature.vt.gui.actions.*;
|
import ghidra.feature.vt.api.main.VTMatch;
|
||||||
import ghidra.feature.vt.gui.filters.*;
|
import ghidra.feature.vt.api.main.VTSession;
|
||||||
|
import ghidra.feature.vt.gui.actions.AcceptMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.ClearMatchAction;
|
||||||
|
import ghidra.feature.vt.gui.actions.SetVTMatchFromOneToManyAction;
|
||||||
|
import ghidra.feature.vt.gui.filters.Filter;
|
||||||
import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
|
import ghidra.feature.vt.gui.filters.Filter.FilterEditingStatus;
|
||||||
import ghidra.feature.vt.gui.plugin.*;
|
import ghidra.feature.vt.gui.filters.FilterDialogModel;
|
||||||
|
import ghidra.feature.vt.gui.filters.FilterStatusListener;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTController;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTControllerListener;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTPlugin;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTSubToolManager;
|
||||||
|
import ghidra.feature.vt.gui.plugin.VTSubToolManagerListener;
|
||||||
import ghidra.feature.vt.gui.provider.markuptable.DisplayableListingAddress;
|
import ghidra.feature.vt.gui.provider.markuptable.DisplayableListingAddress;
|
||||||
import ghidra.feature.vt.gui.provider.matchtable.MatchTableRenderer;
|
import ghidra.feature.vt.gui.provider.matchtable.MatchTableRenderer;
|
||||||
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.StatusTableColumn;
|
import ghidra.feature.vt.gui.util.AbstractVTMatchTableModel.StatusTableColumn;
|
||||||
import ghidra.feature.vt.gui.util.MatchInfo;
|
import ghidra.feature.vt.gui.util.MatchInfo;
|
||||||
import ghidra.feature.vt.gui.util.MatchStatusRenderer;
|
import ghidra.feature.vt.gui.util.MatchStatusRenderer;
|
||||||
import ghidra.framework.model.*;
|
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||||
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
|
import ghidra.framework.model.DomainObjectEvent;
|
||||||
|
import ghidra.framework.model.EventType;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
import ghidra.program.model.symbol.SymbolTable;
|
||||||
|
@ -58,24 +89,25 @@ import ghidra.util.table.GhidraTable;
|
||||||
import ghidra.util.table.GhidraThreadedTablePanel;
|
import ghidra.util.table.GhidraThreadedTablePanel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The docking window that provides a table of the other tool's function matches for the function
|
* The docking window that provides a table of the other tool's function matches
|
||||||
* containing the current cursor location in this tool's listing.
|
* for the function containing the current cursor location in this tool's
|
||||||
|
* listing.
|
||||||
*/
|
*/
|
||||||
public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAdapter
|
public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAdapter
|
||||||
implements FilterDialogModel<VTMatch>, VTControllerListener, VTSubToolManagerListener {
|
implements FilterDialogModel<VTMatch>, VTControllerListener, VTSubToolManagerListener {
|
||||||
|
|
||||||
private static final String TITLE_PREFIX = "Version Tracking Matches for ";
|
private static final String TITLE_PREFIX = "Version Tracking Matches for ";
|
||||||
private static final Icon ICON = new GIcon("icon.version.tracking.provider.one.to.many");
|
private static final Icon ICON = new GIcon("icon.version.tracking.provider.one.to.many");
|
||||||
|
private static final Icon COMPARISON_ICON = new GIcon("icon.plugin.functioncompare.new");
|
||||||
|
|
||||||
protected static final Color LOCAL_INFO_FOREGROUND_COLOR =
|
protected static final Color LOCAL_INFO_FOREGROUND_COLOR = new GColor(
|
||||||
new GColor("color.fg.version.tracking.function.match.local.info");
|
"color.fg.version.tracking.function.match.local.info");
|
||||||
|
|
||||||
private JComponent component;
|
private JComponent component;
|
||||||
private MatchThreadedTablePanel tablePanel;
|
private MatchThreadedTablePanel tablePanel;
|
||||||
protected GhidraTable matchesTable;
|
protected GhidraTable matchesTable;
|
||||||
private ListSelectionListener matchSelectionListener;
|
private ListSelectionListener matchSelectionListener;
|
||||||
protected VTMatchOneToManyTableModel oneToManyTableModel;
|
protected VTMatchOneToManyTableModel oneToManyTableModel;
|
||||||
|
|
||||||
private JToggleButton ancillaryFilterButton;
|
private JToggleButton ancillaryFilterButton;
|
||||||
private Set<Filter<VTMatch>> filters = new HashSet<>();
|
private Set<Filter<VTMatch>> filters = new HashSet<>();
|
||||||
private FilterStatusListener refilterListener = new RefilterListener();
|
private FilterStatusListener refilterListener = new RefilterListener();
|
||||||
|
@ -100,7 +132,8 @@ public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAda
|
||||||
private VTMatch pendingMatchSelection;
|
private VTMatch pendingMatchSelection;
|
||||||
|
|
||||||
public VTMatchOneToManyTableProvider(PluginTool tool, VTController controller,
|
public VTMatchOneToManyTableProvider(PluginTool tool, VTController controller,
|
||||||
VTSubToolManager subToolManager, boolean isSource) {
|
VTSubToolManager subToolManager,
|
||||||
|
boolean isSource) {
|
||||||
super(tool, TITLE_PREFIX + (isSource ? "Source" : "Destination"), VTPlugin.OWNER);
|
super(tool, TITLE_PREFIX + (isSource ? "Source" : "Destination"), VTPlugin.OWNER);
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.subToolManager = subToolManager;
|
this.subToolManager = subToolManager;
|
||||||
|
@ -130,6 +163,43 @@ public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAda
|
||||||
addLocalAction(new SetVTMatchFromOneToManyAction(controller, true));
|
addLocalAction(new SetVTMatchFromOneToManyAction(controller, true));
|
||||||
addLocalAction(new ClearMatchAction(controller));
|
addLocalAction(new ClearMatchAction(controller));
|
||||||
addLocalAction(new AcceptMatchAction(controller));
|
addLocalAction(new AcceptMatchAction(controller));
|
||||||
|
new ActionBuilder("Compare Functions", getName())
|
||||||
|
.popupMenuPath("Compare Functions")
|
||||||
|
.popupMenuIcon(COMPARISON_ICON)
|
||||||
|
.popupMenuGroup("AAA_VT_Main")
|
||||||
|
.keyBinding("shift c")
|
||||||
|
.sharedKeyBinding()
|
||||||
|
.description("Compares the Function(s) with its remote match")
|
||||||
|
.helpLocation(new HelpLocation("VersionTrackingPlugin", "Compare_Functions"))
|
||||||
|
.withContext(VTMatchOneToManyContext.class)
|
||||||
|
.enabledWhen(this::isValidFunctionComparison)
|
||||||
|
.onAction(this::compareFunctions)
|
||||||
|
.buildAndInstallLocal(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidFunctionComparison(VTMatchOneToManyContext context) {
|
||||||
|
List<VTMatch> functionMatches = context.getFunctionMatches();
|
||||||
|
return !functionMatches.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void compareFunctions(VTMatchOneToManyContext c) {
|
||||||
|
List<VTMatch> selectedMatches = c.getSelectedMatches();
|
||||||
|
|
||||||
|
for (VTMatch match : selectedMatches) {
|
||||||
|
MatchInfo matchInfo = controller.getMatchInfo(match);
|
||||||
|
|
||||||
|
// Whichever codebrowser we are currently in, is what will be on the left
|
||||||
|
// side of the compare functions window.
|
||||||
|
Function leftFunction = matchInfo.getSourceFunction(),
|
||||||
|
rightFunction = matchInfo.getDestinationFunction();
|
||||||
|
if (!isSource) {
|
||||||
|
leftFunction = matchInfo.getDestinationFunction();
|
||||||
|
rightFunction = matchInfo.getSourceFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionComparisonService service = tool.getService(FunctionComparisonService.class);
|
||||||
|
service.compareFunctions(leftFunction, rightFunction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -292,9 +362,9 @@ public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAda
|
||||||
|
|
||||||
private List<VTMatch> getSelectedMatches() {
|
private List<VTMatch> getSelectedMatches() {
|
||||||
List<VTMatch> list = new ArrayList<>();
|
List<VTMatch> list = new ArrayList<>();
|
||||||
int selectedRowCount = matchesTable.getSelectedRowCount();
|
int[] selectedRows = matchesTable.getSelectedRows();
|
||||||
if (selectedRowCount == 1) {
|
|
||||||
int row = matchesTable.getSelectedRow();
|
for (int row : selectedRows) {
|
||||||
VTMatch mySelectedMatch = oneToManyTableModel.getRowObject(row);
|
VTMatch mySelectedMatch = oneToManyTableModel.getRowObject(row);
|
||||||
list.add(mySelectedMatch);
|
list.add(mySelectedMatch);
|
||||||
}
|
}
|
||||||
|
@ -467,7 +537,8 @@ public abstract class VTMatchOneToManyTableProvider extends ComponentProviderAda
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void markupItemSelected(VTMarkupItem markupItem) {
|
public void markupItemSelected(VTMarkupItem markupItem) {
|
||||||
// Do nothing since the one to many match table doesn't need to respond to the mark-up that is selected.
|
// Do nothing since the one to many match table doesn't need to respond to the
|
||||||
|
// mark-up that is selected.
|
||||||
}
|
}
|
||||||
|
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue