diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index f855e3ef0..897951e94 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -21,6 +21,9 @@ import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; import com.jpexs.decompiler.flash.abc.avm2.ConvertException; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instructions; +import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugFileIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugIns; +import com.jpexs.decompiler.flash.abc.avm2.instructions.debug.DebugLineIns; import com.jpexs.decompiler.flash.abc.types.ConvertData; import com.jpexs.decompiler.flash.abc.types.MethodBody; import com.jpexs.decompiler.flash.abc.types.Multiname; @@ -299,10 +302,7 @@ public class ScriptPack extends AS3ClassTreeItem { if (scriptIndex != other.scriptIndex) { return false; } - if (!Objects.equals(path, other.path)) { - return false; - } - return true; + return Objects.equals(path, other.path); } @Override @@ -318,6 +318,7 @@ public class ScriptPack extends AS3ClassTreeItem { */ public void injectDebugInfo(File directoryPath) { Map> bodyToPosToLine = new HashMap<>(); + Set lonelyBody = new HashSet<>(); try { CachedDecompilation decompiled = SWF.getCached(this); int line = 1; @@ -328,48 +329,55 @@ public class ScriptPack extends AS3ClassTreeItem { line++; } Highlighting cls = Highlighting.searchPos(decompiled.classHilights, i); - if (cls == null) { - continue; - } + /*if (cls == null) { + continue; + }*/ Highlighting trt = Highlighting.searchPos(decompiled.traitHilights, i); - if (trt == null) { - continue; - } + /*if (trt == null) { + continue; + }*/ Highlighting method = Highlighting.searchPos(decompiled.methodHilights, i); if (method == null) { continue; } Highlighting instr = Highlighting.searchPos(decompiled.instructionHilights, i); - if (instr == null) { - continue; - } - int classIndex = (int) cls.getProperties().index; + /*if (instr == null) { + continue; + }*/ + int classIndex = cls == null ? -1 : (int) cls.getProperties().index; int methodIndex = (int) method.getProperties().index; int bodyIndex = abc.findBodyIndex(methodIndex); if (bodyIndex == -1) { continue; } - long instrOffset = instr.getProperties().offset; - int traitIndex = (int) trt.getProperties().index; - - Trait trait = abc.findTraitByTraitId(classIndex, traitIndex); - if (((trait instanceof TraitMethodGetterSetter) && (((TraitMethodGetterSetter) trait).method_info != methodIndex)) - || ((trait instanceof TraitFunction) && (((TraitFunction) trait).method_info != methodIndex))) { - continue; //inner anonymous function - ignore. TODO: make work - } int pos = -1; - try { - pos = abc.bodies.get(bodyIndex).getCode().adr2pos(instrOffset); - } catch (ConvertException cex) { - //ignore + if (instr != null) { + long instrOffset = instr.getProperties().offset; + if (trt != null && cls != null) { + int traitIndex = (int) trt.getProperties().index; + + Trait trait = abc.findTraitByTraitId(classIndex, traitIndex); + if (((trait instanceof TraitMethodGetterSetter) && (((TraitMethodGetterSetter) trait).method_info != methodIndex)) + || ((trait instanceof TraitFunction) && (((TraitFunction) trait).method_info != methodIndex))) { + continue; //inner anonymous function - ignore. TODO: make work + } + } + + try { + pos = abc.bodies.get(bodyIndex).getCode().adr2pos(instrOffset); + } catch (ConvertException cex) { + //ignore + } + if (pos == -1) { + continue; + } + if (!bodyToPosToLine.containsKey(bodyIndex)) { + bodyToPosToLine.put(bodyIndex, new HashMap<>()); + } + bodyToPosToLine.get(bodyIndex).put(pos, line); + } else { + lonelyBody.add(bodyIndex); } - if (pos == -1) { - continue; - } - if (!bodyToPosToLine.containsKey(bodyIndex)) { - bodyToPosToLine.put(bodyIndex, new HashMap<>()); - } - bodyToPosToLine.get(bodyIndex).put(pos, line); } } catch (InterruptedException ex) { @@ -381,8 +389,45 @@ public class ScriptPack extends AS3ClassTreeItem { String cls = path.className; String filename = new File(directoryPath, path.packageStr.toFilePath()) + ";" + pkg.replace(".", File.separator) + ";" + cls + ".as"; + //Remove debug info from lonely bodies + for (int bodyIndex : lonelyBody) { + if (!bodyToPosToLine.keySet().contains(bodyIndex)) { + MethodBody b = abc.bodies.get(bodyIndex); + List code = b.getCode().code; + for (int i = 0; i < code.size(); i++) { + AVM2Instruction ins = code.get(i); + if (ins.definition instanceof DebugLineIns) { + b.removeInstruction(i); + i--; + } else if (ins.definition instanceof DebugFileIns) { + b.removeInstruction(i); + i--; + } else if (ins.definition instanceof DebugIns) { + b.removeInstruction(i); + i--; + } + } + b.setModified(); + } + } + for (int bodyIndex : bodyToPosToLine.keySet()) { + List delIns = new ArrayList<>(); + MethodBody b = abc.bodies.get(bodyIndex); + List code = b.getCode().code; + //add old debug instructions to TOREMOVE list + for (AVM2Instruction ins : code) { + if (ins.definition instanceof DebugLineIns) { + delIns.add(ins); + } + if (ins.definition instanceof DebugFileIns) { + delIns.add(ins); + } + if (ins.definition instanceof DebugIns) { + delIns.add(ins); + } + } b.insertInstruction(0, new AVM2Instruction(0, AVM2Instructions.DebugFile, new int[]{abc.constants.getStringId(filename, true)}), true); List pos = new ArrayList<>(bodyToPosToLine.get(bodyIndex).keySet()); Collections.sort(pos); @@ -394,9 +439,21 @@ public class ScriptPack extends AS3ClassTreeItem { continue; } addedLines.add(line); - Logger.getLogger(ScriptPack.class.getName()).log(Level.WARNING, "Script " + path + ": Insert debugline(" + line + ") at pos " + i + " to body " + bodyIndex); + Logger.getLogger(ScriptPack.class.getName()).log(Level.FINE, "Script " + path + ": Insert debugline(" + line + ") at pos " + i + " to body " + bodyIndex); b.insertInstruction(i, new AVM2Instruction(0, AVM2Instructions.DebugLine, new int[]{line})); } + //remove old debug instructions + for (int i = 0; i < code.size(); i++) { + AVM2Instruction ins = code.get(i); + for (AVM2Instruction d : delIns) { + if (ins == d) { + b.removeInstruction(i); + i--; + break; + } + } + } + b.setModified(); } diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index d9055876d..11bce10e7 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -21,8 +21,10 @@ import com.jpexs.debugger.flash.DebugMessageListener; import com.jpexs.debugger.flash.Debugger; import com.jpexs.debugger.flash.DebuggerCommands; import com.jpexs.debugger.flash.DebuggerConnection; +import com.jpexs.debugger.flash.InDebuggerMessage; import com.jpexs.debugger.flash.messages.in.InAskBreakpoints; import com.jpexs.debugger.flash.messages.in.InBreakAt; +import com.jpexs.debugger.flash.messages.in.InContinue; import com.jpexs.debugger.flash.messages.in.InNumScript; import com.jpexs.debugger.flash.messages.in.InScript; import com.jpexs.debugger.flash.messages.in.InSwfInfo; @@ -45,6 +47,11 @@ public class DebuggerHandler implements DebugConnectionListener { private boolean connected = false; private DebuggerCommands commands = null; private List swfs = new ArrayList<>(); + private boolean paused = true; + + public synchronized boolean isPaused() { + return paused; + } public List getSwfs() { return swfs; @@ -61,6 +68,12 @@ public class DebuggerHandler implements DebugConnectionListener { @Override public void connected(DebuggerConnection con) { + synchronized (DebuggerHandler.this) { + paused = true; + } + + Main.getMainFrame().getPanel().updateMenu(); + Level level = Level.FINER; Logger rootLog = Logger.getLogger(Debugger.class.getName()); @@ -103,10 +116,24 @@ public class DebuggerHandler implements DebugConnectionListener { } con.getMessage(InAskBreakpoints.class); + con.addMessageListener(new DebugMessageListener() { + + @Override + public void message(InContinue msg) { + synchronized (DebuggerHandler.this) { + paused = false; + } + Main.getMainFrame().getPanel().updateMenu(); + } + }); con.addMessageListener(new DebugMessageListener() { @Override public void message(InBreakAt message) { + synchronized (DebuggerHandler.this) { + paused = true; + } + Main.getMainFrame().getPanel().updateMenu(); Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "break at {0}:{1}", new Object[]{moduleNames.get(message.file), message.line}); if (!modulePaths.containsKey(message.file)) { return; @@ -116,7 +143,7 @@ public class DebuggerHandler implements DebugConnectionListener { //dc.sendContinue(); } }); - commands.sendContinue(); + //commands.sendContinue(); connected = true; } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index b138eee1d..4ea37793f 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -645,6 +645,7 @@ public abstract class MainFrameMenu implements MenuBuilder { boolean isRunning = isRunning(); boolean isDebugRunning = isDebugRunning(); boolean isRunningOrDebugging = isRunning || isDebugRunning; + boolean isDebugPaused = isDebugPaused(); boolean swfSelected = swf != null; boolean isWorking = Main.isWorking(); @@ -704,17 +705,17 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuEnabled("_/about", !isWorking); setMenuEnabled("/help/about", !isWorking); - setMenuEnabled("/execution/start/run", !isRunningOrDebugging); + setMenuEnabled("/execution/start/run", swfSelected && !isRunningOrDebugging); setMenuEnabled("/execution/start/debug", !isRunningOrDebugging); setMenuEnabled("/execution/start/stop", isRunningOrDebugging); setMenuEnabled("/execution/debug", isDebugRunning); - setMenuEnabled("/execution/debug/pause", isDebugRunning); - setMenuEnabled("/execution/debug/stepOver", isDebugRunning); - setMenuEnabled("/execution/debug/stepInto", isDebugRunning); - setMenuEnabled("/execution/debug/stepOut", isDebugRunning); - setMenuEnabled("/execution/debug/continue", isDebugRunning); - setMenuEnabled("/execution/debug/stack", isDebugRunning); - setMenuEnabled("/execution/debug/watch", isDebugRunning); + //setMenuEnabled("/execution/debug/pause", isDebugRunning); + setMenuEnabled("/execution/debug/stepOver", isDebugPaused); + setMenuEnabled("/execution/debug/stepInto", isDebugPaused); + setMenuEnabled("/execution/debug/stepOut", isDebugPaused); + setMenuEnabled("/execution/debug/continue", isDebugPaused); + setMenuEnabled("/execution/debug/stack", isDebugPaused); + setMenuEnabled("/execution/debug/watch", isDebugPaused); } @@ -819,7 +820,7 @@ public abstract class MainFrameMenu implements MenuBuilder { finishMenu("/execution/start"); addMenuItem("/execution/debug", translate("menu.execution.debug"), null, null, 0, null, false); - addMenuItem("/execution/debug/pause", translate("menu.execution.debug.pause"), "pause32", this::pauseActionPerformed, PRIORITY_TOP, null, true); + //addMenuItem("/execution/debug/pause", translate("menu.execution.debug.pause"), "pause32", this::pauseActionPerformed, PRIORITY_TOP, null, true); addMenuItem("/execution/debug/continue", translate("menu.execution.debug.continue"), "continue32", this::continueActionPerformed, PRIORITY_TOP, null, true); addMenuItem("/execution/debug/stepOver", translate("menu.execution.debug.stepOver"), "stepover32", this::stepOverActionPerformed, PRIORITY_MEDIUM, null, true); addMenuItem("/execution/debug/stepInto", translate("menu.execution.debug.stepInto"), "stepinto32", this::stepIntoActionPerformed, PRIORITY_MEDIUM, null, true); @@ -1074,8 +1075,13 @@ public abstract class MainFrameMenu implements MenuBuilder { private Process runProcess; private boolean runProcessDebug; + private File runTempFile; + public synchronized boolean isDebugPaused() { + return runProcess != null && runProcessDebug && Main.getDebugHandler().isPaused(); + } + public synchronized boolean isDebugRunning() { return runProcess != null && runProcessDebug; } @@ -1084,16 +1090,13 @@ public abstract class MainFrameMenu implements MenuBuilder { return runProcess != null && !runProcessDebug; } - private synchronized void setProcess(Process p) { - this.runProcess = p; - } - private synchronized void freeRun() { if (runTempFile != null) { runTempFile.delete(); runTempFile = null; } runProcess = null; + mainFrame.getPanel().clearDebuggerColors(); } private void runPlayer(String exePath, String file, String flashVars) { @@ -1239,6 +1242,7 @@ public abstract class MainFrameMenu implements MenuBuilder { public boolean stepOverActionPerformed(ActionEvent evt) { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); if (cmd != null) { + mainFrame.getPanel().clearDebuggerColors(); cmd.stepOver(); } return true; @@ -1247,6 +1251,7 @@ public abstract class MainFrameMenu implements MenuBuilder { public boolean stepIntoActionPerformed(ActionEvent evt) { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); if (cmd != null) { + mainFrame.getPanel().clearDebuggerColors(); cmd.stepInto(); } return true; @@ -1255,6 +1260,7 @@ public abstract class MainFrameMenu implements MenuBuilder { public boolean stepOutActionPerformed(ActionEvent evt) { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); if (cmd != null) { + mainFrame.getPanel().clearDebuggerColors(); cmd.stepOut(); } return true; @@ -1263,7 +1269,8 @@ public abstract class MainFrameMenu implements MenuBuilder { public boolean continueActionPerformed(ActionEvent evt) { DebuggerCommands cmd = Main.getDebugHandler().getCommands(); if (cmd != null) { - cmd.stepContinue(); + mainFrame.getPanel().clearDebuggerColors(); + cmd.sendContinue(); } return true; } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index f8a8bfbff..55f6cf7a2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -342,6 +342,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } + public void updateMenu() { + mainMenu.updateComponents(); + } + private static void addTab(JTabbedPane tabbedPane, Component tab, String title, Icon icon) { tabbedPane.add(tab); @@ -1530,14 +1534,15 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se public void gotoClassLine(SWF swf, String cls, int line) { gotoClass(swf, cls); if (abcPanel != null) { - abcPanel.decompiledTextArea.selectLine(line); + abcPanel.decompiledTextArea.gotoLine(line); } + } public void debuggerBreakAt(SWF swf, String cls, int line) { gotoClassLine(swf, cls, line); if (abcPanel != null) { - abcPanel.decompiledTextArea.setLineColor(line, Color.green); + abcPanel.decompiledTextArea.setLineColor(line - 1, Color.green); } } @@ -1663,7 +1668,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se new CancellableWorker() { @Override protected Void doInBackground() throws Exception { - List textResult = null; + List textResult; SearchPanel textSearchPanel = previewPanel.getTextPanel().getSearchPanel(); textSearchPanel.setOptions(ignoreCase, regexp); textResult = searchText(txt, ignoreCase, regexp, swf); @@ -2494,19 +2499,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } public boolean alignText(TextTag textTag, TextAlign textAlign) { - if (textTag.alignText(textAlign)) { - return true; - } - - return false; + return (textTag.alignText(textAlign)); } public boolean translateText(TextTag textTag, int diff) { - if (textTag.translateText(diff)) { - return true; - } - - return false; + return textTag.translateText(diff); } public boolean previousTag() { @@ -2807,6 +2804,12 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } + public void clearDebuggerColors() { + if (abcPanel != null) { + abcPanel.decompiledTextArea.clearLineColors(); + } + } + private void stopFlashPlayer() { if (flashPanel != null) { if (!flashPanel.isStopped()) { @@ -3040,7 +3043,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se ABCPanel abcPanel = getABCPanel(); abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear(); abcPanel.setAbc(scriptLeaf.abc); - abcPanel.decompiledTextArea.setScript(scriptLeaf); + abcPanel.decompiledTextArea.setScript(scriptLeaf, true); abcPanel.decompiledTextArea.setNoTrait(); return null; } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index e7728f025..905692f73 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -200,6 +200,9 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener lineColors = new HashMap<>(); + public void clearLineColors() { + lineColors.clear(); + repaint(); + } + public void setLineColor(int line, Color color) { lineColors.remove(line); if (color != null) { lineColors.put(line, color); } + repaint(); } public int getLine() {