From d5b9d54314b0b004691c73da7c26cc2759711bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 14 Feb 2026 18:49:28 +0100 Subject: [PATCH] Debugging in the browser, improved --- .../flash/gui/BreakpointListDialog.java | 6 +- .../decompiler/flash/gui/DebugPanel.java | 92 +- .../decompiler/flash/gui/DebugStackPanel.java | 47 +- .../decompiler/flash/gui/DebuggerHandler.java | 1251 ++--------------- .../decompiler/flash/gui/DebuggerSession.java | 1176 ++++++++++++++++ src/com/jpexs/decompiler/flash/gui/Main.java | 325 +++-- .../decompiler/flash/gui/MainFrameMenu.java | 20 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 32 +- .../decompiler/flash/gui/abc/ABCPanel.java | 15 +- .../decompiler/flash/gui/abc/DetailPanel.java | 8 +- .../flash/gui/action/ActionPanel.java | 8 +- .../gui/editor/DebuggableEditorPane.java | 2 +- 12 files changed, 1674 insertions(+), 1308 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/DebuggerSession.java diff --git a/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java b/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java index 8c8e53009..dfaf82bb2 100644 --- a/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java @@ -197,16 +197,16 @@ public class BreakpointListDialog extends AppDialog { defaultTableModel.addColumn(translate("breakpoint.line")); defaultTableModel.addColumn(translate("breakpoint.status")); - Map> breakpoints = Main.getDebugHandler().getAllBreakPoints(swf, false); + Map> breakpoints = Main.getDebugHandler().getAllSessionsBreakPoints(swf); List newBreakpointList = new ArrayList<>(); for (String scriptName : breakpoints.keySet()) { for (int line : breakpoints.get(scriptName)) { newBreakpointList.add(new Breakpoint(scriptName, line)); String status = "unknown"; - if (Main.getDebugHandler().isBreakpointInvalid(swf, scriptName, line)) { + if (Main.getCurrentDebugSession().isBreakpointInvalid(swf, scriptName, line)) { status = "invalid"; - } else if (Main.getDebugHandler().isBreakpointConfirmed(swf, scriptName, line)) { + } else if (Main.getCurrentDebugSession().isBreakpointConfirmed(swf, scriptName, line)) { status = "confirmed"; } defaultTableModel.addRow(new Object[]{scriptName, line, translate("breakpoint.status." + status)}); diff --git a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java index 8a484c6f0..2a7abfd4b 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java @@ -36,6 +36,7 @@ import java.awt.event.MouseEvent; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -89,6 +90,8 @@ public class DebugPanel extends JPanel { private boolean loading = false; public ABCPanel.VariablesTableModel localsTable; + + private WeakReference currentSessionRef = null; public static enum SelectedTab { @@ -140,7 +143,7 @@ public class DebugPanel extends JPanel { } - private void logAdd(String message) { + private void logAdd(DebuggerSession session, String message) { boolean wasEmpty = logLength == 0; String add = message + "\r\n"; logLength += add.length(); @@ -151,7 +154,7 @@ public class DebugPanel extends JPanel { //ignore } if (wasEmpty) { - refresh(); + refresh(session); } } @@ -177,6 +180,15 @@ public class DebugPanel extends JPanel { } private void dopop(MouseEvent e) { + + if (currentSessionRef == null) { + return; + } + DebuggerSession session = currentSessionRef.get(); + if (session == null) { + return; + } + if (debugLocalsTable.getSelectedRow() == -1) { return; } @@ -241,8 +253,8 @@ public class DebugPanel extends JPanel { }*/ //Variant using comma separated bytes, pretty fast try { - Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent; - String dataStr = (String) Main.getDebugHandler().callMethod(debugConnectionClass, "readCommaSeparatedFromByteArray", Arrays.asList(v)).variables.get(0).value; + Variable debugConnectionClass = session.getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent; + String dataStr = (String) session.callMethod(debugConnectionClass, "readCommaSeparatedFromByteArray", Arrays.asList(v)).variables.get(0).value; String[] parts = dataStr.split(","); byte[] data = new byte[parts.length]; for (int i = 0; i < parts.length; i++) { @@ -313,9 +325,9 @@ public class DebugPanel extends JPanel { splitter = ","; } String dataStr = sb.toString(); - Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent; + Variable debugConnectionClass = session.getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent; try { - Main.getDebugHandler().callMethod(debugConnectionClass, "writeCommaSeparatedToByteArray", Arrays.asList(dataStr, v)); + session.callMethod(debugConnectionClass, "writeCommaSeparatedToByteArray", Arrays.asList(dataStr, v)); } catch (DebuggerHandler.ActionScriptException ex) { Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, "Error exporting ByteArray", ex); } @@ -334,19 +346,19 @@ public class DebugPanel extends JPanel { JMenu addWatchMenu = new JMenu(AppStrings.translate("debug.watch.add").replace("%name%", v.name)); JMenuItem watchReadMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.read")); watchReadMenuItem.addActionListener((ActionEvent e1) -> { - if (!Main.addWatch(v, watchParentId, true, false)) { + if (!Main.addWatch(session, v, watchParentId, true, false)) { ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); } }); JMenuItem watchWriteMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.write")); watchWriteMenuItem.addActionListener((ActionEvent e1) -> { - if (!Main.addWatch(v, watchParentId, false, true)) { + if (!Main.addWatch(session, v, watchParentId, false, true)) { ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); } }); JMenuItem watchReadWriteMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.readwrite")); watchReadWriteMenuItem.addActionListener((ActionEvent e1) -> { - if (!Main.addWatch(v, watchParentId, true, true)) { + if (!Main.addWatch(session, v, watchParentId, true, true)) { ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); } }); @@ -376,41 +388,41 @@ public class DebugPanel extends JPanel { Main.getDebugHandler().addTraceListener(new DebuggerHandler.TraceListener() { @Override - public void trace(String... val) { + public void trace(DebuggerSession session, String... val) { for (String s : val) { - logAdd("trace: " + s); + logAdd(session, "trace: " + s); } } }); Main.getDebugHandler().addErrorListener(new DebuggerHandler.ErrorListener() { @Override - public void errorException(String message, Variable thrownVar) { - logAdd("unhandled exception: " + message); + public void errorException(DebuggerSession session, String message, Variable thrownVar) { + logAdd(session, "unhandled exception: " + message); selectedTab = tabTypes.get(tabTypes.size() - 1); - refresh(); + refresh(session); } }); Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() { @Override - public void connected() { + public void connected(DebuggerSession session) { } @Override - public void disconnected() { - refresh(); + public void disconnected(DebuggerSession session) { + refresh(session); } }); Main.getDebugHandler().addFrameChangeListener(frameChangeListener = new DebuggerHandler.FrameChangeListener() { @Override - public void frameChanged() { + public void frameChanged(DebuggerSession session) { View.execInEventDispatchLater(new Runnable() { @Override public void run() { - refresh(); + refresh(session); } }); } @@ -419,17 +431,17 @@ public class DebugPanel extends JPanel { Main.getDebugHandler().addBreakListener(breakListener = new DebuggerHandler.BreakListener() { @Override - public void doContinue() { + public void doContinue(DebuggerSession session) { View.execInEventDispatch(new Runnable() { @Override public void run() { - refresh(); + refresh(session); } }); } @Override - public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { + public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { } }); @@ -484,8 +496,9 @@ public class DebugPanel extends JPanel { } return v.getMembers(this); }*/ - public void refresh() { - + public void refresh(DebuggerSession session) { + + currentSessionRef = session == null ? null : new WeakReference<>(session); View.execInEventDispatch(new Runnable() { @Override @@ -495,19 +508,14 @@ public class DebugPanel extends JPanel { SelectedTab oldSel = selectedTab; localsTable = null; - SWF swf = Main.getDebuggedSWF(); - if (swf == null) { - return; - } - boolean as3 = swf.isAS3(); - InFrame f = Main.getDebugHandler().getFrame(); + InFrame f = session == null ? null : session.getFrame(); if (f != null) { List locals = new ArrayList<>(); - Map placedObjects = Main.getDebugHandler().getPlacedObjects(); + Map placedObjects = session.getPlacedObjects(); for (String poName : placedObjects.keySet()) { String realName = poName; if ("/".equals(realName)) { @@ -515,7 +523,7 @@ public class DebugPanel extends JPanel { } else if (realName.startsWith("/")) { continue; } - Variable placedVar = Main.getDebugHandler().getVariable(0, realName, false, false).parent; + Variable placedVar = session.getVariable(0, realName, false, false).parent; if (placedVar != null) { locals.add(placedVar); } @@ -540,26 +548,26 @@ public class DebugPanel extends JPanel { TreeModelListener refreshListener = new TreeModelListener() { @Override public void treeNodesChanged(TreeModelEvent e) { - Main.getDebugHandler().refreshFrame(); - refresh(); + session.refreshFrame(); + refresh(session); } @Override public void treeNodesInserted(TreeModelEvent e) { - Main.getDebugHandler().refreshFrame(); - refresh(); + session.refreshFrame(); + refresh(session); } @Override public void treeNodesRemoved(TreeModelEvent e) { - Main.getDebugHandler().refreshFrame(); - refresh(); + session.refreshFrame(); + refresh(session); } @Override public void treeStructureChanged(TreeModelEvent e) { - Main.getDebugHandler().refreshFrame(); - refresh(); + session.refreshFrame(); + refresh(session); } }; debugLocalsTable.getTreeTableModel().addTreeModelListener(refreshListener); @@ -569,7 +577,7 @@ public class DebugPanel extends JPanel { debugLocalsTable.setTreeModel(new ABCPanel.VariablesTableModel(debugLocalsTable, new ArrayList<>())); debugScopeTable.setTreeModel(new ABCPanel.VariablesTableModel(debugScopeTable, new ArrayList<>())); } - InConstantPool cpool = Main.getDebugHandler().getConstantPool(); + InConstantPool cpool = session == null ? null : session.getConstantPool(); if (cpool != null) { Object[][] data2 = new Object[cpool.vars.size()][2]; for (int i = 0; i < cpool.vars.size(); i++) { @@ -635,7 +643,7 @@ public class DebugPanel extends JPanel { public void actionPerformed(ActionEvent e) { traceLogTextarea.setText(""); logLength = 0; - refresh(); + refresh(session); } }); JPanel butPanel = new JPanel(new FlowLayout()); diff --git a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java index a63fb9969..f1024602c 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java @@ -23,6 +23,7 @@ import java.awt.Component; import java.awt.Font; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.lang.ref.WeakReference; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTable; @@ -46,35 +47,40 @@ public class DebugStackPanel extends JPanel { private int[] classIndices = new int[0]; private int[] methodIndices = new int[0]; private int[] traitIndices = new int[0]; - + private WeakReference currentSessionRef = null; + public DebugStackPanel() { stackTable = new JTable(); Main.getDebugHandler().addFrameChangeListener(new DebuggerHandler.FrameChangeListener() { @Override - public void frameChanged() { - depth = Main.getDebugHandler().getDepth(); - refresh(); + public void frameChanged(DebuggerSession session) { + if (session == null) { + refresh(null); + return; + } + depth = session.getDepth(); + refresh(session); } }); Main.getDebugHandler().addBreakListener(new DebuggerHandler.BreakListener() { @Override - public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { + public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { } @Override - public void doContinue() { + public void doContinue(DebuggerSession session) { clear(); } }); Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() { @Override - public void connected() { + public void connected(DebuggerSession session) { } @Override - public void disconnected() { + public void disconnected(DebuggerSession session) { clear(); } }); @@ -96,7 +102,13 @@ public class DebugStackPanel extends JPanel { SWF swf = swfHash == null ? Main.getRunningSWF() : Main.getSwfByHash(swfHash); Main.getMainFrame().getPanel().gotoScriptLine(swf, scriptName, line, classIndices[row], traitIndices[row], methodIndices[row], Main.isDebugPCode()); - Main.getDebugHandler().setDepth(row); + DebuggerSession session = null; + if (currentSessionRef != null) { + session = currentSessionRef.get(); + } + if (session != null) { + session.setDepth(row); + } } } } @@ -112,8 +124,12 @@ public class DebugStackPanel extends JPanel { return active; } - public void refresh() { - InBreakAtExt info = Main.getDebugHandler().getBreakInfo(); + public void refresh(DebuggerSession session) { + if (session == null) { + clear(); + return; + } + InBreakAtExt info = session.getBreakInfo(); if (info == null) { clear(); return; @@ -126,7 +142,7 @@ public class DebugStackPanel extends JPanel { int[] newTraitIndices = new int[info.files.size()]; for (int i = 0; i < info.files.size(); i++) { int f = info.files.get(i); - String moduleName = Main.getDebugHandler().moduleToString(f); + String moduleName = session.moduleToString(f); String swfHash = null; if (moduleName.contains(":")) { swfHash = moduleName.substring(0, moduleName.indexOf(":")); @@ -137,11 +153,11 @@ public class DebugStackPanel extends JPanel { data[i][1] = moduleName; data[i][2] = info.lines.get(i); data[i][3] = info.stacks.get(i); - Integer newClassIndex = Main.getDebugHandler().moduleToClassIndex(f); + Integer newClassIndex = session.moduleToClassIndex(f); newClassIndices[i] = newClassIndex == null ? -1 : newClassIndex; - Integer newMethodIndex = Main.getDebugHandler().moduleToMethodIndex(f); + Integer newMethodIndex = session.moduleToMethodIndex(f); newMethodIndices[i] = newMethodIndex == null ? -1 : newMethodIndex; - Integer newTraitIndex = Main.getDebugHandler().moduleToTraitIndex(f); + Integer newTraitIndex = session.moduleToTraitIndex(f); ; newTraitIndices[i] = newTraitIndex == null ? -1 : newTraitIndex; } @@ -184,6 +200,7 @@ public class DebugStackPanel extends JPanel { repaint(); } }); + currentSessionRef = new WeakReference<>(session); } public int getDepth() { diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index fa84f362d..fd9ac4972 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -17,51 +17,13 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.debugger.flash.DebugConnectionListener; -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.Variable; -import com.jpexs.debugger.flash.VariableFlags; -import com.jpexs.debugger.flash.VariableType; -import com.jpexs.debugger.flash.messages.in.InBreakAt; -import com.jpexs.debugger.flash.messages.in.InBreakAtExt; -import com.jpexs.debugger.flash.messages.in.InBreakReason; -import com.jpexs.debugger.flash.messages.in.InCallFunction; -import com.jpexs.debugger.flash.messages.in.InConstantPool; -import com.jpexs.debugger.flash.messages.in.InContinue; -import com.jpexs.debugger.flash.messages.in.InErrorException; -import com.jpexs.debugger.flash.messages.in.InExit; -import com.jpexs.debugger.flash.messages.in.InFrame; -import com.jpexs.debugger.flash.messages.in.InGetSwf; -import com.jpexs.debugger.flash.messages.in.InGetVariable; -import com.jpexs.debugger.flash.messages.in.InNumScript; -import com.jpexs.debugger.flash.messages.in.InPlaceObject; -import com.jpexs.debugger.flash.messages.in.InProcessTag; -import com.jpexs.debugger.flash.messages.in.InScript; -import com.jpexs.debugger.flash.messages.in.InSetBreakpoint; -import com.jpexs.debugger.flash.messages.in.InSwfInfo; -import com.jpexs.debugger.flash.messages.in.InTrace; -import com.jpexs.debugger.flash.messages.in.InVersion; -import com.jpexs.debugger.flash.messages.out.OutAddWatch2; -import com.jpexs.debugger.flash.messages.out.OutGetBreakReason; -import com.jpexs.debugger.flash.messages.out.OutGetSwf; -import com.jpexs.debugger.flash.messages.out.OutPlay; -import com.jpexs.debugger.flash.messages.out.OutProcessedTag; -import com.jpexs.debugger.flash.messages.out.OutRewind; -import com.jpexs.debugger.flash.messages.out.OutStopDebug; -import com.jpexs.debugger.flash.messages.out.OutSwfInfo; import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.configuration.Configuration; -import com.jpexs.decompiler.graph.DottedChain; -import com.jpexs.helpers.Helper; -import java.io.FileOutputStream; import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -70,59 +32,17 @@ import java.util.Set; import java.util.TreeSet; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * @author JPEXS */ public class DebuggerHandler implements DebugConnectionListener { - - private boolean connected = false; - private DebuggerCommands commands = null; + private List sessions = Collections.synchronizedList(new ArrayList<>()); - //private List swfs = new ArrayList<>(); - private boolean paused = true; + private boolean terminating = false; - private Map modulePaths = new HashMap<>(); - - private Map moduleToSwfIndex = new HashMap<>(); - - //Marks swfIndices that are fully loaded - at least one break was on it (including onloaded break) - private Set swfIndicesCommitted = new HashSet<>(); - - private Map swfIndicesNewToSwfHash = new HashMap<>(); - - private Map scriptToModule = new HashMap<>(); - - private Map moduleToTraitIndex = new HashMap<>(); - - private Map moduleToClassIndex = new HashMap<>(); - - private Map moduleToMethodIndex = new HashMap<>(); - - private Map>> toAddBPointMap = new WeakHashMap<>(); - - private Map>> confirmedPointMap = new WeakHashMap<>(); - - private Map>> invalidBreakPointMap = new WeakHashMap<>(); - - private Map>> toRemoveBPointMap = new WeakHashMap<>(); - - private int breakIp = -1; - - private String breakScriptName = null; - - private List stackScriptNames = new ArrayList<>(); - - private List stackLines = new ArrayList<>(); - - private List debuggedSwfs = new ArrayList<>(); - - private Map placedObjects = new LinkedHashMap<>(); + private Map>> allBreakPoints = new WeakHashMap<>(); public static class ActionScriptException extends Exception { @@ -142,521 +62,103 @@ public class DebuggerHandler implements DebugConnectionListener { } } - public void setMainDebuggedSwf(SWF debuggedSwf) { - debuggedSwfs.clear(); - //debuggedSwfs.add(debuggedSwf); - } - - public List getDebuggedSwfs() { - return debuggedSwfs; - } - - public int getBreakIp() { - if (!isPaused()) { - return -1; - } - return breakIp; - } - - public int getDepth() { - return depth; - } - - public String getBreakScriptName() { - if (!isPaused()) { - return "-"; - } - return breakScriptName; - } - - public synchronized List getStackScripts() { - if (!isPaused()) { - return new ArrayList<>(); - } - return stackScriptNames; - } - - public synchronized List getStackLines() { - if (!isPaused()) { - return new ArrayList<>(); - } - return stackLines; - } - - public InGetVariable getVariable(long parentId, String varName, boolean children, boolean useGetter) { - try { - return commands.getVariable(parentId, varName, useGetter, children); - } catch (IOException ex) { - return null; - } - } - - public void setVariable(long parentId, String varName, int valueType, Object value) { - try { - String svalue = ""; - switch (valueType) { - case VariableType.STRING: - svalue = "" + value; - break; - case VariableType.NUMBER: - svalue = "" + value; - break; - case VariableType.BOOLEAN: - svalue = ((Boolean) value) ? "true" : "false"; - break; - case VariableType.UNDEFINED: - svalue = "undefined"; - break; - case VariableType.NULL: - svalue = "undefined"; - break; - } - commands.setVariable(parentId, varName, valueType, svalue); - } catch (IOException ex) { - //ignore - } - } - - public synchronized void removeBreakPoint(SWF swf, String scriptName, int line) { - if (isBreakpointInvalid(swf, scriptName, line)) { - invalidBreakPointMap.get(swf).get(scriptName).remove(line); - if (invalidBreakPointMap.get(swf).get(scriptName).isEmpty()) { - invalidBreakPointMap.get(swf).remove(scriptName); - } - return; - } - if (isBreakpointToAdd(swf, scriptName, line)) { - toAddBPointMap.get(swf).get(scriptName).remove(line); - if (toAddBPointMap.get(swf).get(scriptName).isEmpty()) { - toAddBPointMap.get(swf).remove(scriptName); - } - } else if (isBreakpointConfirmed(swf, scriptName, line)) { - if (!toRemoveBPointMap.containsKey(swf)) { - toRemoveBPointMap.put(swf, new HashMap<>()); - } - if (!toRemoveBPointMap.get(swf).containsKey(scriptName)) { - toRemoveBPointMap.get(swf).put(scriptName, new TreeSet<>()); - } - toRemoveBPointMap.get(swf).get(scriptName).add(line); - } - try { - sendBreakPoints(); - } catch (IOException ex) { - //ignore - } - } - - private int watchTag = 1; - - public synchronized com.jpexs.debugger.flash.DebuggerCommands.Watch addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) { - int tag = watchTag++; - try { - return commands.addWatch(v_id, v.name, (watchRead ? OutAddWatch2.FLAG_READ : 0) | (watchWrite ? OutAddWatch2.FLAG_WRITE : 0), tag); - } catch (IOException ex) { - return null; - } - } - - public synchronized Set getBreakPoints(SWF swf, String scriptName, boolean onlyValid) { - Set lines = new TreeSet<>(); - if (confirmedPointMap.containsKey(swf) && confirmedPointMap.get(swf).containsKey(scriptName)) { - lines.addAll(confirmedPointMap.get(swf).get(scriptName)); - } - if (toAddBPointMap.containsKey(swf) && toAddBPointMap.get(swf).containsKey(scriptName)) { - lines.addAll(toAddBPointMap.get(swf).get(scriptName)); - } - if (!onlyValid && invalidBreakPointMap.containsKey(swf) && invalidBreakPointMap.get(swf).containsKey(scriptName)) { - lines.addAll(invalidBreakPointMap.get(swf).get(scriptName)); - } - return lines; - } - - public synchronized void clearBreakPoints(SWF swf) { - Map> breakpoints = getAllBreakPoints(swf, false); - for (String scriptName : breakpoints.keySet()) { - for (int line : breakpoints.get(scriptName)) { - removeBreakPoint(swf, scriptName, line); - } - } - } - - public synchronized void makeBreakPointsUnconfirmed(SWF swf) { - if (confirmedPointMap.containsKey(swf)) { - for (String scriptName : confirmedPointMap.get(swf).keySet()) { - if (!toAddBPointMap.containsKey(swf)) { - toAddBPointMap.put(swf, new HashMap<>()); - } - if (!toAddBPointMap.get(swf).containsKey(scriptName)) { - toAddBPointMap.get(swf).put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(swf).get(scriptName).addAll(confirmedPointMap.get(swf).get(scriptName)); - } - confirmedPointMap.get(swf).clear(); - } - if (invalidBreakPointMap.containsKey(swf)) { - for (String scriptName : invalidBreakPointMap.get(swf).keySet()) { - if (!toAddBPointMap.containsKey(swf)) { - toAddBPointMap.put(swf, new HashMap<>()); - } - if (!toAddBPointMap.get(swf).containsKey(scriptName)) { - toAddBPointMap.get(swf).put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(swf).get(scriptName).addAll(invalidBreakPointMap.get(swf).get(scriptName)); - } - - invalidBreakPointMap.get(swf).clear(); - } - - } - - public synchronized Map> getAllBreakPoints(SWF swf, boolean validOnly) { - Map> ret = new HashMap<>(); - if (confirmedPointMap.containsKey(swf)) { - for (String scriptName : confirmedPointMap.get(swf).keySet()) { - Set lines = new TreeSet<>(); - lines.addAll(confirmedPointMap.get(swf).get(scriptName)); - ret.put(scriptName, lines); - } - } - if (toAddBPointMap.containsKey(swf)) { - for (String scriptName : toAddBPointMap.get(swf).keySet()) { - if (!ret.containsKey(scriptName)) { - ret.put(scriptName, new TreeSet<>()); - } - ret.get(scriptName).addAll(toAddBPointMap.get(swf).get(scriptName)); - } - } - if (!validOnly) { - if (invalidBreakPointMap.containsKey(swf)) { - for (String scriptName : invalidBreakPointMap.get(swf).keySet()) { - if (!ret.containsKey(scriptName)) { - ret.put(scriptName, new TreeSet<>()); - } - ret.get(scriptName).addAll(invalidBreakPointMap.get(swf).get(scriptName)); - } - } - } - return ret; - } - - public boolean addBreakPoint(SWF swf, String scriptName, int line) { - synchronized (this) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "adding bp {0}:{1}", new Object[]{scriptName, line}); - if (isBreakpointToRemove(swf, scriptName, line)) { - toRemoveBPointMap.get(swf).get(scriptName).remove(line); - if (toRemoveBPointMap.get(swf).get(scriptName).isEmpty()) { - toRemoveBPointMap.get(swf).remove(scriptName); - } - } - - if (isBreakpointConfirmed(swf, scriptName, line)) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp {0}:{1} already confirmed", new Object[]{scriptName, line}); - return true; - - } - if (isBreakpointInvalid(swf, scriptName, line)) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp {0}:{1} already invalid", new Object[]{scriptName, line}); - return false; - } - if (!toAddBPointMap.containsKey(swf)) { - toAddBPointMap.put(swf, new HashMap<>()); - } - if (!toAddBPointMap.get(swf).containsKey(scriptName)) { - toAddBPointMap.get(swf).put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(swf).get(scriptName).add(line); - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "bp {0}:{1} added to todo", new Object[]{scriptName, line}); - } - try { - sendBreakPoints(); - } catch (IOException ex) { - //ignored - } - - return true; - } - - public synchronized boolean isBreakpointConfirmed(SWF swf, String scriptName, int line) { - return confirmedPointMap.containsKey(swf) && confirmedPointMap.get(swf).containsKey(scriptName) && confirmedPointMap.get(swf).get(scriptName).contains(line); - } - - public synchronized boolean isBreakpointToAdd(SWF swf, String scriptName, int line) { - return toAddBPointMap.containsKey(swf) && toAddBPointMap.get(swf).containsKey(scriptName) && toAddBPointMap.get(swf).get(scriptName).contains(line); - } - - public synchronized boolean isBreakpointToRemove(SWF swf, String scriptName, int line) { - return toRemoveBPointMap.containsKey(swf) && toRemoveBPointMap.get(swf).containsKey(scriptName) && toRemoveBPointMap.get(swf).get(scriptName).contains(line); - } - - public synchronized boolean isBreakpointInvalid(SWF swf, String scriptName, int line) { - return invalidBreakPointMap.containsKey(swf) && invalidBreakPointMap.get(swf).containsKey(scriptName) && invalidBreakPointMap.get(swf).get(scriptName).contains(line); - } - - private synchronized void markBreakPointInvalid(SWF swf, String scriptName, int line) { - if (!invalidBreakPointMap.containsKey(swf)) { - invalidBreakPointMap.put(swf, new HashMap<>()); - } - if (!invalidBreakPointMap.get(swf).containsKey(scriptName)) { - invalidBreakPointMap.get(swf).put(scriptName, new TreeSet<>()); - } - invalidBreakPointMap.get(swf).get(scriptName).add(line); - } - - private synchronized void markBreakPointConfirmed(SWF swf, String scriptName, int line) { - if (!confirmedPointMap.containsKey(swf)) { - confirmedPointMap.put(swf, new HashMap<>()); - } - if (!confirmedPointMap.get(swf).containsKey(scriptName)) { - confirmedPointMap.get(swf).put(scriptName, new TreeSet<>()); - } - confirmedPointMap.get(swf).get(scriptName).add(line); - } - - private synchronized void markBreakPointValid(SWF swf, String scriptName, int line) { - if (!invalidBreakPointMap.containsKey(swf)) { - return; - } - if (!invalidBreakPointMap.get(swf).containsKey(scriptName)) { - return; - } - invalidBreakPointMap.get(swf).get(scriptName).remove(line); - if (invalidBreakPointMap.get(swf).get(scriptName).isEmpty()) { - invalidBreakPointMap.get(swf).remove(scriptName); - } - if (invalidBreakPointMap.get(swf).isEmpty()) { - invalidBreakPointMap.remove(swf); - } - } - - private InFrame frame; - - private int depth; - - private InConstantPool pool; - - private InBreakAtExt breakInfo; - - private InBreakReason breakReason; - - private final List breakListeners = new CopyOnWriteArrayList<>(); - - private final List traceListeners = new ArrayList<>(); - - private final List errorListeners = new ArrayList<>(); - - private final List frameChangeListeners = new ArrayList<>(); - - private final List clisteners = new ArrayList<>(); - - public void setDepth(int depth) { - this.depth = depth; - refreshFrame(); - } - - public String moduleToString(int file) { - if (!modulePaths.containsKey(file)) { - return "unknown"; - } - return modulePaths.get(file); - } - - public Integer moduleToMethodIndex(int file) { - return moduleToMethodIndex.get(file); - } - - public Integer moduleToClassIndex(int file) { - return moduleToClassIndex.get(file); - } - - public Integer moduleToTraitIndex(int file) { - return moduleToTraitIndex.get(file); - } - - public synchronized InBreakAtExt getBreakInfo() { - if (!paused) { - return null; - } - return breakInfo; - } - - public synchronized InBreakReason getBreakReason() { - if (!paused) { - return null; - } - return breakReason; - } - public static interface ConnectionListener { - public void connected(); + public void connected(DebuggerSession session); - public void disconnected(); + public void disconnected(DebuggerSession session); } public static interface TraceListener { - public void trace(String... val); + public void trace(DebuggerSession session, String... val); } public static interface ErrorListener { - public void errorException(String message, Variable thrownVar); + public void errorException(DebuggerSession session, String message, Variable thrownVar); } public static interface FrameChangeListener { - public void frameChanged(); + public void frameChanged(DebuggerSession session); } public static interface BreakListener { - public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex); + public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex); - public void doContinue(); + public void doContinue(DebuggerSession session); } - public void addBreakListener(BreakListener l) { + private final List breakListeners = new CopyOnWriteArrayList<>(); + + private final List traceListeners = new ArrayList<>(); + + private final List errorListeners = new ArrayList<>(); + + private final List frameChangeListeners = new ArrayList<>(); + + private final List connectionListeners = new ArrayList<>(); + + public void addBreakListener(DebuggerHandler.BreakListener l) { breakListeners.add(l); } - public void addFrameChangeListener(FrameChangeListener l) { + public void addFrameChangeListener(DebuggerHandler.FrameChangeListener l) { frameChangeListeners.add(l); } - public void removeFrameChangeListener(FrameChangeListener l) { + public void removeFrameChangeListener(DebuggerHandler.FrameChangeListener l) { frameChangeListeners.remove(l); } - public void addTraceListener(TraceListener l) { + public void addTraceListener(DebuggerHandler.TraceListener l) { traceListeners.add(l); } - public void removeTraceListener(TraceListener l) { + public void removeTraceListener(DebuggerHandler.TraceListener l) { traceListeners.remove(l); } - public void addErrorListener(ErrorListener l) { + public void addErrorListener(DebuggerHandler.ErrorListener l) { errorListeners.add(l); } - public void removeErrorListener(ErrorListener l) { + public void removeErrorListener(DebuggerHandler.ErrorListener l) { errorListeners.remove(l); } - public void removeBreakListener(BreakListener l) { + public void removeBreakListener(DebuggerHandler.BreakListener l) { breakListeners.remove(l); } - public void addConnectionListener(ConnectionListener l) { - clisteners.add(l); + public void addConnectionListener(DebuggerHandler.ConnectionListener l) { + connectionListeners.add(l); } - public void removeConnectionListener(ConnectionListener l) { - clisteners.remove(l); + public void removeConnectionListener(DebuggerHandler.ConnectionListener l) { + connectionListeners.remove(l); } - public synchronized void refreshFrame() { - if (!paused) { - return; - } - try { - frame = commands.getFrame(depth); - pool = commands.getConstantPool(0); - } catch (IOException ex) { - //ignore - } - for (FrameChangeListener l : frameChangeListeners) { - l.frameChanged(); - } + public List getBreakListeners() { + return Collections.unmodifiableList(breakListeners); } - public synchronized InFrame getFrame() { - if (!paused) { - return null; - } - return frame; + public List getErrorListeners() { + return Collections.unmodifiableList(errorListeners); } - public synchronized int moduleIdOf(String packWithHash) { - if (!scriptToModule.containsKey(packWithHash)) { - return -1; - } - return scriptToModule.get(packWithHash); + public List getConnectionListeners() { + return Collections.unmodifiableList(connectionListeners); } - public boolean isPaused() { - if (!isConnected()) { - return false; - } - synchronized (this) { - return paused; - } + public List getFrameChangeListeners() { + return Collections.unmodifiableList(frameChangeListeners); } - - private void disconnected() { - frame = null; - pool = null; - breakInfo = null; - breakReason = null; - connected = false; - commands = null; - synchronized (this) { - for (SWF debuggedSwf : debuggedSwfs) { - if (confirmedPointMap.containsKey(debuggedSwf)) { - for (String scriptName : confirmedPointMap.get(debuggedSwf).keySet()) { - if (!toAddBPointMap.containsKey(debuggedSwf)) { - toAddBPointMap.put(debuggedSwf, new HashMap<>()); - } - if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) { - toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(confirmedPointMap.get(debuggedSwf).get(scriptName)); - } - confirmedPointMap.get(debuggedSwf).clear(); - } - - if (invalidBreakPointMap.containsKey(debuggedSwf)) { - for (String scriptName : invalidBreakPointMap.get(debuggedSwf).keySet()) { - if (!toAddBPointMap.containsKey(debuggedSwf)) { - toAddBPointMap.put(debuggedSwf, new HashMap<>()); - } - if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) { - toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>()); - } - toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(invalidBreakPointMap.get(debuggedSwf).get(scriptName)); - } - invalidBreakPointMap.get(debuggedSwf).clear(); - } - } - } - for (ConnectionListener l : clisteners) { - l.disconnected(); - } - debuggedSwfs.clear(); - } - - public void disconnect() { - frame = null; - pool = null; - breakInfo = null; - breakReason = null; - connected = false; - if (commands != null) { - commands.disconnect(); - } - disconnected(); - } - - public synchronized boolean isConnected() { - return connected; - } - - public DebuggerCommands getCommands() throws IOException { - if (!isConnected() || commands == null) { - throw new IOException("Not connected"); - } - return commands; + public List getTraceListeners() { + return Collections.unmodifiableList(traceListeners); } @Override @@ -664,588 +166,137 @@ public class DebuggerHandler implements DebugConnectionListener { View.execInEventDispatch(new Runnable() { @Override public void run() { - disconnect(); + //disconnect(); Main.stopRun(); Main.stopWork(); ViewMessages.showMessageDialog(Main.getMainFrame().getPanel(), AppStrings.translate("error.debug.listen").replace("%port%", "" + Debugger.DEBUG_PORT)); Main.getMainFrame().getPanel().updateMenu(); } }); - } @Override - public void connected(DebuggerConnection con) { - Main.startWork(AppStrings.translate("work.debugging"), null); - - synchronized (this) { - paused = false; - } - - Main.getMainFrame().getPanel().updateMenu(); - - //enlog(DebuggerConnection.class); - //enlog(DebuggerCommands.class); - //enlog(DebuggerHandler.class); - try { - con.getMessage(InVersion.class); - } catch (IOException ex) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.SEVERE, null, ex); - } - - //Respond to InProcessTag with OutProcessedTag - con.addMessageListener(new DebugMessageListener() { - @Override - public void message(InProcessTag message) { - try { - con.writeMessage(new OutProcessedTag(con)); - } catch (IOException ex) { - //disconnect(); - //ignore - } - } - }); - - swfIndicesCommitted.clear(); - swfIndicesNewToSwfHash.clear(); - - Map moduleNames = new HashMap<>(); - - final Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$"); - final Pattern patAS3PCode = Pattern.compile("^(?[0-9a-z_]+):#PCODE abc:(?[0-9]+),script:(?