Debug (breakpoints, step) P-code for both AS1/2 and AS3

This commit is contained in:
Jindra Petřík
2015-12-06 06:29:08 +01:00
parent e2c299afa0
commit 0724b4a3f0
75 changed files with 670 additions and 264 deletions
@@ -459,10 +459,12 @@ public class CommandLineArgumentParser {
}
if (filter == null || filter.equals("enabledebugging")) {
out.println(" " + (cnt++) + ") -enabledebugging [-injectas3] <infile> <outfile>");
out.println(" " + (cnt++) + ") -enabledebugging [-injectas3|-generateswd] [-pcode] <infile> <outfile>");
out.println(" ...Enables debugging for <infile> and saves result to <outfile>");
out.println(" ...When optional -injectas3 parameter specified, debugfile and debugline instructions are injected into the code to match decompiled source.");
out.println(" ...WARNING: not everything works yet");
out.println(" ...-injectas3 (optional) causes debugfile and debugline instructions to be injected into the code to match decompiled/pcode source.");
out.println(" ...-generateswd (optional) parameter creates SWD file needed for AS1/2 debugging. for <outfile.swf>, <outfile.swd> is generated");
out.println(" ...-pcode (optional) parameter specified after -injectas3 or -generateswd causes lines to be handled as lines in P-code => All P-code lines are injected, etc.");
out.println(" ...WARNING: Injected/SWD script filenames may be different than from standard compiler");
}
printCmdLineUsageExamples(out, filter);
@@ -522,6 +524,7 @@ public class CommandLineArgumentParser {
if (filter == null || filter.equals("enabledebugging")) {
out.println("java -jar ffdec.jar -enabledebugging -injectas3 myas3file.swf myas3file_debug.swf");
out.println("java -jar ffdec.jar -enabledebugging -generateswd myas2file.swf myas2file_debug.swf");
exampleFound = true;
}
@@ -2788,7 +2791,16 @@ public class CommandLineArgumentParser {
}
boolean injectas3 = false;
boolean doPCode = false;
boolean generateSwd = false;
String file = args.pop();
if (file.equals("-generateswd")) {
if (args.size() < 2) {
badArguments("enabledebugging");
}
file = args.pop();
generateSwd = true;
}
if (file.equals("-injectas3")) {
if (args.size() < 2) {
badArguments("enabledebugging");
@@ -2796,16 +2808,53 @@ public class CommandLineArgumentParser {
file = args.pop();
injectas3 = true;
}
if (file.equals("-pcode")) {
if (args.size() < 2) {
badArguments("enabledebugging");
}
doPCode = true;
file = args.pop();
}
String outfile = args.pop();
try {
System.out.print("Working...");
FileInputStream fis = new FileInputStream(file);
SWF swf = new SWF(fis, Configuration.parallelSpeedUp.get());
fis.close();
swf.enableDebugging(injectas3, new File(outfile).getParentFile());
if (swf.isAS3()) {
swf.enableDebugging(injectas3, new File(outfile).getParentFile(), doPCode);
} else {
swf.enableDebugging();
}
FileOutputStream fos = new FileOutputStream(outfile);
swf.saveTo(fos);
fos.close();
if (!swf.isAS3()) {
if (generateSwd) {
fis = new FileInputStream(outfile);
swf = new SWF(fis, Configuration.parallelSpeedUp.get());
fis.close();
String outSwd = outfile;
if (outSwd.toLowerCase().endsWith(".swf")) {
outSwd = outSwd.substring(0, outSwd.length() - 4) + ".swd";
} else {
outSwd = outSwd + ".swd";
}
if (doPCode) {
if (!swf.generatePCodeSwdFile(new File(outSwd), new HashMap<>())) {
System.err.println("Generating SWD failed");
}
} else {
if (!swf.generateSwdFile(new File(outSwd), new HashMap<>())) {
System.err.println("Generating SWD failed");
}
}
}
} else {
if (generateSwd) {
System.err.println("WARNING: Cannot generate SWD for AS3 file");
}
}
System.out.println("OK");
} catch (FileNotFoundException ex) {
Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, "Cannot read " + file);
@@ -143,7 +143,7 @@ public class DebugPanel extends JPanel {
}
@Override
public void breakAt(String scriptName, int line) {
public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
View.execInEventDispatch(new Runnable() {
@Override
@@ -73,7 +73,11 @@ public class DebuggerHandler implements DebugConnectionListener {
private Map<Integer, String> modulePaths = new HashMap<>();
private Map<String, Integer> classToModule = new HashMap<>();
private Map<String, Integer> scriptToModule = new HashMap<>();
private Map<Integer, Integer> moduleToTraitIndex = new HashMap<>();
private Map<Integer, Integer> moduleToClassIndex = new HashMap<>();
private Map<Integer, Integer> moduleToMethodIndex = new HashMap<>();
private Map<String, Set<Integer>> toAddBPointMap = new HashMap<>();
@@ -127,7 +131,7 @@ public class DebuggerHandler implements DebugConnectionListener {
}
}
public synchronized Set<Integer> getBreakPoints(String scriptName) {
public synchronized Set<Integer> getBreakPoints(String scriptName, boolean onlyValid) {
Set<Integer> lines = new TreeSet<>();
if (confirmedPointMap.containsKey(scriptName)) {
lines.addAll(confirmedPointMap.get(scriptName));
@@ -135,6 +139,9 @@ public class DebuggerHandler implements DebugConnectionListener {
if (toAddBPointMap.containsKey(scriptName)) {
lines.addAll(toAddBPointMap.get(scriptName));
}
if (!onlyValid && invalidBreakPointMap.containsKey(scriptName)) {
lines.addAll(invalidBreakPointMap.get(scriptName));
}
return lines;
}
@@ -145,6 +152,12 @@ public class DebuggerHandler implements DebugConnectionListener {
}
toAddBPointMap.get(scriptName).addAll(confirmedPointMap.get(scriptName));
}
for (String scriptName : invalidBreakPointMap.keySet()) {
if (!toAddBPointMap.containsKey(scriptName)) {
toAddBPointMap.put(scriptName, new TreeSet<>());
}
toAddBPointMap.get(scriptName).addAll(invalidBreakPointMap.get(scriptName));
}
confirmedPointMap.clear();
invalidBreakPointMap.clear();
}
@@ -276,7 +289,7 @@ public class DebuggerHandler implements DebugConnectionListener {
public static interface BreakListener {
public void breakAt(String scriptName, int line);
public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex);
public void doContinue();
}
@@ -313,8 +326,8 @@ public class DebuggerHandler implements DebugConnectionListener {
}
public synchronized int moduleIdOf(String pack) {
if (classToModule.containsKey(pack)) {
return classToModule.get(pack);
if (scriptToModule.containsKey(pack)) {
return scriptToModule.get(pack);
}
return -1;
}
@@ -349,13 +362,17 @@ public class DebuggerHandler implements DebugConnectionListener {
toAddBPointMap.get(scriptName).addAll(confirmedPointMap.get(scriptName));
}
confirmedPointMap.clear();
for (String scriptName : invalidBreakPointMap.keySet()) {
if (!toAddBPointMap.containsKey(scriptName)) {
toAddBPointMap.put(scriptName, new TreeSet<>());
}
toAddBPointMap.get(scriptName).addAll(invalidBreakPointMap.get(scriptName));
}
invalidBreakPointMap.clear();
}
for (ConnectionListener l : clisteners) {
l.disconnected();
}
/*for (BreakListener l : breakListeners) {
l.breakAt();
}*/
}
public synchronized boolean isConnected() {
@@ -440,30 +457,36 @@ public class DebuggerHandler implements DebugConnectionListener {
}
modulePaths = new HashMap<>();
classToModule = new HashMap<>();
scriptToModule = new HashMap<>();
//Pattern patMainFrame = Pattern.compile("^Actions for Scene ([0-9]+): Frame ([0-9]+) of Layer Name .*$");
//Pattern patSymbol = Pattern.compile("^Actions for Symbol ([0-9]+): Frame ([0-9]+) of Layer Name .*$");
//Pattern patAS2 = Pattern.compile("^([^:]+): .*\\.as$");
Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$");
//"abc:" + abcIndex + ",script:" + scriptIndex + ",class:" + classIndex + ",trait:" + traitIndex + ",method:"
Pattern patAS3PCode = Pattern.compile("^#PCODE abc:([0-9]+),script:([0-9]+),class:(-?[0-9]+),trait:(-?[0-9]+),method:([0-9]+),body:([0-9]+);(.*)$");
for (int file : moduleNames.keySet()) {
String name = moduleNames.get(file);
String[] parts = name.split(";");
Matcher m;
/*if ((m = patMainFrame.matcher(name)).matches()) {
name = "\\frame_" + m.group(2) + "\\DoAction";
} else if ((m = patSymbol.matcher(name)).matches()) {
name = "\\DefineSprite(" + m.group(1) + ")\\frame_" + m.group(2) + "\\DoAction";
} else if ((m = patAS2.matcher(name)).matches()) {
name = "\\_Packages\\" + m.group(1).replace(".", "\\");
} else*/
if ((m = patAS3.matcher(name)).matches()) {
String clsName = m.group(3);
String pkg = m.group(2).replace("\\", ".");
name = DottedChain.parse(pkg).add(clsName).toString();
m = patAS3PCode.matcher(name);
if (m.matches()) {
moduleToClassIndex.put(file, Integer.parseInt(m.group(3)));
moduleToTraitIndex.put(file, Integer.parseInt(m.group(4)));
moduleToMethodIndex.put(file, Integer.parseInt(m.group(5)));
name = DottedChain.parse(pkg).add(clsName).toString();
name = "#PCODE abc:" + m.group(1) + ",body:" + m.group(6) + ";" + name;
} else {
name = DottedChain.parse(pkg).add(clsName).toString();
}
}
modulePaths.put(file, name);
classToModule.put(name, file);
scriptToModule.put(name, file);
}
//con.getMessage(InSetBreakpoint.class);
@@ -577,7 +600,11 @@ public class DebuggerHandler implements DebugConnectionListener {
frame = commands.getFrame(0);
for (BreakListener l : breakListeners) {
l.breakAt(newBreakScriptName, message.line);
l.breakAt(newBreakScriptName, message.line,
moduleToClassIndex.containsKey(message.file) ? moduleToClassIndex.get(message.file) : -1,
moduleToTraitIndex.containsKey(message.file) ? moduleToTraitIndex.get(message.file) : -1,
moduleToMethodIndex.containsKey(message.file) ? moduleToMethodIndex.get(message.file) : -1
);
}
} catch (IOException ex) {
@@ -654,9 +681,14 @@ public class DebuggerHandler implements DebugConnectionListener {
markBreakPointInvalid(scriptName, line);
}
}
} else {
for (int line : toAddBPointMap.get(scriptName)) {
markBreakPointInvalid(scriptName, line);
}
}
}
toAddBPointMap.clear();
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "sending bps finished");
+28 -9
View File
@@ -81,6 +81,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -151,6 +152,8 @@ public class Main {
private static boolean runProcessDebug;
private static boolean runProcessDebugPCode;
private static boolean inited = false;
private static File runTempFile;
@@ -180,6 +183,10 @@ public class Main {
return runProcess != null && runProcessDebug;
}
public static synchronized boolean isDebugPCode() {
return runProcessDebugPCode;
}
public static synchronized boolean isDebugConnected() {
return getDebugHandler().isConnected();
}
@@ -326,7 +333,7 @@ public class Main {
}
}
public static void runDebug(SWF swf) {
public static void runDebug(SWF swf, final boolean doPCode) {
String flashVars = "";//key=val&key2=val2
String playerLocation = Configuration.playerDebugLocation.get();
if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) {
@@ -344,6 +351,7 @@ public class Main {
} catch (Exception ex) {
}
if (tempFile != null) {
final File fTempFile = tempFile;
CancellableWorker instrumentWorker = new CancellableWorker() {
@@ -364,7 +372,7 @@ public class Main {
if (instrSWF.isAS3() && Configuration.autoOpenLoadedSWFs.get()) {
DebuggerTools.injectDebugLoader(instrSWF);
}
instrSWF.enableDebugging(true, new File("."));
instrSWF.enableDebugging(true, new File("."), true, doPCode);
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) {
instrSWF.saveTo(fos);
}
@@ -378,8 +386,18 @@ public class Main {
Logger.getLogger(MainFrameMenu.class.getName()).log(Level.SEVERE, null, ex);
}
if (instrSWF != null) {
File swdFile = new File(fTempFile.getAbsolutePath().replace(".swf", ".swd"));
instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true));
String swfFileName = fTempFile.getAbsolutePath();
if (swfFileName.toLowerCase().endsWith(".swf")) {
swfFileName = swfFileName.substring(0, swfFileName.length() - 4) + ".swd";
} else {
swfFileName = swfFileName + ".swd";
}
File swdFile = new File(swfFileName);
if (doPCode) {
instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true));
} else {
instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true));
}
}
}
}
@@ -396,6 +414,7 @@ public class Main {
synchronized (Main.class) {
runTempFile = fTempFile;
runProcessDebug = true;
runProcessDebugPCode = doPCode;
}
Main.stopWork();
Main.startDebugger();
@@ -450,8 +469,8 @@ public class Main {
return getDebugHandler().getAllBreakPoints(validOnly);
}
public synchronized static Set<Integer> getScriptBreakPoints(String pack) {
return getDebugHandler().getBreakPoints(pack);
public synchronized static Set<Integer> getScriptBreakPoints(String pack, boolean onlyValid) {
return getDebugHandler().getBreakPoints(pack, onlyValid);
}
public static DebuggerHandler getDebugHandler() {
@@ -1349,12 +1368,12 @@ public class Main {
}
@Override
public void breakAt(String scriptName, int line) {
public void breakAt(String scriptName, int line, final int classIndex, final int traitIndex, final int methodIndex) {
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
mainFrame.getPanel().gotoClassLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line);
mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex);
}
});
}
@@ -1368,7 +1387,7 @@ public class Main {
@Override
public void disconnected() {
Main.mainFrame.getPanel().refreshBreakPoints();
}
});
flashDebugger.addConnectionListener(debugHandler);
@@ -701,6 +701,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
setMenuEnabled("/file/start/run", swfSelected && !isRunningOrDebugging);
setMenuEnabled("/file/start/debug", swfSelected && !isRunningOrDebugging);
setMenuEnabled("/file/start/debugpcode", swfSelected && !isRunningOrDebugging);
setMenuEnabled("/file/start/stop", isRunningOrDebugging);
setMenuEnabled("/debugging/debug/stop", isRunningOrDebugging); //same as previous
@@ -779,6 +780,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
addMenuItem("/file/start/run", translate("menu.file.start.run"), "play32", this::runActionPerformed, PRIORITY_TOP, null, true, new HotKey("F6"), false);
addMenuItem("/file/start/debug", translate("menu.file.start.debug"), "debug32", this::debugActionPerformed, PRIORITY_TOP, null, true, new HotKey("CTRL+F5"), false);
addMenuItem("/file/start/stop", translate("menu.file.start.stop"), "stop32", this::stopActionPerformed, PRIORITY_TOP, null, true, null, false);
addMenuItem("/file/start/debugpcode", translate("menu.file.start.debugpcode"), "debug32", this::debugPCodeActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
finishMenu("/file/start");
addMenuItem("/file/view", translate("menu.view"), null, null, 0, null, false, null, false);
@@ -1093,9 +1095,13 @@ public abstract class MainFrameMenu implements MenuBuilder {
}
public boolean debugActionPerformed(ActionEvent evt) {
Main.runDebug(swf);
Main.runDebug(swf, false);
return true;
}
public boolean debugPCodeActionPerformed(ActionEvent evt) {
Main.runDebug(swf, true);
return true;
}
public boolean stopActionPerformed(ActionEvent evt) {
@@ -1533,12 +1533,30 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
}
public void gotoClassLine(SWF swf, String cls, int line) {
gotoScriptName(swf, cls);
public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
gotoScriptName(swf, scriptName);
if (abcPanel != null) {
abcPanel.decompiledTextArea.gotoLine(line);
if (Main.isDebugPCode()) {
if (classIndex != -1) {
boolean classChanged = false;
if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) {
abcPanel.decompiledTextArea.setClassIndex(classIndex);
classChanged = true;
}
if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) {
abcPanel.decompiledTextArea.gotoTrait(traitIndex);
}
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line);
} else {
abcPanel.decompiledTextArea.gotoLine(line);
}
} else if (actionPanel != null) {
actionPanel.decompiledEditor.gotoLine(line);
if (Main.isDebugPCode()) {
actionPanel.editor.gotoLine(line);
} else {
actionPanel.decompiledEditor.gotoLine(line);
}
}
refreshBreakPoints();
@@ -1547,6 +1565,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
public void refreshBreakPoints() {
if (abcPanel != null) {
abcPanel.decompiledTextArea.refreshMarkers();
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.refreshMarkers();
}
if (actionPanel != null) {
actionPanel.decompiledEditor.refreshMarkers();
actionPanel.editor.refreshMarkers();
}
}
/*
@@ -1569,15 +1592,24 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
return;
}
if (swf.isAS3()) {
String rawScriptName = scriptName;
if (rawScriptName.startsWith("#PCODE ")) {
rawScriptName = rawScriptName.substring(rawScriptName.indexOf(";") + 1);
}
List<ABCContainerTag> abcList = swf.getAbcList();
if (!abcList.isEmpty()) {
ABCPanel abcPanel = getABCPanel();
abcPanel.setAbc(abcList.get(0).getABC());
abcPanel.hilightScript(swf, scriptName);
abcPanel.hilightScript(swf, rawScriptName);
}
} else {
if (actionPanel != null && asms.containsKey(scriptName)) {
actionPanel.setSource(asms.get(scriptName), true);
String rawScriptName = scriptName;
if (rawScriptName.startsWith("#PCODE ")) {
rawScriptName = rawScriptName.substring("#PCODE ".length());
}
if (actionPanel != null && asms.containsKey(rawScriptName)) {
actionPanel.setSource(asms.get(rawScriptName), true);
}
}
}
@@ -2341,8 +2373,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
boolean isStatic = decompiledTextArea.getIsStatic();
abc.bodies.get(bi).deobfuscate(level, t, scriptIndex, classIndex, isStatic, ""/*FIXME*/);
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(bi, abc, t, abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getScriptIndex());
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setBodyIndex(decompiledTextArea.getScriptLeaf().getPathScriptName(), bi, abc, t, abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getScriptIndex());
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "Deobfuscation error", ex);
@@ -2795,9 +2826,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
public void clearDebuggerColors() {
if (abcPanel != null) {
abcPanel.decompiledTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clearDebuggerColors();
}
if (actionPanel != null) {
actionPanel.decompiledEditor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
actionPanel.editor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
}
}
@@ -29,11 +29,13 @@ import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.gui.GraphDialog;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.gui.editor.DebuggableEditorPane;
import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane;
import com.jpexs.decompiler.flash.helpers.HighlightedText;
import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.flash.helpers.hilight.Highlighting;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.graph.ScopeStack;
import com.jpexs.helpers.Helper;
@@ -47,7 +49,7 @@ import java.util.logging.Logger;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretListener {
public class ASMSourceEditorPane extends DebuggableEditorPane implements CaretListener {
public ABC abc;
@@ -79,6 +81,8 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi
private Trait trait;
private int firstInstrLine = -1;
public ABCPanel getAbcPanel() {
return decompiledEditor.getAbcPanel();
}
@@ -172,7 +176,7 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi
return super.getName();
}
public void setBodyIndex(int bodyIndex, ABC abc, String name, Trait trait, int scriptIndex) {
public void setBodyIndex(String scriptPathName, int bodyIndex, ABC abc, String name, Trait trait, int scriptIndex) {
this.bodyIndex = bodyIndex;
this.abc = abc;
this.name = name;
@@ -184,6 +188,16 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi
textWithHex = null;
textNoHex = null;
textHexOnly = null;
List<ABCContainerTag> cs = abc.getAbcTags();
int abcIndex = -1;
for (int i = 0; i < cs.size(); i++) {
if (cs.get(i).getABC() == abc) {
abcIndex = i;
break;
}
}
String aname = "#PCODE abc:" + abcIndex + ",body:" + bodyIndex + ";" + scriptPathName;
setScriptName(aname);
setHex(exportMode, true);
}
@@ -266,13 +280,34 @@ public class ASMSourceEditorPane extends LineMarkedEditorPane implements CaretLi
setCaretPosition(0);
}
public void setText(HighlightedText HighlightedText) {
disassembledHilights = HighlightedText.instructionHilights;
specialHilights = HighlightedText.specialHilights;
super.setText(HighlightedText.text);
public void setText(HighlightedText highlightedText) {
disassembledHilights = highlightedText.instructionHilights;
if (!disassembledHilights.isEmpty()) {
int firstPos = disassembledHilights.get(0).startPos;
String txt = highlightedText.text;
txt = txt.replace("\r", "");
int line = 0;
for (int i = 0; i < firstPos; i++) {
if (txt.charAt(i) == '\n') {
line++;
}
}
firstInstrLine = line;
}
specialHilights = highlightedText.specialHilights;
super.setText(highlightedText.text);
setCaretPosition(0);
}
@Override
public int firstLineOffset() {
return firstInstrLine;
}
public void gotoInstrLine(int line) {
super.gotoLine(firstInstrLine + line);
}
public void clear() {
setText("");
bodyIndex = -1;
@@ -221,7 +221,7 @@ public class DecompiledEditorPane extends DebuggableEditorPane implements CaretL
abcPanel.detailPanel.showCard(DetailPanel.METHOD_TRAIT_CARD, trait);
MethodCodePanel methodCodePanel = abcPanel.detailPanel.methodTraitPanel.methodCodePanel;
if (reset || (methodCodePanel.getBodyIndex() != bi)) {
methodCodePanel.setBodyIndex(bi, abc, name, trait, script.scriptIndex);
methodCodePanel.setBodyIndex(scriptName, bi, abc, name, trait, script.scriptIndex);
abcPanel.detailPanel.setEditMode(false);
this.isStatic = isStatic;
}
@@ -50,6 +50,18 @@ public class MethodCodePanel extends JPanel {
private final JToggleButton hexOnlyButton;
public void refreshMarkers() {
sourceTextArea.refreshMarkers();
}
public void clearDebuggerColors() {
sourceTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
}
public void gotoInstrLine(int line) {
sourceTextArea.gotoInstrLine(line);
}
public void focusEditor() {
sourceTextArea.requestFocusInWindow();
}
@@ -74,12 +86,12 @@ public class MethodCodePanel extends JPanel {
sourceTextArea.hilighSpecial(type, specialValue);
}
public void setBodyIndex(int bodyIndex, ABC abc, Trait trait, int scriptIndex) {
sourceTextArea.setBodyIndex(bodyIndex, abc, sourceTextArea.getName(), trait, scriptIndex);
public void setBodyIndex(String scriptPathName, int bodyIndex, ABC abc, Trait trait, int scriptIndex) {
sourceTextArea.setBodyIndex(scriptPathName, bodyIndex, abc, sourceTextArea.getName(), trait, scriptIndex);
}
public void setBodyIndex(int bodyIndex, ABC abc, String name, Trait trait, int scriptIndex) {
sourceTextArea.setBodyIndex(bodyIndex, abc, name, trait, scriptIndex);
public void setBodyIndex(String scriptPathName, int bodyIndex, ABC abc, String name, Trait trait, int scriptIndex) {
sourceTextArea.setBodyIndex(scriptPathName, bodyIndex, abc, name, trait, scriptIndex);
}
public int getBodyIndex() {
@@ -103,7 +103,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
private MainPanel mainPanel;
public LineMarkedEditorPane editor;
public DebuggableEditorPane editor;
public DebuggableEditorPane decompiledEditor;
@@ -182,26 +182,6 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
srcConstants = null;
}
/*public void refreshMarkers() {
decompiledEditor.removeColorMarkerOnAllLines(FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR, PRIORITY_BREAKPOINT);
decompiledEditor.removeColorMarkerOnAllLines(FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR, PRIORITY_INVALID_BREAKPOINT);
decompiledEditor.removeColorMarkerOnAllLines(FG_IP_COLOR, BG_IP_COLOR, PRIORITY_IP);
Set<Integer> bkptLines = Main.getScriptBreakPoints(sc);
for (int line : bkptLines) {
if (Main.isBreakPointValid(lastASM, line)) {
decompiledEditor.addColorMarker(line, FG_BREAKPOINT_COLOR, BG_BREAKPOINT_COLOR, PRIORITY_BREAKPOINT);
} else {
decompiledEditor.addColorMarker(line, FG_INVALID_BREAKPOINT_COLOR, BG_INVALID_BREAKPOINT_COLOR, PRIORITY_INVALID_BREAKPOINT);
}
}
int ip = Main.getIp(lastASM);
String ipPath = Main.getIpClass();
if (ip > 0 && ipPath != null && lastASM.getSwf().getASMs(false).get(ipPath) == lastASM) {
decompiledEditor.addColorMarker(ip, FG_IP_COLOR, BG_IP_COLOR, PRIORITY_IP);
}
}*/
public String getStringUnderCursor() {
int pos = decompiledEditor.getCaretPosition();
@@ -315,16 +295,17 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
});
}
private void setEditorText(final String text, final String contentType) {
private void setEditorText(final String scriptName, final String text, final String contentType) {
View.execInEventDispatch(() -> {
ignoreCarret = true;
editor.setScriptName("#PCODE " + scriptName);
editor.changeContentType(contentType);
editor.setText(text);
ignoreCarret = false;
});
}
private void setText(final HighlightedText text, final String contentType) {
private void setText(final HighlightedText text, final String contentType, final String scriptName) {
View.execInEventDispatch(() -> {
int pos = editor.getCaretPosition();
Highlighting lastH = null;
@@ -337,7 +318,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
Long offset = lastH == null ? 0 : lastH.getProperties().offset;
disassembledHilights = text.instructionHilights;
String stripped = text.text;
setEditorText(stripped, contentType);
setEditorText(scriptName, stripped, contentType);
Highlighting h = Highlighting.searchOffset(disassembledHilights, offset);
if (h != null) {
if (h.startPos <= editor.getDocument().getLength()) {
@@ -361,21 +342,21 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
return new HighlightedText(writer);
}
public void setHex(ScriptExportMode exportMode) {
public void setHex(ScriptExportMode exportMode, String scriptName) {
switch (exportMode) {
case PCODE:
if (srcNoHex == null) {
srcNoHex = getHighlightedText(exportMode);
}
setText(srcNoHex, "text/flasm");
setText(srcNoHex, "text/flasm", scriptName);
break;
case PCODE_HEX:
if (srcWithHex == null) {
srcWithHex = getHighlightedText(exportMode);
}
setText(srcWithHex, "text/flasm");
setText(srcWithHex, "text/flasm", scriptName);
break;
case HEX:
if (srcHexOnly == null) {
@@ -384,14 +365,14 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
srcHexOnly = new HighlightedText(writer);
}
setText(srcHexOnly, "text/plain");
setText(srcHexOnly, "text/plain", scriptName);
break;
case CONSTANTS:
if (srcConstants == null) {
srcConstants = getHighlightedText(exportMode);
}
setText(srcConstants, "text/plain");
setText(srcConstants, "text/plain", scriptName);
break;
default:
throw new Error("Export mode not supported: " + exportMode);
@@ -413,7 +394,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
percent = newpercent;
this.phase = phase;
// todo: honfika: it is very slow to show every percent
setEditorText("; " + AppStrings.translate("work.disassembling") + " - " + phase + " " + percent + "%...", "text/flasm");
setEditorText("-", "; " + AppStrings.translate("work.disassembling") + " - " + phase + " " + percent + "%...", "text/flasm");
}
}
@@ -449,7 +430,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
@Override
protected Void doInBackground() throws Exception {
setEditorText("; " + AppStrings.translate("work.disassembling") + "...", "text/flasm");
setEditorText(asm.getScriptName(), "; " + AppStrings.translate("work.disassembling") + "...", "text/flasm");
if (Configuration.decompile.get()) {
setDecompiledText("-", "// " + AppStrings.translate("work.waitingfordissasembly") + "...");
} else {
@@ -465,7 +446,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
srcNoHex = null;
srcHexOnly = null;
srcConstants = null;
setHex(getExportMode());
setHex(getExportMode(), asm.getScriptName());
if (Configuration.decompile.get()) {
setDecompiledText("-", "// " + AppStrings.translate("work.decompiling") + "...");
if (!useCache) {
@@ -498,7 +479,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
try {
get();
} catch (CancellationException ex) {
setEditorText("; " + AppStrings.translate("work.canceled"), "text/flasm");
setEditorText("-", "; " + AppStrings.translate("work.canceled"), "text/flasm");
} catch (Exception ex) {
setDecompiledText("-", "// " + AppStrings.translate("decompilationError") + ": " + ex);
}
@@ -566,7 +547,7 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
public ActionPanel(MainPanel mainPanel) {
this.mainPanel = mainPanel;
editor = new LineMarkedEditorPane();
editor = new DebuggableEditorPane();
editor.setEditable(false);
decompiledEditor = new DebuggableEditorPane();
decompiledEditor.setEditable(false);
@@ -825,11 +806,11 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
View.execInEventDispatch(() -> {
if (val) {
if (hexOnlyButton.isSelected()) {
setHex(ScriptExportMode.HEX);
setHex(ScriptExportMode.HEX, src.getScriptName());
} else if (constantsViewButton.isSelected()) {
setHex(ScriptExportMode.CONSTANTS);
setHex(ScriptExportMode.CONSTANTS, src.getScriptName());
} else {
setHex(ScriptExportMode.PCODE);
setHex(ScriptExportMode.PCODE, src.getScriptName());
}
}
@@ -900,15 +881,15 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
}
private void hexButtonActionPerformed(ActionEvent evt) {
setHex(getExportMode());
setHex(getExportMode(), src.getScriptName());
}
private void hexOnlyButtonActionPerformed(ActionEvent evt) {
setHex(getExportMode());
setHex(getExportMode(), src.getScriptName());
}
private void constantsViewButtonActionPerformed(ActionEvent evt) {
setHex(getExportMode());
setHex(getExportMode(), src.getScriptName());
}
private void resolveConstantsButtonActionPerformed(ActionEvent evt) {
@@ -918,12 +899,12 @@ public class ActionPanel extends JPanel implements SearchListener<ActionSearchRe
srcWithHex = null;
srcNoHex = null;
// srcHexOnly = null; is not needed since it does not contains the resolved constant names
setHex(getExportMode());
setHex(getExportMode(), src.getScriptName());
}
private void cancelActionButtonActionPerformed(ActionEvent evt) {
setEditMode(false);
setHex(getExportMode());
setHex(getExportMode(), src.getScriptName());
}
private void saveActionButtonActionPerformed(ActionEvent evt) {
@@ -75,10 +75,10 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
if (scriptName == null) {
return;
}
boolean on = Main.toggleBreakPoint(scriptName, line);
boolean on = Main.toggleBreakPoint(scriptName, line - firstLineOffset());
removeColorMarker(line, INVALID_BREAKPOINT_MARKER);
if (on) {
if (Main.isBreakPointValid(scriptName, line)) {
if (Main.isBreakPointValid(scriptName, line - firstLineOffset())) {
addColorMarker(line, BREAKPOINT_MARKER);
} else {
addColorMarker(line, INVALID_BREAKPOINT_MARKER);
@@ -98,19 +98,19 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
return;
}
Set<Integer> bkptLines = Main.getScriptBreakPoints(scriptName);
Set<Integer> bkptLines = Main.getScriptBreakPoints(scriptName, false);
for (int line : bkptLines) {
if (Main.isBreakPointValid(scriptName, line)) {
addColorMarker(line, BREAKPOINT_MARKER);
addColorMarker(line + firstLineOffset(), BREAKPOINT_MARKER);
} else {
addColorMarker(line, INVALID_BREAKPOINT_MARKER);
addColorMarker(line + firstLineOffset(), INVALID_BREAKPOINT_MARKER);
}
}
int ip = Main.getIp(scriptName);
String ipPath = Main.getIpClass();
if (ip > 0 && ipPath != null && ipPath.equals(scriptName)) {
addColorMarker(ip, IP_MARKER);
addColorMarker(ip + firstLineOffset(), IP_MARKER);
}
}
@@ -159,6 +159,7 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan
}
public boolean hasColorMarker(int line, LineMarker lm) {
line -= firstLineOffset();
if (lineMarkers.containsKey(line)) {
return lineMarkers.get(line).contains(lm);
}
@@ -166,6 +167,7 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan
}
public void removeColorMarker(int line, LineMarker lm) {
line -= firstLineOffset();
if (lineMarkers.containsKey(line)) {
lineMarkers.get(line).remove(lm);
}
@@ -174,15 +176,20 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan
public void removeColorMarkerOnAllLines(LineMarker lm) {
for (int line : lineMarkers.keySet()) {
line += firstLineOffset();
removeColorMarker(line, lm);
}
}
public int firstLineOffset() {
return 0;
}
public void toggleColorMarker(int line, LineMarker lm) {
if (!lineMarkers.containsKey(line)) {
if (!lineMarkers.containsKey(line - firstLineOffset())) {
addColorMarker(line, lm);
} else {
if (lineMarkers.get(line).contains(lm)) {
if (lineMarkers.get(line - firstLineOffset()).contains(lm)) {
removeColorMarker(line, lm);
} else {
addColorMarker(line, lm);
@@ -192,6 +199,7 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan
}
public void addColorMarker(int line, LineMarker lm) {
line -= firstLineOffset();
if (!lineMarkers.containsKey(line)) {
lineMarkers.put(line, Collections.synchronizedSortedSet(new TreeSet<>()));
}
@@ -621,16 +629,21 @@ public class LineMarkedEditorPane extends UndoFixedEditorPane implements LinkHan
continue;
}
g.setColor(lastMarker.getBgColor());
line += firstLineOffset();
g.fillRect(0, d + lh * (line - 1), getWidth(), lh);
}
super.paint(g);
for (int line : lineMarkers.keySet()) {
SortedSet<LineMarker> cs = lineMarkers.get(line);
if (cs.isEmpty()) {
continue;
}
line += firstLineOffset();
Reference<Integer> lineStart = new Reference<>(0);
Reference<Integer> lineEnd = new Reference<>(0);
getLineBounds(line, lineStart, lineEnd);
FgPainter fgp = cs.first().getForegroundPainter();
if (fgp != null) {
@@ -692,4 +692,6 @@ debug.break.reason.fault = (Fault)
debug.break.reason.stopRequest = (Stop request)
debug.break.reason.step = (Step)
debug.break.reason.halt = (Halt)
debug.break.reason.scriptLoaded = (Script loaded)
debug.break.reason.scriptLoaded = (Script loaded)
menu.file.start.debugpcode = Debug P-code