Changes Program Graph actions to not graph entire program when there is no selection

This commit is contained in:
ghidravore 2020-11-03 13:43:03 -05:00
parent 5b8be18b40
commit c02ab0160c
4 changed files with 135 additions and 65 deletions

View file

@ -46,10 +46,40 @@
program.</P> program.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H2>Graph Scope</H2>
<P>When creating any of the graphs described below, the scope of the graph is determined by the
current location and selection present in the listing. </P>
<BLOCKQUOTE>
<H3>If there is a selection:</H3>
<BLOCKQUOTE><P> The graph will
include all the code that is selected and exclude all the code that is not selected.</P>
</BLOCKQUOTE>
<H3>If there is no selection:</H3>
<BLOCKQUOTE>
<P> The scope is determined by the current cursor location and the type of graph:</P>
</BLOCKQUOTE>
<BLOCKQUOTE>
<H4>Current Location is in a Function</H4>
<UL>
<LI>Block Flow Graphs: The scope is the body of the containing functions</LI>
<LI>Call Graphs: The scope is the containing function and all the functions that
either call it or it calls</LI>
</UL>
<H4>Current Location is not in a Function</H4>
<UL>
<LI>the scope will be the entire program</LI>
</UL>
</BLOCKQUOTE>
<P><IMG src="../../shared/tip.png"> To graph the entire program, press "&lt;ctrl&gt; a" to
select all before creating the graph.</P>
</BLOCKQUOTE>
<H2>Synchronization</H2>
<P>Selection and Location events are synchronized between each <P>Selection and Location events are synchronized between each
graph and the other windows in the tool. graph and the other windows in the tool.
<BLOCKQUOTE>
<H2>Selection</H2> <H3>Selection</H3>
<P>The current selection within the graph display is represented by a red box around selected <P>The current selection within the graph display is represented by a red box around selected
nodes as shown below on the node labeled "00408133". A node is selected if any addresses it represents are contained within the nodes as shown below on the node labeled "00408133". A node is selected if any addresses it represents are contained within the
@ -74,7 +104,7 @@
from the basic blocks found within the selected subroutine.</P> from the basic blocks found within the selected subroutine.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H2>Location</H2> <H3>Location</H3>
<P>The node containing the current address location is marked with a large red arrow as shown <P>The node containing the current address location is marked with a large red arrow as shown
below on the graph node labeled "00408133".</P> below on the graph node labeled "00408133".</P>
@ -94,7 +124,7 @@
<P align="left">Clicking on a node in the graph display causes the <P align="left">Clicking on a node in the graph display causes the
current address location within Ghidra to change to the minimum address represented by the current address location within Ghidra to change to the minimum address represented by the
graph node.</P> graph node.</P>
</BLOCKQUOTE>
<H2>Graph Representation</H2> <H2>Graph Representation</H2>
<P>By Default, the graphs use the following icons and colors to represent the nodes and edges.</P> <P>By Default, the graphs use the following icons and colors to represent the nodes and edges.</P>

View file

