Convert IntInterpreter to Kotlin

pull/48/head
Graham 4 years ago
parent f56b288663
commit 1864b6b630
  1. 239
      deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.java
  2. 167
      deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.kt

@ -1,239 +0,0 @@
package dev.openrs2.deob.analysis;
import java.util.List;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import dev.openrs2.asm.InsnNodeUtilsKt;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicInterpreter;
import org.objectweb.asm.tree.analysis.BasicValue;
import org.objectweb.asm.tree.analysis.Interpreter;
public final class IntInterpreter extends Interpreter<IntValue> {
private static final int MAX_TRACKED_VALUES = 1;
private final Interpreter<BasicValue> basicInterpreter = new BasicInterpreter();
private final ImmutableSet<Integer>[] parameters;
public IntInterpreter(ImmutableSet<Integer>[] parameters) {
super(Opcodes.ASM7);
this.parameters = parameters;
}
@Override
public IntValue newValue(Type type) {
var basicValue = basicInterpreter.newValue(type);
if (basicValue == null) {
return null;
}
return IntValue.newUnknown(basicValue);
}
@Override
public IntValue newParameterValue(boolean isInstanceMethod, int local, Type type) {
var basicValue = basicInterpreter.newParameterValue(isInstanceMethod, local, type);
if (basicValue == null) {
return null;
}
if (parameters != null) {
int parameterIndex;
if (isInstanceMethod) {
if (local == 0) {
return IntValue.newUnknown(basicValue);
}
parameterIndex = local - 1;
} else {
parameterIndex = local;
}
var parameter = parameters[parameterIndex];
if (parameter != null) {
return IntValue.newConstant(basicValue, parameter);
}
}
return IntValue.newUnknown(basicValue);
}
@Override
public IntValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
var basicValue = basicInterpreter.newOperation(insn);
if (basicValue == null) {
return null;
}
var v = InsnNodeUtilsKt.getIntConstant(insn);
if (v != null) {
return IntValue.newConstant(basicValue, v);
}
return IntValue.newUnknown(basicValue);
}
@Override
public IntValue copyOperation(AbstractInsnNode insn, IntValue value) {
return value;
}
@Override
public IntValue unaryOperation(AbstractInsnNode insn, IntValue value) throws AnalyzerException {
var basicValue = basicInterpreter.unaryOperation(insn, value.getBasicValue());
if (basicValue == null) {
return null;
}
if (value.isUnknown()) {
return IntValue.newUnknown(basicValue);
}
var set = ImmutableSet.<Integer>builder();
for (var v : value.getIntValues()) {
switch (insn.getOpcode()) {
case Opcodes.INEG:
set.add(-v);
break;
case Opcodes.IINC:
var iinc = (IincInsnNode) insn;
set.add(v + iinc.incr);
break;
case Opcodes.I2B:
set.add((int) (byte) (int) v);
break;
case Opcodes.I2C:
set.add((int) (char) (int) v);
break;
case Opcodes.I2S:
set.add((int) (short) (int) v);
break;
default:
return IntValue.newUnknown(basicValue);
}
}
return IntValue.newConstant(basicValue, set.build());
}
@Override
public IntValue binaryOperation(AbstractInsnNode insn, IntValue value1, IntValue value2) throws AnalyzerException {
var basicValue = basicInterpreter.binaryOperation(insn, value1.getBasicValue(), value2.getBasicValue());
if (basicValue == null) {
return null;
}
if (value1.isUnknown() || value2.isUnknown()) {
return IntValue.newUnknown(basicValue);
}
var set = ImmutableSet.<Integer>builder();
for (var v1 : value1.getIntValues()) {
for (var v2 : value2.getIntValues()) {
switch (insn.getOpcode()) {
case Opcodes.IADD:
set.add(v1 + v2);
break;
case Opcodes.ISUB:
set.add(v1 - v2);
break;
case Opcodes.IMUL:
set.add(v1 * v2);
break;
case Opcodes.IDIV:
if (v2 == 0) {
return IntValue.newUnknown(basicValue);
}
set.add(v1 / v2);
break;
case Opcodes.IREM:
if (v2 == 0) {
return IntValue.newUnknown(basicValue);
}
set.add(v1 % v2);
break;
case Opcodes.ISHL:
set.add(v1 << v2);
break;
case Opcodes.ISHR:
set.add(v1 >> v2);
break;
case Opcodes.IUSHR:
set.add(v1 >>> v2);
break;
case Opcodes.IAND:
set.add(v1 & v2);
break;
case Opcodes.IOR:
set.add(v1 | v2);
break;
case Opcodes.IXOR:
set.add(v1 ^ v2);
break;
default:
return IntValue.newUnknown(basicValue);
}
}
}
return IntValue.newConstant(basicValue, set.build());
}
@Override
public IntValue ternaryOperation(AbstractInsnNode insn, IntValue value1, IntValue value2, IntValue value3) throws AnalyzerException {
var basicValue = basicInterpreter.ternaryOperation(insn, value1.getBasicValue(), value2.getBasicValue(), value3.getBasicValue());
if (basicValue == null) {
return null;
}
return IntValue.newUnknown(basicValue);
}
@Override
public IntValue naryOperation(AbstractInsnNode insn, List<? extends IntValue> values) throws AnalyzerException {
var args = values.stream()
.map(IntValue::getBasicValue)
.collect(ImmutableList.toImmutableList());
var basicValue = basicInterpreter.naryOperation(insn, args);
if (basicValue == null) {
return null;
}
return IntValue.newUnknown(basicValue);
}
@Override
public void returnOperation(AbstractInsnNode insn, IntValue value, IntValue expected) throws AnalyzerException {
basicInterpreter.returnOperation(insn, value.getBasicValue(), expected.getBasicValue());
}
@Override
public IntValue merge(IntValue value1, IntValue value2) {
var basicValue = basicInterpreter.merge(value1.getBasicValue(), value2.getBasicValue());
if (basicValue == null) {
return null;
}
if (value1.equals(value2)) {
return value1;
}
if (value1.isUnknown() || value2.isUnknown()) {
return IntValue.newUnknown(basicValue);
}
var set = ImmutableSet.copyOf(Sets.union(value1.getIntValues(), value2.getIntValues()));
if (set.size() > MAX_TRACKED_VALUES) {
return IntValue.newUnknown(basicValue);
}
return IntValue.newConstant(basicValue, set);
}
}

