More universal GraphExporter

Log exceptions on copy to clipboard graph
This commit is contained in:
Jindra Petřík
2018-02-04 10:37:09 +01:00
parent 7f7945e9c2
commit cdd1acb1f9
12 changed files with 148 additions and 38 deletions

View File

@@ -303,6 +303,16 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
public long pos2adr(int pos) {
return code.pos2adr(pos);
}
@Override
public Set<Long> 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++) {

View File

@@ -266,6 +266,16 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
public long pos2adr(int pos) {
return code.pos2adr(pos);
}
@Override
public Set<Long> 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++) {

View File

@@ -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<Long> 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();

View File

@@ -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++) {

View File

@@ -347,6 +347,7 @@ public abstract class Action implements GraphSourceItem {
*
* @return Length
*/
@Override
public final int getBytesLength() {
return getContentBytesLength() + (actionCode >= 0x80 ? 3 : 1);
}

View File

@@ -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<Action> actions;
private final ActionList actions;
public int version;
@@ -55,7 +58,7 @@ public class ActionGraphSource extends GraphSource {
}
public ActionGraphSource(String path, boolean insideDoInitAction, List<Action> actions, int version, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> 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<Long> 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();

View File

@@ -100,7 +100,7 @@ public class ExportScriptTask implements Callable<File> {
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);

View File

@@ -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<GraphPart> 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<GraphPart> allBlocks = new ArrayList<>();
List<GraphPart> 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<GraphPart> allBlocks = new HashSet<>();
List<GraphPart> heads = graph.heads;
for (GraphPart h : heads) {
populateParts(h, allBlocks);
}
writer.append("digraph pcode {\r\n");
Set<Long> knownAddresses = Action.getActionsAllRefs(alist);
Set<Long> 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");
}
}

View File

@@ -80,6 +80,10 @@ public class Graph {
private boolean debugGetLoops = false;
private boolean debugPrintGraph = false;
public GraphSource getGraphCode() {
return code;
}
/**
* Identify loop exits
*

View File

@@ -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<GraphTargetItem> translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException;
public abstract Set<Long> getImportantAddresses();
public abstract String insToString(int pos);
private void visitCode(int ip, int lastIp, HashMap<Integer, List<Integer>> 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);
}
;
}

View File

@@ -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();
}