Debugging in the browser, improved 2

This commit is contained in:
Jindra Petřík
2026-02-15 10:21:58 +01:00
parent d5b9d54314
commit 8645679ce9
10 changed files with 363 additions and 239 deletions

View File

@@ -583,7 +583,8 @@ public final class AbcIndexing {
*/
public void rebuildPkgToObjectsNameMap() {
pkgToObjectsName.clear();
for (ClassDef cd : classes.keySet()) {
Set<ClassDef> cs = new LinkedHashSet<>(classes.keySet());
for (ClassDef cd : cs) {
if (!(cd.type instanceof TypeItem)) {
continue;
}
@@ -592,7 +593,8 @@ public final class AbcIndexing {
}
pkgToObjectsName.get(cd.pkg).add(((TypeItem) cd.type).fullTypeName.getLast());
}
for (PropertyNsDef nsdef : scriptProperties.keySet()) {
Set<PropertyNsDef> nss = new LinkedHashSet<>(scriptProperties.keySet());
for (PropertyNsDef nsdef : nss) {
if (!pkgToObjectsName.containsKey(nsdef.ns)) {
pkgToObjectsName.put(nsdef.ns, new LinkedHashSet<>());
}

View File

@@ -194,9 +194,11 @@ public class DebugStackPanel extends JPanel {
}
};
stackTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
if (stackTable.getColumnModel().getColumnCount() >= 3) {
stackTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
}
repaint();
}
});

View File

@@ -222,14 +222,21 @@ public class DebuggerHandler implements DebugConnectionListener {
return count;
}
public synchronized void terminateAllSessions() {
terminating = true;
public void terminateAllSessions() {
synchronized (this) {
if (terminating) {
return;
}
terminating = true;
}
for (DebuggerSession session : sessions) {
if (session.isConnected()) {
session.disconnect();
}
}
terminating = false;
synchronized (this) {
terminating = false;
}
}
public synchronized Map<String, Set<Integer>> getAllSessionsBreakPoints(SWF swf) {

View File

@@ -52,10 +52,12 @@ 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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -63,6 +65,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.WeakHashMap;
import java.util.logging.Level;
@@ -77,8 +81,6 @@ import java.util.regex.Pattern;
public class DebuggerSession {
private boolean connected = false;
private boolean inited = false;
private DebuggerCommands commands = null;
@@ -117,7 +119,7 @@ public class DebuggerSession {
private List<Integer> stackLines = new ArrayList<>();
private List<SWF> debuggedSwfs = new ArrayList<>();
private Map<Integer, SWF> debuggedSwfs = new LinkedHashMap<>();
private Map<String, Long> placedObjects = new LinkedHashMap<>();
@@ -132,17 +134,19 @@ public class DebuggerSession {
private InBreakReason breakReason;
private DebuggerHandler handler;
private InSetBreakpoint inSetBreakpoint;
private int id;
private static int lastId = 0;
private List<Thread> getSwfThreadList = Collections.synchronizedList(new ArrayList<>());
public DebuggerSession(DebuggerHandler handler, DebuggerConnection con, Map<SWF, Map<String, Set<Integer>>> breakpoints) {
lastId++;
id = lastId;
toAddBPointMap = breakpoints;
this.handler = handler;
Main.startWork(AppStrings.translate("work.debugging"), null);
@@ -226,7 +230,7 @@ public class DebuggerSession {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "Received script added - index {0} name: {1}", new Object[]{file, name});
String swfHash = "main";
String swfHash = "unknown";
Matcher m;
if ((m = patAS3.matcher(name)).matches()) {
String clsNameWithSuffix = m.group(3).replace("{{semicolon}}", ";");
@@ -256,7 +260,11 @@ public class DebuggerSession {
modulePaths.put(file, name);
scriptToModule.put(name, file);
moduleToSwfIndex.put(file, swfIndex);
/*if (swfIndex > debuggedSwfs.size() - 1) {
/*if (!"main".equals(swfHash)) {
SWF swf = Main.getSwfByHash(swfHash);
debuggedSwfs.put(swfIndex, swf);
}*/
/*if (swfIndex > debuggedSwfs.size() - 1) {
SWF swf = Main.getSwfByHash(swfHash);
if (swf == null) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.WARNING, "SWF with hash {0} not found", swfHash);
@@ -329,101 +337,116 @@ public class DebuggerSession {
});
}*/
con.dropMessage(t);
View.execInEventDispatch(new Runnable() {
//View.execInEventDispatch(
Runnable r = new Runnable() {
@Override
public void run() {
for (InSwfInfo.SwfInfo s : t.swfInfos) {
try {
/*try {
try {
for (InSwfInfo.SwfInfo s : t.swfInfos) {
try {
/*try {
con.sendMessageWithTimeout(new OutGetSwf(con, (int) s.index), InGetSwf.class);
con.sendMessageWithTimeout(new OutGetSwd(con, (int) s.index), InGetSwd.class);
} catch (IOException ex) {
//ignore
}*/
InGetSwf inGetSwf = con.sendMessageWithTimeout(new OutGetSwf(con, (int) s.index), InGetSwf.class);
Logger.getLogger(DebuggerSession.class.getName()).fine("Received SWF");
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "Received SWF.URL = {0}", s.url);
String sha256 = Helper.byteArrayToHex(MessageDigest.getInstance("SHA-256").digest(inGetSwf.swfData));
}*/
/*if (s.scriptCount == 0) {
continue;
}*/
InGetSwf inGetSwf = con.sendMessage(new OutGetSwf(con, (int) s.index), InGetSwf.class);
Logger.getLogger(DebuggerSession.class.getName()).fine("Received SWF");
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "Received SWF.URL = {0}", s.url);
if (inGetSwf == null) {
Logger.getLogger(DebuggerSession.class.getName()).fine("Cannot read SWF");
continue;
}
String sha256 = Helper.byteArrayToHex(MessageDigest.getInstance("SHA-256").digest(inGetSwf.swfData));
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "Received SWF hash = {0}", sha256);
SWF debuggedSwf = Main.findOpenedSwfByHash(sha256);
if (debuggedSwf == null) {
con.disconnect();
synchronized (DebuggerSession.this) {
paused = false;
connected = false;
}
disconnected();
} else {
debuggedSwfs.put((int) s.index, debuggedSwf);
if (debuggedSwfs.size() == 1) { //it's the first one
con.isAS3 = debuggedSwf.isAS3();
}
}
} catch (IOException | NoSuchAlgorithmException ex) {
//ignore
SWF debuggedSwf = Main.findOpenedSwfByHash(sha256);
if (debuggedSwf == null) {
con.disconnect();
synchronized (DebuggerSession.this) {
paused = false;
connected = false;
}
disconnected();
} else {
debuggedSwfs.add(debuggedSwf);
if (debuggedSwfs.size() == 1) { //it's the first one
con.isAS3 = debuggedSwf.isAS3();
}
}
} catch (IOException | NoSuchAlgorithmException ex) {
//ignore
return;
}
}
try {
if (con.isAS3) {
//FIXME
//Widelines - only AS3, it hangs in AS1/2 and SWD does not support UI32 lines
/*con.wideLines = commands.getOption("wide_line_player", "false").equals("true");
if (con.wideLines) {
commands.setOption("wide_line_debugger", "on");
}*/
}
if (!con.isAS3) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINER, "End of connect - sending continue");
con.writeMessage(new OutRewind(con));
con.writeMessage(new OutPlay(con));
commands.sendContinue();
}
synchronized (DebuggerSession.this) {
for (int i = 0; i < inSetBreakpoint.files.size(); i++) {
String sname = moduleNames.get(inSetBreakpoint.files.get(i));
int swfIndex = moduleToSwfIndex.get(inSetBreakpoint.files.get(i));
SWF debuggedSwf = debuggedSwfs.get(swfIndex);
if (!confirmedPointMap.containsKey(debuggedSwf)) {
confirmedPointMap.put(debuggedSwf, new HashMap<>());
}
if (!confirmedPointMap.get(debuggedSwf).containsKey(sname)) {
confirmedPointMap.get(debuggedSwf).put(sname, new TreeSet<>());
}
if (toAddBPointMap.containsKey(debuggedSwf)) {
if (toAddBPointMap.get(debuggedSwf).containsKey(sname)) {
toAddBPointMap.get(debuggedSwf).get(sname).remove(inSetBreakpoint.lines.get(i));
if (toAddBPointMap.get(debuggedSwf).get(sname).isEmpty()) {
toAddBPointMap.get(debuggedSwf).remove(sname);
}
}
}
confirmedPointMap.get(debuggedSwf).get(sname).add(inSetBreakpoint.lines.get(i));
Logger.getLogger(DebuggerSession.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{sname, inSetBreakpoint.lines.get(i)});
}
}
} catch (IOException ex) {
con.disconnect();
synchronized (DebuggerSession.this) {
paused = false;
connected = false;
}
disconnected();
return;
}
}
try {
if (con.isAS3) {
//Widelines - only AS3, it hangs in AS1/2 and SWD does not support UI32 lines
con.wideLines = commands.getOption("wide_line_player", "false").equals("true");
if (con.wideLines) {
commands.setOption("wide_line_debugger", "on");
}
} else {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINER, "End of connect - sending continue");
con.writeMessage(new OutRewind(con));
con.writeMessage(new OutPlay(con));
commands.sendContinue();
}
synchronized (DebuggerSession.this) {
for (int i = 0; i < inSetBreakpoint.files.size(); i++) {
String sname = moduleNames.get(inSetBreakpoint.files.get(i));
int swfIndex = moduleToSwfIndex.get(inSetBreakpoint.files.get(i));
SWF debuggedSwf = debuggedSwfs.get(swfIndex);
if (!confirmedPointMap.containsKey(debuggedSwf)) {
confirmedPointMap.put(debuggedSwf, new HashMap<>());
}
if (!confirmedPointMap.get(debuggedSwf).containsKey(sname)) {
confirmedPointMap.get(debuggedSwf).put(sname, new TreeSet<>());
}
if (toAddBPointMap.containsKey(debuggedSwf)) {
if (toAddBPointMap.get(debuggedSwf).containsKey(sname)) {
toAddBPointMap.get(debuggedSwf).get(sname).remove(inSetBreakpoint.lines.get(i));
if (toAddBPointMap.get(debuggedSwf).get(sname).isEmpty()) {
toAddBPointMap.get(debuggedSwf).remove(sname);
}
}
}
confirmedPointMap.get(debuggedSwf).get(sname).add(inSetBreakpoint.lines.get(i));
Logger.getLogger(DebuggerSession.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{sname, inSetBreakpoint.lines.get(i)});
}
}
inited = true;
handler.sessionInited(DebuggerSession.this);
} catch (IOException ex) {
con.disconnect();
synchronized (DebuggerSession.this) {
paused = false;
connected = false;
}
disconnected();
} finally {
getSwfThreadList.remove(Thread.currentThread());
}
}
});
};
Thread thread = new Thread(r, "Debugger session " + this.toString() + " - Get SWF");
thread.start();
getSwfThreadList.add(thread);
}
});
@@ -435,7 +458,7 @@ public class DebuggerSession {
}
});
inSetBreakpoint = con.getMessage(InSetBreakpoint.class);
inSetBreakpoint = con.getMessage(InSetBreakpoint.class);
con.addMessageListener(new DebugMessageListener<InContinue>() {
@Override
@@ -453,88 +476,123 @@ public class DebuggerSession {
con.addMessageListener(new DebugMessageListener<InBreakAt>() {
@Override
public void message(InBreakAt message) {
synchronized (DebuggerSession.this) {
paused = true;
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "paused");
}
try {
//ignore single InSetBreakpoint, otherwise setting breakpoints later won't work
con.getMessage(InSetBreakpoint.class, DebuggerConnection.PREF_RESPONSE_TIMEOUT);
breakInfo = con.getMessage(InBreakAtExt.class, DebuggerConnection.PREF_RESPONSE_TIMEOUT);
breakReason = con.sendMessageWithTimeout(new OutGetBreakReason(con), InBreakReason.class);
int reasonInt = breakReason == null ? 0 : breakReason.reason;
String newBreakScriptName = "unknown";
String userBreakScriptName = "unknown";
if (modulePaths.containsKey(message.file)) {
newBreakScriptName = modulePaths.get(message.file);
userBreakScriptName = newBreakScriptName;
if (newBreakScriptName.contains(":")) {
//String swfHash = newBreakScriptName.substring(0, newBreakScriptName.indexOf(":"));
//SWF swf = Main.getSwfByHash(swfHash);
SWF swf = debuggedSwfs.get(moduleToSwfIndex.get(message.file));
userBreakScriptName = swf.toString() + ": " + newBreakScriptName.substring(newBreakScriptName.indexOf(":") + 1);
Runnable r = new Runnable() {
@Override
public void run() {
synchronized (DebuggerSession.this) {
paused = true;
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "paused");
}
} else if (reasonInt != InBreakReason.REASON_SCRIPT_LOADED) {
Logger.getLogger(DebuggerCommands.class.getName()).log(Level.SEVERE, "Invalid file: {0}", message.file);
//return;
}
final String[] reasonNames = new String[]{"unknown", "breakpoint", "watch", "fault", "stopRequest", "step", "halt", "scriptLoaded"};
String reason = reasonInt < reasonNames.length ? reasonNames[reasonInt] : reasonNames[0];
try {
//ignore single InSetBreakpoint, otherwise setting breakpoints later won't work
con.getMessage(InSetBreakpoint.class, DebuggerConnection.PREF_RESPONSE_TIMEOUT);
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "break at {0}:{1}, reason: {2}", new Object[]{newBreakScriptName, message.line, reason});
breakInfo = con.getMessage(InBreakAtExt.class, DebuggerConnection.PREF_RESPONSE_TIMEOUT);
breakReason = con.sendMessageWithTimeout(new OutGetBreakReason(con), InBreakReason.class);
try {
sendBreakPoints();
} catch (IOException ex) {
//ignore
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "send breakpoints exception: " + ex.getMessage());
}
int reasonInt = breakReason == null ? 0 : breakReason.reason;
synchronized (DebuggerSession.this) {
breakScriptName = newBreakScriptName;
breakIp = message.line;
if (breakInfo != null) {
List<String> files = new ArrayList<>();
for (int i = 0; i < breakInfo.files.size(); i++) {
files.add(DebuggerSession.this.moduleToString(breakInfo.files.get(i)));
String newBreakScriptName = "unknown";
String userBreakScriptName = "unknown";
String userSwfName = "unknown";
if (moduleToSwfIndex.containsKey(message.file)) {
SWF swf = debuggedSwfs.get(moduleToSwfIndex.get(message.file));
userSwfName = swf.toString();
} else if(!debuggedSwfs.isEmpty()) {
userSwfName = debuggedSwfs.get(debuggedSwfs.size() - 1).toString();
}
stackScriptNames = files;
List<Integer> lines = new ArrayList<>(breakInfo.lines);
stackLines = lines;
if (modulePaths.containsKey(message.file)) {
newBreakScriptName = modulePaths.get(message.file);
userBreakScriptName = newBreakScriptName;
if (newBreakScriptName.contains(":")) {
userBreakScriptName = userSwfName + ": " + newBreakScriptName.substring(newBreakScriptName.indexOf(":") + 1);
}
} else if (reasonInt != InBreakReason.REASON_SCRIPT_LOADED) {
Logger.getLogger(DebuggerCommands.class.getName()).log(Level.SEVERE, "Invalid file: {0}", message.file);
//return;
}
final String[] reasonNames = new String[]{"unknown", "breakpoint", "watch", "fault", "stopRequest", "step", "halt", "scriptLoaded"};
String reason = reasonInt < reasonNames.length ? reasonNames[reasonInt] : reasonNames[0];
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "break at {0}:{1}, reason: {2}", new Object[]{newBreakScriptName, message.line, reason});
try {
sendBreakPoints();
} catch (IOException ex) {
//ignore
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "send breakpoints exception: " + ex.getMessage());
}
synchronized (DebuggerSession.this) {
breakScriptName = newBreakScriptName;
breakIp = message.line;
if (breakInfo != null) {
List<String> files = new ArrayList<>();
for (int i = 0; i < breakInfo.files.size(); i++) {
files.add(DebuggerSession.this.moduleToString(breakInfo.files.get(i)));
}
stackScriptNames = files;
List<Integer> lines = new ArrayList<>(breakInfo.lines);
stackLines = lines;
}
}
if (reasonInt == InBreakReason.REASON_SCRIPT_LOADED) {
if (!Configuration.debugHalt.get()) {
try {
commands.sendContinue();
} catch (IOException iex) {
//ignore
}
return;
}
Main.startWork(AppStrings.translate("work.halted.with").replace("%file%", userSwfName), null, true);
} else {
Main.startWork(AppStrings.translate("work.breakat") + userBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null, true);
}
depth = 0;
refreshFrame();
for (DebuggerHandler.BreakListener l : handler.getBreakListeners()) {
l.breakAt(DebuggerSession.this, 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 iex) {
//ignore ??
}
}
};
if (reasonInt == InBreakReason.REASON_SCRIPT_LOADED) {
if (!Configuration.debugHalt.get()) {
commands.sendContinue();
return;
if (getSwfThreadList.isEmpty()) {
r.run();
} else {
//Wait till all SWFs are loaded
int delay = 500; //check each 500ms
Timer tim = new Timer();
tim.schedule(new TimerTask() {
@Override
public void run() {
TimerTask that = this;
if (getSwfThreadList.isEmpty()) {
r.run();
} else {
Timer tim = new Timer();
tim.schedule(new TimerTask() {
@Override
public void run() {
that.run();
}
}, delay);
}
}
Main.startWork(AppStrings.translate("work.halted"), null, true);
} else {
Main.startWork(AppStrings.translate("work.breakat") + userBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null, true);
}
depth = 0;
refreshFrame();
for (DebuggerHandler.BreakListener l : handler.getBreakListeners()) {
l.breakAt(DebuggerSession.this, 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) {
//ignore
}, delay);
}
}
});
@@ -573,9 +631,9 @@ public class DebuggerSession {
disconnected();
}
}
public boolean containsSwf(SWF swf) {
return debuggedSwfs.contains(swf);
return debuggedSwfs.containsValue(swf);
}
public void setMainDebuggedSwf(SWF debuggedSwf) {
@@ -583,7 +641,7 @@ public class DebuggerSession {
//debuggedSwfs.add(debuggedSwf);
}
public List<SWF> getDebuggedSwfs() {
public Map<Integer, SWF> getDebuggedSwfs() {
return debuggedSwfs;
}
@@ -948,7 +1006,7 @@ public class DebuggerSession {
connected = false;
commands = null;
synchronized (this) {
for (SWF debuggedSwf : debuggedSwfs) {
for (SWF debuggedSwf : debuggedSwfs.values()) {
if (confirmedPointMap.containsKey(debuggedSwf)) {
for (String scriptName : confirmedPointMap.get(debuggedSwf).keySet()) {
if (!toAddBPointMap.containsKey(debuggedSwf)) {
@@ -991,6 +1049,11 @@ public class DebuggerSession {
if (commands != null) {
commands.disconnect();
}
List<Thread> threads = new ArrayList<>(getSwfThreadList);
for (Thread t : threads) {
t.interrupt();
}
disconnected();
}
@@ -1017,7 +1080,7 @@ public class DebuggerSession {
continue;
}
SWF debuggedSwf = debuggedSwfs.get(swfIndex);
String hash = swfIndex == 0 ? "main" : Main.getSwfHash(debuggedSwf); //??
String hash = Main.getSwfHash(debuggedSwf); //??
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINEST, "sending breakpoints of {0}", hash);
@@ -1172,5 +1235,5 @@ public class DebuggerSession {
@Override
public String toString() {
return "[s:" + id + "]";
}
}
}

View File

@@ -97,6 +97,7 @@ import java.awt.geom.AffineTransform;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -131,6 +132,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -140,6 +142,7 @@ import java.util.ResourceBundle;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -235,13 +238,15 @@ public class Main {
private static SWF debuggedSWF = null;
private static String preparedHashSha256 = null;
//private static String preparedHashSha256 = null;
private static SwfPreparation runningPreparation = null;
private static boolean loggingFileLoaded = false;
private static boolean debugListening = false;
private static Map<String, Set<String>> hash2PreparedHash = new HashMap<>();
public static SWF getDebuggedSWF() {
return debuggedSWF;
@@ -260,18 +265,40 @@ public class Main {
public static SWF findOpenedSwfByHash(String hashSha256) {
Logger.getLogger(Main.class.getName()).log(Level.FINE, "Searching for hash {0}...", hashSha256);
for (String origKey : hash2PreparedHash.keySet()) {
if (hash2PreparedHash.get(origKey).contains(hashSha256)) {
hashSha256 = origKey;
break;
}
}
if (hashSha256.startsWith("loaded_")) {
hashSha256 = hashSha256.substring("loaded_".length());
}
if (hashSha256.startsWith("imported_")) {
hashSha256 = hashSha256.substring("loaded_".length());
}
for (SWF swf : mainFrame.getPanel().getAllSwfs()) {
Logger.getLogger(Main.class.getName()).log(Level.FINE, "Checking {0} with hash {1}", new Object[]{swf.toString(), swf.getHashSha256()});
if (Objects.equals(hashSha256, swf.getHashSha256())) {
Logger.getLogger(Main.class.getName()).log(Level.FINE, "RECEIVED SWF FOUND");
return swf;
}
String t = swf.getTitleOrShortFileName();
if (t == null) {
t = "";
}
if (t.endsWith(":" + hashSha256)) {
Logger.getLogger(Main.class.getName()).log(Level.FINE, "RECEIVED SUB SWF FOUND");
return swf;
}
}
if (preparedHashSha256 != null && hashSha256.equals(preparedHashSha256)) {
/*if (preparedHashSha256 != null && hashSha256.equals(preparedHashSha256)) {
Logger.getLogger(Main.class.getName()).log(Level.FINE, "RECEIVED SWF IS ONE THAT WAS PREPARED FOR RUN...");
return runningSWF;
}
}*/
Logger.getLogger(Main.class.getName()).log(Level.FINE, "RECEIVED SWF IS NOT ANY OF OURS");
return null;
@@ -285,7 +312,8 @@ public class Main {
if (session != null) {
return session.getDebuggedSwfs().get(0);
}
return null;
return runningSWF;
//return null;
}
public static WatchService getWatcher() {
@@ -632,8 +660,9 @@ public class Main {
private static void prepareSwf(String swfHash, SwfPreparation prep, File toPrepareFile, File origFile, File tempFilesDir, List<File> tempFiles) throws IOException, InterruptedException {
SWF instrSWF = null;
String origHash = swfHash;
try (FileInputStream fis = new FileInputStream(toPrepareFile)) {
instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile == null ? "unknown.swf" : origFile.getName(), false);
instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile == null ? "unknown.swf" : origFile.getName(), false);
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
@@ -648,9 +677,11 @@ public class Main {
File newTempFile = createTempFileInDir(tempFilesDir, "~ffdec_run_import_", ".swf");
it.setUrl("./" + newTempFile.getName());
byte[] impData = Helper.readFile(importedFile.getAbsolutePath());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWF.decompress(new ByteArrayInputStream(impData), baos);
Helper.writeFile(newTempFile.getAbsolutePath(), impData);
tempFiles.add(newTempFile);
prepareSwf("imported_" + md5(impData), prep, newTempFile, importedFile, tempFilesDir, tempFiles);
prepareSwf("imported_" + sha256(baos.toByteArray()), prep, newTempFile, importedFile, tempFilesDir, tempFiles);
}
}
}
@@ -663,9 +694,15 @@ public class Main {
try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) {
instrSWF.saveTo(fos);
}
if ("main".equals(swfHash)) {
preparedHashSha256 = instrSWF.getHashSha256();
if (!hash2PreparedHash.containsKey(origHash)) {
hash2PreparedHash.put(origHash, new LinkedHashSet<>());
}
String preparedHash = instrSWF.getHashSha256();
hash2PreparedHash.get(origHash).add(preparedHash);
Logger.getLogger(Main.class.getName()).log(Level.FINE, "Prepared {0} as {1}", new Object[]{origHash, preparedHash});
/*if ("main".equals(swfHash)) {
preparedHashSha256 = instrSWF.getHashSha256();
}*/
}
}
@@ -677,7 +714,7 @@ public class Main {
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) {
swfToSave.saveTo(fos, false, swf.gfx);
}
prepareSwf("main", new SwfDebugPrepare(doPCode), fTempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
prepareSwf(swf.getHashSha256(), new SwfDebugPrepare(doPCode), fTempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
}
private static File createTempFileInDir(File tempFilesDir, String prefix, String suffix) throws IOException {
@@ -741,7 +778,7 @@ public class Main {
swfToSave.saveTo(fos, false, swf.gfx);
}
prepareSwf("main", new SwfRunPrepare(), tempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
prepareSwf(swf.getHashSha256(), new SwfRunPrepare(), tempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
} catch (IOException ex) {
return;
@@ -901,7 +938,7 @@ public class Main {
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) {
swfToSave.saveTo(fos, false, swf.gfx);
}
prepareSwf("main", new SwfDebugPrepare(doPCode), fTempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
prepareSwf(swf.getHashSha256(), new SwfDebugPrepare(doPCode), fTempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
return null;
}
@@ -1892,7 +1929,8 @@ public class Main {
List<OpenableList> openableLists = new ArrayList<>();
for (int index = 0; index < sourceInfos.length; index++) {
OpenableSourceInfo sourceInfo = sourceInfos[index];
OpenableList openables = null;
//Logger.getLogger(Main.class.getName()).log(Level.FINE, "Loading source info {0}", sourceInfo.getFile());
OpenableList openables = null;
try {
Main.startWork(AppStrings.translate("work.reading.swf") + "...", null);
try {
@@ -1966,15 +2004,15 @@ public class Main {
mainFrame.getPanel().getABCPanel().updateLinksLabel();
}
}
}
List<String> breakpointsList = conf.getCustomDataAsList(CustomConfigurationKeys.KEY_BREAKPOINTS);
for (String breakpoint : breakpointsList) {
if (breakpoint.matches("^.*:[0-9]+$")) {
int line = Integer.parseInt(breakpoint.substring(breakpoint.lastIndexOf(":") + 1));
String scriptName = breakpoint.substring(0, breakpoint.lastIndexOf(":"));
getDebugHandler().addBreakPoint(swf, scriptName, line);
List<String> breakpointsList = conf.getCustomDataAsList(CustomConfigurationKeys.KEY_BREAKPOINTS);
for (String breakpoint : breakpointsList) {
if (breakpoint.matches("^.*:[0-9]+$")) {
int line = Integer.parseInt(breakpoint.substring(breakpoint.lastIndexOf(":") + 1));
String scriptName = breakpoint.substring(0, breakpoint.lastIndexOf(":"));
getDebugHandler().addBreakPoint(swf, scriptName, line);
}
}
}
}
}
}
}
@@ -2836,9 +2874,9 @@ public class Main {
ErrorLogFrame.getInstance().setVisible(true);
}
private static String md5(byte[] data) {
private static String sha256(byte[] data) {
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
byte[] array = md.digest(data);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < array.length; ++i) {
@@ -2995,7 +3033,9 @@ public class Main {
modifiedListener.dataModified(inputData);
return;
}
final String hash = md5(inputData);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWF.decompress(new ByteArrayInputStream(inputData), baos);
final String hash = sha256(baos.toByteArray());
OpenableOpened afterLoad = new OpenableOpened() {
@Override
public void opened(Openable openable) {
@@ -3024,6 +3064,13 @@ public class Main {
for (OpenableList sl : Main.getMainFrame().getPanel().getSwfs()) {
for (int s = 0; s < sl.size(); s++) {
Openable op = sl.get(s);
if (op instanceof SWF) {
SWF swf = (SWF) op;
if (hash.equals(swf.getHashSha256())) {
afterLoad.opened(op);
return;
}
}
String t = op.getTitleOrShortFileName();
if (t == null) {
t = "";
@@ -3064,13 +3111,13 @@ public class Main {
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
String hash = "main";
String hash = "unknown";
String scriptNameNoHash = scriptName;
if (scriptName.contains(":")) {
hash = scriptName.substring(0, scriptName.indexOf(":"));
scriptNameNoHash = scriptName.substring(scriptName.indexOf(":") + 1);
}
SWF swf = "main".equals(hash) ? session.getDebuggedSwfs().get(0) : Main.getSwfByHash(hash);
SWF swf = Main.getSwfByHash(hash);
Logger.getLogger(Main.class.getName()).log(Level.FINE, "Break. Current session: {0}, New break session: {1}", new Object[]{Main.getCurrentDebugSession(), session});
if (
@@ -3081,6 +3128,10 @@ public class Main {
mainFrame.getPanel().refreshBreakPoints();
return;
}
if (swf == null) {
Logger.getLogger(Main.class.getName()).log(Level.FINE, "Break at unknown SWF.");
return;
}
mainFrame.getPanel().gotoScriptLine(swf, scriptNameNoHash, line, classIndex, traitIndex, methodIndex, Main.isDebugPCode());
}
});
@@ -3935,40 +3986,56 @@ public class Main {
}
public static String getSwfHash(SWF swf) {
if (swf == getRunningSWF()) {
/*if (swf == getRunningSWF()) {
return "main";
}
}*/
String tit = swf.getTitleOrShortFileName();
if (tit != null && tit.contains(":")) {
return "loaded_" + tit.substring(tit.lastIndexOf(":") + 1);
}
return "";
return swf.getHashSha256();
}
public static SWF getSwfByHash(String hash) {
if ("main".equals(hash)) {
public static SWF getSwfByHash(String hashSha256) {
/*if ("main".equals(hash)) {
SWF runningSwf = getRunningSWF();
if (runningSwf == null) {
return mainFrame.getPanel().getCurrentSwf();
}
return runningSwf;
}*/
for (String origKey : hash2PreparedHash.keySet()) {
if (hash2PreparedHash.get(origKey).contains(hashSha256)) {
hashSha256 = origKey;
break;
}
}
if (!hash.startsWith("loaded_")) {
return null;
if (hashSha256.startsWith("loaded_")) {
hashSha256 = hashSha256.substring("loaded_".length());
}
hash = hash.substring("loaded_".length());
if (hashSha256.startsWith("imported_")) {
hashSha256 = hashSha256.substring("imported_".length());
}
for (OpenableList sl : Main.getMainFrame().getPanel().getSwfs()) {
for (int s = 0; s < sl.size(); s++) {
Openable op = sl.get(s);
if (!(op instanceof SWF)) {
continue;
}
SWF swf = (SWF) op;
if (hashSha256.equals(swf.getHashSha256())) {
return swf;
}
String t = op.getTitleOrShortFileName();
if (t == null) {
t = "";
}
if (t.endsWith(":" + hash)) { //this one is already opened
return (SWF) op;
if (t.endsWith(":" + hashSha256)) { //this one is already opened
return swf;
}
}
}

View File

@@ -143,16 +143,16 @@ public final class MainFrameRibbon extends AppRibbonFrame {
boolean first = true;
for (OpenableList swf : panel.getSwfs()) {
if (!first) {
sb.append(File.pathSeparator);
sbt.append(File.pathSeparator);
}
first = false;
String file = swf.sourceInfo.getFile();
if (file != null) {
if (!first) {
sb.append(File.pathSeparator);
sbt.append(File.pathSeparator);
}
sb.append(file);
String t = swf.sourceInfo.getFileTitle();
sbt.append(t == null ? "" : t);
first = false;
}
}

View File

@@ -388,6 +388,9 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
boolean isAS3 = (Main.getMainFrame().getPanel().getCurrentSwf().isAS3());
if (Main.getCurrentDebugSession() == null) {
return;
}
if (parentObjectId == 0 && objectId != 0L && isAS3) {
igv = Main.getCurrentDebugSession().getVariable(objectId, "", true, useGetter);
} else {
@@ -1758,27 +1761,8 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
}
String swfHash = nameIncludingSwfHash.substring(nameIncludingSwfHash.indexOf(":"));
String name = nameIncludingSwfHash.substring(nameIncludingSwfHash.indexOf(":") + 1);
Openable openable = null;
if (swfHash.equals("main")) {
openable = Main.getRunningSWF();
} else if (swfHash.startsWith("loaded_")) {
String hashToSearch = swfHash.substring("loaded_".length());
loop:
for (OpenableList sl : Main.getMainFrame().getPanel().getSwfs()) {
for (int s = 0; s < sl.size(); s++) {
Openable op = sl.get(s);
String t = op.getTitleOrShortFileName();
if (t == null) {
t = "";
}
if (t.endsWith(":" + hashToSearch)) { //this one is already opened
openable = op;
break loop;
}
}
}
}
Openable openable = Main.getSwfByHash(swfHash);
if (openable != null) {
hilightScript(openable, name);
}

View File

@@ -137,7 +137,7 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
}
int ip = Main.getIp(breakPointScriptName);
String ipPath = Main.getIpClass();
String ipHash = "main";
String ipHash = "unknown";
if (ipPath != null && ipPath.contains(":")) {
ipHash = ipPath.substring(0, ipPath.indexOf(":"));
ipPath = ipPath.substring(ipPath.indexOf(":") + 1);
@@ -150,7 +150,7 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
List<String> stackClasses = Main.getStackClasses();
for (int i = 1; i < stackClasses.size(); i++) {
String cls = stackClasses.get(i);
String clsHash = "main";
String clsHash = "unknown";
if (cls.contains(":")) {
clsHash = cls.substring(0, cls.indexOf(":"));
cls = cls.substring(cls.indexOf(":") + 1);

View File

@@ -1112,3 +1112,5 @@ menu.file.start.debuglisten = Debug listen...
work.debugging.listening = Listening for incoming connections...
contextmenu.prepareDebug.injectDebug = Prepare file for debugging (+ inject debug info)
contextmenu.prepareDebug.generateSwd = Prepare file for debugging (+ generate SWD)
prepareDebug.title = Hit Save to overwrite current file or select another file.
work.halted.with = Debugging of %file% started, execution halted. Add breakpoints and click Continue (F5) to resume running.

View File

@@ -3077,17 +3077,14 @@ public class TagTreeContextMenu extends JPopupMenu {
private void prepareDebugActionPerformed(ActionEvent evt) {
TreeItem item = getCurrentItem();
SWF swf = (SWF) item.getOpenable();
File dir = null;
String newName = "debug.swf";
SWF swf = (SWF) item.getOpenable();
JFileChooser chooser = View.getFileChooserWithIcon("debug");
if (swf.getFile() != null) {
dir = new File(swf.getFile()).getParentFile();
String name = new File(swf.getFile()).getName();
newName = name.substring(0, name.lastIndexOf(".")) + "_debug" + name.substring(name.lastIndexOf("."));
File dir = new File(swf.getFile()).getParentFile();
chooser.setCurrentDirectory(dir);
chooser.setSelectedFile(new File(swf.getFile()));
chooser.setDialogTitle(AppStrings.translate("prepareDebug.title"));
}
JFileChooser chooser = View.getFileChooserWithIcon("debug");
chooser.setCurrentDirectory(dir);
chooser.setSelectedFile(new File(dir, newName));
chooser.setFileFilter(new FileFilter() {
@Override
public boolean accept(File f) {