@ -0,0 +1,167 @@
package dev.openrs2.deob.analysis
import com.google.common.collect.ImmutableSet
import com.google.common.collect.Sets
import dev.openrs2.asm.intConstant
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.AbstractInsnNode
import org.objectweb.asm.tree.IincInsnNode
import org.objectweb.asm.tree.analysis.AnalyzerException
import org.objectweb.asm.tree.analysis.BasicInterpreter
import org.objectweb.asm.tree.analysis.Interpreter
class IntInterpreter(private val parameters: Array<ImmutableSet<Int>?>?) : Interpreter<IntValue>(Opcodes.ASM7) {
private val basicInterpreter = BasicInterpreter()
override fun newValue(type: Type?): IntValue? {
val basicValue = basicInterpreter.newValue(type) ?: return null
return IntValue.newUnknown(basicValue)
}
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): IntValue {
val basicValue = basicInterpreter.newParameterValue(isInstanceMethod, local, type)
if (parameters != null) {
val parameterIndex = when {
isInstanceMethod && local == 0 -> return IntValue.newUnknown(basicValue)
isInstanceMethod -> local - 1
else -> local
}
val parameter = parameters[parameterIndex]
if (parameter != null) {
return IntValue.newConstant(basicValue, parameter)
}
}
return IntValue.newUnknown(basicValue)
}
@Throws(AnalyzerException::class)
override fun newOperation(insn: AbstractInsnNode): IntValue {
val basicValue = basicInterpreter.newOperation(insn)
val v = insn.intConstant
return if (v != null) {
IntValue.newConstant(basicValue, v)
} else {
IntValue.newUnknown(basicValue)
}
}
override fun copyOperation(insn: AbstractInsnNode, value: IntValue): IntValue {
return value
}
@Throws(AnalyzerException::class)
override fun unaryOperation(insn: AbstractInsnNode, value: IntValue): IntValue? {
val basicValue = basicInterpreter.unaryOperation(insn, value.basicValue) ?: return null
if (value.isUnknown) {
return IntValue.newUnknown(basicValue)
}
val set = ImmutableSet.builder<Int>()
for (v in value.intValues) {
val result = when {
insn.opcode == Opcodes.INEG -> -v
insn is IincInsnNode -> v + insn.incr
insn.opcode == Opcodes.I2B -> v.toByte().toInt()
insn.opcode == Opcodes.I2C -> v.toChar().toInt()
insn.opcode == Opcodes.I2S -> v.toShort().toInt()
else -> return IntValue.newUnknown(basicValue)
}
set.add(result)
}
return IntValue.newConstant(basicValue, set.build())
}
@Throws(AnalyzerException::class)
override fun binaryOperation(insn: AbstractInsnNode, value1: IntValue, value2: IntValue): IntValue? {
val basicValue = basicInterpreter.binaryOperation(insn, value1.basicValue, value2.basicValue) ?: return null
if (value1.isUnknown || value2.isUnknown) {
return IntValue.newUnknown(basicValue)
}
val set = ImmutableSet.builder<Int>()
for (v1 in value1.intValues) {
for (v2 in value2.intValues) {
val result = when (insn.opcode) {
Opcodes.IADD -> v1 + v2
Opcodes.ISUB -> v1 - v2
Opcodes.IMUL -> v1 * v2
Opcodes.IDIV -> {
if (v2 == 0) {
return IntValue.newUnknown(basicValue)
}
v1 / v2
}
Opcodes.IREM -> {
if (v2 == 0) {
return IntValue.newUnknown(basicValue)
}
v1 % v2
}
Opcodes.ISHL -> v1 shl v2
Opcodes.ISHR -> v1 shr v2
Opcodes.IUSHR -> v1 ushr v2
Opcodes.IAND -> v1 and v2
Opcodes.IOR -> v1 or v2
Opcodes.IXOR -> v1 xor v2
else -> return IntValue.newUnknown(basicValue)
}
set.add(result)
}
}
return IntValue.newConstant(basicValue, set.build())
}
@Throws(AnalyzerException::class)
override fun ternaryOperation(
insn: AbstractInsnNode,
value1: IntValue,
value2: IntValue,
value3: IntValue
): IntValue? {
val basicValue =
basicInterpreter.ternaryOperation(insn, value1.basicValue, value2.basicValue, value3.basicValue)
?: return null
return IntValue.newUnknown(basicValue)
}
@Throws(AnalyzerException::class)
override fun naryOperation(insn: AbstractInsnNode, values: List<IntValue>): IntValue? {
val args = values.map { it.basicValue }.toList()
val basicValue = basicInterpreter.naryOperation(insn, args) ?: return null
return IntValue.newUnknown(basicValue)
}
@Throws(AnalyzerException::class)
override fun returnOperation(insn: AbstractInsnNode, value: IntValue, expected: IntValue) {
basicInterpreter.returnOperation(insn, value.basicValue, expected.basicValue)
}
override fun merge(value1: IntValue, value2: IntValue): IntValue {
val basicValue = basicInterpreter.merge(value1.basicValue, value2.basicValue)
if (value1 == value2) {
return value1
}
if (value1.isUnknown || value2.isUnknown) {
return IntValue.newUnknown(basicValue)
}
val set = ImmutableSet.copyOf(Sets.union(value1.intValues, value2.intValues))
return if (set.size > MAX_TRACKED_VALUES) {
IntValue.newUnknown(basicValue)
} else {
IntValue.newConstant(basicValue, set)
}
}
companion object {
private const val MAX_TRACKED_VALUES = 1
}
}
Loading…
Cancel
Save