Fixed AS3 Debugging - activation object was not visible in locals

This commit is contained in:
Jindra Petřík
2023-11-19 10:11:59 +01:00
parent f6afdfb9d2
commit 24602a4a0d
12 changed files with 136 additions and 17 deletions

View File

@@ -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<Integer, Map<Integer, Integer>> bodyLineToPos = new HashMap<>();
Map<Integer, Map<Integer, String>> bodyToRegToName = new HashMap<>();
Map<Integer, Map<Integer, Integer>> bodyToRegToLine = new HashMap<>();
Map<Integer, Integer> bodyToActivationReg = new HashMap<>();
Set<Integer> lonelyBody = new HashSet<>();
Map<Integer, Integer> bodyLines = new HashMap<>();
Map<Integer, String> 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<Object> 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<Integer> 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<Integer> pos = new ArrayList<>(bodyToPosToLine.get(bodyIndex).keySet());
Collections.sort(pos);
Collections.reverse(pos);
Set<Integer> addedLines = new HashSet<>();
Set<Long> importantOffsets = b.getCode().getImportantOffsets(b, true);
List<Object> code2 = new ArrayList<>();
Map<Integer, Integer> origPosToNewPos = new HashMap<>();
for (int i = 0; i < code.size(); i++) {
long adr = b.getCode().pos2adr(i);

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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));

View File

@@ -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<DottedChain> 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<DottedChain> 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) {

View File

@@ -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);

View File

@@ -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));

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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