diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/GraphAST.java b/Ghidra/Features/Decompiler/ghidra_scripts/GraphAST.java deleted file mode 100644 index fd865dee4a..0000000000 --- a/Ghidra/Features/Decompiler/ghidra_scripts/GraphAST.java +++ /dev/null @@ -1,317 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -//Decompile the function at the cursor, then build data-flow graph (AST) -//@category PCode - -import java.util.*; - -import ghidra.app.decompiler.*; -import ghidra.app.plugin.core.graph.AddressBasedGraphDisplayListener; -import ghidra.app.script.GhidraScript; -import ghidra.app.services.GraphDisplayBroker; -import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.address.*; -import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.Function; -import ghidra.program.model.listing.Program; -import ghidra.program.model.pcode.*; -import ghidra.service.graph.*; -import ghidra.util.Msg; -import ghidra.util.WebColors; - -public class GraphAST extends GhidraScript { - private static final String SHAPE_ATTRIBUTE = "Shape"; - - protected static final String DEFAULT = "Default"; - protected static final String CONSTANT = "Constant"; - protected static final String REGISTER = "Register"; - protected static final String UNIQUE = "Unique"; - protected static final String PERSISTENT = "Persistent"; - protected static final String ADDRESS_TIED = "Address Tied"; - protected static final String OP = "Op"; - - protected static final String WITHIN_BLOCK = "Within Block"; - protected static final String BETWEEN_BLOCK = "Between Block"; - private Function func; - private AttributedGraph graph; - protected HighFunction high; - - @Override - public void run() throws Exception { - PluginTool tool = state.getTool(); - if (tool == null) { - println("Script is not running in GUI"); - } - GraphDisplayBroker graphDisplayBroker = tool.getService(GraphDisplayBroker.class); - if (graphDisplayBroker == null) { - Msg.showError(this, tool.getToolFrame(), "GraphAST Error", - "No graph display providers found: Please add a graph display provider to your tool"); - return; - } - - func = this.getFunctionContaining(this.currentAddress); - if (func == null) { - Msg.showWarn(this, state.getTool().getToolFrame(), "GraphAST Error", - "No Function at current location"); - return; - } - - buildAST(); - - GraphType graphType = new GraphTypeBuilder("AST") - .vertexType(DEFAULT) - .vertexType(CONSTANT) - .vertexType(REGISTER) - .vertexType(UNIQUE) - .vertexType(PERSISTENT) - .vertexType(ADDRESS_TIED) - .vertexType(OP) - .edgeType(DEFAULT) - .edgeType(WITHIN_BLOCK) - .edgeType(BETWEEN_BLOCK) - .build(); - - GraphDisplayOptions displayOptions = new GraphDisplayOptionsBuilder(graphType) - .vertexSelectionColor(WebColors.DEEP_PINK) - .edgeSelectionColor(WebColors.DEEP_PINK) - .defaultVertexColor(WebColors.RED) - .defaultEdgeColor(WebColors.NAVY) - .defaultVertexShape(VertexShape.ELLIPSE) - .defaultLayoutAlgorithm("Hierarchical MinCross Coffman Graham") - .useIcons(false) - .arrowLength(15) - .labelPosition(GraphLabelPosition.SOUTH) - .shapeOverrideAttribute(SHAPE_ATTRIBUTE) - .vertex(DEFAULT, VertexShape.ELLIPSE, WebColors.RED) - .vertex(CONSTANT, VertexShape.ELLIPSE, WebColors.DARK_GREEN) - .vertex(REGISTER, VertexShape.ELLIPSE, WebColors.NAVY) - .vertex(UNIQUE, VertexShape.ELLIPSE, WebColors.BLACK) - .vertex(PERSISTENT, VertexShape.ELLIPSE, WebColors.DARK_ORANGE) - .vertex(ADDRESS_TIED, VertexShape.ELLIPSE, WebColors.ORANGE) - .vertex(OP, VertexShape.RECTANGLE, WebColors.RED) - .edge(DEFAULT, WebColors.BLUE) - .edge(WITHIN_BLOCK, WebColors.BLACK) - .edge(BETWEEN_BLOCK, WebColors.RED) - .build(); - - graph = new AttributedGraph("AST Graph", graphType); - buildGraph(); - - GraphDisplay graphDisplay = graphDisplayBroker.getDefaultGraphDisplay(false, monitor); - - String description = "AST Data Flow Graph For " + func.getName(); - graphDisplay.setGraph(graph, displayOptions, description, false, monitor); - - // Install a handler so the selection/location will map - graphDisplay.setGraphDisplayListener( - new ASTGraphDisplayListener(tool, graphDisplay, high, func.getProgram())); - } - - private void buildAST() throws DecompileException { - DecompileOptions options = new DecompileOptions(); - DecompInterface ifc = new DecompInterface(); - ifc.setOptions(options); - - if (!ifc.openProgram(this.currentProgram)) { - throw new DecompileException("Decompiler", - "Unable to initialize: " + ifc.getLastMessage()); - } - ifc.setSimplificationStyle("normalize"); - DecompileResults res = ifc.decompileFunction(func, 30, null); - high = res.getHighFunction(); - - } - - private String getVarnodeKey(VarnodeAST vn) { - PcodeOp op = vn.getDef(); - String id; - if (op != null) { - id = op.getSeqnum().getTarget().toString(true) + " v " + - Integer.toString(vn.getUniqueId()); - } - else { - id = "i v " + Integer.toString(vn.getUniqueId()); - } - return id; - } - - private String getOpKey(PcodeOpAST op) { - SequenceNumber sq = op.getSeqnum(); - String id = - sq.getTarget().toString(true) + " o " + Integer.toString(op.getSeqnum().getTime()); - return id; - } - - protected AttributedVertex createVarnodeVertex(VarnodeAST vn) { - String name = vn.getAddress().toString(true); - String id = getVarnodeKey(vn); - String vertexType = DEFAULT; - if (vn.isConstant()) { - vertexType = CONSTANT; - } - else if (vn.isRegister()) { - vertexType = REGISTER; - Register reg = func.getProgram().getRegister(vn.getAddress(), vn.getSize()); - if (reg != null) { - name = reg.getName(); - } - } - else if (vn.isUnique()) { - vertexType = UNIQUE; - } - else if (vn.isPersistent()) { - vertexType = PERSISTENT; - } - else if (vn.isAddrTied()) { - vertexType = ADDRESS_TIED; - } - AttributedVertex vert = graph.addVertex(id, name); - vert.setVertexType(vertexType); - - // if it is an input override the shape to be a triangle - if (vn.isInput()) { - vert.setAttribute(SHAPE_ATTRIBUTE, VertexShape.TRIANGLE_DOWN.getName()); - } - return vert; - } - - protected AttributedVertex createOpVertex(PcodeOpAST op) { - String name = op.getMnemonic(); - String id = getOpKey(op); - int opcode = op.getOpcode(); - if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) { - Varnode vn = op.getInput(0); - AddressSpace addrspace = - func.getProgram().getAddressFactory().getAddressSpace((int) vn.getOffset()); - name += ' ' + addrspace.getName(); - } - else if (opcode == PcodeOp.INDIRECT) { - Varnode vn = op.getInput(1); - if (vn != null) { - PcodeOp indOp = high.getOpRef((int) vn.getOffset()); - if (indOp != null) { - name += " (" + indOp.getMnemonic() + ')'; - } - } - } - AttributedVertex vert = graph.addVertex(id, name); - vert.setVertexType(OP); - return vert; - } - - protected AttributedVertex getVarnodeVertex(Map vertices, - VarnodeAST vn) { - AttributedVertex res; - res = vertices.get(vn.getUniqueId()); - if (res == null) { - res = createVarnodeVertex(vn); - vertices.put(vn.getUniqueId(), res); - } - return res; - } - - protected AttributedEdge createEdge(AttributedVertex in, AttributedVertex out) { - AttributedEdge newEdge = graph.addEdge(in, out); - newEdge.setEdgeType(DEFAULT); - return newEdge; - } - - protected void buildGraph() { - - HashMap vertices = new HashMap<>(); - - Iterator opiter = getPcodeOpIterator(); - while (opiter.hasNext()) { - PcodeOpAST op = opiter.next(); - AttributedVertex o = createOpVertex(op); - for (int i = 0; i < op.getNumInputs(); ++i) { - int opcode = op.getOpcode(); - if ((i == 0) && ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE))) { - continue; - } - if ((i == 1) && (opcode == PcodeOp.INDIRECT)) { - continue; - } - VarnodeAST vn = (VarnodeAST) op.getInput(i); - if (vn != null) { - AttributedVertex v = getVarnodeVertex(vertices, vn); - createEdge(v, o); - } - } - VarnodeAST outvn = (VarnodeAST) op.getOutput(); - if (outvn != null) { - AttributedVertex outv = getVarnodeVertex(vertices, outvn); - if (outv != null) { - createEdge(o, outv); - } - } - } - } - - protected Iterator getPcodeOpIterator() { - Iterator opiter = high.getPcodeOps(); - return opiter; - } - - class ASTGraphDisplayListener extends AddressBasedGraphDisplayListener { - - HighFunction highfunc; - - public ASTGraphDisplayListener(PluginTool tool, GraphDisplay display, HighFunction high, - Program program) { - super(tool, program, display); - highfunc = high; - } - - @Override - protected Set getVertices(AddressSetView selection) { - return Collections.emptySet(); - } - - @Override - protected AddressSet getAddresses(Set vertices) { - AddressSet set = new AddressSet(); - for (AttributedVertex vertex : vertices) { - Address address = getAddress(vertex); - if (address != null) { - set.add(address); - } - } - return set; - } - - @Override - protected Address getAddress(AttributedVertex vertex) { - if (vertex == null) { - return null; - } - String vertexId = vertex.getId(); - int firstcolon = vertexId.indexOf(':'); - if (firstcolon == -1) { - return null; - } - - int firstSpace = vertexId.indexOf(' '); - String addrString = vertexId.substring(0, firstSpace); - return getAddress(addrString); - } - - @Override - public GraphDisplayListener cloneWith(GraphDisplay graphDisplay) { - return new ASTGraphDisplayListener(tool, graphDisplay, highfunc, currentProgram); - } - } -} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/GraphSelectedAST.java b/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTAndFlowScript.java similarity index 61% rename from Ghidra/Features/Decompiler/ghidra_scripts/GraphSelectedAST.java rename to Ghidra/Features/Decompiler/ghidra_scripts/GraphASTAndFlowScript.java index ff654c9de9..93b4c5b933 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/GraphSelectedAST.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTAndFlowScript.java @@ -13,18 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -//Decompile the function at the cursor, then build data-flow graph (AST) for the current address +//Decompile the function at the cursor, then build data-flow graph (AST) with flow edges //@category PCode -import java.util.Iterator; +import ghidra.app.plugin.core.decompile.actions.PCodeCombinedGraphTask; +import ghidra.app.plugin.core.decompile.actions.PCodeDfgGraphTask; +import ghidra.app.services.GraphDisplayBroker; -import ghidra.program.model.pcode.PcodeOpAST; +public class GraphASTAndFlowScript extends GraphASTScript { -public class GraphSelectedAST extends GraphAST { - - protected Iterator getPcodeOpIterator() { - Iterator opiter = high.getPcodeOps(this.currentAddress); - return opiter; + protected PCodeDfgGraphTask createTask(GraphDisplayBroker graphDisplayBroker) { + return new PCodeCombinedGraphTask(state.getTool(), graphDisplayBroker, high); } - } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTScript.java new file mode 100644 index 0000000000..fd426e462d --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTScript.java @@ -0,0 +1,77 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//Decompile the function at the cursor, then build data-flow graph (AST) +//@category PCode + +import ghidra.app.decompiler.*; +import ghidra.app.plugin.core.decompile.actions.PCodeDfgGraphTask; +import ghidra.app.script.GhidraScript; +import ghidra.app.services.GraphDisplayBroker; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.listing.Function; +import ghidra.program.model.pcode.HighFunction; +import ghidra.util.Msg; + +public class GraphASTScript extends GhidraScript { + + private Function func; + protected HighFunction high; + + @Override + public void run() throws Exception { + PluginTool tool = state.getTool(); + if (tool == null) { + println("Script is not running in GUI"); + } + GraphDisplayBroker graphDisplayBroker = tool.getService(GraphDisplayBroker.class); + if (graphDisplayBroker == null) { + Msg.showError(this, tool.getToolFrame(), "GraphAST Error", + "No graph display providers found: Please add a graph display provider to your tool"); + return; + } + + func = this.getFunctionContaining(this.currentAddress); + if (func == null) { + Msg.showWarn(this, state.getTool().getToolFrame(), "GraphAST Error", + "No Function at current location"); + return; + } + + buildAST(); + PCodeDfgGraphTask astGraphTask = createTask(graphDisplayBroker); + astGraphTask.monitoredRun(monitor); + } + + protected PCodeDfgGraphTask createTask(GraphDisplayBroker graphDisplayBroker) { + return new PCodeDfgGraphTask(state.getTool(), graphDisplayBroker, high); + } + + private void buildAST() throws DecompileException { + DecompileOptions options = new DecompileOptions(); + DecompInterface ifc = new DecompInterface(); + ifc.setOptions(options); + + if (!ifc.openProgram(this.currentProgram)) { + throw new DecompileException("Decompiler", + "Unable to initialize: " + ifc.getLastMessage()); + } + ifc.setSimplificationStyle("normalize"); + DecompileResults res = ifc.decompileFunction(func, 30, null); + high = res.getHighFunction(); + + } + +} diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/GraphSelectedASTScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/GraphSelectedASTScript.java new file mode 100644 index 0000000000..928fa6260e --- /dev/null +++ b/Ghidra/Features/Decompiler/ghidra_scripts/GraphSelectedASTScript.java @@ -0,0 +1,28 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//Decompile the function at the cursor, then build data flow graph for the current address +//@category PCode +import ghidra.app.plugin.core.decompile.actions.PCodeDfgGraphTask; +import ghidra.app.plugin.core.decompile.actions.SelectedPCodeDfgGraphTask; +import ghidra.app.services.GraphDisplayBroker; + +public class GraphSelectedASTScript extends GraphASTScript { + protected PCodeDfgGraphTask createTask(GraphDisplayBroker graphDisplayBroker) { + return new SelectedPCodeDfgGraphTask(state.getTool(), graphDisplayBroker, high, + currentAddress); + } +} diff --git a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml index 4bec5c8c27..f2529f9e2e 100644 --- a/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml +++ b/Ghidra/Features/Decompiler/src/main/doc/decompileplugin.xml @@ -3872,14 +3872,26 @@ - - Graph AST Control Flow + + Graph Data Flow This action is located in the drop-down menu on the right side of the Decompiler window tool/title bar. - Generate a control-flow graph based upon the results in the active Decompiler window, + Generate a data flow graph based upon the results in the active Decompiler window, + and render it using the current Graph Service. + + + + + Graph Control Flow + + This action is located in the drop-down menu on the right side of the Decompiler + window tool/title bar. + + + Generate a control flow graph based upon the results in the active Decompiler window, and render it using the current Graph Service. diff --git a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerWindow.html b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerWindow.html index d66560a87d..c45a94b81c 100644 --- a/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerWindow.html +++ b/Ghidra/Features/Decompiler/src/main/help/help/topics/DecompilePlugin/DecompilerWindow.html @@ -342,16 +342,28 @@

