Graphing - (various fixes; see below)

-fixed bug that prevented actions being added to sub graphs
-subgraph gets bad tab text
-properties documentation
-fixed incorrect vertex shape function applied to lightweight renderer
-dispose actions on close
This commit is contained in:
dragonmacher 2021-02-04 14:04:39 -05:00
parent 4041c3693b
commit e983784753
10 changed files with 262 additions and 179 deletions

View file

@ -362,9 +362,9 @@
<BLOCKQUOTE>
<H3><A NAME="Rename_Vertex"></A>Rename Vertex</H3>
<H3><A NAME="Rename_Symbol"></A>Rename Symbol</H3>
<BLOCKQUOTE>
<P>Allows the user to rename the symbol represented by the given vertex.
<P>Allows the user to rename the symbol in the program represented by the given vertex.
</P>
</BLOCKQUOTE>

View file

@ -18,8 +18,10 @@ package ghidra.graph.program;
import java.awt.Color;
import java.util.*;
import docking.action.builder.ActionBuilder;
import docking.widgets.EventTrigger;
import ghidra.app.plugin.core.colorizer.ColorizingService;
import ghidra.app.util.AddEditDialog;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.block.*;
@ -28,8 +30,7 @@ import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.service.graph.*;
import ghidra.util.HTMLUtilities;
import ghidra.util.Msg;
import ghidra.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.GraphException;
import ghidra.util.task.Task;
@ -145,6 +146,7 @@ public class BlockGraphTask extends Task {
GraphDisplay display = graphProvider.getGraphDisplay(reuseGraph, monitor);
BlockModelGraphDisplayListener listener =
new BlockModelGraphDisplayListener(tool, blockModel, display);
addActions(display, v -> listener.getAddress(v));
display.setGraphDisplayListener(listener);
if (showCode) {
@ -175,6 +177,37 @@ public class BlockGraphTask extends Task {
}
}
private void addActions(GraphDisplay display,
java.util.function.Function<AttributedVertex, Address> addressFunction) {
display.addAction(new ActionBuilder("Rename Symbol", "Block Graph")
.popupMenuPath("Rename Symbol")
.withContext(VertexGraphActionContext.class)
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename_Symbol"))
// only enable action when vertex corresponds to an address
.enabledWhen(c -> addressFunction.apply(c.getClickedVertex()) != null)
.onAction(c -> updateVertexName(addressFunction, c))
.build());
}
private void updateVertexName(
java.util.function.Function<AttributedVertex, Address> addressFunction,
VertexGraphActionContext context) {
AttributedVertex vertex = context.getClickedVertex();
Address address = addressFunction.apply(vertex);
Symbol symbol = program.getSymbolTable().getPrimarySymbol(address);
if (symbol == null) {
AddEditDialog dialog = new AddEditDialog("Create Label", tool);
dialog.addLabel(address, program, context.getComponentProvider());
}
else {
AddEditDialog dialog = new AddEditDialog("Edit Label", tool);
dialog.editLabel(symbol, program, context.getComponentProvider());
}
}
/**
* Set the maximum number of code lines which will be used per block when
* showCode is enabled.
@ -318,10 +351,8 @@ public class BlockGraphTask extends Task {
CodeBlockReference cbRef = refIter.next();
CodeBlock db = cbRef.getDestinationBlock();
// must be a reference to a data block
if (db == null) {
continue;
continue; // must be a reference to a data block
}
// don't include destination if it does not overlap selection
@ -336,7 +367,6 @@ public class BlockGraphTask extends Task {
}
// put the edge in the graph
String edgeAddr = cbRef.getReferent().toString();
AttributedEdge newEdge = graph.addEdge(fromVertex, toVertex);
// set it's attributes (really its name)

View file

@ -17,16 +17,13 @@ package ghidra.graph.program;
import java.util.*;
import docking.action.builder.ActionBuilder;
import ghidra.app.plugin.core.graph.AddressBasedGraphDisplayListener;
import ghidra.app.util.AddEditDialog;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.*;
import ghidra.program.model.block.*;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.service.graph.*;
import ghidra.util.HelpLocation;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -41,18 +38,11 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
GraphDisplay display) {
super(tool, blockModel.getProgram(), display);
this.blockModel = blockModel;
addActions(display);
}
private void addActions(GraphDisplay display) {
display.addAction(new ActionBuilder("Rename Vertex", "Block Graph")
.popupMenuPath("Rename Vertex")
.withContext(VertexGraphActionContext.class)
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename Vertex"))
// only enable action when vertex corresponds to an address
.enabledWhen(c -> getAddress(c.getClickedVertex().getId()) != null)
.onAction(this::updateVertexName)
.build());
@Override
public Address getAddress(AttributedVertex vertex) {
return super.getAddress(vertex);
}
@Override
@ -79,25 +69,7 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
// Identify all blocks which have an entry point within the selection address set
Set<AttributedVertex> vertices = new HashSet<>();
try {
SymbolTable symTable = program.getSymbolTable();
CodeBlockIterator cbIter =
blockModel.getCodeBlocksContaining(addrSet, TaskMonitor.DUMMY);
while (cbIter.hasNext()) {
CodeBlock block = cbIter.next();
String addrString;
Address addr = block.getFirstStartAddress();
if (addr.isExternalAddress()) {
Symbol s = symTable.getPrimarySymbol(addr);
addrString = s.getName(true);
}
else {
addrString = addr.toString();
}
AttributedVertex vertex = graphDisplay.getGraph().getVertex(addrString);
if (vertex != null) {
vertices.add(vertex);
}
}
addVerticesForAddresses(addrSet, vertices);
}
catch (CancelledException e) {
// Will not happen with dummyMonitor
@ -107,37 +79,39 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
return vertices;
}
private void addVerticesForAddresses(AddressSetView addrSet, Set<AttributedVertex> vertices)
throws CancelledException {
SymbolTable symTable = program.getSymbolTable();
CodeBlockIterator it =
blockModel.getCodeBlocksContaining(addrSet, TaskMonitor.DUMMY);
while (it.hasNext()) {
CodeBlock block = it.next();
String addrString;
Address addr = block.getFirstStartAddress();
if (addr.isExternalAddress()) {
Symbol s = symTable.getPrimarySymbol(addr);
addrString = s.getName(true);
}
else {
addrString = addr.toString();
}
AttributedVertex vertex = graphDisplay.getGraph().getVertex(addrString);
if (vertex != null) {
vertices.add(vertex);
}
}
}
@Override
protected AddressSet getAddresses(Set<AttributedVertex> vertices) {
AddressSet addrSet = new AddressSet();
AddressSet addrSet = new AddressSet();
try {
// for each address string, translate it into a block
// and add it to the address set.
for (AttributedVertex vertex : vertices) {
Address blockAddr = getAddress(vertex);
if (!isValidAddress(blockAddr)) {
continue;
}
CodeBlock blocks[] = null;
if (blockModel != null) {
CodeBlock block = blockModel.getCodeBlockAt(blockAddr, TaskMonitor.DUMMY);
if (block != null) {
blocks = new CodeBlock[1];
blocks[0] = block;
}
else {
blocks = blockModel.getCodeBlocksContaining(blockAddr, TaskMonitor.DUMMY);
}
}
if (blocks != null && blocks.length > 0) {
for (CodeBlock block : blocks) {
addrSet.add(block);
}
}
else {
addrSet.addRange(blockAddr, blockAddr);
}
addBlockAddresses(addrSet, vertex);
}
}
catch (CancelledException e) {
@ -147,6 +121,35 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
return addrSet;
}
private void addBlockAddresses(AddressSet addrSet, AttributedVertex vertex)
throws CancelledException {
Address blockAddr = getAddress(vertex);
if (!isValidAddress(blockAddr)) {
return;
}
CodeBlock blocks[] = null;
if (blockModel != null) {
CodeBlock block = blockModel.getCodeBlockAt(blockAddr, TaskMonitor.DUMMY);
if (block != null) {
blocks = new CodeBlock[1];
blocks[0] = block;
}
else {
blocks = blockModel.getCodeBlocksContaining(blockAddr, TaskMonitor.DUMMY);
}
}
if (blocks != null && blocks.length > 0) {
for (CodeBlock block : blocks) {
addrSet.add(block);
}
}
else {
addrSet.addRange(blockAddr, blockAddr);
}
}
protected boolean isValidAddress(Address addr) {
if (addr == null || program == null) {
return false;
@ -154,21 +157,6 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
return program.getMemory().contains(addr) || addr.isExternalAddress();
}
private void updateVertexName(VertexGraphActionContext context) {
AttributedVertex vertex = context.getClickedVertex();
Address address = getAddress(vertex);
Symbol symbol = program.getSymbolTable().getPrimarySymbol(address);
if (symbol == null) {
AddEditDialog dialog = new AddEditDialog("Create Label", tool);
dialog.addLabel(address, program, context.getComponentProvider());
}
else {
AddEditDialog dialog = new AddEditDialog("Edit Label", tool);
dialog.editLabel(symbol, program, context.getComponentProvider());
}
}
@Override
public GraphDisplayListener cloneWith(GraphDisplay newGraphDisplay) {
return new BlockModelGraphDisplayListener(tool, blockModel, newGraphDisplay);