mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-08 07:05:06 +00:00
More universal GraphExporter
Log exceptions on copy to clipboard graph
This commit is contained in:
@@ -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++) {
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -347,6 +347,7 @@ public abstract class Action implements GraphSourceItem {
|
||||
*
|
||||
* @return Length
|
||||
*/
|
||||
@Override
|
||||
public final int getBytesLength() {
|
||||
return getContentBytesLength() + (actionCode >= 0x80 ? 3 : 1);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,10 @@ public class Graph {
|
||||
private boolean debugGetLoops = false;
|
||||
private boolean debugPrintGraph = false;
|
||||
|
||||
public GraphSource getGraphCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identify loop exits
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user