diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/services/GraphDisplayBroker.java b/Ghidra/Features/Base/src/main/java/ghidra/app/services/GraphDisplayBroker.java index 69eb011903..a3156f3047 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/services/GraphDisplayBroker.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/services/GraphDisplayBroker.java @@ -68,9 +68,8 @@ public interface GraphDisplayBroker { /** * A convenience method for getting a {@link GraphDisplay} from the currently active provider * - *
This method allows users to override default graph properties defined by - * jungrapht. See that library for a complete list of available properties. - * Default properties can be changed in the {@code jungrapht.properties} file. + *
This method allows users to override default graph properties for the graph provider + * being created. See the graph provider implementation for a list of supported properties * * @param reuseGraph if true, the provider will attempt to re-use a current graph display * @param properties a {@code Map} of property key/values that can be used to customize the display diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/ExportAttributedGraphDisplay.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/ExportAttributedGraphDisplay.java index 2aa5a928e0..85b415c096 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/ExportAttributedGraphDisplay.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/export/ExportAttributedGraphDisplay.java @@ -19,7 +19,7 @@ import java.util.*; import org.jgrapht.Graph; -import docking.action.DockingAction; +import docking.action.DockingActionIf; import docking.widgets.EventTrigger; import ghidra.app.services.GraphDisplayBroker; import ghidra.framework.plugintool.PluginTool; @@ -59,8 +59,6 @@ class ExportAttributedGraphDisplay implements GraphDisplay { listener.dispose(); } - - /** * set the {@link AttributedGraph} for visualization * @param attributedGraph the {@link AttributedGraph} to visualize @@ -90,7 +88,8 @@ class ExportAttributedGraphDisplay implements GraphDisplay { } @Override - public void setVertexLabelAttribute(String attributeName, int alignment, int size, boolean monospace, + public void setVertexLabelAttribute(String attributeName, int alignment, int size, + boolean monospace, int maxLines) { // no effect } @@ -122,7 +121,7 @@ class ExportAttributedGraphDisplay implements GraphDisplay { } @Override - public void addAction(DockingAction action) { + public void addAction(DockingActionIf action) { // do nothing, actions are not supported by this display } diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java index e2bc4e9098..a3074cf957 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java @@ -19,10 +19,12 @@ import static org.jungrapht.visualization.MultiLayerTransformer.Layer.*; import static org.jungrapht.visualization.renderers.BiModalRenderer.*; import java.awt.*; +import java.awt.Dimension; import java.awt.event.*; import java.awt.geom.Point2D; import java.util.*; import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -43,9 +45,11 @@ import org.jungrapht.visualization.layout.algorithms.LayoutAlgorithm; import org.jungrapht.visualization.layout.algorithms.util.InitialDimensionFunction; import org.jungrapht.visualization.layout.model.LayoutModel; import org.jungrapht.visualization.layout.model.Point; +import org.jungrapht.visualization.layout.model.Rectangle; import org.jungrapht.visualization.renderers.*; import org.jungrapht.visualization.renderers.Renderer; import org.jungrapht.visualization.renderers.Renderer.VertexLabel; +import org.jungrapht.visualization.renderers.Renderer.VertexLabel.Position; import org.jungrapht.visualization.selection.MutableSelectedState; import org.jungrapht.visualization.selection.VertexEndpointsSelectedEdgeSelectedState; import org.jungrapht.visualization.transform.*; @@ -54,7 +58,8 @@ import org.jungrapht.visualization.transform.shape.MagnifyShapeTransformer; import org.jungrapht.visualization.util.RectangleUtils; import docking.ActionContext; -import docking.action.DockingAction; +import docking.DockingActionProxy; +import docking.action.DockingActionIf; import docking.action.ToggleDockingAction; import docking.action.builder.*; import docking.menu.ActionState; @@ -75,6 +80,24 @@ import resources.Icons; /** * Delegates to a {@link VisualizationViewer} to draw a graph visualization + * + *
This graph uses the following properties: + *
-Rename Vertex
+Rename Symbol
-diff --git a/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockGraphTask.java b/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockGraphTask.java index ed2cf88e91..c524e880c2 100644 --- a/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockGraphTask.java +++ b/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockGraphTask.java @@ -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.FunctionAllows the user to rename the symbol represented by the given vertex. +
Allows the user to rename the symbol in the program represented by the given vertex.
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 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) diff --git a/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockModelGraphDisplayListener.java b/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockModelGraphDisplayListener.java index 7a03962fca..2acd7567ca 100644 --- a/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockModelGraphDisplayListener.java +++ b/Ghidra/Features/ProgramGraph/src/main/java/ghidra/graph/program/BlockModelGraphDisplayListener.java @@ -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 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 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 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); diff --git a/Ghidra/Features/ProgramGraph/src/test/java/ghidra/graph/program/TestGraphDisplay.java b/Ghidra/Features/ProgramGraph/src/test/java/ghidra/graph/program/TestGraphDisplay.java index 77b6364441..61c2d279c0 100644 --- a/Ghidra/Features/ProgramGraph/src/test/java/ghidra/graph/program/TestGraphDisplay.java +++ b/Ghidra/Features/ProgramGraph/src/test/java/ghidra/graph/program/TestGraphDisplay.java @@ -18,7 +18,7 @@ package ghidra.graph.program; import java.util.HashSet; import java.util.Set; -import docking.action.DockingAction; +import docking.action.DockingActionIf; import docking.widgets.EventTrigger; import ghidra.service.graph.*; import ghidra.util.exception.CancelledException; @@ -74,7 +74,8 @@ public class TestGraphDisplay implements GraphDisplay { } @Override - public void setVertexLabelAttribute(String attributeName, int alignment, int size, boolean monospace, + public void setVertexLabelAttribute(String attributeName, int alignment, int size, + boolean monospace, int maxLines) { // nothing } @@ -116,8 +117,7 @@ public class TestGraphDisplay implements GraphDisplay { } @Override - public void addAction(DockingAction action) { + public void addAction(DockingActionIf action) { // do nothing, actions are not supported by this display } - } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/GraphDisplay.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/GraphDisplay.java index 6a64ebb425..696671614e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/GraphDisplay.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/GraphDisplay.java @@ -17,7 +17,7 @@ package ghidra.service.graph; import java.util.Set; -import docking.action.DockingAction; +import docking.action.DockingActionIf; import docking.widgets.EventTrigger; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -43,7 +43,7 @@ public interface GraphDisplay { public void setGraphDisplayListener(GraphDisplayListener listener); /** - * Tells the graph display window to focus the vertex with the given id. + * Tells the graph display window to focus the vertex with the given id * * @param vertex the vertex to focus * @param eventTrigger Provides a hint to the GraphDisplay as to why we are updating the @@ -63,7 +63,8 @@ public interface GraphDisplay { /** * Returns the currently focused vertex or null if no vertex is focused - * @return the currently focused vertex or null if no vertex is focused. + * + * @return the currently focused vertex or null if no vertex is focused */ public AttributedVertex getFocusedVertex(); @@ -82,6 +83,7 @@ public interface GraphDisplay { /** * Returns a set of vertex ids for all the currently selected vertices + * * @return a set of vertex ids for all the currently selected vertices */ public Set getSelectedVertices(); @@ -94,7 +96,7 @@ public interface GraphDisplay { /** * Defines a vertex attribute type for this graph window * - * @param name the name of the attribute which may be attached to vertices. + * @param name the name of the attribute which may be attached to vertices */ public void defineVertexAttribute(String name); @@ -106,22 +108,25 @@ public interface GraphDisplay { public void defineEdgeAttribute(String name); /** - * Sets the name of the attribute which should be used as the primary vertex label in the display. - * @param attributeName the name of the attribute to use as the display label for vertices. + * Sets the name of the attribute which should be used as the primary vertex label + * + * @param attributeName the name of the attribute to use as the display label for vertices * @param alignment (ALIGN_LEFT, ALIGN_RIGHT, or ALIGN_CENTER) * @param size the font size to use for the display label * @param monospace true if the font should be monospaced * @param maxLines the maximum number lines to display in the vertex labels */ - public void setVertexLabelAttribute(String attributeName, int alignment, int size, boolean monospace, + public void setVertexLabelAttribute(String attributeName, int alignment, int size, + boolean monospace, int maxLines); /** * Sets the graph to be displayed or consumed by this graph display + * * @param graph the graph to display or consume * @param title a title for the graph * @param monitor a {@link TaskMonitor} which can be used to cancel the graphing operation - * @param append if true, append the new graph to any existing graph. + * @param append if true, append the new graph to any existing graph * @throws CancelledException thrown if the graphing operation was cancelled */ public void setGraph(AttributedGraph graph, String title, boolean append, @@ -135,6 +140,7 @@ public interface GraphDisplay { /** * Updates a vertex to a new name + * * @param vertex the vertex to rename * @param newName the new name for the vertex */ @@ -142,6 +148,7 @@ public interface GraphDisplay { /** * Returns the title of the current graph + * * @return the title of the current graph */ public String getGraphTitle(); @@ -149,7 +156,8 @@ public interface GraphDisplay { /** * Adds the action to the graph display. Not all GraphDisplays support adding custom * actions, so this may have no effect. - * @param action the action to add. + * + * @param action the action to add */ - public void addAction(DockingAction action); + public void addAction(DockingActionIf action); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/VertexGraphActionContext.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/VertexGraphActionContext.java index f155ca3023..192aa9175c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/VertexGraphActionContext.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/service/graph/VertexGraphActionContext.java @@ -15,6 +15,7 @@ */ package ghidra.service.graph; +import java.util.Objects; import java.util.Set; import docking.ComponentProvider; @@ -31,7 +32,7 @@ public class VertexGraphActionContext extends GraphActionContext { AttributedVertex locatedVertex, AttributedVertex clickedVertex) { super(componentProvider, graph, selectedVertices, locatedVertex); - this.clickedVertex = clickedVertex; + this.clickedVertex = Objects.requireNonNull(clickedVertex); } /**