mirror of
https://github.com/JHUAPL/CodeCut.git
synced 2026-01-09 13:28:06 -05:00
addition of graphcut module
Addition of GraphCut module allows graphing of Namespaces and their relationships. Also allows for filtering through the CodeCut table.
This commit is contained in:
23
codecut-gui/src/main/help/help/topics/skeleton/help.html
Normal file
23
codecut-gui/src/main/help/help/topics/skeleton/help.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
<META http-equiv="Content-Language" content="en-us">
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<META name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<META name="ProgId" content="FrontPage.Editor.Document">
|
||||
|
||||
<TITLE>Skeleton Help File for a Module</TITLE>
|
||||
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<H1><a name="HelpAnchor"></a>Skeleton Help File for a Module</H1>
|
||||
|
||||
<P>This is a simple skeleton help topic. For a better description of what should and should not
|
||||
go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your
|
||||
favorite help topic. In general, language modules do not have their own help topics.</P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
215
codecut-gui/src/main/java/codecutguiv2/ChecklistProvider.java
Normal file
215
codecut-gui/src/main/java/codecutguiv2/ChecklistProvider.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package codecutguiv2;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.WindowPosition;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.services.BlockModelService;
|
||||
import ghidra.feature.vt.api.db.TableColumn;
|
||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.table.GhidraTableCellRenderer;
|
||||
import ghidra.util.table.GhidraThreadedTablePanel;
|
||||
import graphcut.GraphCutProvider;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class ChecklistProvider extends ComponentProviderAdapter implements ActionListener {
|
||||
|
||||
private static final ImageIcon ICON = ResourceManager.loadImage("images/textfield.png");
|
||||
private static final String BUTTON_STRING = "Apply Changes";
|
||||
private static final String RESET_STRING = "Reset Graph Filter";
|
||||
|
||||
private CodeCutGUIPlugin plugin;
|
||||
private GraphCutProvider graphProvider;
|
||||
GhidraTable table;
|
||||
DefaultTableModel model;
|
||||
|
||||
private JPanel boxPanel;
|
||||
|
||||
ChecklistProvider(CodeCutGUIPlugin plugin){
|
||||
super(plugin.getTool(), "Namespaces in Graph", plugin.getName(), ProgramActionContext.class);
|
||||
this.plugin = plugin;
|
||||
this.graphProvider = plugin.getGraphProvider();
|
||||
|
||||
setIcon(ICON);
|
||||
addToToolbar();
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), "CodeCut_Table"));
|
||||
setWindowGroup("codecutTable");
|
||||
setIntraGroupPosition(WindowPosition.BOTTOM);
|
||||
|
||||
boxPanel = new JPanel();
|
||||
boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
Object[] columnNames = {"Namespace", "Added to Graph"};
|
||||
Object[][] data = {};
|
||||
model = new DefaultTableModel(data, columnNames) {
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
if(column == 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
table = new GhidraTable(model) {
|
||||
@Override
|
||||
public Class getColumnClass(int column) {
|
||||
switch(column) {
|
||||
case 0:
|
||||
return Namespace.class;
|
||||
case 1:
|
||||
return Boolean.class;
|
||||
default:
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
};
|
||||
table.getTableHeader().setReorderingAllowed(false);
|
||||
table.setPreferredScrollableViewportSize(table.getPreferredSize());
|
||||
table.setDefaultRenderer(Namespace.class, new DefaultTableCellRenderer() {
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
setText(((Namespace) value).getName());
|
||||
}
|
||||
});
|
||||
JScrollPane scrollPane = new JScrollPane(table);
|
||||
boxPanel.add(scrollPane);
|
||||
boxPanel.setSize(boxPanel.getPreferredSize());
|
||||
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
|
||||
JButton applyButton = new JButton(BUTTON_STRING);
|
||||
applyButton.setVerticalTextPosition(AbstractButton.CENTER);
|
||||
applyButton.setActionCommand(BUTTON_STRING);
|
||||
applyButton.addActionListener(this);
|
||||
|
||||
JButton resetButton = new JButton(RESET_STRING);
|
||||
resetButton.setVerticalTextPosition(AbstractButton.CENTER);
|
||||
resetButton.setActionCommand(RESET_STRING);
|
||||
resetButton.addActionListener(this);
|
||||
|
||||
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
|
||||
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
|
||||
buttonPane.add(Box.createHorizontalGlue());
|
||||
buttonPane.add(applyButton);
|
||||
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
buttonPane.add(resetButton);
|
||||
boxPanel.add(buttonPane);
|
||||
|
||||
setIntraGroupPosition(WindowPosition.RIGHT);
|
||||
buildTable();
|
||||
}
|
||||
|
||||
void buildTable() {
|
||||
model.setRowCount(0);
|
||||
Set<Namespace>inGraph = graphProvider.getNamespacesInFilter();
|
||||
for(Namespace ns: inGraph) {
|
||||
model.addRow(new Object[]{ns, true});
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
plugin = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if(BUTTON_STRING.equals(e.getActionCommand())) {
|
||||
Vector<Vector> data = model.getDataVector();
|
||||
for(int i = 0; i < model.getRowCount(); i++) {
|
||||
Namespace victim = (Namespace)data.elementAt(i).elementAt(0);
|
||||
if(!(boolean)data.elementAt(i).elementAt(1)) {
|
||||
graphProvider.removeFromWhitelist(victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(RESET_STRING.equals(e.getActionCommand())) {
|
||||
graphProvider.resetWhitelist();
|
||||
}
|
||||
|
||||
buildTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return boxPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
Program program = plugin.getProgram();
|
||||
if(program == null) {
|
||||
return null;
|
||||
}
|
||||
return new ProgramActionContext(this, program);
|
||||
}
|
||||
|
||||
public void open() {
|
||||
if (!isVisible()) {
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package codecutguiv2;
|
||||
|
||||
import java.awt.Cursor;
|
||||
@@ -56,6 +57,7 @@ import ghidra.app.decompiler.component.DecompilerController;
|
||||
import ghidra.app.events.ProgramActivatedPluginEvent;
|
||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerProvider;
|
||||
import ghidra.app.plugin.core.symboltree.actions.*;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
@@ -65,11 +67,14 @@ import ghidra.app.services.GoToService;
|
||||
//import ghidra.app.services.DecExtendService;
|
||||
import ghidra.app.util.SymbolInspector;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.OptionsChangeListener;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.AddressRangeImpl;
|
||||
@@ -88,9 +93,12 @@ import ghidra.util.HTMLUtilities;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.task.SwingUpdateManager;
|
||||
import graphcut.*;
|
||||
import ghidra.util.task.*;
|
||||
import ghidra.util.datastruct.*;
|
||||
import resources.Icons;
|
||||
@@ -112,13 +120,14 @@ import static ghidra.program.util.ProgramEvent.*;
|
||||
" provides navigation to the symbols in the Code Browser, and " +
|
||||
"allows symbols to be renamed and deleted. This plugin also " +
|
||||
"shows references to a symbol. Filters can be set " +
|
||||
"to show subsets of the symbols.",
|
||||
"to show subsets of the symbols." +
|
||||
" Allows the graphing of namespaces and their relations.",
|
||||
servicesRequired = { GoToService.class, BlockModelService.class },
|
||||
eventsProduced = { ProgramLocationPluginEvent.class },
|
||||
eventsConsumed = { ProgramActivatedPluginEvent.class }
|
||||
)
|
||||
//@formatter:on
|
||||
public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
public class CodeCutGUIPlugin extends ProgramPlugin implements DomainObjectListener, OptionsChangeListener{
|
||||
|
||||
final static Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
|
||||
final static Cursor NORM_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
|
||||
@@ -154,6 +163,20 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
private Map<Namespace, String> suggestedModuleNames;
|
||||
//private DecExtendService decExtService;
|
||||
|
||||
//GraphCut Variables
|
||||
public static final String GRAPH_NAME = "CodeCut Object Graph";
|
||||
static final String SHOW_PROVIDER_ACTION_NAME = "Display CodeCut Object Graph";
|
||||
public static final HelpLocation DEFAULT_HELP =
|
||||
new HelpLocation(CodeCutGUIPlugin.class.getSimpleName(),
|
||||
CodeCutGUIPlugin.class.getSimpleName());
|
||||
private GraphCutProvider graphProvider;
|
||||
private VisualGraphOptions vgOptions = new VisualGraphOptions();
|
||||
private static final int MIN_UPDATE_DELAY = 750;
|
||||
private SwingUpdateManager locationUpdater = new SwingUpdateManager(MIN_UPDATE_DELAY, () ->{
|
||||
doLocationChanged();
|
||||
});
|
||||
private ChecklistProvider checklistProvider;
|
||||
|
||||
public CodeCutGUIPlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
|
||||
@@ -180,12 +203,17 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
createProvider = new CreateProvider(this);
|
||||
combineProvider = new CombineProvider(this);
|
||||
decompProvider = new DecompileRangeProvider(this);
|
||||
graphProvider = new GraphCutProvider(tool, this);
|
||||
checklistProvider = new ChecklistProvider(this);
|
||||
|
||||
createNamespaceActions();
|
||||
createSymActions();
|
||||
createRefActions();
|
||||
createMapActions();
|
||||
createExportActions();
|
||||
createGraphActions();
|
||||
initializeGraphOptions();
|
||||
createChecklistActions();
|
||||
|
||||
//decExtService = tool.getService(DecExtendService.class);
|
||||
//if (decExtService == null) {
|
||||
@@ -195,6 +223,9 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
inspector = new SymbolInspector(getTool(), symProvider.getComponent());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tells a plugin that it is no longer needed.
|
||||
* The plugin should remove itself from anything that
|
||||
@@ -250,20 +281,27 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
suggestedModuleNames.clear();
|
||||
suggestedModuleNames = null;
|
||||
}
|
||||
|
||||
graphProvider.dispose();
|
||||
checklistProvider.dispose();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readConfigState(SaveState saveState) {
|
||||
symProvider.readConfigState(saveState);
|
||||
graphProvider.readConfigState(saveState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeConfigState(SaveState saveState) {
|
||||
symProvider.writeConfigState(saveState);
|
||||
graphProvider.writeConfigState(saveState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processEvent(PluginEvent event) {
|
||||
super.processEvent(event);
|
||||
if (event instanceof ProgramActivatedPluginEvent) {
|
||||
ProgramActivatedPluginEvent progEvent = (ProgramActivatedPluginEvent) event;
|
||||
Program oldProg = currentProgram;
|
||||
@@ -440,6 +478,10 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
return symProvider;
|
||||
}
|
||||
|
||||
GraphCutProvider getGraphProvider() {
|
||||
return graphProvider;
|
||||
}
|
||||
|
||||
ReferenceProvider getReferenceProvider() {
|
||||
return refProvider;
|
||||
}
|
||||
@@ -1415,4 +1457,131 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createGraphActions() {
|
||||
DockingAction showProviderAction = new DockingAction(SHOW_PROVIDER_ACTION_NAME, getName(), true) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
graphProvider.setVisible(true);
|
||||
}
|
||||
};
|
||||
tool.addAction(showProviderAction);
|
||||
|
||||
DockingAction addToGraphAction = new DockingAction("Add Namespace to Graph", getName(), KeyBindingType.SHARED) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
graphProvider.addToWhitelist(symProvider.getCurrentSymbol().getParentNamespace());
|
||||
checklistProvider.buildTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return symProvider.getCurrentSymbol() != null;
|
||||
}
|
||||
};
|
||||
addToGraphAction.setPopupMenuData(
|
||||
new MenuData(new String[] { "Add Namespace to Graph" }, "0"));
|
||||
addToGraphAction.setDescription("Add this Namespace to the CodeCut Graph");
|
||||
tool.addLocalAction(symProvider, addToGraphAction);
|
||||
|
||||
DockingAction displayCodeCutGraphAction =
|
||||
new DockingAction("Display_CodeCut_Graph", this.getName()) {
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return symProvider.getCurrentSymbol() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
graphProvider.setVisible(true);
|
||||
}
|
||||
};
|
||||
MenuData graphModule = new MenuData(new String[] {ToolConstants.MENU_GRAPH, "Display CodeCut Object Graph"}, null, "Display CodeCut Object Graph");
|
||||
graphModule.setMenuSubGroup("1");
|
||||
displayCodeCutGraphAction.setMenuBarData(graphModule);
|
||||
displayCodeCutGraphAction.setHelpLocation(null);
|
||||
displayCodeCutGraphAction.setAddToAllWindows(true);
|
||||
tool.addAction(displayCodeCutGraphAction);
|
||||
|
||||
}
|
||||
|
||||
void showProvider() {
|
||||
graphProvider.setVisible(true);
|
||||
}
|
||||
|
||||
public Address getCurrentAddress() {
|
||||
if (currentLocation == null) {
|
||||
return null;
|
||||
}
|
||||
return currentLocation.getAddress();
|
||||
}
|
||||
|
||||
public VisualGraphOptions getOptions() {
|
||||
return vgOptions;
|
||||
}
|
||||
|
||||
public ProgramLocation getCurrentLocation() {
|
||||
return currentLocation;
|
||||
}
|
||||
|
||||
private void initializeGraphOptions() {
|
||||
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
|
||||
options.addOptionsChangeListener(this);
|
||||
|
||||
HelpLocation help = new HelpLocation(getName(), "Options");
|
||||
|
||||
Options graphOptions = options.getOptions(GRAPH_NAME);
|
||||
vgOptions.registerOptions(graphOptions, help);
|
||||
vgOptions.loadOptions(graphOptions);
|
||||
graphProvider.optionsChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue, Object newValue) throws OptionsVetoException {
|
||||
|
||||
Options graphOptions = options.getOptions(GRAPH_NAME);
|
||||
vgOptions.loadOptions(graphOptions);
|
||||
graphProvider.optionsChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void locationChanged(ProgramLocation loc) {
|
||||
locationUpdater.update();
|
||||
}
|
||||
|
||||
private void doLocationChanged() {
|
||||
graphProvider.locationChanged(getCurrentLocation());
|
||||
}
|
||||
|
||||
public void handleProviderLocationChanged(ProgramLocation location) {
|
||||
GoToService goTo = getGoToService();
|
||||
if (goTo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
SystemUtilities.runSwingLater(() -> {
|
||||
goTo.goTo(location);
|
||||
});
|
||||
}
|
||||
|
||||
public void createChecklistActions() {
|
||||
String popupGroup = "0";
|
||||
|
||||
DockingAction showChecklistAction = new DockingAction("Show Namespaces in Graph Filter", getName(), KeyBindingType.SHARED) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
checklistProvider.open();
|
||||
checklistProvider.buildTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
return symProvider.getCurrentSymbol() != null;
|
||||
}
|
||||
};
|
||||
showChecklistAction.setPopupMenuData(
|
||||
new MenuData(new String[] { "Show Namespaces in Graph Filter" }, popupGroup));
|
||||
showChecklistAction.setDescription("Show Namespaces that have been added to the CodeCut Graph");
|
||||
tool.addLocalAction(symProvider, showChecklistAction);
|
||||
}
|
||||
}
|
||||
|
||||
88
codecut-gui/src/main/java/graphcut/EmptyGraphCutData.java
Normal file
88
codecut-gui/src/main/java/graphcut/EmptyGraphCutData.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/EmptyFcgData.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.GraphPerspectiveInfo;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* empty data used to avoid null checks
|
||||
*/
|
||||
public class EmptyGraphCutData implements GraphCutData {
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace() {
|
||||
throw new UnsupportedOperationException("Empty data has no namespace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamespace(Namespace ns) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph getGraph() {
|
||||
throw new UnsupportedOperationException("Empty data has no graph");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceEdgeCache getNamespaceEdgeCache() {
|
||||
throw new UnsupportedOperationException("Empty data has no namespace edge cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective(){
|
||||
throw new UnsupportedOperationException("Empty data does not need view information");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGraphPerspective(GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info) {
|
||||
throw new UnsupportedOperationException("Empty data does not need view information");
|
||||
}
|
||||
}
|
||||
126
codecut-gui/src/main/java/graphcut/GraphCutComponent.java
Normal file
126
codecut-gui/src/main/java/graphcut/GraphCutComponent.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import edu.uci.ics.jung.visualization.renderers.Renderer;
|
||||
import functioncalls.graph.FcgEdge;
|
||||
import functioncalls.graph.FcgVertex;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.graph.viewer.GraphComponent;
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
import ghidra.graph.viewer.SatelliteGraphViewer;
|
||||
import ghidra.graph.viewer.VisualGraphViewUpdater;
|
||||
import ghidra.graph.viewer.edge.VisualEdgeRenderer;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.graph.viewer.renderer.VisualVertexSatelliteRenderer;
|
||||
import ghidra.graph.viewer.vertex.VisualVertexRenderer;
|
||||
|
||||
/**
|
||||
* A graph component for GraphCut
|
||||
*/
|
||||
public class GraphCutComponent extends GraphComponent<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
|
||||
|
||||
private GraphCutGraph gcGraph;
|
||||
|
||||
private GraphCutVertexPaintTransformer vertexPaintTransformer =
|
||||
new GraphCutVertexPaintTransformer(GraphCutVertex.DEFAULT_VERTEX_SHAPE_COLOR);
|
||||
|
||||
private GraphCutEdgePaintTransformer edgePaintTransformer =
|
||||
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.primary.direct"),
|
||||
new GColor("color.bg.plugin.fcg.edge.primary.indirect"));
|
||||
|
||||
private GraphCutEdgePaintTransformer selectedEdgePaintTransformer =
|
||||
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.primary.direct.selected"),
|
||||
new GColor("color.bg.plugin.fcg.edge.primary.indirect.selected"));
|
||||
|
||||
private GraphCutEdgePaintTransformer satelliteEdgePaintTransformer =
|
||||
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.satellite.direct"),
|
||||
new GColor("color.bg.plugin.fcg.edge.satellite.indirect"));
|
||||
|
||||
GraphCutComponent(GraphCutGraph g){
|
||||
setGraph(g);
|
||||
build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphCutVertex getInitialVertex() {
|
||||
return gcGraph.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decoratePrimaryViewer(GraphViewer<GraphCutVertex, GraphCutEdge> viewer,
|
||||
VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
|
||||
|
||||
super.decoratePrimaryViewer(viewer, layout);
|
||||
|
||||
Renderer<GraphCutVertex, GraphCutEdge> renderer = viewer.getRenderer();
|
||||
VisualVertexRenderer<GraphCutVertex, GraphCutEdge> vertexRenderer =
|
||||
(VisualVertexRenderer<GraphCutVertex, GraphCutEdge>) renderer.getVertexRenderer();
|
||||
vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer);
|
||||
|
||||
VisualEdgeRenderer<GraphCutVertex, GraphCutEdge> edgeRenderer =
|
||||
(VisualEdgeRenderer<GraphCutVertex, GraphCutEdge>) renderer.getEdgeRenderer();
|
||||
edgeRenderer.setDrawColorTransformer(edgePaintTransformer);
|
||||
edgeRenderer.setSelectedColorTransformer(selectedEdgePaintTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorateSatelliteViewer(SatelliteGraphViewer<GraphCutVertex, GraphCutEdge> viewer,
|
||||
VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
|
||||
|
||||
super.decorateSatelliteViewer(viewer, layout);
|
||||
|
||||
Renderer<GraphCutVertex, GraphCutEdge> renderer = viewer.getRenderer();
|
||||
VisualVertexSatelliteRenderer<GraphCutVertex, GraphCutEdge> vertexRenderer =
|
||||
(VisualVertexSatelliteRenderer<GraphCutVertex, GraphCutEdge>) renderer.getVertexRenderer();
|
||||
vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer);
|
||||
|
||||
VisualEdgeRenderer<GraphCutVertex, GraphCutEdge> edgeRenderer =
|
||||
(VisualEdgeRenderer<GraphCutVertex, GraphCutEdge>) renderer.getEdgeRenderer();
|
||||
edgeRenderer.setDrawColorTransformer(satelliteEdgePaintTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
gcGraph = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisualGraphViewUpdater<GraphCutVertex, GraphCutEdge> getViewUpdater(){
|
||||
return super.getViewUpdater();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
97
codecut-gui/src/main/java/graphcut/GraphCutData.java
Normal file
97
codecut-gui/src/main/java/graphcut/GraphCutData.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/FcgData.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.GraphPerspectiveInfo;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* Allows us to retrieve and work on the graph. Makes caching data simple
|
||||
*/
|
||||
public interface GraphCutData {
|
||||
|
||||
/**
|
||||
* The namespace of this data
|
||||
* @return the namespace
|
||||
*/
|
||||
Namespace getNamespace();
|
||||
|
||||
/**
|
||||
* The graph of this data
|
||||
* @return the graph
|
||||
*/
|
||||
GraphCutGraph getGraph();
|
||||
|
||||
/**
|
||||
* Returns the cache of edges. Not in the graph but used to track existing edges that are not yet in the graph.
|
||||
* @return
|
||||
*/
|
||||
NamespaceEdgeCache getNamespaceEdgeCache();
|
||||
|
||||
/**
|
||||
* True if this data has a valid namespace
|
||||
* @return true if this data has a valid namespace
|
||||
*/
|
||||
boolean hasResults();
|
||||
|
||||
/**
|
||||
* False if the graph in this data has not yet been loaded
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Dispose the contents of this data
|
||||
*/
|
||||
void dispose();
|
||||
|
||||
/**
|
||||
* Returns the view's graph perspective. this is used by the view to restore itself.
|
||||
* @return the view's graph perspective
|
||||
*/
|
||||
GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective();
|
||||
|
||||
/**
|
||||
* Set the view information for this graph data
|
||||
* @param info the perspective to set
|
||||
*/
|
||||
void setGraphPerspective(GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info);
|
||||
|
||||
/**
|
||||
* Returns true if this data's namespace is equal to the given one
|
||||
* @param ns the namespace to test
|
||||
* @return true if this data's namespace is equal to the given one
|
||||
*/
|
||||
boolean isNamespace(Namespace ns);
|
||||
}
|
||||
79
codecut-gui/src/main/java/graphcut/GraphCutDataFactory.java
Normal file
79
codecut-gui/src/main/java/graphcut/GraphCutDataFactory.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/FcgDataFactory.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import com.google.common.cache.*;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* A factory that will create GraphCutGraph data objects for a given namespace
|
||||
*/
|
||||
public class GraphCutDataFactory {
|
||||
|
||||
private LoadingCache<Namespace, GraphCutData> cache;
|
||||
|
||||
GraphCutDataFactory(RemovalListener<Namespace, GraphCutData> listener){
|
||||
|
||||
cache = CacheBuilder
|
||||
.newBuilder()
|
||||
.maximumSize(5)
|
||||
.removalListener(listener)
|
||||
.build(new CacheLoader<Namespace, GraphCutData> () {
|
||||
@Override
|
||||
public GraphCutData load(Namespace ns) throws Exception {
|
||||
return new ValidGraphCutData(ns, new GraphCutGraph());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
GraphCutData create(Namespace ns) {
|
||||
if (ns == null) {
|
||||
return new EmptyGraphCutData();
|
||||
}
|
||||
|
||||
GraphCutData data = cache.getUnchecked(ns);
|
||||
return data;
|
||||
}
|
||||
|
||||
void remove(Namespace ns) {
|
||||
cache.invalidate(ns);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
cache.invalidateAll();
|
||||
}
|
||||
|
||||
}
|
||||
70
codecut-gui/src/main/java/graphcut/GraphCutEdge.java
Normal file
70
codecut-gui/src/main/java/graphcut/GraphCutEdge.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.edge.AbstractVisualEdge;
|
||||
import graphcut.GraphCutVertex;
|
||||
/**
|
||||
* A GraphCut Edge
|
||||
*/
|
||||
|
||||
public class GraphCutEdge extends AbstractVisualEdge<GraphCutVertex> {
|
||||
|
||||
public GraphCutEdge(GraphCutVertex start, GraphCutVertex end) {
|
||||
super(start, end);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@Override
|
||||
public GraphCutEdge cloneEdge(GraphCutVertex start, GraphCutVertex end) {
|
||||
return new GraphCutEdge(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an edge is direct from a lower level.
|
||||
* @return true if this edge is a direct edge
|
||||
*/
|
||||
public boolean isDirectEdge() {
|
||||
GraphCutLevel startLevel = getStart().getLevel();
|
||||
GraphCutLevel endLevel = getEnd().getLevel();
|
||||
if(startLevel.isSource() || endLevel.isSource()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GraphCutLevel parent = startLevel.parent();
|
||||
if (parent.equals(endLevel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GraphCutLevel child = startLevel.child();
|
||||
return child.equals(endLevel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import java.awt.Color;
|
||||
import ghidra.util.ColorUtils;
|
||||
|
||||
public class GraphCutEdgePaintTransformer implements Function<GraphCutEdge, Color> {
|
||||
private Color directColor;
|
||||
private Color indirectColor;
|
||||
|
||||
private Color[] directColorWithAlpha = new Color[10];
|
||||
|
||||
public GraphCutEdgePaintTransformer(Color directColor, Color indirectColor) {
|
||||
this.directColor = directColor;
|
||||
this.indirectColor = indirectColor;
|
||||
|
||||
directColorWithAlpha = alphatize(directColor);
|
||||
}
|
||||
|
||||
private Color[] alphatize(Color c) {
|
||||
Color[] alphad = new Color[10];
|
||||
alphad[0] = c;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
double newAlpha = 255 - (i * 25.5);
|
||||
alphad[i] = ColorUtils.withAlpha(c, (int) newAlpha);
|
||||
}
|
||||
return alphad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color apply(GraphCutEdge e) {
|
||||
if (e.isDirectEdge()) {
|
||||
return getDirectEdgeColor(e);
|
||||
}
|
||||
|
||||
return indirectColor;
|
||||
}
|
||||
|
||||
private Color getDirectEdgeColor(GraphCutEdge e) {
|
||||
return directColor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/FcgEmphasizeEdgesJob.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import ghidra.graph.job.AbstractGraphVisibilityTransitionJob;
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
|
||||
public class GraphCutEmphasizeEdgesJob extends AbstractGraphVisibilityTransitionJob<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
private Set<GraphCutEdge> edges;
|
||||
|
||||
public GraphCutEmphasizeEdgesJob(GraphViewer<GraphCutVertex, GraphCutEdge> viewer, Set<GraphCutEdge> edges) {
|
||||
super(viewer, true);
|
||||
this.edges = edges;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateOpacity(double percentComplete) {
|
||||
|
||||
double remaining = percentComplete;
|
||||
if(percentComplete > 0.5){
|
||||
remaining = 1 - percentComplete;
|
||||
}
|
||||
|
||||
double modified = remaining * 10;
|
||||
|
||||
for (GraphCutEdge e : edges) {
|
||||
e.setEmphasis(modified);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/FcgExpandingVertexCollection.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||
import functioncalls.graph.FcgDirection;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public class GraphCutExpandingVertexCollection {
|
||||
|
||||
private Comparator<GraphCutVertex> vertexComparator =
|
||||
(v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0;
|
||||
private Comparator<GraphCutVertex> sourceVertexComparator = this::compareVerticesByLayoutPosition;
|
||||
|
||||
private Map<GraphCutVertex, TreeSet<GraphCutVertex>> newVerticesBySource = LazyMap.lazyMap(
|
||||
new TreeMap<>(sourceVertexComparator), () -> new TreeSet<>(vertexComparator));
|
||||
|
||||
private GraphViewer<GraphCutVertex, GraphCutEdge> viewer;
|
||||
private GraphCutLevel parentLevel;
|
||||
private GraphCutLevel expandingLevel;
|
||||
private Set<GraphCutVertex> newVertices;
|
||||
private Set<GraphCutEdge> newEdges;
|
||||
private Set<GraphCutEdge> indirectEdges = Collections.emptySet();
|
||||
private boolean isIncoming;
|
||||
private Iterable<GraphCutVertex> sources;
|
||||
|
||||
public GraphCutExpandingVertexCollection(Iterable<GraphCutVertex> sources, GraphCutLevel parentLevel, GraphCutLevel expandingLevel,
|
||||
Set<GraphCutVertex> newVertices, Set<GraphCutEdge> newEdges, Set<GraphCutEdge> allParentLevelEdges, boolean isIncoming,
|
||||
GraphViewer<GraphCutVertex, GraphCutEdge> viewer) {
|
||||
|
||||
this.sources = sources;
|
||||
this.parentLevel = parentLevel;
|
||||
this.newVertices = newVertices;
|
||||
this.newEdges = newEdges;
|
||||
this.isIncoming = isIncoming;
|
||||
this.viewer = viewer;
|
||||
this.expandingLevel = expandingLevel;
|
||||
|
||||
for(GraphCutEdge e: allParentLevelEdges) {
|
||||
|
||||
GraphCutVertex start = e.getStart();
|
||||
GraphCutVertex end = e.getEnd();
|
||||
GraphCutLevel startLevel = start.getLevel();
|
||||
GraphCutLevel endLevel = end.getLevel();
|
||||
|
||||
if (expandingLevel.equals(startLevel)) {
|
||||
if(expandingLevel.equals(endLevel)) {
|
||||
newVerticesBySource.get(start).add(end);
|
||||
newVerticesBySource.get(end).add(start);
|
||||
}
|
||||
else {
|
||||
newVerticesBySource.get(end).add(start);
|
||||
}
|
||||
}
|
||||
else {
|
||||
newVerticesBySource.get(start).add(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int compareVerticesByLayoutPosition(GraphCutVertex v1, GraphCutVertex v2) {
|
||||
|
||||
Layout<GraphCutVertex, GraphCutEdge> layout = viewer.getGraphLayout();
|
||||
|
||||
GraphCutLevel l1 = v1.getLevel();
|
||||
GraphCutLevel l2 = v2.getLevel();
|
||||
|
||||
int result = l1.compareTo(l2);
|
||||
if (result != 0) {
|
||||
|
||||
if(l1.equals(parentLevel)) {
|
||||
return -1;
|
||||
}
|
||||
if(l2.equals(parentLevel)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Point2D p1 = layout.apply(v1);
|
||||
Point2D p2 = layout.apply(v2);
|
||||
return (int) (p1.getX() - p2.getX());
|
||||
}
|
||||
|
||||
public List<GraphCutVertex> getVerticesByLevel(GraphCutLevel level){
|
||||
|
||||
Set<GraphCutVertex> existingVertices = newVerticesBySource.keySet();
|
||||
|
||||
List<GraphCutVertex> verticesAtLevel = existingVertices.stream().filter(v -> v.getLevel().equals(level)).collect(Collectors.toList());
|
||||
return verticesAtLevel;
|
||||
}
|
||||
|
||||
public List<GraphCutVertex> getAllVerticesAtNewLevel(){
|
||||
|
||||
Set<GraphCutVertex> existingVertices = newVerticesBySource.keySet();
|
||||
LinkedHashSet<GraphCutVertex> sortedVertices = existingVertices
|
||||
.stream()
|
||||
.map(v -> newVerticesBySource.get(v))
|
||||
.flatMap(set -> set.stream())
|
||||
.filter(v -> v.getLevel().equals(expandingLevel))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
return new ArrayList<>(sortedVertices);
|
||||
|
||||
}
|
||||
|
||||
public Set<GraphCutVertex> getNewVertices(){
|
||||
return newVertices;
|
||||
}
|
||||
|
||||
public Set<GraphCutEdge> getIndirectEdges() {
|
||||
return indirectEdges;
|
||||
}
|
||||
|
||||
public Iterable<GraphCutEdge> getNewEdges(){
|
||||
return IterableUtils.chainedIterable(newEdges, indirectEdges);
|
||||
}
|
||||
|
||||
public int getNewEdgeCount() {
|
||||
return newEdges.size() + indirectEdges.size();
|
||||
}
|
||||
|
||||
public void setIndirectEdges(Set<GraphCutEdge> indirectEdges) {
|
||||
this.indirectEdges = CollectionUtils.asSet(indirectEdges);
|
||||
}
|
||||
|
||||
public GraphCutLevel getExpandingLevel() {
|
||||
return expandingLevel;
|
||||
}
|
||||
|
||||
public FcgDirection getExpandingDirection() {
|
||||
return expandingLevel.getDirection();
|
||||
}
|
||||
|
||||
public Iterable<GraphCutVertex> getSources(){
|
||||
return sources;
|
||||
}
|
||||
|
||||
public boolean isIncoming() {
|
||||
return isIncoming;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
|
||||
public interface GraphCutExpansionListener {
|
||||
|
||||
/**
|
||||
* Show or hide those vertices that are on incoming edges to v
|
||||
*
|
||||
* @param v the vertex
|
||||
*/
|
||||
public void toggleIncomingVertices(GraphCutVertex v);
|
||||
|
||||
/**
|
||||
* Show or hide those vertices that are on outgoing edges to v
|
||||
*
|
||||
* @param v the vertex
|
||||
*/
|
||||
public void toggleOutgoingVertices(GraphCutVertex v);
|
||||
|
||||
}
|
||||
177
codecut-gui/src/main/java/graphcut/GraphCutGraph.java
Normal file
177
codecut-gui/src/main/java/graphcut/GraphCutGraph.java
Normal file
@@ -0,0 +1,177 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FunctionCallGraph.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import functioncalls.graph.FcgDirection;
|
||||
import ghidra.graph.graphs.FilteringVisualGraph;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
|
||||
/*
|
||||
* A graph for the GraphCut Plugin
|
||||
*/
|
||||
public class GraphCutGraph extends FilteringVisualGraph<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
private VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout;
|
||||
private GraphCutVertex source;
|
||||
private Map<Namespace, GraphCutVertex> verticesByNamespace = new HashMap<>();
|
||||
private Comparator<GraphCutVertex> vertexComparator =
|
||||
(v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0;
|
||||
private Map<GraphCutLevel, Set<GraphCutVertex>> verticesByLevel =
|
||||
LazyMap.lazyMap(new HashMap<>(), () -> new TreeSet<>(vertexComparator));
|
||||
|
||||
/**
|
||||
* Sets the source vertex from which the graph originates
|
||||
* @param the source vertex
|
||||
*/
|
||||
public void setSource(GraphCutVertex source) {
|
||||
if (this.source != null) {
|
||||
throw new IllegalStateException("Cannot change graph source once it has been created");
|
||||
}
|
||||
|
||||
this.source = source;
|
||||
addVertex(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex from which the graph is created
|
||||
* @return source vertex
|
||||
*/
|
||||
public GraphCutVertex getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns whether there is a vertex for the given namespace
|
||||
* @param ns Namespace
|
||||
* @return True if graph contains a vertex for the namespace
|
||||
*/
|
||||
public boolean containsNamespace(Namespace ns) {
|
||||
return verticesByNamespace.containsKey(ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex for the given namespace
|
||||
* @param ns Namespace
|
||||
* @return the vertex for the given namespace
|
||||
*/
|
||||
public GraphCutVertex getVertex(Namespace ns) {
|
||||
return verticesByNamespace.get(ns);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return all vertices in the given level
|
||||
* @param level the level to retrieve
|
||||
* @return all vertices in the given level
|
||||
*/
|
||||
public Iterable<GraphCutVertex> getVerticesByLevel(GraphCutLevel level){
|
||||
return IterableUtils.unmodifiableIterable(verticesByLevel.get(level));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level furthest from the source node in the given direction
|
||||
* @param direction the direction to search
|
||||
* @return the furthest level
|
||||
*/
|
||||
public GraphCutLevel getLargestLevel(FcgDirection direction) {
|
||||
GraphCutLevel greatest = new GraphCutLevel(1, direction);
|
||||
|
||||
Set<GraphCutLevel> keys = verticesByLevel.keySet();
|
||||
for (GraphCutLevel level : keys) {
|
||||
if (level.getDirection() != direction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (level.getRow() > greatest.getRow()) {
|
||||
greatest = level;
|
||||
}
|
||||
}
|
||||
return greatest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisualGraphLayout<GraphCutVertex, GraphCutEdge> getLayout(){
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph copy() {
|
||||
|
||||
GraphCutGraph newGraph = new GraphCutGraph();
|
||||
for (GraphCutVertex v : vertices.keySet()) {
|
||||
newGraph.addVertex(v);
|
||||
}
|
||||
|
||||
for (GraphCutEdge e : edges.keySet()) {
|
||||
newGraph.addEdge(e);
|
||||
}
|
||||
|
||||
return newGraph;
|
||||
}
|
||||
|
||||
public void setLayout(VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verticesAdded(Collection<GraphCutVertex> added) {
|
||||
for (GraphCutVertex v : added) {
|
||||
Namespace ns = v.getNamespace();
|
||||
verticesByNamespace.put(ns, v);
|
||||
verticesByLevel.get(v.getLevel()).add(v);
|
||||
}
|
||||
super.verticesAdded(added);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verticesRemoved(Collection<GraphCutVertex> removed) {
|
||||
for (GraphCutVertex v : removed) {
|
||||
Namespace ns = v.getNamespace();
|
||||
verticesByNamespace.remove(ns);
|
||||
verticesByLevel.get(v.getLevel()).remove(v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
137
codecut-gui/src/main/java/graphcut/GraphCutLayout.java
Normal file
137
codecut-gui/src/main/java/graphcut/GraphCutLayout.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows heavily from Ghidra File /Features Graph FunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayout.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.graph.VisualGraph;
|
||||
import ghidra.graph.viewer.layout.AbstractVisualGraphLayout;
|
||||
import ghidra.graph.viewer.layout.Column;
|
||||
import ghidra.graph.viewer.layout.GridLocationMap;
|
||||
import ghidra.graph.viewer.layout.LayoutPositions;
|
||||
import ghidra.graph.viewer.layout.Row;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class GraphCutLayout extends AbstractVisualGraphLayout<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
protected GraphCutLayout(GraphCutGraph graph, String name){
|
||||
super(graph, name);
|
||||
}
|
||||
|
||||
public AbstractVisualGraphLayout<GraphCutVertex, GraphCutEdge> createClonedLayout(VisualGraph<GraphCutVertex, GraphCutEdge> newGraph){
|
||||
if (!(newGraph instanceof GraphCutGraph)) {
|
||||
throw new IllegalArgumentException("Must pass a GraphCut Graph to clone");
|
||||
}
|
||||
|
||||
GraphCutLayout newLayout = new GraphCutLayout((GraphCutGraph) newGraph, getLayoutName());
|
||||
return newLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D getVertexLocation(GraphCutVertex v, Column col, Row<GraphCutVertex> row, Rectangle bounds) {
|
||||
return getCenteredVertexLocation(v, col, row, bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCondensedLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph getVisualGraph() {
|
||||
return (GraphCutGraph) getGraph();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GridLocationMap<GraphCutVertex, GraphCutEdge> performInitialGridLayout(VisualGraph<GraphCutVertex,GraphCutEdge> g) throws CancelledException {
|
||||
if (!(g instanceof GraphCutGraph)) {
|
||||
throw new IllegalArgumentException("This layout can only be used with the GraphCutGraph");
|
||||
}
|
||||
|
||||
return layoutGraphCutGraph((GraphCutGraph)g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutPositions<GraphCutVertex, GraphCutEdge> calculateLocations(VisualGraph<GraphCutVertex, GraphCutEdge> g, TaskMonitor taskMonitor){
|
||||
LayoutPositions<GraphCutVertex, GraphCutEdge> locs = super.calculateLocations(g, taskMonitor);
|
||||
return locs;
|
||||
}
|
||||
|
||||
private GridLocationMap<GraphCutVertex, GraphCutEdge> layoutGraphCutGraph(GraphCutGraph g){
|
||||
GridLocationMap<GraphCutVertex, GraphCutEdge> grid = new GridLocationMap<>();
|
||||
|
||||
GraphCutVertex source = Objects.requireNonNull(g.getSource());
|
||||
// Incoming nodes on top
|
||||
// Sorted by id
|
||||
|
||||
List<GraphCutEdge> inEdges = new ArrayList<>(g.getInEdges(source));
|
||||
List<GraphCutVertex> inVertices = inEdges.stream().map(e -> e.getStart()).collect(Collectors.toList());
|
||||
inVertices.sort((v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0);
|
||||
|
||||
//first row -> incoming nodes
|
||||
int row = 0;
|
||||
for(int col = 0; col < inVertices.size(); col++) {
|
||||
GraphCutVertex v = inVertices.get(col);
|
||||
grid.set(v, row, col);
|
||||
}
|
||||
|
||||
//middle row -> source
|
||||
row = 1;
|
||||
grid.set(source, row, 0);
|
||||
|
||||
//bottom row -> outgoing nodes
|
||||
List<GraphCutEdge> outEdges = new ArrayList<>(g.getOutEdges(source));
|
||||
List<GraphCutVertex> outVertices = outEdges.stream().map(e -> e.getEnd()).collect(Collectors.toList());
|
||||
|
||||
outVertices.removeAll(inVertices); //prevent cycles
|
||||
outVertices.sort((v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0);
|
||||
row = 2;
|
||||
for (int col = 0; col < outVertices.size(); col++) {
|
||||
GraphCutVertex v = outVertices.get(col);
|
||||
grid.set(v, row, col);
|
||||
}
|
||||
|
||||
grid.centerRows();
|
||||
return grid;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/BowTieExpandVerticesJob.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||
import edu.uci.ics.jung.visualization.RenderContext;
|
||||
import ghidra.graph.job.AbstractGraphTransitionJob;
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
import ghidra.graph.viewer.GraphViewerUtils;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
|
||||
|
||||
// bowTieExpandVerticesJob
|
||||
public class GraphCutLayoutExpandVerticesJob extends AbstractGraphTransitionJob<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
private boolean incoming;
|
||||
private GraphCutLevel expandingLevel;
|
||||
private GraphCutExpandingVertexCollection newVertexCollection;
|
||||
|
||||
public GraphCutLayoutExpandVerticesJob(GraphViewer<GraphCutVertex, GraphCutEdge> viewer,
|
||||
GraphCutExpandingVertexCollection newVertexCollection, boolean useAnimation) {
|
||||
super(viewer, useAnimation);
|
||||
|
||||
this.newVertexCollection = newVertexCollection;
|
||||
this.incoming = newVertexCollection.isIncoming();
|
||||
this.expandingLevel = newVertexCollection.getExpandingLevel();
|
||||
|
||||
if(!(graphLayout instanceof GraphCutLayout)) {
|
||||
throw new IllegalArgumentException("The current graph layout must be the GraphCut Layout to use this job");
|
||||
}
|
||||
|
||||
Msg.trace(this, "\n Layout Expand Job - new vertices: " + newVertexCollection.getNewVertices());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTooBigToAnimate() {
|
||||
return graph.getVertexCount() > 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateOpacity(double percentComplete) {
|
||||
double x = percentComplete;
|
||||
double x2 = x*x;
|
||||
double remaining = 1-percentComplete;
|
||||
double y = x2 - remaining;
|
||||
|
||||
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
|
||||
|
||||
double vertexAlpha = x;
|
||||
double edgeAlpha = Math.max(y, 0);
|
||||
for(GraphCutVertex v : newVertices) {
|
||||
v.setAlpha(vertexAlpha);
|
||||
}
|
||||
|
||||
Iterable<GraphCutEdge> newEdges = newVertexCollection.getNewEdges();
|
||||
for(GraphCutEdge e : newEdges) {
|
||||
e.setAlpha(edgeAlpha);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShortcut() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shortcut() {
|
||||
isShortcut = true;
|
||||
|
||||
if(vertexLocations.isEmpty()) {
|
||||
initializeVertexLocations();
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeVertexLocations() {
|
||||
Map<GraphCutVertex, TransitionPoints> destinationLocations = createDestinationLocation();
|
||||
vertexLocations.putAll(destinationLocations);
|
||||
}
|
||||
|
||||
private Map<GraphCutVertex, TransitionPoints> createDestinationLocation(){
|
||||
|
||||
Map<GraphCutVertex, Point2D> finalDestinations = arrangeNewVertices();
|
||||
|
||||
Map<GraphCutVertex, TransitionPoints> transitions = new HashMap<>();
|
||||
GraphCutLevel parentLevel = expandingLevel.parent();
|
||||
Iterable<GraphCutEdge> newEdges = newVertexCollection.getNewEdges();
|
||||
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
|
||||
for(GraphCutEdge e : newEdges) {
|
||||
GraphCutVertex newVertex = incoming ? e.getStart() : e.getEnd();
|
||||
if(!finalDestinations.containsKey(newVertex)) {
|
||||
continue;
|
||||
}
|
||||
if(!newVertices.contains(newVertex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GraphCutVertex existingVertex = incoming ? e.getEnd() : e.getStart();
|
||||
GraphCutLevel existingLevel = existingVertex.getLevel();
|
||||
if (!existingLevel.equals(parentLevel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Point2D start = (Point2D) toLocation(existingVertex).clone();
|
||||
Point2D end = finalDestinations.get(newVertex);
|
||||
|
||||
TransitionPoints trans = new TransitionPoints(start, end);
|
||||
transitions.put(newVertex, trans);
|
||||
}
|
||||
return transitions;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Map<GraphCutVertex, Point2D> arrangeNewVertices(){
|
||||
|
||||
GraphCutLayout bowTie = (GraphCutLayout) graphLayout;
|
||||
boolean isCondensed = bowTie.isCondensedLayout();
|
||||
int widthPadding = isCondensed ? GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING_CONDENSED :
|
||||
GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING;
|
||||
|
||||
widthPadding *= expandingLevel.getDistance();
|
||||
int heightPadding = calculateHeightPadding(isCondensed);
|
||||
|
||||
GraphCutLevel parentLevel = expandingLevel.parent();
|
||||
List<GraphCutVertex> parentLevelVertices = newVertexCollection.getVerticesByLevel(parentLevel);
|
||||
if(parentLevelVertices.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Rectangle existingRowBounds = getBounds(parentLevelVertices);
|
||||
Msg.trace(this, "existing row bounds " + existingRowBounds);
|
||||
double existingY = existingRowBounds.y;
|
||||
double existingCenterX = existingRowBounds.x + (existingRowBounds.width/2);
|
||||
|
||||
List<GraphCutVertex> allLevelVertices = newVertexCollection.getAllVerticesAtNewLevel();
|
||||
double newRowWidth = getWidth(allLevelVertices, widthPadding);
|
||||
double newRowHeight = getHeight(allLevelVertices);
|
||||
double newRowX = existingCenterX - (newRowWidth/2);
|
||||
|
||||
double newRowY = 0;
|
||||
if(newVertexCollection.isIncoming()) {
|
||||
newRowY = existingY - newRowHeight - heightPadding;
|
||||
}
|
||||
else {
|
||||
newRowY = existingY +existingRowBounds.height + heightPadding;
|
||||
}
|
||||
|
||||
Msg.trace(this, "new row bounds " + new Rectangle2D.Double(newRowX, newRowY, newRowWidth, newRowHeight));
|
||||
|
||||
Map<GraphCutVertex, Point2D> locations = getExistingLocations(allLevelVertices);
|
||||
if(!locations.isEmpty()) {
|
||||
return locations;
|
||||
}
|
||||
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
double x = newRowX;
|
||||
double y = newRowY;
|
||||
|
||||
int n = allLevelVertices.size();
|
||||
|
||||
//Dynamic Layout
|
||||
Set<GraphCutVertex> placed = new HashSet<>();
|
||||
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
|
||||
//Make shallow copy
|
||||
List<GraphCutVertex> allLevelVerticesOrig = new ArrayList<>();
|
||||
for(GraphCutVertex v : allLevelVertices) {
|
||||
allLevelVerticesOrig.add(v);
|
||||
}
|
||||
// 1. Place visible vertices
|
||||
for(GraphCutVertex v: allLevelVerticesOrig) {
|
||||
if(v.visible) {
|
||||
GraphCutVertex tmpVertex = allLevelVertices.get(v.layoutIndex);
|
||||
int tmpIndex = allLevelVertices.indexOf(v);
|
||||
allLevelVertices.set(v.layoutIndex, v);
|
||||
allLevelVertices.set(tmpIndex, tmpVertex);
|
||||
placed.add(v);
|
||||
}
|
||||
}
|
||||
// 2. Place newVertices
|
||||
for(GraphCutVertex v: newVertices) {
|
||||
if(placed.contains(v)) {
|
||||
continue;
|
||||
}
|
||||
placed.add(v);
|
||||
int index = findEmptyLayoutIndex(allLevelVertices);
|
||||
v.layoutIndex = index;
|
||||
v.visible = true;
|
||||
GraphCutVertex tmpVertex = allLevelVertices.get(index);
|
||||
int tmpIndex = allLevelVertices.indexOf(v);
|
||||
allLevelVertices.set(tmpIndex, tmpVertex);
|
||||
allLevelVertices.set(v.layoutIndex, v);
|
||||
|
||||
}
|
||||
|
||||
// 3. Place all invisible vertices randomly
|
||||
int curr = 0;
|
||||
for(GraphCutVertex v: allLevelVerticesOrig) {
|
||||
if(placed.contains(v)) {
|
||||
continue;
|
||||
}
|
||||
//find empty spot
|
||||
while(allLevelVertices.get(curr).visible) {
|
||||
curr++;
|
||||
}
|
||||
allLevelVertices.set(curr, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < n; i++) {
|
||||
GraphCutVertex v = allLevelVertices.get(i);
|
||||
Rectangle myBounds = shaper.apply(v).getBounds();
|
||||
double myHalf = myBounds.width / 2;
|
||||
|
||||
double nextHalf = 0;
|
||||
boolean isLast = i == n-1;
|
||||
if(!isLast) {
|
||||
GraphCutVertex nextV = allLevelVertices.get(i+1);
|
||||
Rectangle nextBounds = shaper.apply(nextV).getBounds();
|
||||
nextHalf = nextBounds.width/2;
|
||||
}
|
||||
|
||||
Point2D p = new Point2D.Double(x,y);
|
||||
locations.put(v, p);
|
||||
|
||||
double vWidth = myHalf + widthPadding + nextHalf;
|
||||
Msg.trace(this, v + " at x,width: "+x+","+vWidth);
|
||||
x+=vWidth;
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
private int findEmptyLayoutIndex(List<GraphCutVertex> vertices) {
|
||||
//Check middle
|
||||
int mid = vertices.size()/2;
|
||||
if(!vertices.get(mid).visible) {
|
||||
return mid;
|
||||
}
|
||||
|
||||
// start checking both sides
|
||||
int left = mid-1;
|
||||
int right = mid+1;
|
||||
while(left >= 0 || right <=vertices.size()-1) {
|
||||
if(left>=0 && !vertices.get(left).visible) {
|
||||
return left;
|
||||
}
|
||||
left--;
|
||||
if(right <= vertices.size()-1 && !vertices.get(right).visible) {
|
||||
return right;
|
||||
}
|
||||
right++;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private int calculateHeightPadding(boolean isCondensed) {
|
||||
|
||||
int basePadding = isCondensed ? GraphViewerUtils.EXTRA_LAYOUT_ROW_SPACING_CONDENSED
|
||||
: GraphViewerUtils.EXTRA_LAYOUT_ROW_SPACING;
|
||||
|
||||
double separationFactor = expandingLevel.getDistance();
|
||||
|
||||
List<GraphCutVertex> allLevelVertices = newVertexCollection.getAllVerticesAtNewLevel();
|
||||
int count = allLevelVertices.size();
|
||||
|
||||
double to = 1.25;
|
||||
double power = Math.pow(separationFactor, to);
|
||||
int maxPadding = (int) (basePadding * power);
|
||||
|
||||
int delta = maxPadding - basePadding;
|
||||
double percent = Math.min(count / 20f, 1);
|
||||
int padding = basePadding + (int) (delta * percent);
|
||||
return padding;
|
||||
}
|
||||
|
||||
|
||||
private Map<GraphCutVertex, Point2D> getExistingLocations(List<GraphCutVertex> vertices){
|
||||
Map<GraphCutVertex, Point2D> locations = new HashMap<>();
|
||||
for(GraphCutVertex v: vertices) {
|
||||
Point2D p = toLocation(v);
|
||||
if (p.getX() == 0 && p.getY() == 0) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
locations.put(v, (Point2D) p.clone());
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Rectangle getBounds(List<GraphCutVertex> vertices) {
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
Layout<GraphCutVertex, GraphCutEdge> layout = viewer.getGraphLayout();
|
||||
|
||||
Rectangle area = null;
|
||||
for (GraphCutVertex v : vertices) {
|
||||
Rectangle bounds = shaper.apply(v).getBounds();
|
||||
Point2D loc = layout.apply(v);
|
||||
int x = (int) loc.getX();
|
||||
int y = (int) loc.getY();
|
||||
bounds.setLocation(x,y);
|
||||
if(area == null) {
|
||||
area = bounds;
|
||||
}
|
||||
area.add(bounds);
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
|
||||
private int getWidth(List<GraphCutVertex> vertices, int widthPadding) {
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
int width = 0;
|
||||
for (GraphCutVertex v : vertices) {
|
||||
width += shaper.apply(v).getBounds().width + widthPadding;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
private int getHeight(List<GraphCutVertex> vertices) {
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
int height = 0;
|
||||
for (GraphCutVertex v: vertices) {
|
||||
height = Math.max(height, shaper.apply(v).getBounds().height);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.graph.viewer.layout.AbstractLayoutProvider;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A layout provider for GraphCut
|
||||
*/
|
||||
public class GraphCutLayoutProvider extends AbstractLayoutProvider<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
|
||||
public static final String NAME = "GraphCut Layout";
|
||||
private static final Icon DEFAULT_ICON = new GIcon("icon.plugin.fcg.layout.bow.tie");
|
||||
|
||||
@Override
|
||||
public VisualGraphLayout<GraphCutVertex, GraphCutEdge> getLayout(GraphCutGraph graph, TaskMonitor taskMonitor) throws CancelledException{
|
||||
|
||||
GraphCutLayout layout = new GraphCutLayout(graph, NAME);
|
||||
initVertexLocations(graph, layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLayoutName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getActionIcon() {
|
||||
return DEFAULT_ICON;
|
||||
}
|
||||
}
|
||||
193
codecut-gui/src/main/java/graphcut/GraphCutLevel.java
Normal file
193
codecut-gui/src/main/java/graphcut/GraphCutLevel.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrowed from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FcgEdge.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import static functioncalls.graph.FcgDirection.*;
|
||||
|
||||
import functioncalls.graph.FcgDirection;
|
||||
|
||||
|
||||
// A container class that represents a GraphCut row.
|
||||
|
||||
public class GraphCutLevel implements Comparable<GraphCutLevel> {
|
||||
|
||||
private int row;
|
||||
private FcgDirection direction;
|
||||
|
||||
public static GraphCutLevel sourceLevel() {
|
||||
return new GraphCutLevel(0, IN_AND_OUT);
|
||||
}
|
||||
|
||||
public GraphCutLevel(int distance, FcgDirection direction) {
|
||||
this.row = toRow(distance);
|
||||
this.direction = direction;
|
||||
|
||||
if (row == 0) {
|
||||
throw new IllegalArgumentException("Graph Cut uses a 1-based row system");
|
||||
}
|
||||
|
||||
if (row == 1 && direction != IN_AND_OUT) {
|
||||
throw new IllegalArgumentException("Row 1 must be FcgDirection.IN_AND_OUT");
|
||||
}
|
||||
}
|
||||
|
||||
private int toRow(int distance) {
|
||||
int oneBased = distance + 1;
|
||||
return (direction == OUT) ? -oneBased : oneBased;
|
||||
}
|
||||
|
||||
public int getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public int getDistance() {
|
||||
return Math.abs(row) - 1;
|
||||
}
|
||||
|
||||
public FcgDirection getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this level is level 1
|
||||
* @return true if this level represents the source level
|
||||
*/
|
||||
public boolean isSource() {
|
||||
return direction.isSource();
|
||||
}
|
||||
|
||||
public GraphCutLevel parent() {
|
||||
if (direction == IN_AND_OUT) {
|
||||
// undefined--we are the parent of all
|
||||
throw new IllegalArgumentException(
|
||||
"To get the parent of the source level you must use the constructor directly");
|
||||
}
|
||||
|
||||
int newDistance = getDistance() - 1;
|
||||
FcgDirection newDirection = direction;
|
||||
if (newDistance == 0) {
|
||||
newDirection = IN_AND_OUT;
|
||||
}
|
||||
return new GraphCutLevel(newDistance, newDirection);
|
||||
}
|
||||
|
||||
public GraphCutLevel child() {
|
||||
if (direction == IN_AND_OUT) {
|
||||
// undefined--this node goes in both directions
|
||||
throw new IllegalArgumentException(
|
||||
"To get the child of the source level you " + "must use the constructor directly");
|
||||
}
|
||||
|
||||
return child(direction);
|
||||
}
|
||||
|
||||
public boolean isParentOf(GraphCutLevel other) {
|
||||
if (isSource()) {
|
||||
return other.getDistance() == 1;
|
||||
}
|
||||
|
||||
if (direction != other.direction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// e.g., row 2 - row 1 = 1
|
||||
return other.getDistance() - getDistance() == 1;
|
||||
}
|
||||
|
||||
public boolean isChildOf(GraphCutLevel other) {
|
||||
return other.isParentOf(this);
|
||||
}
|
||||
|
||||
public GraphCutLevel child(FcgDirection newDirection) {
|
||||
if (newDirection == IN_AND_OUT) {
|
||||
// undefined--IN_AND_OUT goes in both directions
|
||||
throw new IllegalArgumentException("Direction cannot be IN_AND_OUT");
|
||||
}
|
||||
|
||||
int newDistance = getDistance() + 1;
|
||||
return new GraphCutLevel(newDistance, newDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return direction + " - row " + Integer.toString(getRelativeRow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((direction == null) ? 0 : direction.hashCode());
|
||||
result = prime * result + row;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GraphCutLevel other = (GraphCutLevel) obj;
|
||||
if (direction != other.direction) {
|
||||
return false;
|
||||
}
|
||||
if (row != other.row) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getRelativeRow() {
|
||||
return direction == OUT ? -row : row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(GraphCutLevel l2) {
|
||||
|
||||
int result = getDirection().compareTo(l2.getDirection());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return -(getRelativeRow() - l2.getRelativeRow());
|
||||
}
|
||||
}
|
||||
1286
codecut-gui/src/main/java/graphcut/GraphCutProvider.java
Normal file
1286
codecut-gui/src/main/java/graphcut/GraphCutProvider.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgTooltipProvider.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.*;
|
||||
|
||||
import ghidra.graph.viewer.event.mouse.VertexTooltipProvider;
|
||||
|
||||
public class GraphCutTooltipProvider implements VertexTooltipProvider<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
@Override
|
||||
public JComponent getTooltip(GraphCutVertex v) {
|
||||
JToolTip tip = new JToolTip();
|
||||
tip.setTipText(v.getName());
|
||||
return tip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getTooltip(GraphCutVertex v, GraphCutEdge e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltipText(GraphCutVertex v, MouseEvent e) {
|
||||
Component child = e.getComponent();
|
||||
if(child instanceof JButton) {
|
||||
return ((JButton) child).getToolTipText();
|
||||
}
|
||||
return v.getName();
|
||||
}
|
||||
|
||||
}
|
||||
664
codecut-gui/src/main/java/graphcut/GraphCutVertex.java
Normal file
664
codecut-gui/src/main/java/graphcut/GraphCutVertex.java
Normal file
@@ -0,0 +1,664 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrowed from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Ellipse2D.Double;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.LineBorder;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
import docking.widgets.EmptyBorderButton;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import functioncalls.graph.FcgDirection;
|
||||
import functioncalls.graph.FcgVertex;
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.graph.viewer.vertex.AbstractVisualVertex;
|
||||
import ghidra.graph.viewer.vertex.VertexShapeProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.util.StringUtilities;
|
||||
import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
|
||||
// A GraphCutVertex
|
||||
|
||||
public class GraphCutVertex extends AbstractVisualVertex implements VertexShapeProvider {
|
||||
|
||||
public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new GColor("color.bg.plugin.fcg.vertex.default");
|
||||
private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = new GColor("color.bg.plugin.fcg.vertex.toobig");
|
||||
|
||||
//@formatter:on
|
||||
|
||||
public static final Icon NOT_ALLOWED_ICON = Icons.ERROR_ICON;
|
||||
private static final Icon EXPAND_ICON =
|
||||
ResourceManager.getScaledIcon(Icons.EXPAND_ALL_ICON, 10, 10);
|
||||
private static final Icon COLLAPSE_ICON =
|
||||
ResourceManager.getScaledIcon(Icons.COLLAPSE_ALL_ICON, 10, 10);
|
||||
|
||||
// higher numbered layers go on top
|
||||
private static final Integer VERTEX_SHAPE_LAYER = 100;
|
||||
private static final Integer TOGGLE_BUTTON_LAYER = 200;
|
||||
private static final Integer LABEL_LAYER = 300;
|
||||
|
||||
private static final int GAP = 2;
|
||||
private static final int VERTEX_SHAPE_SIZE = 50;
|
||||
|
||||
private static final int MAX_NAME_LENGTH = 30;
|
||||
|
||||
private Namespace namespace;
|
||||
|
||||
private JLayeredPane layeredPane;
|
||||
private JButton toggleInsButton = new EmptyBorderButton(EXPAND_ICON);
|
||||
private JButton toggleOutsButton = new EmptyBorderButton(EXPAND_ICON);
|
||||
private JLabel nameLabel = new GDLabel();
|
||||
private JLabel vertexImageLabel = new GDLabel();
|
||||
|
||||
private Double vertexShape;
|
||||
private Double compactShape;
|
||||
private Shape fullShape;
|
||||
|
||||
// these values are set after construction from external sources
|
||||
private boolean hasIncomingReferences;
|
||||
private boolean hasOutgoingReferences;
|
||||
private boolean tooManyIncomingReferences;
|
||||
private boolean tooManyOutgoingReferences;
|
||||
private boolean incomingExpanded;
|
||||
private boolean outgoingExpanded;
|
||||
|
||||
// set this to true to see borders around the components of this vertex
|
||||
private boolean useDebugBorders = false;
|
||||
|
||||
private Paint inPaint;
|
||||
private Paint outPaint;
|
||||
|
||||
private GraphCutLevel level;
|
||||
|
||||
// Dynamic Layout Variables
|
||||
public int layoutIndex;
|
||||
public boolean visible;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param namespace Namespace represented by this vertex
|
||||
* @param level The level of this vertex
|
||||
* @param expansionListener listener for expanding connections to this vertex
|
||||
*/
|
||||
public GraphCutVertex(Namespace namespace, GraphCutLevel level, GraphCutExpansionListener expansionListener) {
|
||||
this.namespace = namespace;
|
||||
this.level = level;
|
||||
Objects.requireNonNull(expansionListener);
|
||||
|
||||
toggleInsButton.addActionListener(e -> {
|
||||
if (tooManyIncomingReferences) {
|
||||
return;
|
||||
}
|
||||
expansionListener.toggleIncomingVertices(GraphCutVertex.this);
|
||||
});
|
||||
|
||||
toggleOutsButton.addActionListener(e -> {
|
||||
if (tooManyOutgoingReferences) {
|
||||
return;
|
||||
}
|
||||
expansionListener.toggleOutgoingVertices(GraphCutVertex.this);
|
||||
});
|
||||
|
||||
buildUi();
|
||||
|
||||
setTogglesVisible(false);
|
||||
}
|
||||
|
||||
private void createPaints() {
|
||||
|
||||
Color vertexShapeColor = getVertexShapeColor();
|
||||
|
||||
Color lightColor = vertexShapeColor;
|
||||
Color darkColor = Gui.darker(vertexShapeColor);
|
||||
Color darkestColor = Gui.darker(darkColor);
|
||||
|
||||
int offset = 5 * level.getDistance();
|
||||
int half = VERTEX_SHAPE_SIZE / 2;
|
||||
int start = 0;
|
||||
int end = half + offset;
|
||||
|
||||
// paint top-down: dark to light for incoming; light to dark for outgoing
|
||||
inPaint = new LinearGradientPaint(new Point(0, start), new Point(0, end),
|
||||
new float[] { .0f, .2f, 1f }, new Color[] { darkestColor, darkColor, lightColor });
|
||||
|
||||
start = half - offset; // (offset + 10);
|
||||
end = VERTEX_SHAPE_SIZE;
|
||||
outPaint = new LinearGradientPaint(new Point(0, start), new Point(0, end),
|
||||
new float[] { .0f, .8f, 1f }, new Color[] { lightColor, darkColor, darkestColor });
|
||||
|
||||
}
|
||||
|
||||
private void buildUi() {
|
||||
|
||||
createPaints();
|
||||
|
||||
String truncated = StringUtilities.trimMiddle(getName(), MAX_NAME_LENGTH);
|
||||
nameLabel.setText(truncated);
|
||||
buildVertexShape();
|
||||
|
||||
// calculate the needed size
|
||||
layeredPane = new JLayeredPane();
|
||||
Border border = createDebugBorder(new LineBorder(Palette.GOLD, 1));
|
||||
layeredPane.setBorder(border);
|
||||
|
||||
updateLayeredPaneSize();
|
||||
|
||||
// layout the components
|
||||
addVertexShape();
|
||||
addToggleButtons();
|
||||
addNameLabel();
|
||||
|
||||
buildFullShape();
|
||||
}
|
||||
|
||||
private Border createDebugBorder(Border border) {
|
||||
if (useDebugBorders) {
|
||||
return border;
|
||||
}
|
||||
return BorderFactory.createEmptyBorder();
|
||||
}
|
||||
|
||||
private void buildFullShape() {
|
||||
|
||||
// Note: this method assumes all bounds have been set
|
||||
Area parent = new Area();
|
||||
|
||||
Area v = new Area(vertexShape);
|
||||
Area name = new Area(nameLabel.getBounds());
|
||||
parent.add(v);
|
||||
parent.add(name);
|
||||
|
||||
// for now, the buttons only appear on hover, but if we want to avoid clipping when
|
||||
// painting, we need to account for them in the shape's overall bounds
|
||||
Area in = new Area(toggleInsButton.getBounds());
|
||||
Area out = new Area(toggleOutsButton.getBounds());
|
||||
parent.add(in);
|
||||
parent.add(out);
|
||||
|
||||
fullShape = parent;
|
||||
}
|
||||
|
||||
private void updateLayeredPaneSize() {
|
||||
|
||||
//
|
||||
// The overall component size is the total width and height of all components, with any
|
||||
// spacing between them.
|
||||
//
|
||||
|
||||
Dimension shapeSize = vertexImageLabel.getPreferredSize();
|
||||
Dimension nameLabelSize = nameLabel.getPreferredSize();
|
||||
int height = shapeSize.height + GAP + nameLabelSize.height;
|
||||
|
||||
Dimension insSize = toggleInsButton.getPreferredSize();
|
||||
Dimension outsSize = toggleOutsButton.getPreferredSize();
|
||||
int buttonWidth = Math.max(insSize.width, outsSize.width);
|
||||
int offset = buttonWidth / 3; // overlap the vertex shape
|
||||
|
||||
int width = offset + shapeSize.width;
|
||||
width = Math.max(width, nameLabelSize.width);
|
||||
|
||||
layeredPane.setPreferredSize(new Dimension(width, height));
|
||||
}
|
||||
|
||||
private void buildVertexShape() {
|
||||
int w = VERTEX_SHAPE_SIZE;
|
||||
int h = VERTEX_SHAPE_SIZE;
|
||||
Double circle = new Ellipse2D.Double(0, 0, w, h);
|
||||
|
||||
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2 = (Graphics2D) image.getGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
FcgDirection direction = level.getDirection();
|
||||
if (direction.isSource()) {
|
||||
g2.setColor(getVertexShapeColor());
|
||||
}
|
||||
else if (direction.isIn()) {
|
||||
g2.setPaint(inPaint);
|
||||
}
|
||||
else {
|
||||
g2.setPaint(outPaint);
|
||||
}
|
||||
|
||||
g2.fill(circle);
|
||||
|
||||
g2.dispose();
|
||||
|
||||
vertexShape = circle;
|
||||
compactShape = (Double) vertexShape.clone();
|
||||
vertexImageLabel.setIcon(new ImageIcon(image));
|
||||
|
||||
Border border = createDebugBorder(new LineBorder(Palette.PINK, 1));
|
||||
vertexImageLabel.setBorder(border);
|
||||
}
|
||||
|
||||
private Color getVertexShapeColor() {
|
||||
|
||||
if (isInDirection() && tooManyIncomingReferences) {
|
||||
return TOO_BIG_VERTEX_SHAPE_COLOR;
|
||||
}
|
||||
|
||||
if (isOutDirection() && tooManyOutgoingReferences) {
|
||||
return TOO_BIG_VERTEX_SHAPE_COLOR;
|
||||
}
|
||||
|
||||
return DEFAULT_VERTEX_SHAPE_COLOR;
|
||||
}
|
||||
|
||||
private boolean isInDirection() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
boolean isIn = direction.isIn() || direction.isSource();
|
||||
return isIn;
|
||||
}
|
||||
|
||||
private boolean isOutDirection() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
boolean isOut = direction.isOut() || direction.isSource();
|
||||
return isOut;
|
||||
}
|
||||
|
||||
private void addVertexShape() {
|
||||
|
||||
Dimension parentSize = layeredPane.getPreferredSize();
|
||||
Dimension size = vertexImageLabel.getPreferredSize();
|
||||
|
||||
// centered
|
||||
int x = (parentSize.width / 2) - (size.width / 2);
|
||||
int y = 0;
|
||||
|
||||
vertexImageLabel.setBounds(x, y, size.width, size.height);
|
||||
Dimension shapeSize = vertexShape.getBounds().getSize();
|
||||
|
||||
// setFrame() will make sure the shape's x,y values are where they need to be
|
||||
// for the later 'full shape' creation
|
||||
vertexShape.setFrame(x, y, shapeSize.width, shapeSize.height);
|
||||
layeredPane.add(vertexImageLabel, VERTEX_SHAPE_LAYER);
|
||||
}
|
||||
|
||||
private void addNameLabel() {
|
||||
Border border = createDebugBorder(new LineBorder(Palette.GREEN, 1));
|
||||
nameLabel.setBorder(border);
|
||||
|
||||
Rectangle parentBounds = vertexImageLabel.getBounds();
|
||||
Dimension size = nameLabel.getPreferredSize();
|
||||
|
||||
int x = (parentBounds.x + (parentBounds.width / 2)) - (size.width / 2);
|
||||
int y = parentBounds.y + parentBounds.height + GAP;
|
||||
nameLabel.setBounds(x, y, size.width, size.height);
|
||||
layeredPane.add(nameLabel, LABEL_LAYER);
|
||||
|
||||
}
|
||||
|
||||
private void addToggleButtons() {
|
||||
|
||||
// hide the button background
|
||||
toggleInsButton.setBackground(Palette.NO_COLOR);
|
||||
toggleOutsButton.setBackground(Palette.NO_COLOR);
|
||||
|
||||
// This is needed for Flat Dark theme to work correctly, due to the fact that it wants to
|
||||
// paint its parent background when the button is opaque. The parent background will get
|
||||
// painted over any items that lie between the button and the parent.
|
||||
toggleInsButton.setOpaque(false);
|
||||
toggleOutsButton.setOpaque(false);
|
||||
|
||||
Rectangle parentBounds = vertexImageLabel.getBounds();
|
||||
Dimension size = toggleInsButton.getPreferredSize();
|
||||
|
||||
// upper toggle; upper-left
|
||||
int x = parentBounds.x - (size.width / 3);
|
||||
int y = 0;
|
||||
toggleInsButton.setBounds(x, y, size.width, size.height);
|
||||
layeredPane.add(toggleInsButton, TOGGLE_BUTTON_LAYER);
|
||||
|
||||
// lower toggle; lower-left, lined-up with the vertex shape
|
||||
size = toggleOutsButton.getPreferredSize();
|
||||
Dimension vertexSize = parentBounds.getSize();
|
||||
y = vertexSize.height - size.height;
|
||||
toggleOutsButton.setBounds(x, y, size.width, size.height);
|
||||
layeredPane.add(toggleOutsButton, TOGGLE_BUTTON_LAYER);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return namespace.getName();
|
||||
}
|
||||
|
||||
public Namespace getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public GraphCutLevel getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public int getDegree() {
|
||||
return level.getRow();
|
||||
}
|
||||
|
||||
public FcgDirection getDirection() {
|
||||
return level.getDirection();
|
||||
}
|
||||
|
||||
public JButton getIncomingToggleButton() {
|
||||
return toggleInsButton;
|
||||
}
|
||||
|
||||
public JButton getOutgoingToggleButton() {
|
||||
return toggleOutsButton;
|
||||
}
|
||||
|
||||
public void setIncomingExpanded(boolean setExpanded) {
|
||||
validateIncomingExpandedState(setExpanded);
|
||||
|
||||
this.incomingExpanded = setExpanded;
|
||||
toggleInsButton.setIcon(setExpanded ? COLLAPSE_ICON : EXPAND_ICON);
|
||||
String hideShow = setExpanded ? "hide" : "show";
|
||||
toggleInsButton.setToolTipText("Click to " + hideShow + " incoming edges");
|
||||
}
|
||||
|
||||
private void validateOutgoingExpandedState(boolean isExpanding) {
|
||||
if (isExpanding) {
|
||||
if (!canExpandOutgoingReferences()) {
|
||||
throw new IllegalStateException("Vertex cannot be expanded: " + this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// collapsing
|
||||
if (!isOutgoingExpanded()) {
|
||||
throw new IllegalStateException("Vertex cannot be collapsed: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIncomingExpandedState(boolean expanding) {
|
||||
|
||||
if (expanding) {
|
||||
if (!canExpandIncomingReferences()) {
|
||||
throw new IllegalStateException("Vertex cannot be expanded: " + this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// collapsing
|
||||
if (!isIncomingExpanded()) {
|
||||
throw new IllegalStateException("Vertex cannot be collapsed: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vertex is showing all edges in the incoming direction
|
||||
*
|
||||
* @return true if this vertex is showing all edges in the incoming direction
|
||||
*/
|
||||
public boolean isIncomingExpanded() {
|
||||
return incomingExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to true if this vertex is showing all edges in the outgoing direction
|
||||
*
|
||||
* @param setExpanded true if this vertex is showing all edges in the outgoing direction
|
||||
*/
|
||||
public void setOutgoingExpanded(boolean setExpanded) {
|
||||
|
||||
validateOutgoingExpandedState(setExpanded);
|
||||
|
||||
this.outgoingExpanded = setExpanded;
|
||||
toggleOutsButton.setIcon(setExpanded ? COLLAPSE_ICON : EXPAND_ICON);
|
||||
String hideShow = setExpanded ? "hide" : "show";
|
||||
toggleInsButton.setToolTipText("Click to " + hideShow + " outgoing edges");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this vertex is showing all edges in the outgoing direction
|
||||
*
|
||||
* @return true if this vertex is showing all edges in the outgoing direction
|
||||
*/
|
||||
public boolean isOutgoingExpanded() {
|
||||
return outgoingExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vertex is fully expanded in its current direction
|
||||
*
|
||||
* @return whether this vertex is fully expanded in its current direction
|
||||
*/
|
||||
public boolean isExpanded() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
if (direction.isSource()) {
|
||||
return isIncomingExpanded() && isOutgoingExpanded();
|
||||
}
|
||||
if (direction.isIn()) {
|
||||
return isIncomingExpanded();
|
||||
}
|
||||
return isOutgoingExpanded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has too many incoming references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @param tooMany if there are too many references
|
||||
*/
|
||||
public void setTooManyIncomingReferences(boolean tooMany) {
|
||||
this.tooManyIncomingReferences = tooMany;
|
||||
toggleInsButton.setIcon(NOT_ALLOWED_ICON);
|
||||
toggleInsButton.setToolTipText("Too many incoming references to show");
|
||||
buildUi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has too many outgoing references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @param tooMany if there are too many references
|
||||
*/
|
||||
public void setTooManyOutgoingReferences(boolean tooMany) {
|
||||
this.tooManyOutgoingReferences = tooMany;
|
||||
toggleOutsButton.setIcon(NOT_ALLOWED_ICON);
|
||||
toggleOutsButton.setToolTipText("Too many outgoing references to show");
|
||||
buildUi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vertex has too many incoming references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @return true if there are too many references
|
||||
*/
|
||||
public boolean hasTooManyIncomingReferences() {
|
||||
return tooManyIncomingReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vertex has too many outgoing references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @return true if there are too many references
|
||||
*/
|
||||
public boolean hasTooManyOutgoingReferences() {
|
||||
return tooManyOutgoingReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vertex can expand itself in its current direction, or in either
|
||||
* direction if this is a source vertex
|
||||
*
|
||||
* @return true if this vertex can be expanded
|
||||
*/
|
||||
public boolean canExpand() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
if (direction.isSource()) {
|
||||
return canExpandIncomingReferences() || canExpandOutgoingReferences();
|
||||
}
|
||||
|
||||
if (direction.isIn()) {
|
||||
return canExpandIncomingReferences();
|
||||
}
|
||||
|
||||
return canExpandOutgoingReferences();
|
||||
}
|
||||
|
||||
|
||||
public boolean canExpandIncomingReferences() {
|
||||
return hasIncomingReferences && !tooManyIncomingReferences && !incomingExpanded;
|
||||
}
|
||||
|
||||
public boolean canExpandOutgoingReferences() {
|
||||
return hasOutgoingReferences && !tooManyOutgoingReferences && !outgoingExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has any incoming references
|
||||
*
|
||||
* @param hasIncoming true if this vertex has any incoming references
|
||||
*/
|
||||
public void setHasIncomingReferences(boolean hasIncoming) {
|
||||
this.hasIncomingReferences = hasIncoming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has any outgoing references
|
||||
*
|
||||
* @param hasOutgoing true if this vertex has any outgoing references
|
||||
*/
|
||||
|
||||
public void setHasOutgoingReferences(boolean hasOutgoing) {
|
||||
this.hasOutgoingReferences = hasOutgoing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHovered(boolean hovered) {
|
||||
super.setHovered(hovered);
|
||||
|
||||
setTogglesVisible(hovered);
|
||||
}
|
||||
|
||||
private void setTogglesVisible(boolean visible) {
|
||||
|
||||
boolean isIn = isInDirection();
|
||||
boolean turnOn = isIn && hasIncomingReferences && visible;
|
||||
toggleInsButton.setVisible(turnOn);
|
||||
|
||||
boolean isOut = isOutDirection();
|
||||
turnOn = isOut && hasOutgoingReferences && visible;
|
||||
toggleOutsButton.setVisible(turnOn);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return layeredPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getCompactShape() {
|
||||
return compactShape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getFullShape() {
|
||||
return fullShape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();// + " @ " + level; // + " (" + System.identityHashCode(this) + ')';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GraphCutVertex other = (GraphCutVertex) obj;
|
||||
return Objects.equals(namespace, other.namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public long getID() {
|
||||
return getNamespace().getID();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgVertexPaintTransformer.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
|
||||
import ghidra.util.ColorUtils;
|
||||
/**
|
||||
* A class that takes a GraphCutVertex and determines which color to paint it with
|
||||
*/
|
||||
public class GraphCutVertexPaintTransformer implements Function<GraphCutVertex, Paint> {
|
||||
private Color color;
|
||||
|
||||
public GraphCutVertexPaintTransformer(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Paint apply(GraphCutVertex v) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
63
codecut-gui/src/main/java/graphcut/GraphCutView.java
Normal file
63
codecut-gui/src/main/java/graphcut/GraphCutView.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/view/FcgView.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.VisualGraphView;
|
||||
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||
|
||||
public class GraphCutView extends VisualGraphView<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
|
||||
private VisualGraphOptions options;
|
||||
public GraphCutView(VisualGraphOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installGraphViewer() {
|
||||
|
||||
GraphCutComponent component = createGraphComponent();
|
||||
component.setGraphOptions(options);
|
||||
setGraphComponent(component);
|
||||
}
|
||||
|
||||
private GraphCutComponent createGraphComponent() {
|
||||
GraphCutComponent component = new GraphCutComponent(getVisualGraph());
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutComponent getGraphComponent() {
|
||||
return (GraphCutComponent) super.getGraphComponent();
|
||||
}
|
||||
}
|
||||
92
codecut-gui/src/main/java/graphcut/NamespaceEdge.java
Normal file
92
codecut-gui/src/main/java/graphcut/NamespaceEdge.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.Objects;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
|
||||
public class NamespaceEdge {
|
||||
|
||||
private Namespace start;
|
||||
private Namespace end;
|
||||
|
||||
NamespaceEdge(Namespace start, Namespace end){
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
Namespace getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
Namespace getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + start + ", " + end + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime*result + ((end == null) ? 0 : end.hashCode());
|
||||
result = prime * result + ((start == null) ? 0 : start.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NamespaceEdge other = (NamespaceEdge) obj;
|
||||
if(!Objects.equals(end, other.end)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Objects.equals(start, other.start)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
65
codecut-gui/src/main/java/graphcut/NamespaceEdgeCache.java
Normal file
65
codecut-gui/src/main/java/graphcut/NamespaceEdgeCache.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* A class to cache known namespace edges
|
||||
*/
|
||||
public class NamespaceEdgeCache {
|
||||
|
||||
//contains all known edges, even those not shown in the graph
|
||||
private Map<Namespace, Set<NamespaceEdge>> allEdgesByNamespace =
|
||||
LazyMap.lazyMap(new HashMap<>(), () -> new HashSet<>());
|
||||
|
||||
// track processed namespaces
|
||||
private Set<Namespace> tracked = new HashSet<>();
|
||||
|
||||
public Set<NamespaceEdge> get(Namespace ns){
|
||||
return allEdgesByNamespace.get(ns);
|
||||
}
|
||||
|
||||
public boolean isTracked(Namespace ns) {
|
||||
return tracked.contains(ns);
|
||||
}
|
||||
|
||||
public void setTracked(Namespace ns) {
|
||||
tracked.add(ns);
|
||||
}
|
||||
}
|
||||
101
codecut-gui/src/main/java/graphcut/ValidGraphCutData.java
Normal file
101
codecut-gui/src/main/java/graphcut/ValidGraphCutData.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/ValidFcgData.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.graph.viewer.GraphPerspectiveInfo;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
public class ValidGraphCutData implements GraphCutData {
|
||||
|
||||
private Namespace namespace;
|
||||
private GraphCutGraph graph;
|
||||
private GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> perspectiveInfo;
|
||||
|
||||
private NamespaceEdgeCache allEdgesByNamespace = new NamespaceEdgeCache();
|
||||
|
||||
ValidGraphCutData(Namespace namespace, GraphCutGraph graph){
|
||||
this.namespace = Objects.requireNonNull(namespace);
|
||||
this.graph = Objects.requireNonNull(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamespace(Namespace ns) {
|
||||
return namespace.equals(ns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceEdgeCache getNamespaceEdgeCache() {
|
||||
return allEdgesByNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return !graph.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
graph.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective(){
|
||||
return perspectiveInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGraphPerspective( GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info) {
|
||||
this.perspectiveInfo = info;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user