From 24602a4a0dd8673384241af08eed4da5b85bfa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 19 Nov 2023 10:11:59 +0100 Subject: [PATCH] Fixed AS3 Debugging - activation object was not visible in locals --- CHANGELOG.md | 1 + .../decompiler/flash/abc/ScriptPack.java | 33 +++++++-- .../localregs/SetLocalTypeIns.java | 2 + .../abc/avm2/model/NewFunctionAVM2Item.java | 2 +- .../model/StoreNewActivationAVM2Item.java | 69 +++++++++++++++++++ .../flash/abc/types/traits/TraitClass.java | 4 +- .../flash/abc/types/traits/TraitFunction.java | 4 +- .../types/traits/TraitMethodGetterSetter.java | 4 +- .../abc/types/traits/TraitSlotConst.java | 2 +- .../flash/helpers/GraphTextWriter.java | 7 +- .../flash/helpers/HighlightedTextWriter.java | 17 ++++- .../flash/helpers/hilight/HighlightData.java | 8 ++- 12 files changed, 136 insertions(+), 17 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/StoreNewActivationAVM2Item.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 076bfe31b..094f85ad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ All notable changes to this project will be documented in this file. - AS3 debugger - obfuscated classes debugging - Delayed open loaded SWFs while playing - AS3 Direct editation - script initializer for main document class +- AS3 Debugging - activation object was not visible in locals ### Changed - [#2120] Exported assets no longer take names from assigned classes if there is more than 1 assigned class 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 98cfba4d2..2b6eadede 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 @@ -225,7 +225,7 @@ public class ScriptPack extends AS3ClassTreeItem { if (bodyIndex != -1 && (isSimple || traitIndices.isEmpty())) { //Note: There must be trait/method highlight even if the initializer is empty to TraitList in GUI to work correctly writer.startTrait(GraphTextWriter.TRAIT_SCRIPT_INITIALIZER); - writer.startMethod(script_init); + writer.startMethod(script_init, null); if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!scriptInitializerIsEmpty) { writer.startBlock(); @@ -398,8 +398,10 @@ public class ScriptPack extends AS3ClassTreeItem { Map> bodyLineToPos = new HashMap<>(); Map> bodyToRegToName = new HashMap<>(); Map> bodyToRegToLine = new HashMap<>(); - + Map bodyToActivationReg = new HashMap<>(); Set lonelyBody = new HashSet<>(); + Map bodyLines = new HashMap<>(); + Map bodyToFunctionName = new HashMap<>(); try { HighlightedText decompiled = SWF.getCached(this); int line = 1; @@ -437,6 +439,14 @@ public class ScriptPack extends AS3ClassTreeItem { if (bodyIndex == -1) { break blk; } + if (!bodyLines.containsKey(bodyIndex)) { + bodyLines.put(bodyIndex, line); + } + if (!bodyToFunctionName.containsKey(bodyIndex)) { + bodyToFunctionName.put(bodyIndex, method.getProperties().localName); + } + + bodyToActivationReg.put(bodyIndex, method.getProperties().activationRegIndex); int pos = -1; int regIndex = -1; String regName = null; @@ -550,21 +560,34 @@ public class ScriptPack extends AS3ClassTreeItem { delIns.add(ins); } } + List code2 = new ArrayList<>(); + int dpos = 0; - b.insertInstruction(0, new AVM2Instruction(0, AVM2Instructions.DebugFile, new int[]{abc.constants.getStringId(filename, true)}), true); + code2.add(new AVM2Instruction(0, AVM2Instructions.DebugFile, new int[]{abc.constants.getStringId(filename, true)})); dpos++; Set regs = bodyToRegToName.containsKey(bodyIndex) ? bodyToRegToName.get(bodyIndex).keySet() : new TreeSet<>(); for (int r : regs) { String name = bodyToRegToName.get(bodyIndex).get(r); int line = bodyToRegToLine.get(bodyIndex).get(r); - b.insertInstruction(dpos++, new AVM2Instruction(0, AVM2Instructions.Debug, new int[]{1, abc.constants.getStringId(name, true), r - 1, line})); + code2.add(new AVM2Instruction(0, AVM2Instructions.Debug, new int[]{1, abc.constants.getStringId(name, true), r - 1, line})); } + int activationReg = -1; + if (bodyToActivationReg.containsKey(bodyIndex)) { + activationReg = bodyToActivationReg.get(bodyIndex); + } + if (activationReg > -1) { + int bodyLine = bodyLines.containsKey(bodyIndex) ? bodyLines.get(bodyIndex) : 0; + String activationRegName = "anonymous$0"; + if (bodyToFunctionName.containsKey(bodyIndex) && bodyToFunctionName.get(bodyIndex) != null) { + activationRegName = bodyToFunctionName.get(bodyIndex) + "$0"; + } + code2.add(new AVM2Instruction(0, AVM2Instructions.Debug, new int[]{1, abc.constants.getStringId(activationRegName, true), activationReg - 1, bodyLine})); + } List pos = new ArrayList<>(bodyToPosToLine.get(bodyIndex).keySet()); Collections.sort(pos); Collections.reverse(pos); Set addedLines = new HashSet<>(); Set importantOffsets = b.getCode().getImportantOffsets(b, true); - List code2 = new ArrayList<>(); Map origPosToNewPos = new HashMap<>(); for (int i = 0; i < code.size(); i++) { long adr = b.getCode().pos2adr(i); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java index 60c8901cb..8a6aa3727 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/instructions/localregs/SetLocalTypeIns.java @@ -30,6 +30,7 @@ import com.jpexs.decompiler.flash.abc.avm2.model.NewActivationAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.PostDecrementAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.PostIncrementAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.SetLocalAVM2Item; +import com.jpexs.decompiler.flash.abc.avm2.model.StoreNewActivationAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreDecrementAVM2Item; import com.jpexs.decompiler.flash.abc.avm2.model.operations.PreIncrementAVM2Item; import com.jpexs.decompiler.graph.GraphTargetItem; @@ -73,6 +74,7 @@ public abstract class SetLocalTypeIns extends InstructionDefinition implements S localData.localRegAssignmentIps.put(regId, localData.localRegAssignmentIps.get(regId) + 1); //localRegsAssignmentIps.put(regId, ip); if (value.getThroughDuplicate() instanceof NewActivationAVM2Item) { + output.add(new StoreNewActivationAVM2Item(ins, localData.lineStartInstruction, regId)); return; } if (value instanceof FindPropertyAVM2Item) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java index 13e1231ff..3de273dea 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/NewFunctionAVM2Item.java @@ -75,7 +75,7 @@ public class NewFunctionAVM2Item extends AVM2Item { } MethodBody body = abc.findBody(methodIndex); writer.append("function"); - writer.startMethod(methodIndex); + writer.startMethod(methodIndex, null); writer.append((!functionName.isEmpty() ? " " + functionName : "")); writer.appendNoHilight("("); abc.method_info.get(methodIndex).getParamStr(writer, abc.constants, body, abc, localData.fullyQualifiedNames); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/StoreNewActivationAVM2Item.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/StoreNewActivationAVM2Item.java new file mode 100644 index 000000000..58998485d --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/avm2/model/StoreNewActivationAVM2Item.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010-2023 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.abc.avm2.model; + +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightData; +import com.jpexs.decompiler.graph.GraphSourceItem; +import com.jpexs.decompiler.graph.GraphTargetItem; +import com.jpexs.decompiler.graph.TypeItem; +import com.jpexs.decompiler.graph.model.LocalData; + +/** + * Store new Activation object. This exists just for the purpose of passing + * activation register to the GraphTextWriter to correctly be read + * by debug info injector. + * @author JPEXS + */ +public class StoreNewActivationAVM2Item extends AVM2Item { + + public int regIndex; + + public StoreNewActivationAVM2Item(GraphSourceItem instruction, GraphSourceItem lineStartIns, int regIndex) { + super(instruction, lineStartIns, PRECEDENCE_PRIMARY); + this.regIndex = regIndex; + } + + @Override + public boolean needsNewLine() { + return false; + } + + @Override + public boolean needsSemicolon() { + return false; + } + + @Override + public GraphTextWriter appendTo(GraphTextWriter writer, LocalData localData) throws InterruptedException { + HighlightData hd = new HighlightData(); + hd.activationRegIndex = regIndex; + writer.addCurrentMethodData(hd); + return writer; + } + + @Override + public boolean hasReturnValue() { + return false; + } + + @Override + public GraphTargetItem returnType() { + return TypeItem.UNBOUNDED; + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java index 476c82a21..7da02d68c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitClass.java @@ -185,7 +185,7 @@ public class TraitClass extends Trait implements TraitWithSlot { int bodyIndex = abc.findBodyIndex(classInfo.cinit_index); if (bodyIndex != -1) { writer.startTrait(GraphTextWriter.TRAIT_CLASS_INITIALIZER); - writer.startMethod(classInfo.cinit_index); + writer.startMethod(classInfo.cinit_index, "cinit"); if (exportMode != ScriptExportMode.AS_METHOD_STUBS) { if (!classInitializerIsEmpty) { writer.startBlock(); @@ -218,7 +218,7 @@ public class TraitClass extends Trait implements TraitWithSlot { writer.newLine(); writer.startTrait(GraphTextWriter.TRAIT_INSTANCE_INITIALIZER); - writer.startMethod(instanceInfo.iinit_index); + writer.startMethod(instanceInfo.iinit_index, "iinit"); writer.appendNoHilight(modifier); writer.appendNoHilight("function "); writer.appendNoHilight(m.getName(abc.constants, null/*do not want full names here*/, false, true)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java index e4207d586..e793f88a0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java @@ -86,7 +86,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { public GraphTextWriter toString(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, GraphTextWriter writer, List fullyQualifiedNames, boolean parallel, boolean insideInterface) throws InterruptedException { writeImports(abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames); getMetaData(parent, convertData, abc, writer); - writer.startMethod(method_info); + writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface); writer.startBlock(); @@ -108,7 +108,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { public void convert(AbcIndexing abcIndex, Trait parent, ConvertData convertData, String path, ABC abc, boolean isStatic, ScriptExportMode exportMode, int scriptIndex, int classIndex, NulWriter writer, List fullyQualifiedNames, boolean parallel, ScopeStack scopeStack) throws InterruptedException { fullyQualifiedNames = new ArrayList<>(); writeImports(abcIndex, scriptIndex, classIndex, false, abc, writer, getPackage(abc), fullyQualifiedNames); - writer.startMethod(method_info); + writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); int bodyIndex = abc.findBodyIndex(method_info); if (bodyIndex != -1) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java index 0c27b9e8f..bf51190ca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitMethodGetterSetter.java @@ -108,7 +108,7 @@ public class TraitMethodGetterSetter extends Trait { if (classIndex < 0) { writeImports(abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames); } - writer.startMethod(method_info); + writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false, true); convertHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel); int bodyIndex = abc.findBodyIndex(method_info); @@ -136,7 +136,7 @@ public class TraitMethodGetterSetter extends Trait { writeImports(abcIndex, scriptIndex, classIndex, isStatic, abc, writer, getPackage(abc), fullyQualifiedNames); } getMetaData(parent, convertData, abc, writer); - writer.startMethod(method_info); + writer.startMethod(method_info, getName(abc).getName(abc.constants, new ArrayList<>(), true, false)); path = path + "." + getName(abc).getName(abc.constants, fullyQualifiedNames, false, true); toStringHeader(parent, convertData, path, abc, isStatic, exportMode, scriptIndex, classIndex, writer, fullyQualifiedNames, parallel, insideInterface); int bodyIndex = abc.findBodyIndex(method_info); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java index b6a9ab4f2..191a7ff51 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/types/traits/TraitSlotConst.java @@ -119,7 +119,7 @@ public class TraitSlotConst extends Trait implements TraitWithSlot { AssignedValue assignment = convertData.assignedValues.get(this); writer.startTrait(assignment.initializer); - writer.startMethod(assignment.method); + writer.startMethod(assignment.method, null); if (Configuration.showMethodBodyId.get()) { writer.appendNoHilight("// method body index: "); writer.appendNoHilight(abc.findBodyIndex(assignment.method)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/GraphTextWriter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/GraphTextWriter.java index 305c3a712..3032fdc4e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/GraphTextWriter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/GraphTextWriter.java @@ -75,9 +75,10 @@ public abstract class GraphTextWriter { * Highlights specified text as method * * @param index MethodInfo index + * @param name * @return GraphTextWriter */ - public GraphTextWriter startMethod(long index) { + public GraphTextWriter startMethod(long index, String name) { return this; } @@ -250,4 +251,8 @@ public abstract class GraphTextWriter { } return this; } + + public GraphTextWriter addCurrentMethodData(HighlightData data) { + return this; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/HighlightedTextWriter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/HighlightedTextWriter.java index e28cec35b..409399e46 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/HighlightedTextWriter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/HighlightedTextWriter.java @@ -116,9 +116,10 @@ public class HighlightedTextWriter extends GraphTextWriter { * @return HighlightedTextWriter */ @Override - public HighlightedTextWriter startMethod(long index) { + public HighlightedTextWriter startMethod(long index, String name) { HighlightData data = new HighlightData(); data.index = index; + data.localName = name; return start(data, HighlightType.METHOD); } @@ -309,7 +310,7 @@ public class HighlightedTextWriter extends GraphTextWriter { private HighlightedTextWriter start(HighlightData data, HighlightType type) { if (hilight) { Highlighting h = new Highlighting(sb.length() - newLineCount, data, type, null); - hilightStack.add(h); + hilightStack.add(h); } return this; } @@ -377,4 +378,16 @@ public class HighlightedTextWriter extends GraphTextWriter { appendNoHilight(formatting.indentString); } } + + @Override + public GraphTextWriter addCurrentMethodData(HighlightData data) { + for (int i = hilightStack.size() - 1; i >= 0; i--) { + Highlighting h = hilightStack.get(i); + if (h.type == HighlightType.METHOD) { + h.getProperties().merge(data); + break; + } + } + return this; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/hilight/HighlightData.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/hilight/HighlightData.java index e18a64606..6515b07d5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/hilight/HighlightData.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/hilight/HighlightData.java @@ -46,6 +46,8 @@ public class HighlightData implements Cloneable, Serializable { public int regIndex = -1; public int namespaceIndex = -1; + + public int activationRegIndex = -1; public boolean isStatic = false; @@ -60,7 +62,8 @@ public class HighlightData implements Cloneable, Serializable { && fileOffset == -1 && namespaceIndex == -1 && propertyType == null - && propertySubType == null; + && propertySubType == null + && activationRegIndex == -1; } public void merge(HighlightData data) { @@ -109,6 +112,9 @@ public class HighlightData implements Cloneable, Serializable { if (data.propertySubType != null) { propertySubType = data.propertySubType; } + if (data.activationRegIndex != -1) { + activationRegIndex = data.activationRegIndex; + } } @Override