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:
AndreQuimper
2024-06-24 15:26:59 -04:00
parent 9400cc6c69
commit bec42aa376
25 changed files with 4620 additions and 5 deletions

View 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>

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

View File

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

View 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");
}
}

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

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

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

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

View File

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

View File

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

View File

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

View File

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

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

View 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;
}
}

View File

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

View File

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

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

File diff suppressed because it is too large Load Diff

View File

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

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

View File

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

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

View 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;
}
}

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

View 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;
}
}