-Graph AST Control Flow

+Graph Data Flow

This action is located in the drop-down menu on the right side of the Decompiler window tool/title bar.

- Generate a control-flow graph based upon the results in the active Decompiler window, + Generate an data flow graph based upon the results in the active Decompiler window, and render it using the current Graph Service.

+

+ Graph Control Flow

+ +

+ This action is located in the drop-down menu on the right side of the Decompiler + window tool/title bar. +

+

+ Generate a control flow graph based upon the results in the active Decompiler window, + and render it using the current Graph Service. +

+ diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java index 714a4ec756..00c88eeea1 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java @@ -63,7 +63,8 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter private static final ImageIcon C_SOURCE_ICON = ResourceManager.loadImage("images/decompileFunction.gif"); - private DockingAction graphASTControlFlowAction; + private DockingAction pcodeGraphAction; + private DockingAction astGraphAction; private final DecompilePlugin plugin; private ClipboardService clipboardService; @@ -1023,21 +1024,26 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter } private void graphServiceRemoved() { - if (graphASTControlFlowAction == null) { + if (pcodeGraphAction == null) { return; } if (tool.getService(GraphDisplayBroker.class) == null) { - tool.removeAction(graphASTControlFlowAction); - graphASTControlFlowAction.dispose(); - graphASTControlFlowAction = null; + tool.removeAction(pcodeGraphAction); + tool.removeAction(astGraphAction); + astGraphAction.dispose(); + pcodeGraphAction.dispose(); + pcodeGraphAction = null; + astGraphAction = null; } } private void graphServiceAdded() { GraphDisplayBroker service = tool.getService(GraphDisplayBroker.class); if (service != null && service.getDefaultGraphDisplayProvider() != null) { - graphASTControlFlowAction = new GraphASTControlFlowAction(); - addLocalAction(graphASTControlFlowAction); + pcodeGraphAction = new PCodeCfgAction(); + addLocalAction(pcodeGraphAction); + astGraphAction = new PCodeDfgAction(); + addLocalAction(astGraphAction); } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/GraphASTControlFlowAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgAction.java similarity index 79% rename from Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/GraphASTControlFlowAction.java rename to Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgAction.java index 202dac3eb6..10caef5526 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/GraphASTControlFlowAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgAction.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.decompile.actions; -import static ghidra.app.plugin.core.decompile.actions.ASTGraphTask.AstGraphSubType.*; +import static ghidra.app.plugin.core.decompile.actions.PCodeCfgGraphTask.PcodeGraphSubType.*; import docking.action.MenuData; import ghidra.app.plugin.core.decompile.DecompilerActionContext; @@ -28,12 +28,13 @@ import ghidra.program.model.pcode.HighFunction; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.task.TaskLauncher; -public class GraphASTControlFlowAction extends AbstractDecompilerAction { - public GraphASTControlFlowAction() { - super("Graph AST Control Flow"); - setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ToolBarGraph")); - setMenuBarData(new MenuData(new String[] { "Graph AST Control Flow" }, "graph")); +public class PCodeCfgAction extends AbstractDecompilerAction { + + public PCodeCfgAction() { + super("Graph PCode Control Flow"); + setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "ControlFlowGraph")); + setMenuBarData(new MenuData(new String[] { "Graph Control Flow" }, "graph")); } @Override @@ -57,8 +58,9 @@ public class GraphASTControlFlowAction extends AbstractDecompilerAction { int codeLimitPerBlock = options.getInt("Max Code Lines Displayed", 10); HighFunction highFunction = context.getHighFunction(); Address locationAddr = context.getLocation().getAddress(); - ASTGraphTask task = new ASTGraphTask(service, !reuseGraph, codeLimitPerBlock, locationAddr, - highFunction, CONTROL_FLOW_GRAPH, tool); + PCodeCfgGraphTask task = + new PCodeCfgGraphTask(tool, service, !reuseGraph, codeLimitPerBlock, + locationAddr, highFunction, CONTROL_FLOW_GRAPH); new TaskLauncher(task, tool.getToolFrame()); } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ASTGraphDisplayListener.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgDisplayListener.java similarity index 88% rename from Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ASTGraphDisplayListener.java rename to Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgDisplayListener.java index c8cecbf527..6d3668a012 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ASTGraphDisplayListener.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgDisplayListener.java @@ -15,11 +15,11 @@ */ package ghidra.app.plugin.core.decompile.actions; -import static ghidra.app.plugin.core.decompile.actions.ASTGraphTask.AstGraphSubType.*; +import static ghidra.app.plugin.core.decompile.actions.PCodeCfgGraphTask.PcodeGraphSubType.*; import java.util.*; -import ghidra.app.plugin.core.decompile.actions.ASTGraphTask.AstGraphSubType; +import ghidra.app.plugin.core.decompile.actions.PCodeCfgGraphTask.PcodeGraphSubType; import ghidra.app.plugin.core.graph.AddressBasedGraphDisplayListener; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.*; @@ -31,12 +31,12 @@ import ghidra.util.exception.AssertException; /** * Listener for when an AST graph's nodes are selected. */ -public class ASTGraphDisplayListener extends AddressBasedGraphDisplayListener { +public class PCodeCfgDisplayListener extends AddressBasedGraphDisplayListener { private HighFunction hfunction; - private AstGraphSubType graphType; + private PcodeGraphSubType graphType; - ASTGraphDisplayListener(PluginTool tool, GraphDisplay display, HighFunction hfunction, - AstGraphSubType graphType) { + PCodeCfgDisplayListener(PluginTool tool, GraphDisplay display, HighFunction hfunction, + PcodeGraphSubType graphType) { super(tool, hfunction.getFunction().getProgram(), display); this.hfunction = hfunction; this.graphType = graphType; @@ -117,7 +117,7 @@ public class ASTGraphDisplayListener extends AddressBasedGraphDisplayListener { @Override public GraphDisplayListener cloneWith(GraphDisplay display) { - return new ASTGraphDisplayListener(tool, graphDisplay, hfunction, graphType); + return new PCodeCfgDisplayListener(tool, graphDisplay, hfunction, graphType); } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ASTGraphTask.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgGraphTask.java similarity index 91% rename from Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ASTGraphTask.java rename to Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgGraphTask.java index 48d1826352..efb318289e 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/ASTGraphTask.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgGraphTask.java @@ -36,12 +36,16 @@ import ghidra.util.exception.GraphException; import ghidra.util.task.Task; import ghidra.util.task.TaskMonitor; -public class ASTGraphTask extends Task { - enum AstGraphSubType { +/** + * Task to create a PCode control flow graph based on decompiler output + */ +public class PCodeCfgGraphTask extends Task { + enum PcodeGraphSubType { CONTROL_FLOW_GRAPH("AST Control Flow"), DATA_FLOW_GRAPH("AST Data Flow"); + private String name; - AstGraphSubType(String name) { + PcodeGraphSubType(String name) { this.name = name; } @@ -57,13 +61,14 @@ public class ASTGraphTask extends Task { private int codeLimitPerBlock; private Address location; private HighFunction hfunction; - private AstGraphSubType astGraphType; + private PcodeGraphSubType pcodeGraphType; private int uniqueNum = 0; private PluginTool tool; - public ASTGraphTask(GraphDisplayBroker graphService, boolean newGraph, int codeLimitPerBlock, - Address location, HighFunction hfunction, AstGraphSubType graphType, PluginTool tool) { + public PCodeCfgGraphTask(PluginTool tool, GraphDisplayBroker graphService, boolean newGraph, + int codeLimitPerBlock, Address location, HighFunction hfunction, + PcodeGraphSubType graphType) { super("Graph " + graphType.getName(), true, false, true); this.graphService = graphService; @@ -71,19 +76,19 @@ public class ASTGraphTask extends Task { this.codeLimitPerBlock = codeLimitPerBlock; this.location = location; this.hfunction = hfunction; - this.astGraphType = graphType; + this.pcodeGraphType = graphType; this.tool = tool; } @Override public void run(TaskMonitor monitor) { - GraphType graphType = new AstGraphType(); + GraphType graphType = new PCodeCfgGraphType(); // get a new graph - AttributedGraph graph = new AttributedGraph(astGraphType.getName(), graphType); + AttributedGraph graph = new AttributedGraph("PCode Graph", graphType); try { monitor.setMessage("Computing Graph..."); - if (astGraphType == AstGraphSubType.DATA_FLOW_GRAPH) { + if (pcodeGraphType == PcodeGraphSubType.DATA_FLOW_GRAPH) { createDataFlowGraph(graph, monitor); } else { @@ -93,8 +98,8 @@ public class ASTGraphTask extends Task { GraphDisplay display = graphService.getDefaultGraphDisplay(!newGraph, monitor); - ASTGraphDisplayListener displayListener = - new ASTGraphDisplayListener(tool, display, hfunction, astGraphType); + PCodeCfgDisplayListener displayListener = + new PCodeCfgDisplayListener(tool, display, hfunction, pcodeGraphType); display.setGraphDisplayListener(displayListener); monitor.setMessage("Obtaining handle to graph provider..."); @@ -106,10 +111,11 @@ public class ASTGraphTask extends Task { monitor.setMessage("Rendering Graph..."); String description = - astGraphType == AstGraphSubType.DATA_FLOW_GRAPH ? "AST Data Flow" : "AST Control Flow"; + pcodeGraphType == PcodeGraphSubType.DATA_FLOW_GRAPH ? "AST Data Flow" + : "AST Control Flow"; description = description + " for " + hfunction.getFunction().getName(); GraphDisplayOptions graphDisplayOptions = - new ProgramGraphDisplayOptions(new AstGraphType(), tool); + new ProgramGraphDisplayOptions(new PCodeCfgGraphType(), tool); graphDisplayOptions.setVertexLabelOverrideAttributeKey(CODE_ATTRIBUTE); display.setGraph(graph, graphDisplayOptions, description, false, monitor); setGraphLocation(display, displayListener); @@ -124,7 +130,7 @@ public class ASTGraphTask extends Task { } - private void setGraphLocation(GraphDisplay display, ASTGraphDisplayListener displayListener) { + private void setGraphLocation(GraphDisplay display, PCodeCfgDisplayListener displayListener) { if (location == null) { return; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/AstGraphType.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgGraphType.java similarity index 82% rename from Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/AstGraphType.java rename to Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgGraphType.java index 1d60cef4cd..3e1febf0af 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/AstGraphType.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCfgGraphType.java @@ -17,10 +17,10 @@ package ghidra.app.plugin.core.decompile.actions; import ghidra.graph.ProgramGraphType; -public class AstGraphType extends ProgramGraphType { +public class PCodeCfgGraphType extends ProgramGraphType { - protected AstGraphType() { - super("AST", "Graph to show pcode for function"); + protected PCodeCfgGraphType() { + super("Pcode", "Graph to show pcode for function"); } } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTAndFlow.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCombinedGraphTask.java similarity index 83% rename from Ghidra/Features/Decompiler/ghidra_scripts/GraphASTAndFlow.java rename to Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCombinedGraphTask.java index ca1eeeb2e3..74cfe9db96 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/GraphASTAndFlow.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeCombinedGraphTask.java @@ -13,16 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -//Decompile the function at the cursor, then build data-flow graph (AST) with flow edges -//@category PCode +package ghidra.app.plugin.core.decompile.actions; import java.util.*; +import ghidra.app.services.GraphDisplayBroker; +import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.pcode.*; import ghidra.service.graph.AttributedEdge; import ghidra.service.graph.AttributedVertex; -public class GraphASTAndFlow extends GraphAST { +/** + * Task to create a combined PCode control flow and data flow graph based on decompiler output + */ +public class PCodeCombinedGraphTask extends PCodeDfgGraphTask { + + public PCodeCombinedGraphTask(PluginTool tool, GraphDisplayBroker graphService, + HighFunction hfunction) { + super(tool, graphService, hfunction); + } @Override protected void buildGraph() { @@ -77,7 +86,7 @@ public class GraphASTAndFlow extends GraphAST { } if (prev != null && map.containsKey(prev) && map.containsKey(next)) { AttributedEdge edge = createEdge(map.get(prev), map.get(next)); - edge.setEdgeType(WITHIN_BLOCK); + edge.setEdgeType(PCodeDfgGraphType.WITHIN_BLOCK); } prev = next; } @@ -92,7 +101,7 @@ public class GraphASTAndFlow extends GraphAST { PcodeBlock in = block.getIn(i); if (last.containsKey(in)) { AttributedEdge edge = createEdge(last.get(in), first.get(block)); - edge.setEdgeType(BETWEEN_BLOCK); + edge.setEdgeType(PCodeDfgGraphType.BETWEEN_BLOCKS); } } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgAction.java new file mode 100644 index 0000000000..1e47267159 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgAction.java @@ -0,0 +1,60 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.decompile.actions; + +import docking.action.MenuData; +import ghidra.app.plugin.core.decompile.DecompilerActionContext; +import ghidra.app.services.GraphDisplayBroker; +import ghidra.app.util.HelpTopics; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.pcode.HighFunction; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; +import ghidra.util.task.TaskLauncher; + +/** + * Action to create a PCode control data graph based on decompiler output + */ +public class PCodeDfgAction extends AbstractDecompilerAction { + + public PCodeDfgAction() { + super("Graph PCode Data Flow"); + setHelpLocation(new HelpLocation(HelpTopics.DECOMPILER, "DataFlowGraph")); + setMenuBarData(new MenuData(new String[] { "Graph Data Flow" }, "graph")); + } + + @Override + protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) { + return context.getFunction() != null; + } + + @Override + protected void decompilerActionPerformed(DecompilerActionContext context) { + PluginTool tool = context.getTool(); + GraphDisplayBroker service = tool.getService(GraphDisplayBroker.class); + if (service == null) { + Msg.showError(this, tool.getToolFrame(), "AST Graph Failed", + "Graph Display Broker service not found!\n" + + "Please add a Graph Display Broker service"); + return; + } + + HighFunction highFunction = context.getHighFunction(); + PCodeDfgGraphTask task = new PCodeDfgGraphTask(tool, service, highFunction); + new TaskLauncher(task, tool.getToolFrame()); + } + +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayListener.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayListener.java new file mode 100644 index 0000000000..2d6e68743e --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayListener.java @@ -0,0 +1,78 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.decompile.actions; + +import java.util.Collections; +import java.util.Set; + +import ghidra.app.plugin.core.graph.AddressBasedGraphDisplayListener; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.address.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.pcode.HighFunction; +import ghidra.service.graph.*; + +/** + * GraphDisplayListener for a PCode data flow graph + */ +class PCodeDfgDisplayListener extends AddressBasedGraphDisplayListener { + + HighFunction highfunc; + + public PCodeDfgDisplayListener(PluginTool tool, GraphDisplay display, HighFunction high, + Program program) { + super(tool, program, display); + highfunc = high; + } + + @Override + protected Set getVertices(AddressSetView selection) { + return Collections.emptySet(); + } + + @Override + protected AddressSet getAddresses(Set vertices) { + AddressSet set = new AddressSet(); + for (AttributedVertex vertex : vertices) { + Address address = getAddress(vertex); + if (address != null) { + set.add(address); + } + } + return set; + } + + @Override + protected Address getAddress(AttributedVertex vertex) { + if (vertex == null) { + return null; + } + String vertexId = vertex.getId(); + int firstColon = vertexId.indexOf(':'); + if (firstColon == -1) { + return null; + } + + int firstSpace = vertexId.indexOf(' '); + String addrString = vertexId.substring(0, firstSpace); + return getAddress(addrString); + } + + @Override + public GraphDisplayListener cloneWith(GraphDisplay display) { + return new PCodeDfgDisplayListener(tool, display, highfunc, program); + } +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java new file mode 100644 index 0000000000..b2b11dce56 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgDisplayOptions.java @@ -0,0 +1,65 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.decompile.actions; + +import static ghidra.app.plugin.core.decompile.actions.PCodeDfgGraphType.*; +import static ghidra.service.graph.VertexShape.*; + +import ghidra.framework.plugintool.PluginTool; +import ghidra.service.graph.*; +import ghidra.util.WebColors; + +/** + * {@link GraphDisplayOptions} for {@link PCodeDfgGraphType} + */ +public class PCodeDfgDisplayOptions extends GraphDisplayOptions { + public static final String SHAPE_ATTRIBUTE = "Shape"; + + /** + * constructor + * @param tool if non-null, will load values from tool options + */ + public PCodeDfgDisplayOptions(PluginTool tool) { + super(new PCodeDfgGraphType(), tool); + } + + @Override + protected void initializeDefaults() { + setDefaultVertexShape(ELLIPSE); + setDefaultVertexColor(WebColors.RED); + setDefaultEdgeColor(WebColors.NAVY); + setVertexSelectionColor(WebColors.DEEP_PINK); + setEdgeSelectionColor(WebColors.DEEP_PINK); + setDefaultLayoutAlgorithmName(LayoutAlgorithmNames.MIN_CROSS_COFFMAN_GRAHAM); + setUsesIcons(false); + setArrowLength(15); + setLabelPosition(GraphLabelPosition.SOUTH); + setVertexShapeOverrideAttributeKey(SHAPE_ATTRIBUTE); + setMaxNodeCount(1000); + + configureVertexType(DEFAULT_VERTEX, VertexShape.ELLIPSE, WebColors.RED); + configureVertexType(CONSTANT, VertexShape.ELLIPSE, WebColors.DARK_GREEN); + configureVertexType(REGISTER, VertexShape.ELLIPSE, WebColors.NAVY); + configureVertexType(UNIQUE, VertexShape.ELLIPSE, WebColors.BLACK); + configureVertexType(PERSISTENT, VertexShape.ELLIPSE, WebColors.DARK_ORANGE); + configureVertexType(ADDRESS_TIED, VertexShape.ELLIPSE, WebColors.ORANGE); + configureVertexType(OP, VertexShape.ELLIPSE, WebColors.RED); + + configureEdgeType(DEFAULT_EDGE, WebColors.BLUE); + configureEdgeType(WITHIN_BLOCK, WebColors.BLACK); + configureEdgeType(BETWEEN_BLOCKS, WebColors.RED); + } +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgGraphTask.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgGraphTask.java new file mode 100644 index 0000000000..27720c29cf --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgGraphTask.java @@ -0,0 +1,220 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.decompile.actions; + +import static ghidra.app.plugin.core.decompile.actions.PCodeDfgDisplayOptions.*; + +import java.util.*; + +import ghidra.app.services.GraphDisplayBroker; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.Function; +import ghidra.program.model.pcode.*; +import ghidra.service.graph.*; +import ghidra.util.Msg; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.GraphException; +import ghidra.util.task.Task; +import ghidra.util.task.TaskMonitor; + +/** + * Task for creating PCode data flow graphs from decompiler output + */ +public class PCodeDfgGraphTask extends Task { + + private GraphDisplayBroker graphService; + protected HighFunction hfunction; + private AttributedGraph graph; + private PluginTool tool; + + public PCodeDfgGraphTask(PluginTool tool, GraphDisplayBroker graphService, + HighFunction hfunction) { + super("Graph AST", true, false, true); + this.graphService = graphService; + this.hfunction = hfunction; + this.tool = tool; + } + + @Override + public void run(TaskMonitor monitor) { + try { + buildAndDisplayGraph(monitor); + } + catch (GraphException e) { + Msg.showError(this, null, "Graph Error", + "Can't create graph display: " + e.getMessage(), e); + } + catch (CancelledException e1) { + // do nothing + } + } + + private void buildAndDisplayGraph(TaskMonitor monitor) + throws GraphException, CancelledException { + + GraphType graphType = new PCodeDfgGraphType(); + Function func = hfunction.getFunction(); + graph = new AttributedGraph("Data Flow Graph", graphType); + buildGraph(); + + GraphDisplay graphDisplay = graphService.getDefaultGraphDisplay(false, monitor); + GraphDisplayOptions displayOptions = new PCodeDfgDisplayOptions(tool); + + String description = "AST Data Flow Graph For " + func.getName(); + graphDisplay.setGraph(graph, displayOptions, description, false, monitor); + + // Install a handler so the selection/location will map + graphDisplay.setGraphDisplayListener(new PCodeDfgDisplayListener(tool, graphDisplay, + hfunction, func.getProgram())); + } + + protected void buildGraph() { + + HashMap vertices = new HashMap<>(); + + Iterator opiter = getPcodeOpIterator(); + while (opiter.hasNext()) { + PcodeOpAST op = opiter.next(); + AttributedVertex o = createOpVertex(op); + for (int i = 0; i < op.getNumInputs(); ++i) { + int opcode = op.getOpcode(); + if ((i == 0) && ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE))) { + continue; + } + if ((i == 1) && (opcode == PcodeOp.INDIRECT)) { + continue; + } + VarnodeAST vn = (VarnodeAST) op.getInput(i); + if (vn != null) { + AttributedVertex v = getVarnodeVertex(vertices, vn); + createEdge(v, o); + } + } + VarnodeAST outvn = (VarnodeAST) op.getOutput(); + if (outvn != null) { + AttributedVertex outv = getVarnodeVertex(vertices, outvn); + if (outv != null) { + createEdge(o, outv); + } + } + } + } + + private String getVarnodeKey(VarnodeAST vn) { + PcodeOp op = vn.getDef(); + String id; + if (op != null) { + id = op.getSeqnum().getTarget().toString(true) + " v " + + Integer.toString(vn.getUniqueId()); + } + else { + id = "i v " + Integer.toString(vn.getUniqueId()); + } + return id; + } + + protected AttributedVertex createVarnodeVertex(VarnodeAST vn) { + String name = vn.getAddress().toString(true); + String id = getVarnodeKey(vn); + String vertexType = PCodeDfgGraphType.DEFAULT_VERTEX; + if (vn.isConstant()) { + vertexType = PCodeDfgGraphType.CONSTANT; + } + else if (vn.isRegister()) { + vertexType = PCodeDfgGraphType.REGISTER; + Register reg = + hfunction.getFunction().getProgram().getRegister(vn.getAddress(), vn.getSize()); + if (reg != null) { + name = reg.getName(); + } + } + else if (vn.isUnique()) { + vertexType = PCodeDfgGraphType.UNIQUE; + } + else if (vn.isPersistent()) { + vertexType = PCodeDfgGraphType.PERSISTENT; + } + else if (vn.isAddrTied()) { + vertexType = PCodeDfgGraphType.ADDRESS_TIED; + } + AttributedVertex vert = graph.addVertex(id, name); + vert.setVertexType(vertexType); + + // if it is an input override the shape to be a triangle + if (vn.isInput()) { + vert.setAttribute(SHAPE_ATTRIBUTE, VertexShape.TRIANGLE_DOWN.getName()); + } + return vert; + } + + protected AttributedVertex getVarnodeVertex(Map vertices, + VarnodeAST vn) { + AttributedVertex res; + res = vertices.get(vn.getUniqueId()); + if (res == null) { + res = createVarnodeVertex(vn); + vertices.put(vn.getUniqueId(), res); + } + return res; + } + + protected AttributedEdge createEdge(AttributedVertex in, AttributedVertex out) { + AttributedEdge newEdge = graph.addEdge(in, out); + newEdge.setEdgeType(PCodeDfgGraphType.DEFAULT_EDGE); + return newEdge; + } + + protected AttributedVertex createOpVertex(PcodeOpAST op) { + String name = op.getMnemonic(); + String id = getOpKey(op); + int opcode = op.getOpcode(); + if ((opcode == PcodeOp.LOAD) || (opcode == PcodeOp.STORE)) { + Varnode vn = op.getInput(0); + AddressSpace addrspace = + hfunction.getFunction() + .getProgram() + .getAddressFactory() + .getAddressSpace((int) vn.getOffset()); + name += ' ' + addrspace.getName(); + } + else if (opcode == PcodeOp.INDIRECT) { + Varnode vn = op.getInput(1); + if (vn != null) { + PcodeOp indOp = hfunction.getOpRef((int) vn.getOffset()); + if (indOp != null) { + name += " (" + indOp.getMnemonic() + ')'; + } + } + } + AttributedVertex vert = graph.addVertex(id, name); + vert.setVertexType(PCodeDfgGraphType.OP); + return vert; + } + + protected Iterator getPcodeOpIterator() { + Iterator opiter = hfunction.getPcodeOps(); + return opiter; + } + + private String getOpKey(PcodeOpAST op) { + SequenceNumber sq = op.getSeqnum(); + String id = + sq.getTarget().toString(true) + " o " + Integer.toString(op.getSeqnum().getTime()); + return id; + } +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgGraphType.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgGraphType.java new file mode 100644 index 0000000000..7c6cae793c --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/PCodeDfgGraphType.java @@ -0,0 +1,59 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.decompile.actions; + +import java.util.ArrayList; +import java.util.List; + +import ghidra.service.graph.GraphType; + +/** + * GraphType for a PCode data flow graph + */ +public class PCodeDfgGraphType extends GraphType { + private static List vertexTypes = new ArrayList<>(); + private static List edgeTypes = new ArrayList<>(); + + // Vertex Types + public static final String DEFAULT_VERTEX = vertex("Default"); + public static final String CONSTANT = vertex("Constant"); + public static final String REGISTER = vertex("Register"); + public static final String UNIQUE = vertex("Unique"); + public static final String PERSISTENT = vertex("Persistent"); + public static final String ADDRESS_TIED = vertex("Address Tied"); + public static final String OP = vertex("Op"); + + // Edge Types + public static final String DEFAULT_EDGE = edge("Default"); + public static final String WITHIN_BLOCK = edge("Within Block"); + public static final String BETWEEN_BLOCKS = edge("Between Blocks"); + + public PCodeDfgGraphType() { + super("AST Graph", "Displays an AST graph for the current function", vertexTypes, + edgeTypes); + } + + private static String edge(String edgeType) { + edgeTypes.add(edgeType); + return edgeType; + } + + private static String vertex(String vertexType) { + vertexTypes.add(vertexType); + return vertexType; + } + +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SelectedPCodeDfgGraphTask.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SelectedPCodeDfgGraphTask.java new file mode 100644 index 0000000000..a9a21e5ce7 --- /dev/null +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/SelectedPCodeDfgGraphTask.java @@ -0,0 +1,43 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.plugin.core.decompile.actions; + +import java.util.Iterator; + +import ghidra.app.services.GraphDisplayBroker; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.address.Address; +import ghidra.program.model.pcode.HighFunction; +import ghidra.program.model.pcode.PcodeOpAST; + +/** + * Task for creating a PCode data flow graph from a selected address + */ +public class SelectedPCodeDfgGraphTask extends PCodeDfgGraphTask { + + private Address address; + + public SelectedPCodeDfgGraphTask(PluginTool tool, GraphDisplayBroker graphService, + HighFunction hfunction, Address address) { + super(tool, graphService, hfunction); + this.address = address; + } + + protected Iterator getPcodeOpIterator() { + Iterator opiter = hfunction.getPcodeOps(address); + return opiter; + } +}