@ -21,8 +21,7 @@ import java.util.*;
import docking.widgets.EventTrigger; import docking.widgets.EventTrigger;
import ghidra.app.plugin.core.colorizer.ColorizingService; import ghidra.app.plugin.core.colorizer.ColorizingService;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.block.*; import ghidra.program.model.block.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@ -110,8 +109,9 @@ public class BlockGraphTask extends Task {
private boolean reuseGraph; private boolean reuseGraph;
private boolean appendGraph; private boolean appendGraph;
private PluginTool tool; private PluginTool tool;
private String actionName;
private Program program; private Program program;
private AddressSetView graphScope;
private String graphTitle;
public BlockGraphTask(String actionName, boolean graphEntryPointNexus, boolean showCode, public BlockGraphTask(String actionName, boolean graphEntryPointNexus, boolean showCode,
boolean reuseGraph, boolean appendGraph, PluginTool tool, ProgramSelection selection, boolean reuseGraph, boolean appendGraph, PluginTool tool, ProgramSelection selection,
@ -119,8 +119,6 @@ public class BlockGraphTask extends Task {
GraphDisplayProvider graphProvider) { GraphDisplayProvider graphProvider) {
super("Graph Program", true, false, true); super("Graph Program", true, false, true);
this.actionName = actionName;
this.graphEntryPointNexus = graphEntryPointNexus; this.graphEntryPointNexus = graphEntryPointNexus;
this.showCode = showCode; this.showCode = showCode;
this.reuseGraph = reuseGraph; this.reuseGraph = reuseGraph;
@ -132,6 +130,7 @@ public class BlockGraphTask extends Task {
this.selection = selection; this.selection = selection;
this.location = location; this.location = location;
this.program = blockModel.getProgram(); this.program = blockModel.getProgram();
this.graphTitle = actionName + ": ";
} }
/** /**
@ -139,6 +138,7 @@ public class BlockGraphTask extends Task {
*/ */
@Override @Override
public void run(TaskMonitor monitor) throws CancelledException { public void run(TaskMonitor monitor) throws CancelledException {
this.graphScope = getGraphScopeAndGenerateGraphTitle();
AttributedGraph graph = createGraph(); AttributedGraph graph = createGraph();
monitor.setMessage("Generating Graph..."); monitor.setMessage("Generating Graph...");
try { try {
@ -153,7 +153,7 @@ public class BlockGraphTask extends Task {
display.setVertexLabel(CODE_ATTRIBUTE, GraphDisplay.ALIGN_LEFT, 12, true, display.setVertexLabel(CODE_ATTRIBUTE, GraphDisplay.ALIGN_LEFT, 12, true,
codeLimitPerBlock + 1); codeLimitPerBlock + 1);
} }
display.setGraph(graph, getDescription(), appendGraph, monitor); display.setGraph(graph, graphTitle, appendGraph, monitor);
if (location != null) { if (location != null) {
// initialize the graph location, but don't have the graph send an event // initialize the graph location, but don't have the graph send an event
@ -175,17 +175,6 @@ public class BlockGraphTask extends Task {
} }
} }
private String getDescription() {
String description = actionName;
if (selection != null && !selection.isEmpty()) {
description += ": " + selection.getMinAddress();
}
else {
description += " (Entire Program)";
}
return description;
}
/** /**
* Set the maximum number of code lines which will be used per block when * Set the maximum number of code lines which will be used per block when
* showCode is enabled. * showCode is enabled.
@ -221,10 +210,62 @@ public class BlockGraphTask extends Task {
} }
private CodeBlockIterator getBlockIterator() throws CancelledException { private CodeBlockIterator getBlockIterator() throws CancelledException {
if (selection == null || selection.isEmpty()) { return blockModel.getCodeBlocksContaining(graphScope, taskMonitor);
return blockModel.getCodeBlocks(taskMonitor);
} }
return blockModel.getCodeBlocksContaining(selection, taskMonitor);
private AddressSetView getGraphScopeAndGenerateGraphTitle() {
if (selection != null && !selection.isEmpty()) {
graphTitle += selection.getMinAddress().toString();
return selection;
}
Function function = getContainingFunction(location);
if (function != null) {
graphTitle += function.getName();
if (isCallGraph()) {
return getScopeForCallGraph(function);
}
return function.getBody();
}
graphTitle += "(Entire Program)";
return blockModel.getProgram().getMemory();
}
private boolean isCallGraph() {
return blockModel instanceof SubroutineBlockModel;
}
private AddressSetView getScopeForCallGraph(Function function) {
AddressSet set = new AddressSet();
set.add(function.getBody());
try {
CodeBlock block = blockModel.getCodeBlockAt(function.getEntryPoint(), taskMonitor);
CodeBlockReferenceIterator it = blockModel.getDestinations(block, taskMonitor);
while (it.hasNext()) {
CodeBlockReference next = it.next();
set.add(next.getDestinationBlock());
}
it = blockModel.getSources(block, taskMonitor);
while (it.hasNext()) {
CodeBlockReference next = it.next();
set.add(next.getSourceBlock());
}
}
catch (CancelledException e) {
// just return, the task is being cancelled.
}
return set;
}
private Function getContainingFunction(ProgramLocation cursorLocation) {
if (cursorLocation == null) {
return null;
}
Address address = cursorLocation.getAddress();
if (address == null) {
return null;
}
return blockModel.getProgram().getFunctionManager().getFunctionContaining(address);
} }
private Address graphBlock(AttributedGraph graph, CodeBlock curBB, private Address graphBlock(AttributedGraph graph, CodeBlock curBB,
@ -285,7 +326,7 @@ public class BlockGraphTask extends Task {
// don't include destination if it does not overlap selection // don't include destination if it does not overlap selection
// always include if selection is empty // always include if selection is empty
if (selection != null && !selection.isEmpty() && !selection.intersects(db)) { if (graphScope != null && !graphScope.isEmpty() && !graphScope.intersects(db)) {
continue; continue;
} }

View file

@ -65,7 +65,6 @@ public class BlockGraphEventTest extends AbstractBlockGraphTest {
assertEquals("01002239", display.getFocusedVertex().getId()); assertEquals("01002239", display.getFocusedVertex().getId());
} }
private AddressSet addrSet(long start, long end) { private AddressSet addrSet(long start, long end) {
return new AddressSet(addr(start), addr(end)); return new AddressSet(addr(start), addr(end));
} }