Skip to content

Commit

Permalink
Fixed AS1/2 - switch with nontrivial expressions like and/or,ternar (…
Browse files Browse the repository at this point in the history
…second pass)
  • Loading branch information
jindrapetrik committed Nov 29, 2021
1 parent 0122db9 commit 526f484
Show file tree
Hide file tree
Showing 115 changed files with 443 additions and 140 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file.
- AS1/2 - typeof precedence / parenthesis
- AS1/2 - switch detection
- AS1/2 - nested tellTarget
- AS1/2 - switch with nontrivial expressions like and/or,ternar (second pass)

## [14.6.0] - 2021-11-22
### Added
Expand Down
Expand Up @@ -12,10 +12,12 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. */
* License along with this library.
*/
package com.jpexs.decompiler.flash;

import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.SecondPassData;

/**
*
Expand All @@ -24,4 +26,6 @@
public abstract class BaseLocalData {

public GraphSourceItem lineStartInstruction;

public SecondPassData secondPassData = null;
}
2 changes: 1 addition & 1 deletion libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java
Expand Up @@ -2205,7 +2205,7 @@ private static void getVariables(ConstantPool constantPool, BaseLocalData localD
}

private static void getVariables(boolean insideDoInitAction, List<MyEntry<DirectValueActionItem, ConstantPool>> variables, List<GraphSourceItem> functions, HashMap<DirectValueActionItem, ConstantPool> strings, HashMap<DirectValueActionItem, String> usageTypes, ActionGraphSource code, int addr, String path) throws InterruptedException {
ActionLocalData localData = new ActionLocalData(insideDoInitAction);
ActionLocalData localData = new ActionLocalData(null, insideDoInitAction);
getVariables(null, localData, new TranslateStack(path), new ArrayList<>(), code, code.adr2pos(addr), variables, functions, strings, new ArrayList<>(), usageTypes, path);
}

Expand Down
21 changes: 14 additions & 7 deletions libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/Action.java
Expand Up @@ -67,6 +67,8 @@
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.decompiler.graph.SecondPassException;
import com.jpexs.decompiler.graph.TranslateException;
import com.jpexs.decompiler.graph.TranslateStack;
import com.jpexs.decompiler.graph.model.CommentItem;
Expand Down Expand Up @@ -744,6 +746,8 @@ public String getASMSource(ActionList container, Set<Long> knownAddreses, Script
/**
* Translates this function to stack and output.
*
* @param secondPassData
* @param insideDoInitAction
* @param lineStartIns Line start instruction
* @param stack Stack
* @param output Output
Expand All @@ -754,7 +758,7 @@ public String getASMSource(ActionList container, Set<Long> knownAddreses, Script
* @param path the value of path
* @throws java.lang.InterruptedException
*/
public void translate(boolean insideDoInitAction, GraphSourceItem lineStartIns, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) throws InterruptedException {
public void translate(SecondPassData secondPassData, boolean insideDoInitAction, GraphSourceItem lineStartIns, TranslateStack stack, List<GraphTargetItem> output, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, int staticOperation, String path) throws InterruptedException {
}

@Override
Expand Down Expand Up @@ -917,8 +921,11 @@ public List<GraphTargetItem> call() throws Exception {
* @throws java.lang.InterruptedException
*/
public static List<GraphTargetItem> actionsToTree(boolean insideDoInitAction, boolean insideFunction, HashMap<Integer, String> regNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, List<Action> actions, int version, int staticOperation, String path) throws InterruptedException {
return ActionGraph.translateViaGraph(insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path
);
try {
return ActionGraph.translateViaGraph(null, insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path);
} catch (SecondPassException spe) {
return ActionGraph.translateViaGraph(spe.getData(), insideDoInitAction, insideFunction, regNames, variables, functions, actions, version, staticOperation, path);
}
}

@Override
Expand All @@ -930,7 +937,7 @@ public void translate(BaseLocalData localData, TranslateStack stack, List<GraphT
}
expectedSize += getStackPushCount(localData, stack);*/

translate(aLocalData.insideDoInitAction, aLocalData.lineStartAction, stack, output, aLocalData.regNames, aLocalData.variables, aLocalData.functions, staticOperation, path);
translate(aLocalData.secondPassData, aLocalData.insideDoInitAction, aLocalData.lineStartAction, stack, output, aLocalData.regNames, aLocalData.variables, aLocalData.functions, staticOperation, path);
/*if (stack.size() != expectedSize && !(this instanceof ActionPushDuplicate)) {
throw new Error("HONFIKA stack size mismatch");
}*/
Expand Down Expand Up @@ -966,11 +973,11 @@ public void setIgnored(boolean ignored, int pos) {
this.ignored = ignored;
}

public static List<GraphTargetItem> actionsPartToTree(boolean insideDoInitAction, Reference<GraphSourceItem> fi, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, TranslateStack stack, List<Action> actions, int start, int end, int version, int staticOperation, String path) throws InterruptedException {
public static List<GraphTargetItem> actionsPartToTree(SecondPassData secondPassData, boolean insideDoInitAction, Reference<GraphSourceItem> fi, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, TranslateStack stack, List<Action> actions, int start, int end, int version, int staticOperation, String path) throws InterruptedException {
if (start < actions.size() && (end > 0) && (start > 0)) {
logger.log(Level.FINE, "Entering {0}-{1}{2}", new Object[]{start, end, actions.size() > 0 ? (" (" + actions.get(start).toString() + " - " + actions.get(end == actions.size() ? end - 1 : end) + ")") : ""});
}
ActionLocalData localData = new ActionLocalData(insideDoInitAction, registerNames, variables, functions);
ActionLocalData localData = new ActionLocalData(secondPassData, insideDoInitAction, registerNames, variables, functions);
localData.lineStartAction = fi.getVal();
List<GraphTargetItem> output = new ArrayList<>();
int ip = start;
Expand Down Expand Up @@ -1040,7 +1047,7 @@ public static List<GraphTargetItem> actionsPartToTree(boolean insideDoInitAction
}
}
}
out = ActionGraph.translateViaGraph(insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName));
out = ActionGraph.translateViaGraph(secondPassData, insideDoInitAction, true, regNames, variables2, functions, actions.subList(adr2ip(actions, endAddr), adr2ip(actions, endAddr + size)), version, staticOperation, path + (cntName == null ? "" : "/" + cntName));
} catch (OutOfMemoryError | TranslateException | StackOverflowError ex) {
logger.log(Level.SEVERE, "Decompilation error in: " + path, ex);
if (ex instanceof OutOfMemoryError) {
Expand Down
132 changes: 117 additions & 15 deletions libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionGraph.java
Expand Up @@ -34,11 +34,13 @@
import com.jpexs.decompiler.flash.action.model.clauses.TellTargetActionItem;
import com.jpexs.decompiler.flash.action.model.operations.NeqActionItem;
import com.jpexs.decompiler.flash.action.model.operations.StrictEqActionItem;
import com.jpexs.decompiler.flash.action.model.operations.StrictNeqActionItem;
import com.jpexs.decompiler.flash.action.swf4.ActionEquals;
import com.jpexs.decompiler.flash.action.swf4.ActionIf;
import com.jpexs.decompiler.flash.action.swf4.ActionJump;
import com.jpexs.decompiler.flash.action.swf4.ActionNot;
import com.jpexs.decompiler.flash.action.swf4.ActionPush;
import com.jpexs.decompiler.flash.action.swf4.RegisterNumber;
import com.jpexs.decompiler.flash.action.swf5.ActionDefineFunction;
import com.jpexs.decompiler.flash.action.swf5.ActionEquals2;
import com.jpexs.decompiler.flash.action.swf6.ActionStrictEquals;
Expand All @@ -52,8 +54,8 @@
import com.jpexs.decompiler.graph.GraphSourceItem;
import com.jpexs.decompiler.graph.GraphSourceItemContainer;
import com.jpexs.decompiler.graph.GraphTargetItem;
import com.jpexs.decompiler.graph.GraphTargetVisitorInterface;
import com.jpexs.decompiler.graph.Loop;
import com.jpexs.decompiler.graph.SecondPassData;
import com.jpexs.decompiler.graph.StopPartKind;
import com.jpexs.decompiler.graph.ThrowState;
import com.jpexs.decompiler.graph.TranslateStack;
Expand All @@ -68,7 +70,6 @@
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Reference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -132,9 +133,9 @@ protected void afterPopupateAllParts(Set<GraphPart> allParts) {

}

public static List<GraphTargetItem> translateViaGraph(boolean insideDoInitAction, boolean insideFunction, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, List<Action> code, int version, int staticOperation, String path) throws InterruptedException {
public static List<GraphTargetItem> translateViaGraph(SecondPassData secondPassData, boolean insideDoInitAction, boolean insideFunction, HashMap<Integer, String> registerNames, HashMap<String, GraphTargetItem> variables, HashMap<String, GraphTargetItem> functions, List<Action> code, int version, int staticOperation, String path) throws InterruptedException {
ActionGraph g = new ActionGraph(path, insideDoInitAction, insideFunction, code, registerNames, variables, functions, version);
ActionLocalData localData = new ActionLocalData(insideDoInitAction, registerNames);
ActionLocalData localData = new ActionLocalData(secondPassData, insideDoInitAction, registerNames);
g.init(localData);
return g.translate(localData, staticOperation, path);
}
Expand Down Expand Up @@ -436,19 +437,37 @@ protected List<GraphTargetItem> check(List<GraphTargetItem> currentRet, List<Got
List<GraphPart> caseBodyParts = new ArrayList<>();
caseBodyParts.add(part.nextParts.get(0));
GraphTargetItem top = null;
int cnt = 1;
while (part.nextParts.size() > 1
&& part.nextParts.get(1).getHeight() > 1
&& code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end) instanceof ActionIf
&& ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqActionItem)) {
cnt++;
part = part.nextParts.get(1);
caseBodyParts.add(part.nextParts.get(0));

set = (StrictEqActionItem) top;
caseValuesMap.add(set.rightSide);
ActionSecondPassData secondPassData = (ActionSecondPassData) localData.secondPassData;
boolean secondSwitchFound = false;
if (secondPassData != null) {
for (int si = 0; si < secondPassData.switchParts.size(); si++) {
if (secondPassData.switchParts.get(si).get(0).equals(part)) {
part = secondPassData.switchParts.get(si).get(secondPassData.switchParts.get(si).size() - 1);
caseBodyParts.clear();
caseBodyParts.addAll(secondPassData.switchOnFalseParts.get(si));
caseValuesMap.clear();
caseValuesMap.addAll(secondPassData.switchCaseExpressions.get(si));
secondSwitchFound = true;
}
}
}

int cnt = 1;
if (!secondSwitchFound) {
while (part.nextParts.size() > 1
&& part.nextParts.get(1).getHeight() > 1
&& code.get(part.nextParts.get(1).end >= code.size() ? code.size() - 1 : part.nextParts.get(1).end) instanceof ActionIf
&& ((top = translatePartGetStack(localData, part.nextParts.get(1), stack, staticOperation)) instanceof StrictEqActionItem)) {
cnt++;
part = part.nextParts.get(1);
caseBodyParts.add(part.nextParts.get(0));

set = (StrictEqActionItem) top;
caseValuesMap.add(set.rightSide);
}
}
if (cnt == 1) {
if (!secondSwitchFound && cnt == 1) {
stack.push(set);
} else {
part = part.nextParts.get(1);
Expand Down Expand Up @@ -504,4 +523,87 @@ protected int checkIp(int ip) {
}
return ip;
}

@Override
public SecondPassData prepareSecondPass(List<GraphTargetItem> list) {
ActionSecondPassData spd = new ActionSecondPassData();
checkSecondPassSwitches(list, spd.switchParts, spd.switchOnFalseParts, spd.switchCaseExpressions);

if (spd.switchParts.isEmpty()) {
return null; //no need to second pass
}
return spd;
}

private void checkSecondPassSwitches(List<GraphTargetItem> list, List<List<GraphPart>> allSwitchParts, List<List<GraphPart>> allSwitchOnFalseParts, List<List<GraphTargetItem>> allSwitchExpressions) {
for (GraphTargetItem item : list) {
List<List<GraphTargetItem>> walkNext = new ArrayList<>();
boolean canUseBlock = true;
if (item instanceof IfItem) {
IfItem ii = (IfItem) item;
if (ii.expression instanceof StrictNeqActionItem) {
List<GraphPart> switchParts = new ArrayList<>();
List<GraphTargetItem> switchExpressions = new ArrayList<>();
List<GraphPart> switchOnFalseParts = new ArrayList<>();
StrictNeqActionItem sneq = (StrictNeqActionItem) ii.expression;
if (sneq.leftSide instanceof StoreRegisterActionItem) {
StoreRegisterActionItem sr = (StoreRegisterActionItem) sneq.leftSide;
int regId = sr.register.number;

switchParts.add(ii.decisionPart);
switchExpressions.add(sneq.rightSide);
switchOnFalseParts.add(ii.onTruePart);

IfItem ii2 = ii;
while (true) {
if (!ii2.onTrue.isEmpty() && (ii2.onTrue.get(0) instanceof IfItem)) {
ii2 = (IfItem) ii2.onTrue.get(0);
if (ii2.expression instanceof StrictNeqActionItem) {
sneq = (StrictNeqActionItem) ii2.expression;
if (sneq.leftSide instanceof DirectValueActionItem) {
DirectValueActionItem dv = (DirectValueActionItem) sneq.leftSide;
if (dv.value instanceof RegisterNumber) {
RegisterNumber rn = (RegisterNumber) dv.value;
if (rn.number == regId) {
switchParts.add(ii2.decisionPart);
switchOnFalseParts.add(ii2.onTruePart);
switchExpressions.add(sneq.rightSide);
walkNext.add(ii2.onFalse);
} else {
break;
}
} else {
break;
}
} else {
break;
}
} else {
break;
}
} else {
break;
}
}

if (switchParts.size() > 1) {
allSwitchParts.add(switchParts);
allSwitchOnFalseParts.add(switchOnFalseParts);
allSwitchExpressions.add(switchExpressions);
walkNext.add(ii2.onFalse);
canUseBlock = false;
}
}
}
}
if ((item instanceof Block) && (canUseBlock)) {
for (List<GraphTargetItem> sub : ((Block) item).getSubs()) {
checkSecondPassSwitches(sub, allSwitchParts, allSwitchOnFalseParts, allSwitchExpressions);
}
}
for (List<GraphTargetItem> next : walkNext) {
checkSecondPassSwitches(next, allSwitchParts, allSwitchOnFalseParts, allSwitchExpressions);
}
}
}
}
Expand Up @@ -102,7 +102,7 @@ public boolean isEmpty() {
public List<GraphTargetItem> translatePart(GraphPart part, BaseLocalData localData, TranslateStack stack, int start, int end, int staticOperation, String path) throws InterruptedException {
Reference<GraphSourceItem> fi = new Reference<>(localData.lineStartInstruction);

List<GraphTargetItem> r = Action.actionsPartToTree(this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path);
List<GraphTargetItem> r = Action.actionsPartToTree(localData.secondPassData, this.insideDoInitAction, fi, registerNames, variables, functions, stack, actions, start, end, version, staticOperation, path);
localData.lineStartInstruction = fi.getVal();
return r;
}
Expand Down

0 comments on commit 526f484

Please sign in to comment.