mirror of
https://github.com/JHUAPL/CodeCut.git
synced 2026-01-13 07:17:59 -05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3953e9d357 | ||
|
|
046f4706d2 | ||
|
|
f2901905ea | ||
|
|
bec42aa376 | ||
|
|
9400cc6c69 | ||
|
|
44dbcdce55 |
54
README.md
54
README.md
@@ -1,12 +1,14 @@
|
||||
# CodeCut Plugin for Ghidra
|
||||
|
||||
Ghidra Plugin for DeepCut / CodeCut GUI
|
||||
|
||||
## Theory of Operation
|
||||
CodeCut allows a user to assign functions to object files in Ghidra, and then interact with the binary at the object file level. Functions are assigned to object files by setting the `Namespace` field in the Ghidra database. DeepCut attempts to establish initial object file boundaries which the user can then adjust using the CodeCut Table window.
|
||||
CodeCut allows a user to assign functions to object files in Ghidra, and then interact with the binary at the object file level. Functions are assigned to object files by setting the `Namespace` field in the Ghidra database. DeepCut attempts to establish initial object file boundaries which the user can then adjust using the CodeCut Table window.
|
||||
|
||||
## Why Is This Useful?
|
||||
Most binaries originate from multiple source code files. When reversing, RE analysts often develop a sense of which functions are related, and therefore likely belonged to the same source file. CodeCut allows the analyst to develop a hypothesis like "I think this block of functions are OS functions." Now if there are unexplored functions in that region, they will show up in disassembly and decompilation as OS::FUN_XXXXXXXX instead of just FUN_XXXXXXXX. This leads to a more rapid understanding of what functions might be used for when viewed in context.
|
||||
|
||||
## Plugin Installation
|
||||
Follow normal Ghidra extension installation procedures. Copy the CodeCut and DeepCut extension zip into `$GHIDRA_INSTALL_DIR/Extensions` then in the main Ghidra window selection **File -> Install Extensions** and select the CodeCut and DeepCut boxes. Ghidra will tell you it needs to restart.
|
||||
Follow normal Ghidra extension installation procedures. Copy the CodeCut and DeepCut extension zip into `$GHIDRA_INSTALL_DIR/Extensions` then in the main Ghidra window selection **File -> Install Extensions** and select the CodeCut and DeepCut boxes. Ghidra will tell you it needs to restart. Now that Ghidra only requires plugins to match the base version's major/minor and not patch versions, we expect to only release even major/minor versions.
|
||||
|
||||
**NOTE:** After restarting and loading a CodeBrowser window, Ghidra will tell you it has found new plugins and ask if you want to configure them. Only CodeCut shows up in this window. This is because DeepCut is a "one-shot" analyzer (it is still installed).
|
||||
|
||||
@@ -18,25 +20,20 @@ CodeCut:
|
||||
- nltk
|
||||
|
||||
DeepCut:
|
||||
- torch 1.7.1
|
||||
- torch-geometric 1.6.3
|
||||
- torch-cluster 1.5.8
|
||||
- torch-sparse 0.6.8
|
||||
- torch-scatter 2.0.5
|
||||
- torch-spline-conv 1.2.0
|
||||
- torch
|
||||
- torch-geometric
|
||||
|
||||
To install dependencies run:
|
||||
|
||||
```
|
||||
pip3 install nltk
|
||||
pip3 install torch==1.7.1+cpu torch-geometric==1.6.3 torch-cluster==1.5.8 torch-spare==0.6.8 torch-scatter==2.0.5 torch-spline-conv==1.2.0
|
||||
pip3 install torch torch-geometric
|
||||
```
|
||||
|
||||
(assuming that pip3 points to the version of Python you plan to use below)
|
||||
|
||||
### Configuring CodeCut Python Path
|
||||

|
||||
|
||||
Configure the native Python path for CodeCut by choosing **Edit -> Tool Options** and selecting "Python Executable."
|
||||
|
||||
### Configuring DeepCut Python Path
|
||||
@@ -50,7 +47,40 @@ DeepCut is best run as a one-shot analyzer *after* initial auto-analysis. Selec
|
||||
## Using CodeCut
|
||||

|
||||
|
||||
After DeepCut runs, you can interact at an object file level with the **CodeCut Table** view. Select **Window -> CodeCut Table** You can have CodeCut guess the module names (based on string references) by choosing **Analysis -> Guess Module Names** in the CodeCut Table window. You can split/combine object files by right clicking on an object and choosing "Split Namespace Here" / "Combine Namespaces." You can move functions between object files (changing the boundaries of the object files) by dragging and dropping them.
|
||||
After DeepCut runs, you can interact at an object file level with the **CodeCut Table** view. Select **Window -> CodeCut Table** to display the table. The CodeCut table is essentially a combined set of symbol tables, one for each module.
|
||||
|
||||
You can have CodeCut guess the module names (based on string references) by choosing **Analysis -> Guess Module Names** in the CodeCut Table window. This is helpful if your target executable has a lot of debug strings. The name guessing script attempts to find source file names first, then falls back to strings (including bigrams and trigrams) that are repeated multiple times.
|
||||
|
||||
You can split/combine object files by right clicking on an object and choosing **Split Namespace Here** / **Combine Namespaces.** You can move functions between object files (changing the boundaries of the object files) by dragging and dropping them.
|
||||
|
||||
## Exporting to Recompilable C
|
||||
|
||||
CodeCut contains two options for exporting a full module or a subrange of a module as recompilable C under the **Export** menu when you right click on a module in the CodeCut table. This feature is marked EXPERIMENTAL and is not well-tested.
|
||||
|
||||
## The CodeCut Graph
|
||||

