From cdd1acb1f9a54bc8a83097bdd05647eae2c37a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 4 Feb 2018 10:37:09 +0100 Subject: [PATCH] More universal GraphExporter Log exceptions on copy to clipboard graph --- .../AVM2DeobfuscatorRegisters.java | 10 +++ .../AVM2DeobfuscatorRegistersOld.java | 10 +++ .../flash/abc/avm2/graph/AVM2GraphSource.java | 15 ++++ .../avm2/instructions/AVM2Instruction.java | 4 +- .../jpexs/decompiler/flash/action/Action.java | 1 + .../flash/action/ActionGraphSource.java | 20 ++++- .../exporters/script/ExportScriptTask.java | 2 +- .../script/PcodeGraphVizExporter.java | 81 ++++++++++++------- .../src/com/jpexs/decompiler/graph/Graph.java | 4 + .../jpexs/decompiler/graph/GraphSource.java | 22 +++++ .../decompiler/graph/GraphSourceItem.java | 5 +- .../flash/gui/action/ActionPanel.java | 12 ++- 12 files changed, 148 insertions(+), 38 deletions(-) diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java index 8d0499b23..0288af0fe 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegisters.java @@ -303,6 +303,16 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple { public long pos2adr(int pos) { return code.pos2adr(pos); } + + @Override + public Set getImportantAddresses() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String insToString(int pos) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } }); idx = branches.get(0); for (int n = 1; n < branches.size(); n++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java index a53ab1816..d0e6392a6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/deobfuscation/AVM2DeobfuscatorRegistersOld.java @@ -266,6 +266,16 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld { public long pos2adr(int pos) { return code.pos2adr(pos); } + + @Override + public Set getImportantAddresses() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String insToString(int pos) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } }); idx = branches.get(0); for (int n = 1; n < branches.size(); n++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java index a6bb038d5..7d8d50788 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/graph/AVM2GraphSource.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.abc.avm2.ConvertOutput; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.helpers.Reference; import com.jpexs.decompiler.flash.abc.types.MethodBody; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphSource; @@ -34,6 +35,7 @@ import com.jpexs.decompiler.graph.TranslateStack; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; /** * @@ -85,6 +87,19 @@ public class AVM2GraphSource extends GraphSource { code.calculateDebugFileLine(abc); } + @Override + public Set getImportantAddresses() { + return code.getImportantOffsets(body, false); + } + + @Override + public String insToString(int pos) { + if (pos < code.code.size()) { + return code.code.get(pos).toStringNoAddress(abc.constants, fullyQualifiedNames); + } + return ""; + } + @Override public int size() { return code.code.size(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java index 63cc0b5dd..f1420e948 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/AVM2Instruction.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.abc.avm2.instructions; import com.jpexs.decompiler.flash.BaseLocalData; @@ -123,6 +124,7 @@ public class AVM2Instruction implements Cloneable, GraphSourceItem { return bos.toByteArray(); } + @Override public int getBytesLength() { int cnt = 1; for (int i = 0; i < definition.operands.length; i++) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java index d52275288..c69e7894c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java @@ -347,6 +347,7 @@ public abstract class Action implements GraphSourceItem { * * @return Length */ + @Override public final int getBytesLength() { return getContentBytesLength() + (actionCode >= 0x80 ? 3 : 1); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java index e1458a84b..fcb5f8c4a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraphSource.java @@ -17,6 +17,8 @@ package com.jpexs.decompiler.flash.action; import com.jpexs.decompiler.flash.BaseLocalData; +import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.helpers.Reference; import com.jpexs.decompiler.graph.GraphPart; import com.jpexs.decompiler.graph.GraphSource; @@ -27,6 +29,7 @@ import com.jpexs.helpers.Helper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -36,7 +39,7 @@ import java.util.logging.Logger; */ public class ActionGraphSource extends GraphSource { - private final List actions; + private final ActionList actions; public int version; @@ -55,7 +58,7 @@ public class ActionGraphSource extends GraphSource { } public ActionGraphSource(String path, boolean insideDoInitAction, List actions, int version, HashMap registerNames, HashMap variables, HashMap functions) { - this.actions = actions; + this.actions = actions instanceof ActionList ? (ActionList) actions : new ActionList(actions); this.version = version; this.registerNames = registerNames; this.variables = variables; @@ -64,6 +67,19 @@ public class ActionGraphSource extends GraphSource { this.path = path; } + @Override + public Set getImportantAddresses() { + return Action.getActionsAllRefs(actions); + } + + @Override + public String insToString(int pos) { + if (pos < actions.size()) { + return actions.get(pos).getASMSource(actions, getImportantAddresses(), ScriptExportMode.PCODE); + } + return ""; + } + @Override public int size() { return actions.size(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java index e33132631..d8c46a514 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/ExportScriptTask.java @@ -100,7 +100,7 @@ public class ExportScriptTask implements Callable { asm.getActionBytesAsHex(writer2); asm.getActionSourceSuffix(writer2); } else if (exportMode == ScriptExportMode.PCODE_GRAPHVIZ) { - new PcodeGraphVizExporter().export(asm, writer2); + new PcodeGraphVizExporter().exportAs12(asm, writer2); } else if (exportMode != ScriptExportMode.AS) { asm.getActionSourcePrefix(writer2); asm.getASMSource(exportMode, writer2, null); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java index 51278d1bd..6b6e68701 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/PcodeGraphVizExporter.java @@ -17,17 +17,26 @@ package com.jpexs.decompiler.flash.exporters.script; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.avm2.graph.AVM2Graph; +import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.ActionGraph; import com.jpexs.decompiler.flash.action.ActionGraphSource; import com.jpexs.decompiler.flash.action.ActionList; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter; import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.graph.Graph; import com.jpexs.decompiler.graph.GraphPart; +import com.jpexs.decompiler.graph.GraphSource; +import com.jpexs.decompiler.graph.ScopeStack; import com.jpexs.helpers.Helper; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -39,33 +48,49 @@ public class PcodeGraphVizExporter { private final String BLOCK_STYLE = "shape=\"box\""; - private String getBlockName(ActionList list, GraphPart part) { - long address = 0; - if (!list.isEmpty()) { - if (part.start >= list.size()) { - address = list.get(list.size() - 1).getAddress() + list.get(list.size() - 1).getBytesLength(); - } else { - address = list.get(part.start).getAddress(); - } - } - - return "loc" + Helper.formatAddress(address); + private String getBlockName(GraphSource list, GraphPart part) { + return "loc" + Helper.formatAddress(list.pos2adr(part.start, true)); } - private boolean isEndOfScript(ActionList list, GraphPart part) { + private boolean isEndOfScript(GraphSource list, GraphPart part) { if (part.start >= list.size()) { return true; } return false; } - public void export(ASMSource src, GraphTextWriter writer) throws InterruptedException { + private static void populateParts(GraphPart part, Set allParts) { + if (allParts.contains(part)) { + return; + } + allParts.add(part); + for (GraphPart p : part.nextParts) { + populateParts(p, allParts); + } + } + + public void exportAs12(ASMSource src, GraphTextWriter writer) throws InterruptedException { ActionList alist = src.getActions(); ActionGraph gr = new ActionGraph("", false, alist, new HashMap<>(), new HashMap<>(), new HashMap<>(), SWF.DEFAULT_VERSION); - List allBlocks = new ArrayList<>(); - List heads = gr.makeGraph(new ActionGraphSource("", false, alist, SWF.DEFAULT_VERSION, new HashMap<>(), new HashMap<>(), new HashMap<>()), allBlocks, new ArrayList<>()); + export(gr, writer); + } + + public void exportAs3(ABC abc, MethodBody body, GraphTextWriter writer) throws InterruptedException { + AVM2Graph gr = new AVM2Graph(body.getCode(), abc, body, false, -1, -1, new HashMap<>(), new ScopeStack(), new HashMap<>(), new ArrayList<>(), new HashMap<>(), body.getCode().visitCode(body)); + export(gr, writer); + } + + public void export(Graph graph, GraphTextWriter writer) throws InterruptedException { + graph.init(null); + GraphSource graphSource = graph.getGraphCode(); + Set allBlocks = new HashSet<>(); + List heads = graph.heads; + for (GraphPart h : heads) { + populateParts(h, allBlocks); + } + writer.append("digraph pcode {\r\n"); - Set knownAddresses = Action.getActionsAllRefs(alist); + Set knownAddresses = graphSource.getImportantAddresses(); int h = 0; for (GraphPart head : heads) { String headName = "start"; @@ -74,26 +99,24 @@ public class PcodeGraphVizExporter { headName = "start" + h; } writer.append(headName + " [shape=\"circle\"]\r\n"); - writer.append(headName + ":s -> " + getBlockName(alist, head) + ":n;\r\n"); + writer.append(headName + ":s -> " + getBlockName(graphSource, head) + ":n;\r\n"); } - for (int i = 0; i < allBlocks.size(); i++) { - - GraphPart part = allBlocks.get(i); - StringBuilder blkCode = new StringBuilder(); + for (GraphPart part : allBlocks) { + StringBuilder blkCodeBuilder = new StringBuilder(); for (int j = part.start; j <= part.end; j++) { - if (j < alist.size()) { - if (knownAddresses.contains(alist.get(j).getAddress())) { - blkCode.append("loc" + Helper.formatAddress(alist.get(j).getAddress())).append(":\\l"); + if (j < graphSource.size()) { + if (knownAddresses.contains(graphSource.get(j).getAddress())) { + blkCodeBuilder.append("loc").append(Helper.formatAddress(graphSource.get(j).getAddress())).append(":\r\n"); } - blkCode.append(alist.get(j).getASMSource(alist, knownAddresses, ScriptExportMode.PCODE)).append("\r\n"); + blkCodeBuilder.append(graphSource.insToString(j)).append("\r\n"); } } - String labelStr = blkCode.toString(); + String labelStr = blkCodeBuilder.toString(); labelStr = labelStr.replace("\"", "\\\""); labelStr = labelStr.replace("\r\n", "\\l"); - String partBlockName = getBlockName(alist, part); + String partBlockName = getBlockName(graphSource, part); String blkStyle = BLOCK_STYLE; - if (isEndOfScript(alist, part)) { + if (isEndOfScript(graphSource, part)) { blkStyle = "shape=\"circle\""; labelStr = "FINISH"; } @@ -107,7 +130,7 @@ public class PcodeGraphVizExporter { if (part.nextParts.size() == 2 && n == 1) { orientation = ""; } - String nextBlockName = getBlockName(alist, next); + String nextBlockName = getBlockName(graphSource, next); writer.append(partBlockName + orientation + " -> " + nextBlockName + ":n;\r\n"); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java index 915dd6f2f..b3f49e3ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/Graph.java @@ -80,6 +80,10 @@ public class Graph { private boolean debugGetLoops = false; private boolean debugPrintGraph = false; + public GraphSource getGraphCode() { + return code; + } + /** * Identify loop exits * diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java index 3bc7e66e3..7c01967b8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSource.java @@ -18,10 +18,12 @@ package com.jpexs.decompiler.graph; import com.jpexs.decompiler.flash.BaseLocalData; import com.jpexs.decompiler.flash.action.Action; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Set; /** * @@ -37,6 +39,10 @@ public abstract class GraphSource implements Serializable { public abstract List translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException; + public abstract Set getImportantAddresses(); + + public abstract String insToString(int pos); + private void visitCode(int ip, int lastIp, HashMap> refs, int endIp) throws InterruptedException { if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); @@ -109,4 +115,20 @@ public abstract class GraphSource implements Serializable { public abstract int adr2pos(long adr); public abstract long pos2adr(int pos); + + public long getAddressAfterCode() { + if (isEmpty()) { + return 0; + } + long lastAddr = pos2adr(size() - 1); + return lastAddr + get(size() - 1).getBytesLength(); + } + + public final long pos2adr(int pos, boolean allowPosAfterCode) { + if (pos == size() && allowPosAfterCode) { + return getAddressAfterCode(); + } + return pos2adr(pos); + } +; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSourceItem.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSourceItem.java index 5c1eb3a97..66bf74294 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSourceItem.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/graph/GraphSourceItem.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.graph; import com.jpexs.decompiler.flash.BaseLocalData; @@ -56,4 +57,6 @@ public interface GraphSourceItem extends Serializable, Cloneable { public int getLine(); public String getFile(); + + public abstract int getBytesLength(); } diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index 7b55af541..9d4bce04e 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -1015,16 +1015,20 @@ public class ActionPanel extends JPanel implements SearchListener