AS3 allow exception start/end to not match instruction boundary

This commit is contained in:
Jindra Petřík
2021-02-08 20:15:19 +01:00
parent 3df1ac57d8
commit a0022ff3b1
16 changed files with 132 additions and 93 deletions
@@ -894,8 +894,7 @@ public class AVM2Code implements Cloneable {
addresses.add(startPos);
if (body != null) {
for (ABCException e : body.exceptions) {
addresses.add((long) e.start);
addresses.add((long) e.end);
//do not process e.start and e.end - they can be not on an instruction boundary
addresses.add((long) e.target);
}
}
@@ -1263,13 +1262,14 @@ public class AVM2Code implements Cloneable {
ABCException exception = body.exceptions[e];
writer.appendNoHilight("try");
//Note: start and end address can be not on instruction boundary - call adr2pos( nearest=true) to make them legal
writer.appendNoHilight(" from ");
writer.appendNoHilight("ofs");
writer.appendNoHilight(Helper.formatAddress(exception.start));
writer.appendNoHilight(Helper.formatAddress(pos2adr(adr2pos(exception.start, true))));
writer.appendNoHilight(" to ");
writer.appendNoHilight("ofs");
writer.appendNoHilight(Helper.formatAddress(exception.end));
writer.appendNoHilight(Helper.formatAddress(pos2adr(adr2pos(exception.end, true))));
writer.appendNoHilight(" target ");
writer.appendNoHilight("ofs");
@@ -1353,9 +1353,9 @@ public class AVM2Code implements Cloneable {
Set<Long> ret = new HashSet<>();
if (body != null) {
for (ABCException exception : body.exceptions) {
ret.add((long) exception.start);
ret.add((long) pos2adr(adr2pos(exception.start, true)));
if (tryEnds) {
ret.add((long) exception.end);
ret.add((long) pos2adr(adr2pos(exception.end, true)));
}
ret.add((long) exception.target);
}
@@ -2451,7 +2451,6 @@ public class AVM2Code implements Cloneable {
return null;
}
int scopePos = -1;
int prevStart = 0;
for (int e = 0; e < body.exceptions.length; e++) {
ABCException ex = body.exceptions[e];
try {
@@ -2475,28 +2474,10 @@ public class AVM2Code implements Cloneable {
}
}
scopePos = stats.instructionStats[maxIp].scopepos_after;
int stackPos = stats.instructionStats[maxIp].stackpos_after;
int nextIp = maxIp + 1;
if (code.get(maxIp).definition instanceof JumpIns) {
nextIp = adr2pos(pos2adr(nextIp) + code.get(maxIp).operands[0]);
}
/*if (nextIp < stats.instructionStats.length) {
InstructionStats nextIpStat = stats.instructionStats[nextIp];
int origScopePos = nextIpStat.scopepos;
int origStackPos = nextIpStat.stackpos;
if (prevStart == ex.start && ex.isFinally() && !code.get(nextIp).isExit() && nextIpStat.seen) {
for (int i = 0; i < stats.instructionStats.length; i++) {
stats.instructionStats[i].seen = false;
}
// Rerun rest with new scopePos, stackPos
if (!walkCode(stats, nextIp, origStackPos + 1, scopePos - 1, abc, autoFill)) {
return null;
}
scopePos--;
}
}*/
prevStart = ex.start;
} catch (ConvertException ex1) {
// ignore
}
@@ -2593,14 +2574,9 @@ public class AVM2Code implements Cloneable {
refs.put(i, new ArrayList<>());
}
visitCode(0, 0, refs);
int pos = 0;
for (ABCException e : body.exceptions) {
pos++;
try {
visitCode(adr2pos(e.start, true), adr2pos(e.start, true) - 1, refs);
visitCode(adr2pos(e.start, true), -1, refs);
visitCode(adr2pos(e.target), adr2pos(e.end, true), refs);
visitCode(adr2pos(e.end, true), -pos, refs);
visitCode(adr2pos(e.target), -1, refs);
} catch (ConvertException ex) {
logger.log(Level.SEVERE, "Visitcode error", ex);
}
@@ -12,7 +12,8 @@
* 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.abc.avm2.deobfuscation;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -303,6 +304,11 @@ public class AVM2DeobfuscatorRegisters extends AVM2DeobfuscatorSimple {
return code.pos2adr(pos);
}
@Override
public int adr2pos(long adr, boolean nearest) {
return code.adr2pos(adr, nearest);
}
@Override
public Set<Long> getImportantAddresses() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
@@ -187,7 +187,7 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
Map<Integer, List<ExceptionTargetIpPair>> exceptionStartToTargets = new HashMap<>();
for (ABCException ex : body.exceptions) {
int startIp = code.adr2pos(ex.start);
int startIp = code.adr2pos(ex.start, true);
int targetIp = code.adr2pos(ex.target);
if (!exceptionStartToTargets.containsKey(startIp)) {
exceptionStartToTargets.put(startIp, new ArrayList<>());
@@ -230,11 +230,6 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
toVisitStacks.add(targetStack);
}
}
for (ABCException ex : body.exceptions) {
if (code.pos2adr(idx) == ex.start) {
}
}
AVM2Instruction ins = code.code.get(idx);
InstructionDefinition def = ins.definition;
@@ -317,6 +312,12 @@ public class AVM2DeobfuscatorRegistersOld extends AVM2DeobfuscatorSimpleOld {
return code.pos2adr(pos);
}
@Override
public int adr2pos(long adr, boolean nearest) {
return code.adr2pos(adr, nearest);
}
@Override
public Set<Long> getImportantAddresses() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
@@ -36,6 +36,9 @@ import com.jpexs.decompiler.flash.abc.avm2.instructions.localregs.SetLocalTypeIn
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.HasNext2Ins;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.LabelIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.NopIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnValueIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ReturnVoidIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other.ThrowIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.DecLocalPIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.other2.IncLocalPIns;
import com.jpexs.decompiler.flash.abc.avm2.instructions.stack.PopIns;
@@ -280,7 +283,7 @@ public class AVM2Graph extends Graph {
}
}
int finEndIp = avm2code.adr2pos(ex.end);
int finEndIp = avm2code.adr2pos(ex.end, true);
GraphPart finallyEndPart = searchPart(finEndIp, allParts);
List<GraphPart> refs = getRealRefs(finallyEndPart);
@@ -315,7 +318,7 @@ public class AVM2Graph extends Graph {
}
} else if (finallyKind == FINALLY_KIND_REGISTER_BASED) {
switchPart = findLookupSwitchWithGetLocal(switchedReg, finallyPart);
int startIp = code.adr2pos(ex.start);
int startIp = code.adr2pos(ex.start, true);
GraphPart tryPart = null;
for (GraphPart p : allParts) {
if (startIp >= p.start && startIp <= p.end) {
@@ -724,18 +727,21 @@ public class AVM2Graph extends Graph {
List<Integer> finnalysIndicesToBe = new ArrayList<>();
int realIp = -1;
for (int e = 0; e < body.exceptions.length; e++) {
if (addr == avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].start)) {
long fixedExStart = avm2code.pos2adr(avm2code.adr2pos(body.exceptions[e].start, true));
long fixedExEnd = avm2code.pos2adr(avm2code.adr2pos(body.exceptions[e].end, true));
if (addr == avm2code.getAddrThroughJumpAndDebugLine(fixedExStart)) {
ABCException ex = body.exceptions[e];
if (!parsedExceptions.contains(ex)) {
if (ex.isFinally()) {
finnalysIndicesToBe.add(e);
} else {
long endAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
long endAddr = avm2code.getAddrThroughJumpAndDebugLine(fixedExEnd);
if (endAddr > maxEndAddr) {
catchedExceptions.clear();
maxEndAddr = avm2code.getAddrThroughJumpAndDebugLine(body.exceptions[e].end);
maxEndAddr = avm2code.getAddrThroughJumpAndDebugLine(fixedExEnd);
endIp = avm2code.adr2pos(maxEndAddr);
realIp = avm2code.adr2pos(body.exceptions[e].end);
realIp = avm2code.adr2pos(fixedExEnd);
catchedExceptions.add(body.exceptions[e]);
} else if (endAddr == maxEndAddr) {
catchedExceptions.add(body.exceptions[e]);
@@ -757,7 +763,7 @@ public class AVM2Graph extends Graph {
finallyException = finallyExceptionToBe;
break;
}
int finEndIp = avm2code.getIpThroughJumpAndDebugLine(avm2code.adr2pos(finallyExceptionToBe.end));
int finEndIp = avm2code.getIpThroughJumpAndDebugLine(avm2code.adr2pos(finallyExceptionToBe.end, true));
if (finEndIp == endIp) {
finallyIndex = e;
finallyException = finallyExceptionToBe;
@@ -800,18 +806,58 @@ public class AVM2Graph extends Graph {
GraphPart afterPart = null;
GraphPart endIpPart = searchPart(endIp, allParts);
if (endIpPart != null && getRealRefs(endIpPart).isEmpty()) { //swftools - there is jump on previous ip
if (avm2code.code.get(endIpPart.start - 1).definition instanceof JumpIns) {
GraphPart prevPart = searchPart(endIpPart.start - 1, allParts);
endIpPart = prevPart.nextParts.get(0);
if (endIpPart != null && getRealRefs(endIpPart).isEmpty()) {
int pos = endIpPart.start - 1;
if (avm2code.code.get(pos).definition instanceof DebugLineIns) {
pos--;
}
if (avm2code.code.get(pos).definition instanceof JumpIns) {
GraphPart prevPart = searchPart(pos, allParts);
if (prevPart.nextParts.get(0).start >= realIp) {
endIpPart = prevPart.nextParts.get(0);
} else {
endIpPart = null;
}
}
else if (avm2code.code.get(pos).definition instanceof ReturnVoidIns) {
endIpPart = null;
}
else if (avm2code.code.get(pos).definition instanceof ReturnValueIns) {
endIpPart = null;
}
else if (avm2code.code.get(pos).definition instanceof ThrowIns) {
endIpPart = null;
}
}
GraphPart realEndIpPart = searchPart(realIp, allParts);
if (realEndIpPart != null && getRealRefs(realEndIpPart).isEmpty()) { //swftools - there is jump on previous ip
if (avm2code.code.get(realEndIpPart.start - 1).definition instanceof JumpIns) {
GraphPart prevPart = searchPart(realEndIpPart.start - 1, allParts);
realEndIpPart = prevPart.nextParts.get(0);
if (realEndIpPart != null && getRealRefs(realEndIpPart).isEmpty()) {
int pos = realEndIpPart.start - 1;
if (avm2code.code.get(pos).definition instanceof DebugLineIns) {
pos--;
}
if (avm2code.code.get(pos).definition instanceof JumpIns) {
GraphPart prevPart = searchPart(pos, allParts);
if (prevPart.nextParts.get(0).start >= realIp) {
realEndIpPart = prevPart.nextParts.get(0);
endIpPart = prevPart.nextParts.get(0);
} else {
realEndIpPart = null;
endIpPart = null;
}
}
else if (avm2code.code.get(pos).definition instanceof ReturnVoidIns) {
realEndIpPart = null;
endIpPart = null;
}
else if (avm2code.code.get(pos).definition instanceof ReturnValueIns) {
realEndIpPart = null;
endIpPart = null;
}
else if (avm2code.code.get(pos).definition instanceof ThrowIns) {
realEndIpPart = null;
endIpPart = null;
}
}
afterPart = realEndIpPart;
@@ -1284,15 +1330,15 @@ public class AVM2Graph extends Graph {
if (spt.object instanceof LocalRegAVM2Item) {
getLocalObjectIp = avm2code.adr2pos(spt.object.getSrc().getAddress());
regIndex = ((LocalRegAVM2Item) spt.object).regIndex;
expr = ift.expression.getNotCoerced();
if (withCommands.size() > 1) {
withCommands.remove(withCommands.size() - 1);
withCommands.add(expr);
expr = new CommaExpressionItem(null, localData.lineStartInstruction, withCommands);
}
}
}
}
expr = ift.expression.getNotCoerced();
if (withCommands.size() > 1) {
withCommands.remove(withCommands.size() - 1);
withCommands.add(expr);
expr = new CommaExpressionItem(null, localData.lineStartInstruction, withCommands);
}
} else {
//There is no if - this means there was something that
// can be evaluated on compiletime and compiler removed the whole if
@@ -12,7 +12,8 @@
* 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.abc.avm2.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -133,4 +134,9 @@ public class AVM2GraphSource extends GraphSource {
public long pos2adr(int pos) {
return code.pos2adr(pos);
}
@Override
public int adr2pos(long adr, boolean nearest) {
return code.adr2pos(adr, true);
}
}
@@ -12,7 +12,8 @@
* 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.action;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -154,37 +155,11 @@ public class ActionGraphSource extends GraphSource {
if (!posCache.isEmpty() && (adr > posCache.get(posCache.size() - 1))) {
return size();
}
//ret = adr2posInside(adr);
if (ret == -1) {
Logger.getLogger(ActionGraphSource.class.getName()).log(Level.SEVERE, "{0} - address loc{1} not found", new Object[]{path, Helper.formatAddress(adr)});
/*System.err.println("Addr loc"+Helper.formatAddress(adr)+" not found");
int pos=0;
for(long l:posCache){
System.err.println("ip "+pos+" action "+get(pos).toString()+" loc"+Helper.formatAddress(l));
pos++;
}*/
}
}
return ret;
/*int pos = 0;
long lastAddr = 0;
for (Action a : actions) {
lastAddr = a.getAddress();
System.err.println("ip "+pos+" addr "+Helper.formatAddress(lastAddr));
if (lastAddr == adr) {
return pos;
}
pos++;
}
if (adr > lastAddr) {
return actions.size();
}
if (adr == 0) {
return 0;
}
//throw new RuntimeException("Address "+Helper.formatAddress(adr)+" not found");
return -1;*/
}
@Override
@@ -195,4 +170,29 @@ public class ActionGraphSource extends GraphSource {
}
return 0;
}
@Override
public int adr2pos(long adr, boolean nearest) {
if (posCache == null) {
rebuildCache();
}
if (adr == 0) {
return 0;
}
int ret = posCache.indexOf((Long) adr);
if (ret == -1) {
if (!posCache.isEmpty() && (adr > posCache.get(posCache.size() - 1))) {
return size();
}
for (int i = 0; i < posCache.size(); i++) {
Long a = posCache.get(i);
if (a > adr) {
return i;
}
}
return size();
}
return ret;
}
}
@@ -12,7 +12,8 @@
* 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.graph;
import com.jpexs.decompiler.flash.BaseLocalData;
@@ -112,6 +113,8 @@ public abstract class GraphSource implements Serializable {
public abstract int adr2pos(long adr);
public abstract int adr2pos(long adr, boolean nearest);
public abstract long pos2adr(int pos);
public long getAddressAfterCode() {