mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-1014 - Function Call Graph - add option to change background color;
consolidated graph options.
This commit is contained in:
@@ -232,6 +232,15 @@
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Options"></A>Options</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The Function Call Graph options are currently a subset of the
|
||||
<A href="help/topics/FunctionGraphPlugin/Function_Graph.html#Options">
|
||||
Function Graph's Options</A>.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
@@ -240,8 +249,7 @@
|
||||
<P class="relatedtopic">Related Topics:</P>
|
||||
|
||||
<UL>
|
||||
<!-- TODO update this when we introduce the generic graphing help -->
|
||||
<LI>Graphs</LI>
|
||||
<LI><A href="help/topics/Graph/GraphIntro.html">Graphs</A></LI>
|
||||
</UL><BR>
|
||||
<BR>
|
||||
</BODY>
|
||||
|
||||
@@ -25,11 +25,17 @@ import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||
*/
|
||||
public class FcgView extends VisualGraphView<FcgVertex, FcgEdge, FunctionCallGraph> {
|
||||
|
||||
private VisualGraphOptions options;
|
||||
|
||||
public FcgView(VisualGraphOptions options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installGraphViewer() {
|
||||
|
||||
FcgComponent component = createGraphComponent();
|
||||
component.setGraphOptions(new VisualGraphOptions());
|
||||
component.setGraphOptions(options);
|
||||
setGraphComponent(component);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package functioncalls.plugin;
|
||||
|
||||
import static functioncalls.graph.FcgDirection.IN;
|
||||
import static functioncalls.graph.FcgDirection.OUT;
|
||||
import static functioncalls.graph.FcgDirection.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -60,7 +59,7 @@ import resources.Icons;
|
||||
import util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* The primary component provider for the {@link FunctionCallGraphPlugin}
|
||||
* The primary component provider for the {@link FunctionCallGraphPlugin}
|
||||
*/
|
||||
public class FcgProvider
|
||||
extends VisualGraphComponentProvider<FcgVertex, FcgEdge, FunctionCallGraph> {
|
||||
@@ -133,6 +132,10 @@ public class FcgProvider
|
||||
installGraph();
|
||||
}
|
||||
|
||||
void optionsChanged() {
|
||||
view.optionsChanged();
|
||||
}
|
||||
|
||||
void locationChanged(ProgramLocation loc) {
|
||||
if (!navigateIncomingToggleAction.isSelected()) {
|
||||
return;
|
||||
@@ -277,7 +280,7 @@ public class FcgProvider
|
||||
|
||||
private void buildComponent() {
|
||||
|
||||
view = new FcgView();
|
||||
view = new FcgView(plugin.getOptions());
|
||||
|
||||
view.setVertexClickListener((v, info) -> {
|
||||
|
||||
@@ -519,7 +522,7 @@ public class FcgProvider
|
||||
addLocalAction(resetGraphAction);
|
||||
|
||||
MultiStateDockingAction<LayoutProvider<FcgVertex, FcgEdge, FunctionCallGraph>> layoutAction =
|
||||
new MultiStateDockingAction<LayoutProvider<FcgVertex, FcgEdge, FunctionCallGraph>>(
|
||||
new MultiStateDockingAction<>(
|
||||
RELAYOUT_GRAPH_ACTION_NAME, plugin.getName()) {
|
||||
|
||||
@Override
|
||||
@@ -627,7 +630,7 @@ public class FcgProvider
|
||||
|
||||
//==================================================================================================
|
||||
// Expand/Collapse Methods
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
/*
|
||||
* Notes
|
||||
@@ -660,8 +663,8 @@ public class FcgProvider
|
||||
|
||||
Set<FcgEdge> newEdges = getModelEdges(sources, expandingLevel, edgeNotInGraphFilter);
|
||||
|
||||
// Need all vertices from the source level, as well as their edges.
|
||||
// This is used to correctly layout the vertices we are adding. This way, if we
|
||||
// Need all vertices from the source level, as well as their edges.
|
||||
// This is used to correctly layout the vertices we are adding. This way, if we
|
||||
// later add the sibling vertices, they will be in the correct spot, without clipping.
|
||||
Iterable<FcgVertex> sourceSiblings = getVerticesByLevel(sourceLevel);
|
||||
Set<FcgEdge> parentLevelEdges = getModelEdges(sourceSiblings, expandingLevel, unfiltered);
|
||||
@@ -756,7 +759,7 @@ public class FcgProvider
|
||||
FcgLevel parentLevel = parent.getLevel();
|
||||
FcgLevel otherLevel = other.getLevel();
|
||||
if (!parentLevel.isParentOf(otherLevel)) {
|
||||
// the other vertex must be in the child level to be a dependent
|
||||
// the other vertex must be in the child level to be a dependent
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -864,7 +867,7 @@ public class FcgProvider
|
||||
}
|
||||
|
||||
private Set<FcgVertex> toStartVertices(Iterable<FcgEdge> edges, Predicate<FcgVertex> filter) {
|
||||
//@formatter:off
|
||||
//@formatter:off
|
||||
return CollectionUtils
|
||||
.asStream(edges)
|
||||
.map(e -> e.getStart())
|
||||
@@ -921,7 +924,7 @@ public class FcgProvider
|
||||
currentLevel = currentLevel.child();
|
||||
}
|
||||
|
||||
// hand out from greatest to least so that we can close the extremities first
|
||||
// hand out from greatest to least so that we can close the extremities first
|
||||
Collections.reverse(result);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -931,8 +934,8 @@ public class FcgProvider
|
||||
|
||||
private void doExpand(FcgExpandingVertexCollection collection) {
|
||||
|
||||
// note: we must do this before adding edges, as that will also add vertices and
|
||||
// we will filter vertices later by those that are not already in the graph
|
||||
// note: we must do this before adding edges, as that will also add vertices and
|
||||
// we will filter vertices later by those that are not already in the graph
|
||||
|
||||
Set<FcgVertex> newVertices = collection.getNewVertices();
|
||||
FunctionCallGraph graph = graphData.getGraph();
|
||||
@@ -979,13 +982,13 @@ public class FcgProvider
|
||||
|
||||
/**
|
||||
* Called when new vertices are added to the graph to ensure that known edges between any
|
||||
* level of the graph get added as the associated vertices are added to the graph. This
|
||||
* is needed because we don't add all known edges for a single vertex when it is added, as
|
||||
* level of the graph get added as the associated vertices are added to the graph. This
|
||||
* is needed because we don't add all known edges for a single vertex when it is added, as
|
||||
* its associated vertex may not yet be in the graph. Calling this method ensures that as
|
||||
* vertices appear, the edges are added.
|
||||
*
|
||||
* @param newVertices the vertices being added to the graph
|
||||
* @param newEdges the set to which should be added any new edges being added to the graph
|
||||
* @param newEdges the set to which should be added any new edges being added to the graph
|
||||
*/
|
||||
private void addEdgesToExistingVertices(Iterable<FcgVertex> newVertices,
|
||||
Set<FcgEdge> newEdges) {
|
||||
@@ -1018,7 +1021,7 @@ public class FcgProvider
|
||||
|
||||
//
|
||||
// Unusual Code Alert
|
||||
// We wish to always use the same vertex *instance* across edges that we are
|
||||
// We wish to always use the same vertex *instance* across edges that we are
|
||||
// creating. If the vertex is already in the graph, then that will happen as we get it
|
||||
// from the graph. However, if the function does not have a vertex in the graph, then
|
||||
// it must be created. Cache the vertices we retrieve here, whether exiting or created,
|
||||
@@ -1026,7 +1029,7 @@ public class FcgProvider
|
||||
//
|
||||
|
||||
//@formatter:off
|
||||
return CollectionUtils.asStream(callees)
|
||||
return CollectionUtils.asStream(callees)
|
||||
.map(f -> {
|
||||
|
||||
if (newVertexCache.containsKey(f)) {
|
||||
|
||||
@@ -17,18 +17,21 @@ package functioncalls.plugin;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.tool.ToolConstants;
|
||||
import ghidra.app.CorePluginPackage;
|
||||
import ghidra.app.plugin.PluginCategoryNames;
|
||||
import ghidra.app.plugin.ProgramPlugin;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.options.*;
|
||||
import ghidra.framework.plugintool.PluginInfo;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.plugintool.util.PluginStatus;
|
||||
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||
import ghidra.util.task.SwingUpdateManager;
|
||||
|
||||
/**
|
||||
@@ -43,7 +46,7 @@ import ghidra.util.task.SwingUpdateManager;
|
||||
description = "Displays a graph of incoming and outgoing calls for a given function."
|
||||
)
|
||||
//@formatter:on
|
||||
public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||
public class FunctionCallGraphPlugin extends ProgramPlugin implements OptionsChangeListener {
|
||||
|
||||
/*package*/ static final String NAME = "Function Call Graph";
|
||||
/*package*/ static final String SHOW_PROVIDER_ACTION_NAME = "Display Function Call Graph";
|
||||
@@ -52,6 +55,7 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||
FunctionCallGraphPlugin.class.getSimpleName());
|
||||
|
||||
private FcgProvider provider;
|
||||
private VisualGraphOptions vgOptions = new VisualGraphOptions();
|
||||
|
||||
// enough time for users to click around without the graph starting its work
|
||||
private static final int MIN_UPDATE_DELAY = 750;
|
||||
@@ -65,8 +69,32 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
|
||||
provider = new FcgProvider(tool, this);
|
||||
createActions();
|
||||
|
||||
initializeOptions();
|
||||
}
|
||||
|
||||
private void initializeOptions() {
|
||||
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
|
||||
options.addOptionsChangeListener(this);
|
||||
|
||||
HelpLocation help = new HelpLocation(getName(), "Options");
|
||||
|
||||
Options callGraphOptions = options.getOptions(NAME);
|
||||
vgOptions.registerOptions(callGraphOptions, help);
|
||||
vgOptions.loadOptions(callGraphOptions);
|
||||
provider.optionsChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||
Object newValue) throws OptionsVetoException {
|
||||
|
||||
Options callGraphOptions = options.getOptions(NAME);
|
||||
vgOptions.loadOptions(callGraphOptions);
|
||||
provider.optionsChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,7 +146,7 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO create icon from scratch: bow-tie
|
||||
// TODO create icon from scratch: bow-tie
|
||||
// ImageIcon icon = ResourceManager.loadImage("images/applications-development.png");
|
||||
// showProviderAction.setToolBarData(new ToolBarData(icon, "View"));
|
||||
tool.addAction(showProviderAction);
|
||||
@@ -142,4 +170,8 @@ public class FunctionCallGraphPlugin extends ProgramPlugin {
|
||||
ProgramLocation getCurrentLocation() {
|
||||
return currentLocation;
|
||||
}
|
||||
|
||||
VisualGraphOptions getOptions() {
|
||||
return vgOptions;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user