|
||||
|
||||
CodeCut now has a graph option for viewing interactions / hierarchy of the modules within a binary. Add namespaces to the graph view by right clicking a function in the CodeCut Table and choosing **Add Namespace to Graph**. You can remove modules from the graph by right clicking and choosing **Show Namespaces in Graph Filter**.
|
||||
|
||||
## Limitations
|
||||
|
||||
### Careful Where You Click
|
||||
While it looks like you can right click on the module names on the right side, CodeCut is actually paying attention to which function is highlighted in the table. So e.g. if you have a function in object3 highlighted and you right click on the grey object2 box to the left and click Combine/Split or Rename Namespaces, CodeCut will perform the operation from the function you have highlighted in object3.
|
||||
|
||||
### Address Range Peculiarities
|
||||
CodeCut attempts to order the namespaces by their starting address. CodeCut may appear to list the modules out of order, however this is usually due to disassembly irregularities from Ghidra. E.g. let's say we have a memory map that looks like:
|
||||
|
||||
```
|
||||
object2: 0x00010000 - 0x00018000
|
||||
object3: 0x00018004 - 0x00020000
|
||||
...
|
||||
object50: 0x00480000 - 0x00480a00
|
||||
```
|
||||
|
||||
Say the function at 0x00480000 makes a branch or jump to an address 0x00016008. This should be a new function entry point, but if only one function uses it, Ghidra might not label this as a function entry point, and just consider it part of FUN_00480000. This means that object50's actual range is 0x00016008 - 0x00480a00. And so object50 will show up in between object2 and object3 in the table. CodeCut outputs the module ranges into Ghidra's application log for help with debugging this. In this case defining 0x00016008 as a function will cause object50's bounds to be the right values and object50 will show up at the right place in the table.
|
||||
|
||||
### Defining Functions Later
|
||||
Functions that get defined after DeepCut analysis has been run are by default added to the Global namespace. In the future we plan to add a feature that automatically adds them to the nearest namespace, or give a mechanism to more easily assign single functions directly to a specific namespace.
|
||||
|
||||
## Building
|
||||
Specific build instructions are provided in the DeepCut and CodeCut subfolders.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<META name="ProgId" content="FrontPage.Editor.Document">
|
||||
|
||||
<TITLE>Skeleton Help File for a Module</TITLE>
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
215
codecut-gui/src/main/java/codecutguiv2/ChecklistProvider.java
Normal file
215
codecut-gui/src/main/java/codecutguiv2/ChecklistProvider.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package codecutguiv2;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.WindowPosition;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.services.BlockModelService;
|
||||
import ghidra.feature.vt.api.db.TableColumn;
|
||||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.table.GhidraTableCellRenderer;
|
||||
import ghidra.util.table.GhidraThreadedTablePanel;
|
||||
import graphcut.GraphCutProvider;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class ChecklistProvider extends ComponentProviderAdapter implements ActionListener {
|
||||
|
||||
private static final ImageIcon ICON = ResourceManager.loadImage("images/textfield.png");
|
||||
private static final String BUTTON_STRING = "Apply Changes";
|
||||
private static final String RESET_STRING = "Reset Graph Filter";
|
||||
|
||||
private CodeCutGUIPlugin plugin;
|
||||
private GraphCutProvider graphProvider;
|
||||
GhidraTable table;
|
||||
DefaultTableModel model;
|
||||
|
||||
private JPanel boxPanel;
|
||||
|
||||
ChecklistProvider(CodeCutGUIPlugin plugin){
|
||||
super(plugin.getTool(), "Namespaces in Graph", plugin.getName(), ProgramActionContext.class);
|
||||
this.plugin = plugin;
|
||||
this.graphProvider = plugin.getGraphProvider();
|
||||
|
||||
setIcon(ICON);
|
||||
addToToolbar();
|
||||
setHelpLocation(new HelpLocation(plugin.getName(), "CodeCut_Table"));
|
||||
setWindowGroup("codecutTable");
|
||||
setIntraGroupPosition(WindowPosition.BOTTOM);
|
||||
|
||||
boxPanel = new JPanel();
|
||||
boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
Object[] columnNames = {"Namespace", "Added to Graph"};
|
||||
Object[][] data = {};
|
||||
model = new DefaultTableModel(data, columnNames) {
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
if(column == 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
table = new GhidraTable(model) {
|
||||
@Override
|
||||
public Class getColumnClass(int column) {
|
||||
switch(column) {
|
||||
case 0:
|
||||
return Namespace.class;
|
||||
case 1:
|
||||
return Boolean.class;
|
||||
default:
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
};
|
||||
table.getTableHeader().setReorderingAllowed(false);
|
||||
table.setPreferredScrollableViewportSize(table.getPreferredSize());
|
||||
table.setDefaultRenderer(Namespace.class, new DefaultTableCellRenderer() {
|
||||
@Override
|
||||
public void setValue(Object value) {
|
||||
setText(((Namespace) value).getName());
|
||||
}
|
||||
});
|
||||
JScrollPane scrollPane = new JScrollPane(table);
|
||||
boxPanel.add(scrollPane);
|
||||
boxPanel.setSize(boxPanel.getPreferredSize());
|
||||
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
|
||||
JButton applyButton = new JButton(BUTTON_STRING);
|
||||
applyButton.setVerticalTextPosition(AbstractButton.CENTER);
|
||||
applyButton.setActionCommand(BUTTON_STRING);
|
||||
applyButton.addActionListener(this);
|
||||
|
||||
JButton resetButton = new JButton(RESET_STRING);
|
||||
resetButton.setVerticalTextPosition(AbstractButton.CENTER);
|
||||
resetButton.setActionCommand(RESET_STRING);
|
||||
resetButton.addActionListener(this);
|
||||
|
||||
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
|
||||
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
|
||||
buttonPane.add(Box.createHorizontalGlue());
|
||||
buttonPane.add(applyButton);
|
||||
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
buttonPane.add(resetButton);
|
||||
boxPanel.add(buttonPane);
|
||||
|
||||
setIntraGroupPosition(WindowPosition.RIGHT);
|
||||
buildTable();
|
||||
}
|
||||
|
||||
void buildTable() {
|
||||
model.setRowCount(0);
|
||||
Set<Namespace>inGraph = graphProvider.getNamespacesInFilter();
|
||||
for(Namespace ns: inGraph) {
|
||||
model.addRow(new Object[]{ns, true});
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
plugin = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if(BUTTON_STRING.equals(e.getActionCommand())) {
|
||||
Vector<Vector> data = model.getDataVector();
|
||||
for(int i = 0; i < model.getRowCount(); i++) {
|
||||
Namespace victim = (Namespace)data.elementAt(i).elementAt(0);
|
||||
if(!(boolean)data.elementAt(i).elementAt(1)) {
|
||||
graphProvider.removeFromWhitelist(victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(RESET_STRING.equals(e.getActionCommand())) {
|
||||
graphProvider.resetWhitelist();
|
||||
}
|
||||
|
||||
buildTable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return boxPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getActionContext(MouseEvent event) {
|
||||
Program program = plugin.getProgram();
|
||||
if(program == null) {
|
||||
return null;
|
||||
}
|
||||
return new ProgramActionContext(this, program);
|
||||
}
|
||||
|
||||
public void open() {
|
||||
if (!isVisible()) {
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package codecutguiv2;
|
||||
|
||||
import java.awt.Cursor;
|
||||
@@ -48,6 +49,7 @@ import docking.action.*;
|
||||
import docking.tool.ToolConstants;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.filechooser.GhidraFileChooser;
|
||||
import functioncalls.plugin.FcgProvider;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.context.ProgramActionContext;
|
||||
import ghidra.app.context.ProgramContextAction;
|
||||
@@ -55,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;
|
||||
@@ -64,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;
|
||||
@@ -87,13 +93,18 @@ 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;
|
||||
import resources.ResourceManager;
|
||||
import static ghidra.program.util.ProgramEvent.*;
|
||||
|
||||
|
||||
/**
|
||||
* Plugin to display the symbol table for a program.
|
||||
@@ -109,20 +120,20 @@ import resources.ResourceManager;
|
||||
" 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);
|
||||
|
||||
private final static String OPTION_NAME_PYTHON_EXEC = "Python Executable";
|
||||
private final static String OPTION_DEFAULT_PYTHON_EXEC = "/projects/venv/bin/python3";
|
||||
//private final static String OPTION_DEFAULT_PYTHON_EXEC = "/usr/local/bin/python3"; // for testing
|
||||
private final static String OPTION_DEFAULT_PYTHON_EXEC = "/usr/bin/python3";
|
||||
private String pythonExec = OPTION_DEFAULT_PYTHON_EXEC;
|
||||
|
||||
private DockingAction openRefsAction;
|
||||
@@ -152,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);
|
||||
|
||||
@@ -178,21 +203,29 @@ 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) {
|
||||
// Msg.info(new Object(), "ERROR: Decompiler Extension is not installed");
|
||||
//}
|
||||
|
||||
|
||||
inspector = new SymbolInspector(getTool(), symProvider.getComponent());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tells a plugin that it is no longer needed.
|
||||
* The plugin should remove itself from anything that
|
||||
@@ -248,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;
|
||||
@@ -312,7 +352,7 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
for (int i = 0; i < eventCnt; ++i) {
|
||||
DomainObjectChangeRecord doRecord = ev.getChangeRecord(i);
|
||||
|
||||
int eventType = doRecord.getEventType();
|
||||
int eventType = doRecord.getEventType().getId();
|
||||
if (!(doRecord instanceof ProgramChangeRecord)) {
|
||||
continue;
|
||||
}
|
||||
@@ -320,105 +360,104 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
ProgramChangeRecord rec = (ProgramChangeRecord) doRecord;
|
||||
Symbol symbol = null;
|
||||
SymbolTable symbolTable = currentProgram.getSymbolTable();
|
||||
switch (eventType) {
|
||||
case ChangeManager.DOCR_CODE_ADDED:
|
||||
case ChangeManager.DOCR_CODE_REMOVED:
|
||||
if (rec.getNewValue() instanceof Data) {
|
||||
symbol = symbolTable.getPrimarySymbol(rec.getStart());
|
||||
if (symbol != null && symbol.isDynamic()) {
|
||||
symProvider.symbolChanged(symbol);
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_ADDED:
|
||||
Address addAddr = rec.getStart();
|
||||
Symbol primaryAtAdd = symbolTable.getPrimarySymbol(addAddr);
|
||||
if (primaryAtAdd != null && primaryAtAdd.isDynamic()) {
|
||||
symProvider.symbolRemoved(primaryAtAdd);
|
||||
}
|
||||
symbol = (Symbol) rec.getNewValue();
|
||||
symProvider.symbolAdded(symbol);
|
||||
refProvider.symbolAdded(symbol);
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_REMOVED:
|
||||
Address removeAddr = rec.getStart();
|
||||
Long symbolID = (Long) rec.getNewValue();
|
||||
Symbol removedSymbol = new SymbolPlaceholder(symbolID, removeAddr, getProgram());
|
||||
symProvider.symbolRemoved(removedSymbol);
|
||||
refProvider.symbolRemoved(removedSymbol);
|
||||
Symbol primaryAtRemove = symbolTable.getPrimarySymbol(removeAddr);
|
||||
if (primaryAtRemove != null && primaryAtRemove.isDynamic()) {
|
||||
symProvider.symbolAdded(primaryAtRemove);
|
||||
refProvider.symbolRemoved(primaryAtRemove);
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_RENAMED:
|
||||
case ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED:
|
||||
case ChangeManager.DOCR_SYMBOL_DATA_CHANGED:
|
||||
symbol = (Symbol) rec.getObject();
|
||||
if (!CodecutUtils.nsUpdating()) {
|
||||
if (!symbol.isDeleted()) {
|
||||
symProvider.symbolChanged(symbol);
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_SOURCE_CHANGED:
|
||||
symbol = (Symbol) rec.getObject();
|
||||
symProvider.symbolChanged(symbol);
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY:
|
||||
symbol = (Symbol) rec.getNewValue();
|
||||
symProvider.symbolChanged(symbol);
|
||||
Symbol oldSymbol = (Symbol) rec.getOldValue();
|
||||
if (oldSymbol != null) {
|
||||
symProvider.symbolChanged(oldSymbol);
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_SYMBOL_ASSOCIATION_ADDED:
|
||||
case ChangeManager.DOCR_SYMBOL_ASSOCIATION_REMOVED:
|
||||
break;
|
||||
case ChangeManager.DOCR_MEM_REFERENCE_ADDED:
|
||||
Reference ref = (Reference) rec.getObject();
|
||||
symbol = symbolTable.getSymbol(ref);
|
||||
if (symbol != null) {
|
||||
|
||||
if(eventType == CODE_ADDED.getId() || eventType == CODE_REMOVED.getId()) {
|
||||
if (rec.getNewValue() instanceof Data) {
|
||||
symbol = symbolTable.getPrimarySymbol(rec.getStart());
|
||||
if (symbol != null && symbol.isDynamic()) {
|
||||
symProvider.symbolChanged(symbol);
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
break;
|
||||
case ChangeManager.DOCR_MEM_REFERENCE_REMOVED:
|
||||
ref = (Reference) rec.getObject();
|
||||
Address toAddr = ref.getToAddress();
|
||||
if (toAddr.isMemoryAddress()) {
|
||||
symbol = symbolTable.getSymbol(ref);
|
||||
if (symbol == null) {
|
||||
|
||||
long id = symbolTable.getDynamicSymbolID(ref.getToAddress());
|
||||
removedSymbol = new SymbolPlaceholder(id, toAddr, getProgram());
|
||||
symProvider.symbolRemoved(removedSymbol);
|
||||
}
|
||||
else {
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_ADDED:
|
||||
case ChangeManager.DOCR_EXTERNAL_ENTRY_POINT_REMOVED:
|
||||
Symbol[] symbols = symbolTable.getSymbols(rec.getStart());
|
||||
for (Symbol element : symbols) {
|
||||
symProvider.symbolChanged(element);
|
||||
refProvider.symbolChanged(element);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else if(eventType == SYMBOL_ADDED.getId()) {
|
||||
Address addAddr = rec.getStart();
|
||||
Symbol primaryAtAdd = symbolTable.getPrimarySymbol(addAddr);
|
||||
if (primaryAtAdd != null && primaryAtAdd.isDynamic()) {
|
||||
symProvider.symbolRemoved(primaryAtAdd);
|
||||
}
|
||||
symbol = (Symbol) rec.getNewValue();
|
||||
symProvider.symbolAdded(symbol);
|
||||
refProvider.symbolAdded(symbol);
|
||||
}
|
||||
|
||||
else if(eventType == SYMBOL_REMOVED.getId()) {
|
||||
Address removeAddr = rec.getStart();
|
||||
Long symbolID = (Long) rec.getNewValue();
|
||||
Symbol removedSymbol;
|
||||
removedSymbol = new SymbolPlaceholder(symbolID, removeAddr, getProgram());
|
||||
symProvider.symbolRemoved(removedSymbol);
|
||||
refProvider.symbolRemoved(removedSymbol);
|
||||
Symbol primaryAtRemove = symbolTable.getPrimarySymbol(removeAddr);
|
||||
if (primaryAtRemove != null && primaryAtRemove.isDynamic()) {
|
||||
symProvider.symbolAdded(primaryAtRemove);
|
||||
refProvider.symbolRemoved(primaryAtRemove);
|
||||
}
|
||||
}
|
||||
|
||||
else if((eventType == SYMBOL_RENAMED.getId())
|
||||
|| (eventType == SYMBOL_SCOPE_CHANGED.getId())
|
||||
|| (eventType == SYMBOL_DATA_CHANGED.getId())) {
|
||||
|
||||
symbol = (Symbol) rec.getObject();
|
||||
if (!CodecutUtils.nsUpdating()) {
|
||||
if (!symbol.isDeleted()) {
|
||||
symProvider.symbolChanged(symbol);
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(eventType == SYMBOL_SOURCE_CHANGED.getId()) {
|
||||
symbol = (Symbol) rec.getObject();
|
||||
symProvider.symbolChanged(symbol);
|
||||
}
|
||||
|
||||
else if(eventType == SYMBOL_PRIMARY_STATE_CHANGED.getId()) {
|
||||
symbol = (Symbol) rec.getNewValue();
|
||||
symProvider.symbolChanged(symbol);
|
||||
Symbol oldSymbol = (Symbol) rec.getOldValue();
|
||||
if (oldSymbol != null) {
|
||||
symProvider.symbolChanged(oldSymbol);
|
||||
}
|
||||
}
|
||||
|
||||
else if(eventType == REFERENCE_ADDED.getId()) {
|
||||
Reference ref = (Reference) rec.getObject();
|
||||
symbol = symbolTable.getSymbol(ref);
|
||||
if (symbol != null) {
|
||||
symProvider.symbolChanged(symbol);
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
else if(eventType == REFERENCE_REMOVED.getId()) {
|
||||
Reference ref = (Reference) rec.getObject();
|
||||
Address toAddr = ref.getToAddress();
|
||||
if (toAddr.isMemoryAddress()) {
|
||||
symbol = symbolTable.getSymbol(ref);
|
||||
if (symbol == null) {
|
||||
|
||||
Symbol removedSymbol;
|
||||
long id = symbolTable.getDynamicSymbolID(ref.getToAddress());
|
||||
removedSymbol = new SymbolPlaceholder(id, toAddr, getProgram());
|
||||
symProvider.symbolRemoved(removedSymbol);
|
||||
}
|
||||
else {
|
||||
refProvider.symbolChanged(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(eventType == EXTERNAL_ENTRY_ADDED.getId() || eventType == EXTERNAL_ENTRY_REMOVED.getId()) {
|
||||
Symbol[] symbols = symbolTable.getSymbols(rec.getStart());
|
||||
for (Symbol element : symbols) {
|
||||
symProvider.symbolChanged(element);
|
||||
refProvider.symbolChanged(element);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -438,6 +477,10 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
SymbolProvider getSymbolProvider() {
|
||||
return symProvider;
|
||||
}
|
||||
|
||||
GraphCutProvider getGraphProvider() {
|
||||
return graphProvider;
|
||||
}
|
||||
|
||||
ReferenceProvider getReferenceProvider() {
|
||||
return refProvider;
|
||||
@@ -750,6 +793,8 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
moduleNameGuessingAction.setHelpLocation(new HelpLocation("Map", moduleNameGuessingAction.getName()));
|
||||
moduleNameGuessingAction.setAddToAllWindows(true);
|
||||
tool.addAction(moduleNameGuessingAction);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void createExportActions() {
|
||||
@@ -892,7 +937,7 @@ public class CodeCutGUIPlugin extends Plugin implements DomainObjectListener {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void guessModuleNames() {
|
||||
Task guessNamesTask = new Task("Guess Module Names", true, true, true) {
|
||||
@Override
|
||||
@@ -1412,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +186,11 @@ public class CodecutUtils {
|
||||
SymbolType type = symbol.getSymbolType();
|
||||
if (type == SymbolType.FUNCTION) {
|
||||
Namespace ns = ((Function)symbol.getObject()).getParentNamespace();
|
||||
if (!namespaceList.contains(ns)) {
|
||||
namespaceList.add(ns);
|
||||
//make sure it's a "real" namespace with a body - otherwise we can't work with it
|
||||
if ((ns.getBody().getMinAddress() != null) && (ns.getBody().getMaxAddress() != null)) {
|
||||
if (!namespaceList.contains(ns)) {
|
||||
namespaceList.add(ns);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,12 @@ class CombineProvider extends ComponentProviderAdapter implements ActionListener
|
||||
private Namespace firstNamespace;
|
||||
private Namespace secondNamespace;
|
||||
private Namespace combinedNamespace;
|
||||
private SymbolProvider symProvider;
|
||||
|
||||
CombineProvider(CodeCutGUIPlugin plugin) {
|
||||
super(plugin.getTool(), "Combine Namespaces", plugin.getName(), ProgramActionContext.class);
|
||||
this.plugin = plugin;
|
||||
symProvider = plugin.getSymbolProvider();
|
||||
|
||||
setIcon(ICON);
|
||||
addToToolbar();
|
||||
@@ -241,12 +243,12 @@ class CombineProvider extends ComponentProviderAdapter implements ActionListener
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this.closeComponent();
|
||||
|
||||
symProvider.reload();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -73,10 +73,13 @@ class CreateProvider extends ComponentProviderAdapter implements ActionListener
|
||||
|
||||
private Namespace namespace;
|
||||
private Symbol symbol;
|
||||
private SymbolProvider symProvider;
|
||||
|
||||
CreateProvider(CodeCutGUIPlugin plugin) {
|
||||
super(plugin.getTool(), "Create Namespace", plugin.getName(), ProgramActionContext.class);
|
||||
this.plugin = plugin;
|
||||
|
||||
symProvider = plugin.getSymbolProvider();
|
||||
|
||||
setIcon(ICON);
|
||||
addToToolbar();
|
||||
@@ -141,9 +144,10 @@ class CreateProvider extends ComponentProviderAdapter implements ActionListener
|
||||
Msg.info(this, "Exception when attempting to change namespace of symbol "
|
||||
+ this.symbol.getName() + " to " + nS.getName());
|
||||
}
|
||||
|
||||
|
||||
this.closeComponent();
|
||||
|
||||
symProvider.reload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,12 @@ class NamespacePanel extends JPanel {
|
||||
|
||||
Namespace ns = it.next();
|
||||
AddressSetView ar = ns.getBody();
|
||||
Msg.info(this, "Add: " + ns.getName() + " " + ar.getMinAddress().toString() + " " + ar.getMaxAddress().toString());
|
||||
if ((ar.getMinAddress() != null) && (ar.getMaxAddress() != null)) {
|
||||
Msg.info(this, "Add: " + ns.getName() + " " + ar.getMinAddress().toString() + " " + ar.getMaxAddress().toString());
|
||||
}
|
||||
else {
|
||||
Msg.info(this, "Add: " + ns.getName() + " null min or max??");
|
||||
}
|
||||
SymbolIterator symIter = this.program.getSymbolTable().getSymbols(ns);
|
||||
SymbolTableModel model = new SymbolTableModel(this.program, this.symProvider, this.tool, symIter, ns);
|
||||
|
||||
|
||||
@@ -73,10 +73,12 @@ class RenameProvider extends ComponentProviderAdapter implements ActionListener
|
||||
private JButton button;
|
||||
|
||||
private Namespace namespace;
|
||||
private SymbolProvider symProvider;
|
||||
|
||||
RenameProvider(CodeCutGUIPlugin plugin) {
|
||||
super(plugin.getTool(), "Rename Namespace", plugin.getName(), ProgramActionContext.class);
|
||||
this.plugin = plugin;
|
||||
symProvider = plugin.getSymbolProvider();
|
||||
|
||||
setIcon(ICON);
|
||||
addToToolbar();
|
||||
@@ -172,6 +174,7 @@ class RenameProvider extends ComponentProviderAdapter implements ActionListener
|
||||
this.closeComponent();
|
||||
}
|
||||
}
|
||||
symProvider.reload();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
88
codecut-gui/src/main/java/graphcut/EmptyGraphCutData.java
Normal file
88
codecut-gui/src/main/java/graphcut/EmptyGraphCutData.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/EmptyFcgData.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.GraphPerspectiveInfo;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* empty data used to avoid null checks
|
||||
*/
|
||||
public class EmptyGraphCutData implements GraphCutData {
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace() {
|
||||
throw new UnsupportedOperationException("Empty data has no namespace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamespace(Namespace ns) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph getGraph() {
|
||||
throw new UnsupportedOperationException("Empty data has no graph");
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceEdgeCache getNamespaceEdgeCache() {
|
||||
throw new UnsupportedOperationException("Empty data has no namespace edge cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective(){
|
||||
throw new UnsupportedOperationException("Empty data does not need view information");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGraphPerspective(GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info) {
|
||||
throw new UnsupportedOperationException("Empty data does not need view information");
|
||||
}
|
||||
}
|
||||
126
codecut-gui/src/main/java/graphcut/GraphCutComponent.java
Normal file
126
codecut-gui/src/main/java/graphcut/GraphCutComponent.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/graph/view/FcgComponent.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import edu.uci.ics.jung.visualization.renderers.Renderer;
|
||||
import functioncalls.graph.FcgEdge;
|
||||
import functioncalls.graph.FcgVertex;
|
||||
import generic.theme.GColor;
|
||||
import ghidra.graph.viewer.GraphComponent;
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
import ghidra.graph.viewer.SatelliteGraphViewer;
|
||||
import ghidra.graph.viewer.VisualGraphViewUpdater;
|
||||
import ghidra.graph.viewer.edge.VisualEdgeRenderer;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.graph.viewer.renderer.VisualVertexSatelliteRenderer;
|
||||
import ghidra.graph.viewer.vertex.VisualVertexRenderer;
|
||||
|
||||
/**
|
||||
* A graph component for GraphCut
|
||||
*/
|
||||
public class GraphCutComponent extends GraphComponent<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
|
||||
|
||||
private GraphCutGraph gcGraph;
|
||||
|
||||
private GraphCutVertexPaintTransformer vertexPaintTransformer =
|
||||
new GraphCutVertexPaintTransformer(GraphCutVertex.DEFAULT_VERTEX_SHAPE_COLOR);
|
||||
|
||||
private GraphCutEdgePaintTransformer edgePaintTransformer =
|
||||
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.primary.direct"),
|
||||
new GColor("color.bg.plugin.fcg.edge.primary.indirect"));
|
||||
|
||||
private GraphCutEdgePaintTransformer selectedEdgePaintTransformer =
|
||||
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.primary.direct.selected"),
|
||||
new GColor("color.bg.plugin.fcg.edge.primary.indirect.selected"));
|
||||
|
||||
private GraphCutEdgePaintTransformer satelliteEdgePaintTransformer =
|
||||
new GraphCutEdgePaintTransformer(new GColor("color.bg.plugin.fcg.edge.satellite.direct"),
|
||||
new GColor("color.bg.plugin.fcg.edge.satellite.indirect"));
|
||||
|
||||
GraphCutComponent(GraphCutGraph g){
|
||||
setGraph(g);
|
||||
build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphCutVertex getInitialVertex() {
|
||||
return gcGraph.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decoratePrimaryViewer(GraphViewer<GraphCutVertex, GraphCutEdge> viewer,
|
||||
VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
|
||||
|
||||
super.decoratePrimaryViewer(viewer, layout);
|
||||
|
||||
Renderer<GraphCutVertex, GraphCutEdge> renderer = viewer.getRenderer();
|
||||
VisualVertexRenderer<GraphCutVertex, GraphCutEdge> vertexRenderer =
|
||||
(VisualVertexRenderer<GraphCutVertex, GraphCutEdge>) renderer.getVertexRenderer();
|
||||
vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer);
|
||||
|
||||
VisualEdgeRenderer<GraphCutVertex, GraphCutEdge> edgeRenderer =
|
||||
(VisualEdgeRenderer<GraphCutVertex, GraphCutEdge>) renderer.getEdgeRenderer();
|
||||
edgeRenderer.setDrawColorTransformer(edgePaintTransformer);
|
||||
edgeRenderer.setSelectedColorTransformer(selectedEdgePaintTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorateSatelliteViewer(SatelliteGraphViewer<GraphCutVertex, GraphCutEdge> viewer,
|
||||
VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
|
||||
|
||||
super.decorateSatelliteViewer(viewer, layout);
|
||||
|
||||
Renderer<GraphCutVertex, GraphCutEdge> renderer = viewer.getRenderer();
|
||||
VisualVertexSatelliteRenderer<GraphCutVertex, GraphCutEdge> vertexRenderer =
|
||||
(VisualVertexSatelliteRenderer<GraphCutVertex, GraphCutEdge>) renderer.getVertexRenderer();
|
||||
vertexRenderer.setVertexFillPaintTransformer(vertexPaintTransformer);
|
||||
|
||||
VisualEdgeRenderer<GraphCutVertex, GraphCutEdge> edgeRenderer =
|
||||
(VisualEdgeRenderer<GraphCutVertex, GraphCutEdge>) renderer.getEdgeRenderer();
|
||||
edgeRenderer.setDrawColorTransformer(satelliteEdgePaintTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
gcGraph = null;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisualGraphViewUpdater<GraphCutVertex, GraphCutEdge> getViewUpdater(){
|
||||
return super.getViewUpdater();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
97
codecut-gui/src/main/java/graphcut/GraphCutData.java
Normal file
97
codecut-gui/src/main/java/graphcut/GraphCutData.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/FcgData.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.GraphPerspectiveInfo;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* Allows us to retrieve and work on the graph. Makes caching data simple
|
||||
*/
|
||||
public interface GraphCutData {
|
||||
|
||||
/**
|
||||
* The namespace of this data
|
||||
* @return the namespace
|
||||
*/
|
||||
Namespace getNamespace();
|
||||
|
||||
/**
|
||||
* The graph of this data
|
||||
* @return the graph
|
||||
*/
|
||||
GraphCutGraph getGraph();
|
||||
|
||||
/**
|
||||
* Returns the cache of edges. Not in the graph but used to track existing edges that are not yet in the graph.
|
||||
* @return
|
||||
*/
|
||||
NamespaceEdgeCache getNamespaceEdgeCache();
|
||||
|
||||
/**
|
||||
* True if this data has a valid namespace
|
||||
* @return true if this data has a valid namespace
|
||||
*/
|
||||
boolean hasResults();
|
||||
|
||||
/**
|
||||
* False if the graph in this data has not yet been loaded
|
||||
*/
|
||||
boolean isInitialized();
|
||||
|
||||
/**
|
||||
* Dispose the contents of this data
|
||||
*/
|
||||
void dispose();
|
||||
|
||||
/**
|
||||
* Returns the view's graph perspective. this is used by the view to restore itself.
|
||||
* @return the view's graph perspective
|
||||
*/
|
||||
GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective();
|
||||
|
||||
/**
|
||||
* Set the view information for this graph data
|
||||
* @param info the perspective to set
|
||||
*/
|
||||
void setGraphPerspective(GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info);
|
||||
|
||||
/**
|
||||
* Returns true if this data's namespace is equal to the given one
|
||||
* @param ns the namespace to test
|
||||
* @return true if this data's namespace is equal to the given one
|
||||
*/
|
||||
boolean isNamespace(Namespace ns);
|
||||
}
|
||||
79
codecut-gui/src/main/java/graphcut/GraphCutDataFactory.java
Normal file
79
codecut-gui/src/main/java/graphcut/GraphCutDataFactory.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/FcgDataFactory.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import com.google.common.cache.*;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* A factory that will create GraphCutGraph data objects for a given namespace
|
||||
*/
|
||||
public class GraphCutDataFactory {
|
||||
|
||||
private LoadingCache<Namespace, GraphCutData> cache;
|
||||
|
||||
GraphCutDataFactory(RemovalListener<Namespace, GraphCutData> listener){
|
||||
|
||||
cache = CacheBuilder
|
||||
.newBuilder()
|
||||
.maximumSize(5)
|
||||
.removalListener(listener)
|
||||
.build(new CacheLoader<Namespace, GraphCutData> () {
|
||||
@Override
|
||||
public GraphCutData load(Namespace ns) throws Exception {
|
||||
return new ValidGraphCutData(ns, new GraphCutGraph());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
GraphCutData create(Namespace ns) {
|
||||
if (ns == null) {
|
||||
return new EmptyGraphCutData();
|
||||
}
|
||||
|
||||
GraphCutData data = cache.getUnchecked(ns);
|
||||
return data;
|
||||
}
|
||||
|
||||
void remove(Namespace ns) {
|
||||
cache.invalidate(ns);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
cache.invalidateAll();
|
||||
}
|
||||
|
||||
}
|
||||
70
codecut-gui/src/main/java/graphcut/GraphCutEdge.java
Normal file
70
codecut-gui/src/main/java/graphcut/GraphCutEdge.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.edge.AbstractVisualEdge;
|
||||
import graphcut.GraphCutVertex;
|
||||
/**
|
||||
* A GraphCut Edge
|
||||
*/
|
||||
|
||||
public class GraphCutEdge extends AbstractVisualEdge<GraphCutVertex> {
|
||||
|
||||
public GraphCutEdge(GraphCutVertex start, GraphCutVertex end) {
|
||||
super(start, end);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@Override
|
||||
public GraphCutEdge cloneEdge(GraphCutVertex start, GraphCutVertex end) {
|
||||
return new GraphCutEdge(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an edge is direct from a lower level.
|
||||
* @return true if this edge is a direct edge
|
||||
*/
|
||||
public boolean isDirectEdge() {
|
||||
GraphCutLevel startLevel = getStart().getLevel();
|
||||
GraphCutLevel endLevel = getEnd().getLevel();
|
||||
if(startLevel.isSource() || endLevel.isSource()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GraphCutLevel parent = startLevel.parent();
|
||||
if (parent.equals(endLevel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GraphCutLevel child = startLevel.child();
|
||||
return child.equals(endLevel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgEdgePaintTransformer.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import java.awt.Color;
|
||||
import ghidra.util.ColorUtils;
|
||||
|
||||
public class GraphCutEdgePaintTransformer implements Function<GraphCutEdge, Color> {
|
||||
private Color directColor;
|
||||
private Color indirectColor;
|
||||
|
||||
private Color[] directColorWithAlpha = new Color[10];
|
||||
|
||||
public GraphCutEdgePaintTransformer(Color directColor, Color indirectColor) {
|
||||
this.directColor = directColor;
|
||||
this.indirectColor = indirectColor;
|
||||
|
||||
directColorWithAlpha = alphatize(directColor);
|
||||
}
|
||||
|
||||
private Color[] alphatize(Color c) {
|
||||
Color[] alphad = new Color[10];
|
||||
alphad[0] = c;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
double newAlpha = 255 - (i * 25.5);
|
||||
alphad[i] = ColorUtils.withAlpha(c, (int) newAlpha);
|
||||
}
|
||||
return alphad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color apply(GraphCutEdge e) {
|
||||
if (e.isDirectEdge()) {
|
||||
return getDirectEdgeColor(e);
|
||||
}
|
||||
|
||||
return indirectColor;
|
||||
}
|
||||
|
||||
private Color getDirectEdgeColor(GraphCutEdge e) {
|
||||
return directColor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/FcgEmphasizeEdgesJob.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import ghidra.graph.job.AbstractGraphVisibilityTransitionJob;
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
|
||||
public class GraphCutEmphasizeEdgesJob extends AbstractGraphVisibilityTransitionJob<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
private Set<GraphCutEdge> edges;
|
||||
|
||||
public GraphCutEmphasizeEdgesJob(GraphViewer<GraphCutVertex, GraphCutEdge> viewer, Set<GraphCutEdge> edges) {
|
||||
super(viewer, true);
|
||||
this.edges = edges;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateOpacity(double percentComplete) {
|
||||
|
||||
double remaining = percentComplete;
|
||||
if(percentComplete > 0.5){
|
||||
remaining = 1 - percentComplete;
|
||||
}
|
||||
|
||||
double modified = remaining * 10;
|
||||
|
||||
for (GraphCutEdge e : edges) {
|
||||
e.setEmphasis(modified);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/FcgExpandingVertexCollection.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||
import functioncalls.graph.FcgDirection;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public class GraphCutExpandingVertexCollection {
|
||||
|
||||
private Comparator<GraphCutVertex> vertexComparator =
|
||||
(v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0;
|
||||
private Comparator<GraphCutVertex> sourceVertexComparator = this::compareVerticesByLayoutPosition;
|
||||
|
||||
private Map<GraphCutVertex, TreeSet<GraphCutVertex>> newVerticesBySource = LazyMap.lazyMap(
|
||||
new TreeMap<>(sourceVertexComparator), () -> new TreeSet<>(vertexComparator));
|
||||
|
||||
private GraphViewer<GraphCutVertex, GraphCutEdge> viewer;
|
||||
private GraphCutLevel parentLevel;
|
||||
private GraphCutLevel expandingLevel;
|
||||
private Set<GraphCutVertex> newVertices;
|
||||
private Set<GraphCutEdge> newEdges;
|
||||
private Set<GraphCutEdge> indirectEdges = Collections.emptySet();
|
||||
private boolean isIncoming;
|
||||
private Iterable<GraphCutVertex> sources;
|
||||
|
||||
public GraphCutExpandingVertexCollection(Iterable<GraphCutVertex> sources, GraphCutLevel parentLevel, GraphCutLevel expandingLevel,
|
||||
Set<GraphCutVertex> newVertices, Set<GraphCutEdge> newEdges, Set<GraphCutEdge> allParentLevelEdges, boolean isIncoming,
|
||||
GraphViewer<GraphCutVertex, GraphCutEdge> viewer) {
|
||||
|
||||
this.sources = sources;
|
||||
this.parentLevel = parentLevel;
|
||||
this.newVertices = newVertices;
|
||||
this.newEdges = newEdges;
|
||||
this.isIncoming = isIncoming;
|
||||
this.viewer = viewer;
|
||||
this.expandingLevel = expandingLevel;
|
||||
|
||||
for(GraphCutEdge e: allParentLevelEdges) {
|
||||
|
||||
GraphCutVertex start = e.getStart();
|
||||
GraphCutVertex end = e.getEnd();
|
||||
GraphCutLevel startLevel = start.getLevel();
|
||||
GraphCutLevel endLevel = end.getLevel();
|
||||
|
||||
if (expandingLevel.equals(startLevel)) {
|
||||
if(expandingLevel.equals(endLevel)) {
|
||||
newVerticesBySource.get(start).add(end);
|
||||
newVerticesBySource.get(end).add(start);
|
||||
}
|
||||
else {
|
||||
newVerticesBySource.get(end).add(start);
|
||||
}
|
||||
}
|
||||
else {
|
||||
newVerticesBySource.get(start).add(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int compareVerticesByLayoutPosition(GraphCutVertex v1, GraphCutVertex v2) {
|
||||
|
||||
Layout<GraphCutVertex, GraphCutEdge> layout = viewer.getGraphLayout();
|
||||
|
||||
GraphCutLevel l1 = v1.getLevel();
|
||||
GraphCutLevel l2 = v2.getLevel();
|
||||
|
||||
int result = l1.compareTo(l2);
|
||||
if (result != 0) {
|
||||
|
||||
if(l1.equals(parentLevel)) {
|
||||
return -1;
|
||||
}
|
||||
if(l2.equals(parentLevel)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Point2D p1 = layout.apply(v1);
|
||||
Point2D p2 = layout.apply(v2);
|
||||
return (int) (p1.getX() - p2.getX());
|
||||
}
|
||||
|
||||
public List<GraphCutVertex> getVerticesByLevel(GraphCutLevel level){
|
||||
|
||||
Set<GraphCutVertex> existingVertices = newVerticesBySource.keySet();
|
||||
|
||||
List<GraphCutVertex> verticesAtLevel = existingVertices.stream().filter(v -> v.getLevel().equals(level)).collect(Collectors.toList());
|
||||
return verticesAtLevel;
|
||||
}
|
||||
|
||||
public List<GraphCutVertex> getAllVerticesAtNewLevel(){
|
||||
|
||||
Set<GraphCutVertex> existingVertices = newVerticesBySource.keySet();
|
||||
LinkedHashSet<GraphCutVertex> sortedVertices = existingVertices
|
||||
.stream()
|
||||
.map(v -> newVerticesBySource.get(v))
|
||||
.flatMap(set -> set.stream())
|
||||
.filter(v -> v.getLevel().equals(expandingLevel))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
return new ArrayList<>(sortedVertices);
|
||||
|
||||
}
|
||||
|
||||
public Set<GraphCutVertex> getNewVertices(){
|
||||
return newVertices;
|
||||
}
|
||||
|
||||
public Set<GraphCutEdge> getIndirectEdges() {
|
||||
return indirectEdges;
|
||||
}
|
||||
|
||||
public Iterable<GraphCutEdge> getNewEdges(){
|
||||
return IterableUtils.chainedIterable(newEdges, indirectEdges);
|
||||
}
|
||||
|
||||
public int getNewEdgeCount() {
|
||||
return newEdges.size() + indirectEdges.size();
|
||||
}
|
||||
|
||||
public void setIndirectEdges(Set<GraphCutEdge> indirectEdges) {
|
||||
this.indirectEdges = CollectionUtils.asSet(indirectEdges);
|
||||
}
|
||||
|
||||
public GraphCutLevel getExpandingLevel() {
|
||||
return expandingLevel;
|
||||
}
|
||||
|
||||
public FcgDirection getExpandingDirection() {
|
||||
return expandingLevel.getDirection();
|
||||
}
|
||||
|
||||
public Iterable<GraphCutVertex> getSources(){
|
||||
return sources;
|
||||
}
|
||||
|
||||
public boolean isIncoming() {
|
||||
return isIncoming;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
|
||||
public interface GraphCutExpansionListener {
|
||||
|
||||
/**
|
||||
* Show or hide those vertices that are on incoming edges to v
|
||||
*
|
||||
* @param v the vertex
|
||||
*/
|
||||
public void toggleIncomingVertices(GraphCutVertex v);
|
||||
|
||||
/**
|
||||
* Show or hide those vertices that are on outgoing edges to v
|
||||
*
|
||||
* @param v the vertex
|
||||
*/
|
||||
public void toggleOutgoingVertices(GraphCutVertex v);
|
||||
|
||||
}
|
||||
177
codecut-gui/src/main/java/graphcut/GraphCutGraph.java
Normal file
177
codecut-gui/src/main/java/graphcut/GraphCutGraph.java
Normal file
@@ -0,0 +1,177 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FunctionCallGraph.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.collections4.IterableUtils;
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import functioncalls.graph.FcgDirection;
|
||||
import ghidra.graph.graphs.FilteringVisualGraph;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
|
||||
/*
|
||||
* A graph for the GraphCut Plugin
|
||||
*/
|
||||
public class GraphCutGraph extends FilteringVisualGraph<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
private VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout;
|
||||
private GraphCutVertex source;
|
||||
private Map<Namespace, GraphCutVertex> verticesByNamespace = new HashMap<>();
|
||||
private Comparator<GraphCutVertex> vertexComparator =
|
||||
(v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0;
|
||||
private Map<GraphCutLevel, Set<GraphCutVertex>> verticesByLevel =
|
||||
LazyMap.lazyMap(new HashMap<>(), () -> new TreeSet<>(vertexComparator));
|
||||
|
||||
/**
|
||||
* Sets the source vertex from which the graph originates
|
||||
* @param the source vertex
|
||||
*/
|
||||
public void setSource(GraphCutVertex source) {
|
||||
if (this.source != null) {
|
||||
throw new IllegalStateException("Cannot change graph source once it has been created");
|
||||
}
|
||||
|
||||
this.source = source;
|
||||
addVertex(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex from which the graph is created
|
||||
* @return source vertex
|
||||
*/
|
||||
public GraphCutVertex getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns whether there is a vertex for the given namespace
|
||||
* @param ns Namespace
|
||||
* @return True if graph contains a vertex for the namespace
|
||||
*/
|
||||
public boolean containsNamespace(Namespace ns) {
|
||||
return verticesByNamespace.containsKey(ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex for the given namespace
|
||||
* @param ns Namespace
|
||||
* @return the vertex for the given namespace
|
||||
*/
|
||||
public GraphCutVertex getVertex(Namespace ns) {
|
||||
return verticesByNamespace.get(ns);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return all vertices in the given level
|
||||
* @param level the level to retrieve
|
||||
* @return all vertices in the given level
|
||||
*/
|
||||
public Iterable<GraphCutVertex> getVerticesByLevel(GraphCutLevel level){
|
||||
return IterableUtils.unmodifiableIterable(verticesByLevel.get(level));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level furthest from the source node in the given direction
|
||||
* @param direction the direction to search
|
||||
* @return the furthest level
|
||||
*/
|
||||
public GraphCutLevel getLargestLevel(FcgDirection direction) {
|
||||
GraphCutLevel greatest = new GraphCutLevel(1, direction);
|
||||
|
||||
Set<GraphCutLevel> keys = verticesByLevel.keySet();
|
||||
for (GraphCutLevel level : keys) {
|
||||
if (level.getDirection() != direction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (level.getRow() > greatest.getRow()) {
|
||||
greatest = level;
|
||||
}
|
||||
}
|
||||
return greatest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisualGraphLayout<GraphCutVertex, GraphCutEdge> getLayout(){
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph copy() {
|
||||
|
||||
GraphCutGraph newGraph = new GraphCutGraph();
|
||||
for (GraphCutVertex v : vertices.keySet()) {
|
||||
newGraph.addVertex(v);
|
||||
}
|
||||
|
||||
for (GraphCutEdge e : edges.keySet()) {
|
||||
newGraph.addEdge(e);
|
||||
}
|
||||
|
||||
return newGraph;
|
||||
}
|
||||
|
||||
public void setLayout(VisualGraphLayout<GraphCutVertex, GraphCutEdge> layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verticesAdded(Collection<GraphCutVertex> added) {
|
||||
for (GraphCutVertex v : added) {
|
||||
Namespace ns = v.getNamespace();
|
||||
verticesByNamespace.put(ns, v);
|
||||
verticesByLevel.get(v.getLevel()).add(v);
|
||||
}
|
||||
super.verticesAdded(added);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void verticesRemoved(Collection<GraphCutVertex> removed) {
|
||||
for (GraphCutVertex v : removed) {
|
||||
Namespace ns = v.getNamespace();
|
||||
verticesByNamespace.remove(ns);
|
||||
verticesByLevel.get(v.getLevel()).remove(v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
137
codecut-gui/src/main/java/graphcut/GraphCutLayout.java
Normal file
137
codecut-gui/src/main/java/graphcut/GraphCutLayout.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows heavily from Ghidra File /Features Graph FunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayout.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.graph.VisualGraph;
|
||||
import ghidra.graph.viewer.layout.AbstractVisualGraphLayout;
|
||||
import ghidra.graph.viewer.layout.Column;
|
||||
import ghidra.graph.viewer.layout.GridLocationMap;
|
||||
import ghidra.graph.viewer.layout.LayoutPositions;
|
||||
import ghidra.graph.viewer.layout.Row;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class GraphCutLayout extends AbstractVisualGraphLayout<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
protected GraphCutLayout(GraphCutGraph graph, String name){
|
||||
super(graph, name);
|
||||
}
|
||||
|
||||
public AbstractVisualGraphLayout<GraphCutVertex, GraphCutEdge> createClonedLayout(VisualGraph<GraphCutVertex, GraphCutEdge> newGraph){
|
||||
if (!(newGraph instanceof GraphCutGraph)) {
|
||||
throw new IllegalArgumentException("Must pass a GraphCut Graph to clone");
|
||||
}
|
||||
|
||||
GraphCutLayout newLayout = new GraphCutLayout((GraphCutGraph) newGraph, getLayoutName());
|
||||
return newLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point2D getVertexLocation(GraphCutVertex v, Column col, Row<GraphCutVertex> row, Rectangle bounds) {
|
||||
return getCenteredVertexLocation(v, col, row, bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCondensedLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph getVisualGraph() {
|
||||
return (GraphCutGraph) getGraph();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GridLocationMap<GraphCutVertex, GraphCutEdge> performInitialGridLayout(VisualGraph<GraphCutVertex,GraphCutEdge> g) throws CancelledException {
|
||||
if (!(g instanceof GraphCutGraph)) {
|
||||
throw new IllegalArgumentException("This layout can only be used with the GraphCutGraph");
|
||||
}
|
||||
|
||||
return layoutGraphCutGraph((GraphCutGraph)g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutPositions<GraphCutVertex, GraphCutEdge> calculateLocations(VisualGraph<GraphCutVertex, GraphCutEdge> g, TaskMonitor taskMonitor){
|
||||
LayoutPositions<GraphCutVertex, GraphCutEdge> locs = super.calculateLocations(g, taskMonitor);
|
||||
return locs;
|
||||
}
|
||||
|
||||
private GridLocationMap<GraphCutVertex, GraphCutEdge> layoutGraphCutGraph(GraphCutGraph g){
|
||||
GridLocationMap<GraphCutVertex, GraphCutEdge> grid = new GridLocationMap<>();
|
||||
|
||||
GraphCutVertex source = Objects.requireNonNull(g.getSource());
|
||||
// Incoming nodes on top
|
||||
// Sorted by id
|
||||
|
||||
List<GraphCutEdge> inEdges = new ArrayList<>(g.getInEdges(source));
|
||||
List<GraphCutVertex> inVertices = inEdges.stream().map(e -> e.getStart()).collect(Collectors.toList());
|
||||
inVertices.sort((v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0);
|
||||
|
||||
//first row -> incoming nodes
|
||||
int row = 0;
|
||||
for(int col = 0; col < inVertices.size(); col++) {
|
||||
GraphCutVertex v = inVertices.get(col);
|
||||
grid.set(v, row, col);
|
||||
}
|
||||
|
||||
//middle row -> source
|
||||
row = 1;
|
||||
grid.set(source, row, 0);
|
||||
|
||||
//bottom row -> outgoing nodes
|
||||
List<GraphCutEdge> outEdges = new ArrayList<>(g.getOutEdges(source));
|
||||
List<GraphCutVertex> outVertices = outEdges.stream().map(e -> e.getEnd()).collect(Collectors.toList());
|
||||
|
||||
outVertices.removeAll(inVertices); //prevent cycles
|
||||
outVertices.sort((v1,v2) -> v1.getID() > v2.getID() ? +1 : v1.getID() < v2.getID() ? -1 : 0);
|
||||
row = 2;
|
||||
for (int col = 0; col < outVertices.size(); col++) {
|
||||
GraphCutVertex v = outVertices.get(col);
|
||||
grid.set(v, row, col);
|
||||
}
|
||||
|
||||
grid.centerRows();
|
||||
return grid;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/job/BowTieExpandVerticesJob.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||
import edu.uci.ics.jung.visualization.RenderContext;
|
||||
import ghidra.graph.job.AbstractGraphTransitionJob;
|
||||
import ghidra.graph.viewer.GraphViewer;
|
||||
import ghidra.graph.viewer.GraphViewerUtils;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
|
||||
|
||||
// bowTieExpandVerticesJob
|
||||
public class GraphCutLayoutExpandVerticesJob extends AbstractGraphTransitionJob<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
private boolean incoming;
|
||||
private GraphCutLevel expandingLevel;
|
||||
private GraphCutExpandingVertexCollection newVertexCollection;
|
||||
|
||||
public GraphCutLayoutExpandVerticesJob(GraphViewer<GraphCutVertex, GraphCutEdge> viewer,
|
||||
GraphCutExpandingVertexCollection newVertexCollection, boolean useAnimation) {
|
||||
super(viewer, useAnimation);
|
||||
|
||||
this.newVertexCollection = newVertexCollection;
|
||||
this.incoming = newVertexCollection.isIncoming();
|
||||
this.expandingLevel = newVertexCollection.getExpandingLevel();
|
||||
|
||||
if(!(graphLayout instanceof GraphCutLayout)) {
|
||||
throw new IllegalArgumentException("The current graph layout must be the GraphCut Layout to use this job");
|
||||
}
|
||||
|
||||
Msg.trace(this, "\n Layout Expand Job - new vertices: " + newVertexCollection.getNewVertices());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTooBigToAnimate() {
|
||||
return graph.getVertexCount() > 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateOpacity(double percentComplete) {
|
||||
double x = percentComplete;
|
||||
double x2 = x*x;
|
||||
double remaining = 1-percentComplete;
|
||||
double y = x2 - remaining;
|
||||
|
||||
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
|
||||
|
||||
double vertexAlpha = x;
|
||||
double edgeAlpha = Math.max(y, 0);
|
||||
for(GraphCutVertex v : newVertices) {
|
||||
v.setAlpha(vertexAlpha);
|
||||
}
|
||||
|
||||
Iterable<GraphCutEdge> newEdges = newVertexCollection.getNewEdges();
|
||||
for(GraphCutEdge e : newEdges) {
|
||||
e.setAlpha(edgeAlpha);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canShortcut() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shortcut() {
|
||||
isShortcut = true;
|
||||
|
||||
if(vertexLocations.isEmpty()) {
|
||||
initializeVertexLocations();
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeVertexLocations() {
|
||||
Map<GraphCutVertex, TransitionPoints> destinationLocations = createDestinationLocation();
|
||||
vertexLocations.putAll(destinationLocations);
|
||||
}
|
||||
|
||||
private Map<GraphCutVertex, TransitionPoints> createDestinationLocation(){
|
||||
|
||||
Map<GraphCutVertex, Point2D> finalDestinations = arrangeNewVertices();
|
||||
|
||||
Map<GraphCutVertex, TransitionPoints> transitions = new HashMap<>();
|
||||
GraphCutLevel parentLevel = expandingLevel.parent();
|
||||
Iterable<GraphCutEdge> newEdges = newVertexCollection.getNewEdges();
|
||||
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
|
||||
for(GraphCutEdge e : newEdges) {
|
||||
GraphCutVertex newVertex = incoming ? e.getStart() : e.getEnd();
|
||||
if(!finalDestinations.containsKey(newVertex)) {
|
||||
continue;
|
||||
}
|
||||
if(!newVertices.contains(newVertex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GraphCutVertex existingVertex = incoming ? e.getEnd() : e.getStart();
|
||||
GraphCutLevel existingLevel = existingVertex.getLevel();
|
||||
if (!existingLevel.equals(parentLevel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Point2D start = (Point2D) toLocation(existingVertex).clone();
|
||||
Point2D end = finalDestinations.get(newVertex);
|
||||
|
||||
TransitionPoints trans = new TransitionPoints(start, end);
|
||||
transitions.put(newVertex, trans);
|
||||
}
|
||||
return transitions;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Map<GraphCutVertex, Point2D> arrangeNewVertices(){
|
||||
|
||||
GraphCutLayout bowTie = (GraphCutLayout) graphLayout;
|
||||
boolean isCondensed = bowTie.isCondensedLayout();
|
||||
int widthPadding = isCondensed ? GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING_CONDENSED :
|
||||
GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING;
|
||||
|
||||
widthPadding *= expandingLevel.getDistance();
|
||||
int heightPadding = calculateHeightPadding(isCondensed);
|
||||
|
||||
GraphCutLevel parentLevel = expandingLevel.parent();
|
||||
List<GraphCutVertex> parentLevelVertices = newVertexCollection.getVerticesByLevel(parentLevel);
|
||||
if(parentLevelVertices.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Rectangle existingRowBounds = getBounds(parentLevelVertices);
|
||||
Msg.trace(this, "existing row bounds " + existingRowBounds);
|
||||
double existingY = existingRowBounds.y;
|
||||
double existingCenterX = existingRowBounds.x + (existingRowBounds.width/2);
|
||||
|
||||
List<GraphCutVertex> allLevelVertices = newVertexCollection.getAllVerticesAtNewLevel();
|
||||
double newRowWidth = getWidth(allLevelVertices, widthPadding);
|
||||
double newRowHeight = getHeight(allLevelVertices);
|
||||
double newRowX = existingCenterX - (newRowWidth/2);
|
||||
|
||||
double newRowY = 0;
|
||||
if(newVertexCollection.isIncoming()) {
|
||||
newRowY = existingY - newRowHeight - heightPadding;
|
||||
}
|
||||
else {
|
||||
newRowY = existingY +existingRowBounds.height + heightPadding;
|
||||
}
|
||||
|
||||
Msg.trace(this, "new row bounds " + new Rectangle2D.Double(newRowX, newRowY, newRowWidth, newRowHeight));
|
||||
|
||||
Map<GraphCutVertex, Point2D> locations = getExistingLocations(allLevelVertices);
|
||||
if(!locations.isEmpty()) {
|
||||
return locations;
|
||||
}
|
||||
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
double x = newRowX;
|
||||
double y = newRowY;
|
||||
|
||||
int n = allLevelVertices.size();
|
||||
|
||||
//Dynamic Layout
|
||||
Set<GraphCutVertex> placed = new HashSet<>();
|
||||
Set<GraphCutVertex> newVertices = newVertexCollection.getNewVertices();
|
||||
//Make shallow copy
|
||||
List<GraphCutVertex> allLevelVerticesOrig = new ArrayList<>();
|
||||
for(GraphCutVertex v : allLevelVertices) {
|
||||
allLevelVerticesOrig.add(v);
|
||||
}
|
||||
// 1. Place visible vertices
|
||||
for(GraphCutVertex v: allLevelVerticesOrig) {
|
||||
if(v.visible) {
|
||||
GraphCutVertex tmpVertex = allLevelVertices.get(v.layoutIndex);
|
||||
int tmpIndex = allLevelVertices.indexOf(v);
|
||||
allLevelVertices.set(v.layoutIndex, v);
|
||||
allLevelVertices.set(tmpIndex, tmpVertex);
|
||||
placed.add(v);
|
||||
}
|
||||
}
|
||||
// 2. Place newVertices
|
||||
for(GraphCutVertex v: newVertices) {
|
||||
if(placed.contains(v)) {
|
||||
continue;
|
||||
}
|
||||
placed.add(v);
|
||||
int index = findEmptyLayoutIndex(allLevelVertices);
|
||||
v.layoutIndex = index;
|
||||
v.visible = true;
|
||||
GraphCutVertex tmpVertex = allLevelVertices.get(index);
|
||||
int tmpIndex = allLevelVertices.indexOf(v);
|
||||
allLevelVertices.set(tmpIndex, tmpVertex);
|
||||
allLevelVertices.set(v.layoutIndex, v);
|
||||
|
||||
}
|
||||
|
||||
// 3. Place all invisible vertices randomly
|
||||
int curr = 0;
|
||||
for(GraphCutVertex v: allLevelVerticesOrig) {
|
||||
if(placed.contains(v)) {
|
||||
continue;
|
||||
}
|
||||
//find empty spot
|
||||
while(allLevelVertices.get(curr).visible) {
|
||||
curr++;
|
||||
}
|
||||
allLevelVertices.set(curr, v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < n; i++) {
|
||||
GraphCutVertex v = allLevelVertices.get(i);
|
||||
Rectangle myBounds = shaper.apply(v).getBounds();
|
||||
double myHalf = myBounds.width / 2;
|
||||
|
||||
double nextHalf = 0;
|
||||
boolean isLast = i == n-1;
|
||||
if(!isLast) {
|
||||
GraphCutVertex nextV = allLevelVertices.get(i+1);
|
||||
Rectangle nextBounds = shaper.apply(nextV).getBounds();
|
||||
nextHalf = nextBounds.width/2;
|
||||
}
|
||||
|
||||
Point2D p = new Point2D.Double(x,y);
|
||||
locations.put(v, p);
|
||||
|
||||
double vWidth = myHalf + widthPadding + nextHalf;
|
||||
Msg.trace(this, v + " at x,width: "+x+","+vWidth);
|
||||
x+=vWidth;
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
private int findEmptyLayoutIndex(List<GraphCutVertex> vertices) {
|
||||
//Check middle
|
||||
int mid = vertices.size()/2;
|
||||
if(!vertices.get(mid).visible) {
|
||||
return mid;
|
||||
}
|
||||
|
||||
// start checking both sides
|
||||
int left = mid-1;
|
||||
int right = mid+1;
|
||||
while(left >= 0 || right <=vertices.size()-1) {
|
||||
if(left>=0 && !vertices.get(left).visible) {
|
||||
return left;
|
||||
}
|
||||
left--;
|
||||
if(right <= vertices.size()-1 && !vertices.get(right).visible) {
|
||||
return right;
|
||||
}
|
||||
right++;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private int calculateHeightPadding(boolean isCondensed) {
|
||||
|
||||
int basePadding = isCondensed ? GraphViewerUtils.EXTRA_LAYOUT_ROW_SPACING_CONDENSED
|
||||
: GraphViewerUtils.EXTRA_LAYOUT_ROW_SPACING;
|
||||
|
||||
double separationFactor = expandingLevel.getDistance();
|
||||
|
||||
List<GraphCutVertex> allLevelVertices = newVertexCollection.getAllVerticesAtNewLevel();
|
||||
int count = allLevelVertices.size();
|
||||
|
||||
double to = 1.25;
|
||||
double power = Math.pow(separationFactor, to);
|
||||
int maxPadding = (int) (basePadding * power);
|
||||
|
||||
int delta = maxPadding - basePadding;
|
||||
double percent = Math.min(count / 20f, 1);
|
||||
int padding = basePadding + (int) (delta * percent);
|
||||
return padding;
|
||||
}
|
||||
|
||||
|
||||
private Map<GraphCutVertex, Point2D> getExistingLocations(List<GraphCutVertex> vertices){
|
||||
Map<GraphCutVertex, Point2D> locations = new HashMap<>();
|
||||
for(GraphCutVertex v: vertices) {
|
||||
Point2D p = toLocation(v);
|
||||
if (p.getX() == 0 && p.getY() == 0) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
locations.put(v, (Point2D) p.clone());
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Rectangle getBounds(List<GraphCutVertex> vertices) {
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
Layout<GraphCutVertex, GraphCutEdge> layout = viewer.getGraphLayout();
|
||||
|
||||
Rectangle area = null;
|
||||
for (GraphCutVertex v : vertices) {
|
||||
Rectangle bounds = shaper.apply(v).getBounds();
|
||||
Point2D loc = layout.apply(v);
|
||||
int x = (int) loc.getX();
|
||||
int y = (int) loc.getY();
|
||||
bounds.setLocation(x,y);
|
||||
if(area == null) {
|
||||
area = bounds;
|
||||
}
|
||||
area.add(bounds);
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
|
||||
private int getWidth(List<GraphCutVertex> vertices, int widthPadding) {
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
int width = 0;
|
||||
for (GraphCutVertex v : vertices) {
|
||||
width += shaper.apply(v).getBounds().width + widthPadding;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
private int getHeight(List<GraphCutVertex> vertices) {
|
||||
RenderContext<GraphCutVertex, GraphCutEdge> renderContext = viewer.getRenderContext();
|
||||
Function<? super GraphCutVertex, Shape> shaper = renderContext.getVertexShapeTransformer();
|
||||
|
||||
int height = 0;
|
||||
for (GraphCutVertex v: vertices) {
|
||||
height = Math.max(height, shaper.apply(v).getBounds().height);
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/layout/BowTieLayoutProvider.java
|
||||
*/
|
||||
|
||||
package graphcut;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.graph.viewer.layout.AbstractLayoutProvider;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* A layout provider for GraphCut
|
||||
*/
|
||||
public class GraphCutLayoutProvider extends AbstractLayoutProvider<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
|
||||
public static final String NAME = "GraphCut Layout";
|
||||
private static final Icon DEFAULT_ICON = new GIcon("icon.plugin.fcg.layout.bow.tie");
|
||||
|
||||
@Override
|
||||
public VisualGraphLayout<GraphCutVertex, GraphCutEdge> getLayout(GraphCutGraph graph, TaskMonitor taskMonitor) throws CancelledException{
|
||||
|
||||
GraphCutLayout layout = new GraphCutLayout(graph, NAME);
|
||||
initVertexLocations(graph, layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLayoutName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getActionIcon() {
|
||||
return DEFAULT_ICON;
|
||||
}
|
||||
}
|
||||
193
codecut-gui/src/main/java/graphcut/GraphCutLevel.java
Normal file
193
codecut-gui/src/main/java/graphcut/GraphCutLevel.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrowed from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FcgEdge.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import static functioncalls.graph.FcgDirection.*;
|
||||
|
||||
import functioncalls.graph.FcgDirection;
|
||||
|
||||
|
||||
// A container class that represents a GraphCut row.
|
||||
|
||||
public class GraphCutLevel implements Comparable<GraphCutLevel> {
|
||||
|
||||
private int row;
|
||||
private FcgDirection direction;
|
||||
|
||||
public static GraphCutLevel sourceLevel() {
|
||||
return new GraphCutLevel(0, IN_AND_OUT);
|
||||
}
|
||||
|
||||
public GraphCutLevel(int distance, FcgDirection direction) {
|
||||
this.row = toRow(distance);
|
||||
this.direction = direction;
|
||||
|
||||
if (row == 0) {
|
||||
throw new IllegalArgumentException("Graph Cut uses a 1-based row system");
|
||||
}
|
||||
|
||||
if (row == 1 && direction != IN_AND_OUT) {
|
||||
throw new IllegalArgumentException("Row 1 must be FcgDirection.IN_AND_OUT");
|
||||
}
|
||||
}
|
||||
|
||||
private int toRow(int distance) {
|
||||
int oneBased = distance + 1;
|
||||
return (direction == OUT) ? -oneBased : oneBased;
|
||||
}
|
||||
|
||||
public int getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public int getDistance() {
|
||||
return Math.abs(row) - 1;
|
||||
}
|
||||
|
||||
public FcgDirection getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this level is level 1
|
||||
* @return true if this level represents the source level
|
||||
*/
|
||||
public boolean isSource() {
|
||||
return direction.isSource();
|
||||
}
|
||||
|
||||
public GraphCutLevel parent() {
|
||||
if (direction == IN_AND_OUT) {
|
||||
// undefined--we are the parent of all
|
||||
throw new IllegalArgumentException(
|
||||
"To get the parent of the source level you must use the constructor directly");
|
||||
}
|
||||
|
||||
int newDistance = getDistance() - 1;
|
||||
FcgDirection newDirection = direction;
|
||||
if (newDistance == 0) {
|
||||
newDirection = IN_AND_OUT;
|
||||
}
|
||||
return new GraphCutLevel(newDistance, newDirection);
|
||||
}
|
||||
|
||||
public GraphCutLevel child() {
|
||||
if (direction == IN_AND_OUT) {
|
||||
// undefined--this node goes in both directions
|
||||
throw new IllegalArgumentException(
|
||||
"To get the child of the source level you " + "must use the constructor directly");
|
||||
}
|
||||
|
||||
return child(direction);
|
||||
}
|
||||
|
||||
public boolean isParentOf(GraphCutLevel other) {
|
||||
if (isSource()) {
|
||||
return other.getDistance() == 1;
|
||||
}
|
||||
|
||||
if (direction != other.direction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// e.g., row 2 - row 1 = 1
|
||||
return other.getDistance() - getDistance() == 1;
|
||||
}
|
||||
|
||||
public boolean isChildOf(GraphCutLevel other) {
|
||||
return other.isParentOf(this);
|
||||
}
|
||||
|
||||
public GraphCutLevel child(FcgDirection newDirection) {
|
||||
if (newDirection == IN_AND_OUT) {
|
||||
// undefined--IN_AND_OUT goes in both directions
|
||||
throw new IllegalArgumentException("Direction cannot be IN_AND_OUT");
|
||||
}
|
||||
|
||||
int newDistance = getDistance() + 1;
|
||||
return new GraphCutLevel(newDistance, newDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return direction + " - row " + Integer.toString(getRelativeRow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((direction == null) ? 0 : direction.hashCode());
|
||||
result = prime * result + row;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GraphCutLevel other = (GraphCutLevel) obj;
|
||||
if (direction != other.direction) {
|
||||
return false;
|
||||
}
|
||||
if (row != other.row) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getRelativeRow() {
|
||||
return direction == OUT ? -row : row;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(GraphCutLevel l2) {
|
||||
|
||||
int result = getDirection().compareTo(l2.getDirection());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return -(getRelativeRow() - l2.getRelativeRow());
|
||||
}
|
||||
}
|
||||
1286
codecut-gui/src/main/java/graphcut/GraphCutProvider.java
Normal file
1286
codecut-gui/src/main/java/graphcut/GraphCutProvider.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgTooltipProvider.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.*;
|
||||
|
||||
import ghidra.graph.viewer.event.mouse.VertexTooltipProvider;
|
||||
|
||||
public class GraphCutTooltipProvider implements VertexTooltipProvider<GraphCutVertex, GraphCutEdge> {
|
||||
|
||||
@Override
|
||||
public JComponent getTooltip(GraphCutVertex v) {
|
||||
JToolTip tip = new JToolTip();
|
||||
tip.setTipText(v.getName());
|
||||
return tip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getTooltip(GraphCutVertex v, GraphCutEdge e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltipText(GraphCutVertex v, MouseEvent e) {
|
||||
Component child = e.getComponent();
|
||||
if(child instanceof JButton) {
|
||||
return ((JButton) child).getToolTipText();
|
||||
}
|
||||
return v.getName();
|
||||
}
|
||||
|
||||
}
|
||||
664
codecut-gui/src/main/java/graphcut/GraphCutVertex.java
Normal file
664
codecut-gui/src/main/java/graphcut/GraphCutVertex.java
Normal file
@@ -0,0 +1,664 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrowed from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/FcgVertex.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Ellipse2D.Double;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.LineBorder;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
import docking.widgets.EmptyBorderButton;
|
||||
import docking.widgets.label.GDLabel;
|
||||
import functioncalls.graph.FcgDirection;
|
||||
import functioncalls.graph.FcgVertex;
|
||||
import generic.theme.GColor;
|
||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import generic.theme.Gui;
|
||||
import ghidra.graph.viewer.vertex.AbstractVisualVertex;
|
||||
import ghidra.graph.viewer.vertex.VertexShapeProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.util.StringUtilities;
|
||||
import resources.Icons;
|
||||
import resources.ResourceManager;
|
||||
|
||||
// A GraphCutVertex
|
||||
|
||||
public class GraphCutVertex extends AbstractVisualVertex implements VertexShapeProvider {
|
||||
|
||||
public static final Color DEFAULT_VERTEX_SHAPE_COLOR = new GColor("color.bg.plugin.fcg.vertex.default");
|
||||
private static final Color TOO_BIG_VERTEX_SHAPE_COLOR = new GColor("color.bg.plugin.fcg.vertex.toobig");
|
||||
|
||||
//@formatter:on
|
||||
|
||||
public static final Icon NOT_ALLOWED_ICON = Icons.ERROR_ICON;
|
||||
private static final Icon EXPAND_ICON =
|
||||
ResourceManager.getScaledIcon(Icons.EXPAND_ALL_ICON, 10, 10);
|
||||
private static final Icon COLLAPSE_ICON =
|
||||
ResourceManager.getScaledIcon(Icons.COLLAPSE_ALL_ICON, 10, 10);
|
||||
|
||||
// higher numbered layers go on top
|
||||
private static final Integer VERTEX_SHAPE_LAYER = 100;
|
||||
private static final Integer TOGGLE_BUTTON_LAYER = 200;
|
||||
private static final Integer LABEL_LAYER = 300;
|
||||
|
||||
private static final int GAP = 2;
|
||||
private static final int VERTEX_SHAPE_SIZE = 50;
|
||||
|
||||
private static final int MAX_NAME_LENGTH = 30;
|
||||
|
||||
private Namespace namespace;
|
||||
|
||||
private JLayeredPane layeredPane;
|
||||
private JButton toggleInsButton = new EmptyBorderButton(EXPAND_ICON);
|
||||
private JButton toggleOutsButton = new EmptyBorderButton(EXPAND_ICON);
|
||||
private JLabel nameLabel = new GDLabel();
|
||||
private JLabel vertexImageLabel = new GDLabel();
|
||||
|
||||
private Double vertexShape;
|
||||
private Double compactShape;
|
||||
private Shape fullShape;
|
||||
|
||||
// these values are set after construction from external sources
|
||||
private boolean hasIncomingReferences;
|
||||
private boolean hasOutgoingReferences;
|
||||
private boolean tooManyIncomingReferences;
|
||||
private boolean tooManyOutgoingReferences;
|
||||
private boolean incomingExpanded;
|
||||
private boolean outgoingExpanded;
|
||||
|
||||
// set this to true to see borders around the components of this vertex
|
||||
private boolean useDebugBorders = false;
|
||||
|
||||
private Paint inPaint;
|
||||
private Paint outPaint;
|
||||
|
||||
private GraphCutLevel level;
|
||||
|
||||
// Dynamic Layout Variables
|
||||
public int layoutIndex;
|
||||
public boolean visible;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param namespace Namespace represented by this vertex
|
||||
* @param level The level of this vertex
|
||||
* @param expansionListener listener for expanding connections to this vertex
|
||||
*/
|
||||
public GraphCutVertex(Namespace namespace, GraphCutLevel level, GraphCutExpansionListener expansionListener) {
|
||||
this.namespace = namespace;
|
||||
this.level = level;
|
||||
Objects.requireNonNull(expansionListener);
|
||||
|
||||
toggleInsButton.addActionListener(e -> {
|
||||
if (tooManyIncomingReferences) {
|
||||
return;
|
||||
}
|
||||
expansionListener.toggleIncomingVertices(GraphCutVertex.this);
|
||||
});
|
||||
|
||||
toggleOutsButton.addActionListener(e -> {
|
||||
if (tooManyOutgoingReferences) {
|
||||
return;
|
||||
}
|
||||
expansionListener.toggleOutgoingVertices(GraphCutVertex.this);
|
||||
});
|
||||
|
||||
buildUi();
|
||||
|
||||
setTogglesVisible(false);
|
||||
}
|
||||
|
||||
private void createPaints() {
|
||||
|
||||
Color vertexShapeColor = getVertexShapeColor();
|
||||
|
||||
Color lightColor = vertexShapeColor;
|
||||
Color darkColor = Gui.darker(vertexShapeColor);
|
||||
Color darkestColor = Gui.darker(darkColor);
|
||||
|
||||
int offset = 5 * level.getDistance();
|
||||
int half = VERTEX_SHAPE_SIZE / 2;
|
||||
int start = 0;
|
||||
int end = half + offset;
|
||||
|
||||
// paint top-down: dark to light for incoming; light to dark for outgoing
|
||||
inPaint = new LinearGradientPaint(new Point(0, start), new Point(0, end),
|
||||
new float[] { .0f, .2f, 1f }, new Color[] { darkestColor, darkColor, lightColor });
|
||||
|
||||
start = half - offset; // (offset + 10);
|
||||
end = VERTEX_SHAPE_SIZE;
|
||||
outPaint = new LinearGradientPaint(new Point(0, start), new Point(0, end),
|
||||
new float[] { .0f, .8f, 1f }, new Color[] { lightColor, darkColor, darkestColor });
|
||||
|
||||
}
|
||||
|
||||
private void buildUi() {
|
||||
|
||||
createPaints();
|
||||
|
||||
String truncated = StringUtilities.trimMiddle(getName(), MAX_NAME_LENGTH);
|
||||
nameLabel.setText(truncated);
|
||||
buildVertexShape();
|
||||
|
||||
// calculate the needed size
|
||||
layeredPane = new JLayeredPane();
|
||||
Border border = createDebugBorder(new LineBorder(Palette.GOLD, 1));
|
||||
layeredPane.setBorder(border);
|
||||
|
||||
updateLayeredPaneSize();
|
||||
|
||||
// layout the components
|
||||
addVertexShape();
|
||||
addToggleButtons();
|
||||
addNameLabel();
|
||||
|
||||
buildFullShape();
|
||||
}
|
||||
|
||||
private Border createDebugBorder(Border border) {
|
||||
if (useDebugBorders) {
|
||||
return border;
|
||||
}
|
||||
return BorderFactory.createEmptyBorder();
|
||||
}
|
||||
|
||||
private void buildFullShape() {
|
||||
|
||||
// Note: this method assumes all bounds have been set
|
||||
Area parent = new Area();
|
||||
|
||||
Area v = new Area(vertexShape);
|
||||
Area name = new Area(nameLabel.getBounds());
|
||||
parent.add(v);
|
||||
parent.add(name);
|
||||
|
||||
// for now, the buttons only appear on hover, but if we want to avoid clipping when
|
||||
// painting, we need to account for them in the shape's overall bounds
|
||||
Area in = new Area(toggleInsButton.getBounds());
|
||||
Area out = new Area(toggleOutsButton.getBounds());
|
||||
parent.add(in);
|
||||
parent.add(out);
|
||||
|
||||
fullShape = parent;
|
||||
}
|
||||
|
||||
private void updateLayeredPaneSize() {
|
||||
|
||||
//
|
||||
// The overall component size is the total width and height of all components, with any
|
||||
// spacing between them.
|
||||
//
|
||||
|
||||
Dimension shapeSize = vertexImageLabel.getPreferredSize();
|
||||
Dimension nameLabelSize = nameLabel.getPreferredSize();
|
||||
int height = shapeSize.height + GAP + nameLabelSize.height;
|
||||
|
||||
Dimension insSize = toggleInsButton.getPreferredSize();
|
||||
Dimension outsSize = toggleOutsButton.getPreferredSize();
|
||||
int buttonWidth = Math.max(insSize.width, outsSize.width);
|
||||
int offset = buttonWidth / 3; // overlap the vertex shape
|
||||
|
||||
int width = offset + shapeSize.width;
|
||||
width = Math.max(width, nameLabelSize.width);
|
||||
|
||||
layeredPane.setPreferredSize(new Dimension(width, height));
|
||||
}
|
||||
|
||||
private void buildVertexShape() {
|
||||
int w = VERTEX_SHAPE_SIZE;
|
||||
int h = VERTEX_SHAPE_SIZE;
|
||||
Double circle = new Ellipse2D.Double(0, 0, w, h);
|
||||
|
||||
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2 = (Graphics2D) image.getGraphics();
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
FcgDirection direction = level.getDirection();
|
||||
if (direction.isSource()) {
|
||||
g2.setColor(getVertexShapeColor());
|
||||
}
|
||||
else if (direction.isIn()) {
|
||||
g2.setPaint(inPaint);
|
||||
}
|
||||
else {
|
||||
g2.setPaint(outPaint);
|
||||
}
|
||||
|
||||
g2.fill(circle);
|
||||
|
||||
g2.dispose();
|
||||
|
||||
vertexShape = circle;
|
||||
compactShape = (Double) vertexShape.clone();
|
||||
vertexImageLabel.setIcon(new ImageIcon(image));
|
||||
|
||||
Border border = createDebugBorder(new LineBorder(Palette.PINK, 1));
|
||||
vertexImageLabel.setBorder(border);
|
||||
}
|
||||
|
||||
private Color getVertexShapeColor() {
|
||||
|
||||
if (isInDirection() && tooManyIncomingReferences) {
|
||||
return TOO_BIG_VERTEX_SHAPE_COLOR;
|
||||
}
|
||||
|
||||
if (isOutDirection() && tooManyOutgoingReferences) {
|
||||
return TOO_BIG_VERTEX_SHAPE_COLOR;
|
||||
}
|
||||
|
||||
return DEFAULT_VERTEX_SHAPE_COLOR;
|
||||
}
|
||||
|
||||
private boolean isInDirection() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
boolean isIn = direction.isIn() || direction.isSource();
|
||||
return isIn;
|
||||
}
|
||||
|
||||
private boolean isOutDirection() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
boolean isOut = direction.isOut() || direction.isSource();
|
||||
return isOut;
|
||||
}
|
||||
|
||||
private void addVertexShape() {
|
||||
|
||||
Dimension parentSize = layeredPane.getPreferredSize();
|
||||
Dimension size = vertexImageLabel.getPreferredSize();
|
||||
|
||||
// centered
|
||||
int x = (parentSize.width / 2) - (size.width / 2);
|
||||
int y = 0;
|
||||
|
||||
vertexImageLabel.setBounds(x, y, size.width, size.height);
|
||||
Dimension shapeSize = vertexShape.getBounds().getSize();
|
||||
|
||||
// setFrame() will make sure the shape's x,y values are where they need to be
|
||||
// for the later 'full shape' creation
|
||||
vertexShape.setFrame(x, y, shapeSize.width, shapeSize.height);
|
||||
layeredPane.add(vertexImageLabel, VERTEX_SHAPE_LAYER);
|
||||
}
|
||||
|
||||
private void addNameLabel() {
|
||||
Border border = createDebugBorder(new LineBorder(Palette.GREEN, 1));
|
||||
nameLabel.setBorder(border);
|
||||
|
||||
Rectangle parentBounds = vertexImageLabel.getBounds();
|
||||
Dimension size = nameLabel.getPreferredSize();
|
||||
|
||||
int x = (parentBounds.x + (parentBounds.width / 2)) - (size.width / 2);
|
||||
int y = parentBounds.y + parentBounds.height + GAP;
|
||||
nameLabel.setBounds(x, y, size.width, size.height);
|
||||
layeredPane.add(nameLabel, LABEL_LAYER);
|
||||
|
||||
}
|
||||
|
||||
private void addToggleButtons() {
|
||||
|
||||
// hide the button background
|
||||
toggleInsButton.setBackground(Palette.NO_COLOR);
|
||||
toggleOutsButton.setBackground(Palette.NO_COLOR);
|
||||
|
||||
// This is needed for Flat Dark theme to work correctly, due to the fact that it wants to
|
||||
// paint its parent background when the button is opaque. The parent background will get
|
||||
// painted over any items that lie between the button and the parent.
|
||||
toggleInsButton.setOpaque(false);
|
||||
toggleOutsButton.setOpaque(false);
|
||||
|
||||
Rectangle parentBounds = vertexImageLabel.getBounds();
|
||||
Dimension size = toggleInsButton.getPreferredSize();
|
||||
|
||||
// upper toggle; upper-left
|
||||
int x = parentBounds.x - (size.width / 3);
|
||||
int y = 0;
|
||||
toggleInsButton.setBounds(x, y, size.width, size.height);
|
||||
layeredPane.add(toggleInsButton, TOGGLE_BUTTON_LAYER);
|
||||
|
||||
// lower toggle; lower-left, lined-up with the vertex shape
|
||||
size = toggleOutsButton.getPreferredSize();
|
||||
Dimension vertexSize = parentBounds.getSize();
|
||||
y = vertexSize.height - size.height;
|
||||
toggleOutsButton.setBounds(x, y, size.width, size.height);
|
||||
layeredPane.add(toggleOutsButton, TOGGLE_BUTTON_LAYER);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return namespace.getName();
|
||||
}
|
||||
|
||||
public Namespace getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public GraphCutLevel getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public int getDegree() {
|
||||
return level.getRow();
|
||||
}
|
||||
|
||||
public FcgDirection getDirection() {
|
||||
return level.getDirection();
|
||||
}
|
||||
|
||||
public JButton getIncomingToggleButton() {
|
||||
return toggleInsButton;
|
||||
}
|
||||
|
||||
public JButton getOutgoingToggleButton() {
|
||||
return toggleOutsButton;
|
||||
}
|
||||
|
||||
public void setIncomingExpanded(boolean setExpanded) {
|
||||
validateIncomingExpandedState(setExpanded);
|
||||
|
||||
this.incomingExpanded = setExpanded;
|
||||
toggleInsButton.setIcon(setExpanded ? COLLAPSE_ICON : EXPAND_ICON);
|
||||
String hideShow = setExpanded ? "hide" : "show";
|
||||
toggleInsButton.setToolTipText("Click to " + hideShow + " incoming edges");
|
||||
}
|
||||
|
||||
private void validateOutgoingExpandedState(boolean isExpanding) {
|
||||
if (isExpanding) {
|
||||
if (!canExpandOutgoingReferences()) {
|
||||
throw new IllegalStateException("Vertex cannot be expanded: " + this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// collapsing
|
||||
if (!isOutgoingExpanded()) {
|
||||
throw new IllegalStateException("Vertex cannot be collapsed: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateIncomingExpandedState(boolean expanding) {
|
||||
|
||||
if (expanding) {
|
||||
if (!canExpandIncomingReferences()) {
|
||||
throw new IllegalStateException("Vertex cannot be expanded: " + this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// collapsing
|
||||
if (!isIncomingExpanded()) {
|
||||
throw new IllegalStateException("Vertex cannot be collapsed: " + this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vertex is showing all edges in the incoming direction
|
||||
*
|
||||
* @return true if this vertex is showing all edges in the incoming direction
|
||||
*/
|
||||
public boolean isIncomingExpanded() {
|
||||
return incomingExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to true if this vertex is showing all edges in the outgoing direction
|
||||
*
|
||||
* @param setExpanded true if this vertex is showing all edges in the outgoing direction
|
||||
*/
|
||||
public void setOutgoingExpanded(boolean setExpanded) {
|
||||
|
||||
validateOutgoingExpandedState(setExpanded);
|
||||
|
||||
this.outgoingExpanded = setExpanded;
|
||||
toggleOutsButton.setIcon(setExpanded ? COLLAPSE_ICON : EXPAND_ICON);
|
||||
String hideShow = setExpanded ? "hide" : "show";
|
||||
toggleInsButton.setToolTipText("Click to " + hideShow + " outgoing edges");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if this vertex is showing all edges in the outgoing direction
|
||||
*
|
||||
* @return true if this vertex is showing all edges in the outgoing direction
|
||||
*/
|
||||
public boolean isOutgoingExpanded() {
|
||||
return outgoingExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vertex is fully expanded in its current direction
|
||||
*
|
||||
* @return whether this vertex is fully expanded in its current direction
|
||||
*/
|
||||
public boolean isExpanded() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
if (direction.isSource()) {
|
||||
return isIncomingExpanded() && isOutgoingExpanded();
|
||||
}
|
||||
if (direction.isIn()) {
|
||||
return isIncomingExpanded();
|
||||
}
|
||||
return isOutgoingExpanded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has too many incoming references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @param tooMany if there are too many references
|
||||
*/
|
||||
public void setTooManyIncomingReferences(boolean tooMany) {
|
||||
this.tooManyIncomingReferences = tooMany;
|
||||
toggleInsButton.setIcon(NOT_ALLOWED_ICON);
|
||||
toggleInsButton.setToolTipText("Too many incoming references to show");
|
||||
buildUi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has too many outgoing references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @param tooMany if there are too many references
|
||||
*/
|
||||
public void setTooManyOutgoingReferences(boolean tooMany) {
|
||||
this.tooManyOutgoingReferences = tooMany;
|
||||
toggleOutsButton.setIcon(NOT_ALLOWED_ICON);
|
||||
toggleOutsButton.setToolTipText("Too many outgoing references to show");
|
||||
buildUi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vertex has too many incoming references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @return true if there are too many references
|
||||
*/
|
||||
public boolean hasTooManyIncomingReferences() {
|
||||
return tooManyIncomingReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this vertex has too many outgoing references, where too many is subjectively
|
||||
* defined by this class. Too many nodes in the display would ruin rendering and general
|
||||
* usability.
|
||||
*
|
||||
* @return true if there are too many references
|
||||
*/
|
||||
public boolean hasTooManyOutgoingReferences() {
|
||||
return tooManyOutgoingReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vertex can expand itself in its current direction, or in either
|
||||
* direction if this is a source vertex
|
||||
*
|
||||
* @return true if this vertex can be expanded
|
||||
*/
|
||||
public boolean canExpand() {
|
||||
FcgDirection direction = level.getDirection();
|
||||
if (direction.isSource()) {
|
||||
return canExpandIncomingReferences() || canExpandOutgoingReferences();
|
||||
}
|
||||
|
||||
if (direction.isIn()) {
|
||||
return canExpandIncomingReferences();
|
||||
}
|
||||
|
||||
return canExpandOutgoingReferences();
|
||||
}
|
||||
|
||||
|
||||
public boolean canExpandIncomingReferences() {
|
||||
return hasIncomingReferences && !tooManyIncomingReferences && !incomingExpanded;
|
||||
}
|
||||
|
||||
public boolean canExpandOutgoingReferences() {
|
||||
return hasOutgoingReferences && !tooManyOutgoingReferences && !outgoingExpanded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has any incoming references
|
||||
*
|
||||
* @param hasIncoming true if this vertex has any incoming references
|
||||
*/
|
||||
public void setHasIncomingReferences(boolean hasIncoming) {
|
||||
this.hasIncomingReferences = hasIncoming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this vertex has any outgoing references
|
||||
*
|
||||
* @param hasOutgoing true if this vertex has any outgoing references
|
||||
*/
|
||||
|
||||
public void setHasOutgoingReferences(boolean hasOutgoing) {
|
||||
this.hasOutgoingReferences = hasOutgoing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHovered(boolean hovered) {
|
||||
super.setHovered(hovered);
|
||||
|
||||
setTogglesVisible(hovered);
|
||||
}
|
||||
|
||||
private void setTogglesVisible(boolean visible) {
|
||||
|
||||
boolean isIn = isInDirection();
|
||||
boolean turnOn = isIn && hasIncomingReferences && visible;
|
||||
toggleInsButton.setVisible(turnOn);
|
||||
|
||||
boolean isOut = isOutDirection();
|
||||
turnOn = isOut && hasOutgoingReferences && visible;
|
||||
toggleOutsButton.setVisible(turnOn);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return layeredPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getCompactShape() {
|
||||
return compactShape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getFullShape() {
|
||||
return fullShape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();// + " @ " + level; // + " (" + System.identityHashCode(this) + ')';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GraphCutVertex other = (GraphCutVertex) obj;
|
||||
return Objects.equals(namespace, other.namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public long getID() {
|
||||
return getNamespace().getID();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/renderer/FcgVertexPaintTransformer.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
|
||||
import ghidra.util.ColorUtils;
|
||||
/**
|
||||
* A class that takes a GraphCutVertex and determines which color to paint it with
|
||||
*/
|
||||
public class GraphCutVertexPaintTransformer implements Function<GraphCutVertex, Paint> {
|
||||
private Color color;
|
||||
|
||||
public GraphCutVertexPaintTransformer(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Paint apply(GraphCutVertex v) {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
63
codecut-gui/src/main/java/graphcut/GraphCutView.java
Normal file
63
codecut-gui/src/main/java/graphcut/GraphCutView.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Heavily Borrows from Ghidra file /Features Graph FunctionCalls/src/main/java/functioncalls/graph/view/FcgView.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import ghidra.graph.viewer.VisualGraphView;
|
||||
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||
|
||||
public class GraphCutView extends VisualGraphView<GraphCutVertex, GraphCutEdge, GraphCutGraph> {
|
||||
private VisualGraphOptions options;
|
||||
public GraphCutView(VisualGraphOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installGraphViewer() {
|
||||
|
||||
GraphCutComponent component = createGraphComponent();
|
||||
component.setGraphOptions(options);
|
||||
setGraphComponent(component);
|
||||
}
|
||||
|
||||
private GraphCutComponent createGraphComponent() {
|
||||
GraphCutComponent component = new GraphCutComponent(getVisualGraph());
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutComponent getGraphComponent() {
|
||||
return (GraphCutComponent) super.getGraphComponent();
|
||||
}
|
||||
}
|
||||
92
codecut-gui/src/main/java/graphcut/NamespaceEdge.java
Normal file
92
codecut-gui/src/main/java/graphcut/NamespaceEdge.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.Objects;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
|
||||
public class NamespaceEdge {
|
||||
|
||||
private Namespace start;
|
||||
private Namespace end;
|
||||
|
||||
NamespaceEdge(Namespace start, Namespace end){
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
Namespace getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
Namespace getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + start + ", " + end + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime*result + ((end == null) ? 0 : end.hashCode());
|
||||
result = prime * result + ((start == null) ? 0 : start.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NamespaceEdge other = (NamespaceEdge) obj;
|
||||
if(!Objects.equals(end, other.end)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Objects.equals(start, other.start)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
65
codecut-gui/src/main/java/graphcut/NamespaceEdgeCache.java
Normal file
65
codecut-gui/src/main/java/graphcut/NamespaceEdgeCache.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections4.map.LazyMap;
|
||||
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
/**
|
||||
* A class to cache known namespace edges
|
||||
*/
|
||||
public class NamespaceEdgeCache {
|
||||
|
||||
//contains all known edges, even those not shown in the graph
|
||||
private Map<Namespace, Set<NamespaceEdge>> allEdgesByNamespace =
|
||||
LazyMap.lazyMap(new HashMap<>(), () -> new HashSet<>());
|
||||
|
||||
// track processed namespaces
|
||||
private Set<Namespace> tracked = new HashSet<>();
|
||||
|
||||
public Set<NamespaceEdge> get(Namespace ns){
|
||||
return allEdgesByNamespace.get(ns);
|
||||
}
|
||||
|
||||
public boolean isTracked(Namespace ns) {
|
||||
return tracked.contains(ns);
|
||||
}
|
||||
|
||||
public void setTracked(Namespace ns) {
|
||||
tracked.add(ns);
|
||||
}
|
||||
}
|
||||
101
codecut-gui/src/main/java/graphcut/ValidGraphCutData.java
Normal file
101
codecut-gui/src/main/java/graphcut/ValidGraphCutData.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/* ###
|
||||
* © 2021 The Johns Hopkins University Applied Physics Laboratory LLC (JHU/APL).
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* This material may be only be used, modified, or reproduced by or for the U.S.
|
||||
* Government pursuant to the license rights granted under the clauses at
|
||||
* DFARS 252.227-7013/7014 or FAR 52.227-14. For any other permission, please
|
||||
* contact the Office of Technology Transfer at JHU/APL.
|
||||
*
|
||||
* NO WARRANTY, NO LIABILITY. THIS MATERIAL IS PROVIDED “AS IS.” JHU/APL MAKES
|
||||
* NO REPRESENTATION OR WARRANTY WITH RESPECT TO THE PERFORMANCE OF THE MATERIALS,
|
||||
* INCLUDING THEIR SAFETY, EFFECTIVENESS, OR COMMERCIAL VIABILITY, AND DISCLAIMS
|
||||
* ALL WARRANTIES IN THE MATERIAL, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* (BUT NOT LIMITED TO) ANY AND ALL IMPLIED WARRANTIES OF PERFORMANCE,
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT OF
|
||||
* INTELLECTUAL PROPERTY OR OTHER THIRD PARTY RIGHTS. ANY USER OF THE MATERIAL
|
||||
* ASSUMES THE ENTIRE RISK AND LIABILITY FOR USING THE MATERIAL. IN NO EVENT SHALL
|
||||
* JHU/APL BE LIABLE TO ANY USER OF THE MATERIAL FOR ANY ACTUAL, INDIRECT,
|
||||
* CONSEQUENTIAL, SPECIAL OR OTHER DAMAGES ARISING FROM THE USE OF, OR INABILITY TO
|
||||
* USE, THE MATERIAL, INCLUDING, BUT NOT LIMITED TO, ANY DAMAGES FOR LOST PROFITS.
|
||||
*
|
||||
* HAVE A NICE DAY.
|
||||
*/
|
||||
|
||||
/* This material is based upon work supported by the Defense Advanced Research
|
||||
* Projects Agency (DARPA) and Naval Information Warfare Center Pacific (NIWC Pacific)
|
||||
* under Contract Number N66001-20-C-4024.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Borrows from /Features Graph FunctionCalls/src/main/java/functioncalls/plugin/ValidFcgData.java
|
||||
*/
|
||||
|
||||
|
||||
package graphcut;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.graph.viewer.GraphPerspectiveInfo;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
|
||||
public class ValidGraphCutData implements GraphCutData {
|
||||
|
||||
private Namespace namespace;
|
||||
private GraphCutGraph graph;
|
||||
private GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> perspectiveInfo;
|
||||
|
||||
private NamespaceEdgeCache allEdgesByNamespace = new NamespaceEdgeCache();
|
||||
|
||||
ValidGraphCutData(Namespace namespace, GraphCutGraph graph){
|
||||
this.namespace = Objects.requireNonNull(namespace);
|
||||
this.graph = Objects.requireNonNull(graph);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamespace(Namespace ns) {
|
||||
return namespace.equals(ns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphCutGraph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceEdgeCache getNamespaceEdgeCache() {
|
||||
return allEdgesByNamespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return !graph.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
graph.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> getGraphPerspective(){
|
||||
return perspectiveInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGraphPerspective( GraphPerspectiveInfo<GraphCutVertex, GraphCutEdge> info) {
|
||||
this.perspectiveInfo = info;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -54,13 +54,13 @@ class Net(torch.nn.Module):
|
||||
ReLU(),
|
||||
Linear(dim, dim), ReLU(), Linear(dim, dim))
|
||||
self.e_bn1 = torch.nn.LayerNorm(dim)
|
||||
self.gin1 = nn.GINEConv(mlp1, train_eps=True).jittable()
|
||||
self.gin1 = nn.GINEConv(mlp1, train_eps=True)
|
||||
self.bn1 = nn.PairNorm() # nn.LayerNorm(dim) #torch.nn.BatchNorm1d(dim)
|
||||
|
||||
mlp2 = Sequential(Linear(dim, dim), ReLU(), Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim))
|
||||
self.gin2 = nn.GINEConv(mlp2, train_eps=True).jittable()
|
||||
self.gin2 = nn.GINEConv(mlp2, train_eps=True)
|
||||
self.bn2 = nn.PairNorm() # nn.LayerNorm(dim) #torch.nn.BatchNorm1d(dim)
|
||||
self.e_mlp2 = Sequential(Linear(3*dim, dim),
|
||||
ReLU(),
|
||||
@@ -74,7 +74,7 @@ class Net(torch.nn.Module):
|
||||
Linear(dim, dim),
|
||||
ReLU(),
|
||||
Linear(dim, dim))
|
||||
self.gin3 = nn.GINEConv(mlp3, train_eps=True).jittable()
|
||||
self.gin3 = nn.GINEConv(mlp3, train_eps=True)
|
||||
self.bn3 = nn.PairNorm() # nn.LayerNorm(dim)
|
||||
self.e_mlp3 = Sequential(Linear(3*dim, dim),
|
||||
ReLU(),
|
||||
@@ -142,7 +142,8 @@ def load_gnn(model_file):
|
||||
)
|
||||
|
||||
loaded_weights = torch.load(model_file,
|
||||
map_location=torch.device('cpu'))
|
||||
map_location=torch.device('cpu'),
|
||||
weights_only=True)
|
||||
model.load_state_dict(loaded_weights)
|
||||
|
||||
return model
|
||||
|
||||
@@ -56,7 +56,7 @@ public class DeepCutAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
private final static String OPTION_NAME_PYTHON_EXEC = "Python Executable";
|
||||
private final static String OPTION_DESCRIPTION_PYTHON_EXEC = "";
|
||||
private final static String OPTION_DEFAULT_PYTHON_EXEC = "/projects/venv/bin/python3";
|
||||
private final static String OPTION_DEFAULT_PYTHON_EXEC = "/usr/bin/python3";
|
||||
private String pythonExec = OPTION_DEFAULT_PYTHON_EXEC;
|
||||
|
||||
public DeepCutAnalyzer() {
|
||||
|
||||
@@ -57,7 +57,7 @@ public class DeepCutPython {
|
||||
|
||||
process = runtime.exec(exec);
|
||||
|
||||
// Yes this is confusing. stdin is a Java OutputStream, stdin is an InputStream
|
||||
// Yes this is confusing. stdin is a Java OutputStream, stdout is an InputStream
|
||||
stdin = process.getOutputStream();
|
||||
stdout = process.getInputStream();
|
||||
stderr = process.getErrorStream();
|
||||
|
||||
BIN
img/graph-pic.png
Normal file
BIN
img/graph-pic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
Reference in New Issue
Block a user