Add IntInterpreter and IntValue

I'm planning to use these to remove dummies.
master
Graham 5 years ago
parent 2cde631fca
commit 751ae183c1
  1. 20
      asm/src/main/java/dev/openrs2/asm/InsnNodeUtils.java
  2. 167
      deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.java
  3. 63
      deob/src/main/java/dev/openrs2/deob/analysis/IntValue.java

@ -35,6 +35,26 @@ public final class InsnNodeUtils {
return insn; return insn;
} }
public static boolean isIntConstant(AbstractInsnNode insn) {
switch (insn.getOpcode()) {
case Opcodes.ICONST_M1:
case Opcodes.ICONST_0:
case Opcodes.ICONST_1:
case Opcodes.ICONST_2:
case Opcodes.ICONST_3:
case Opcodes.ICONST_4:
case Opcodes.ICONST_5:
case Opcodes.BIPUSH:
case Opcodes.SIPUSH:
return true;
case Opcodes.LDC:
var ldc = (LdcInsnNode) insn;
return ldc.cst instanceof Integer;
}
return false;
}
public static int getIntConstant(AbstractInsnNode insn) { public static int getIntConstant(AbstractInsnNode insn) {
switch (insn.getOpcode()) { switch (insn.getOpcode()) {
case Opcodes.ICONST_M1: case Opcodes.ICONST_M1:

@ -0,0 +1,167 @@
package dev.openrs2.deob.analysis;
import java.util.List;
import java.util.stream.Collectors;
import dev.openrs2.asm.InsnNodeUtils;
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 final Interpreter<BasicValue> basicInterpreter = new BasicInterpreter();
public IntInterpreter() {
super(Opcodes.ASM7);
}
@Override
public IntValue newValue(Type type) {
var basicValue = basicInterpreter.newValue(type);
if (basicValue == null) {
return null;
}
return IntValue.newUnknown(basicValue);
}
@Override
public IntValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
var basicValue = basicInterpreter.newOperation(insn);
if (basicValue == null) {
return null;
}
if (InsnNodeUtils.isIntConstant(insn)) {
return IntValue.newConstant(basicValue, InsnNodeUtils.getIntConstant(insn));
}
return IntValue.newUnknown(basicValue);
}
@Override
public IntValue copyOperation(AbstractInsnNode insn, IntValue value) throws AnalyzerException {
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.isConstant()) {
var v = value.getIntValue();
switch (insn.getOpcode()) {
case Opcodes.INEG:
return IntValue.newConstant(basicValue, -v);
case Opcodes.IINC:
var iinc = (IincInsnNode) insn;
return IntValue.newConstant(basicValue, v + iinc.incr);
case Opcodes.I2B:
return IntValue.newConstant(basicValue, (byte) v);
case Opcodes.I2C:
return IntValue.newConstant(basicValue, (char) v);
case Opcodes.I2S:
return IntValue.newConstant(basicValue, (short) v);
}
}
return IntValue.newUnknown(basicValue);
}
@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.isConstant() && value2.isConstant()) {
var v1 = value1.getIntValue();
var v2 = value2.getIntValue();
switch (insn.getOpcode()) {
case Opcodes.IADD:
return IntValue.newConstant(basicValue, v1 + v2);
case Opcodes.ISUB:
return IntValue.newConstant(basicValue, v1 - v2);
case Opcodes.IMUL:
return IntValue.newConstant(basicValue, v1 * v2);
case Opcodes.IDIV:
if (v2 == 0) {
return IntValue.newUnknown(basicValue);
}
return IntValue.newConstant(basicValue, v1 / v2);
case Opcodes.IREM:
if (v2 == 0) {
return IntValue.newUnknown(basicValue);
}
return IntValue.newConstant(basicValue, v1 % v2);
case Opcodes.ISHL:
return IntValue.newConstant(basicValue, v1 << v2);
case Opcodes.ISHR:
return IntValue.newConstant(basicValue, v1 >> v2);
case Opcodes.IUSHR:
return IntValue.newConstant(basicValue, v1 >>> v2);
case Opcodes.IAND:
return IntValue.newConstant(basicValue, v1 & v2);
case Opcodes.IOR:
return IntValue.newConstant(basicValue, v1 | v2);
case Opcodes.IXOR:
return IntValue.newConstant(basicValue, v1 ^ v2);
}
}
return IntValue.newUnknown(basicValue);
}
@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(Collectors.toUnmodifiableList());
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.isConstant() && value2.isConstant() && value1.getIntValue() == value2.getIntValue()) {
return IntValue.newConstant(basicValue, value1.getIntValue());
}
return IntValue.newUnknown(basicValue);
}
}

@ -0,0 +1,63 @@
package dev.openrs2.deob.analysis;
import java.util.Objects;
import com.google.common.base.Preconditions;
import org.objectweb.asm.tree.analysis.BasicValue;
import org.objectweb.asm.tree.analysis.Value;
public final class IntValue implements Value {
public static IntValue newConstant(BasicValue basicValue, int intValue) {
Preconditions.checkArgument(basicValue == BasicValue.INT_VALUE);
return new IntValue(basicValue, intValue);
}
public static IntValue newUnknown(BasicValue basicValue) {
Preconditions.checkNotNull(basicValue);
return new IntValue(basicValue, null);
}
private final BasicValue basicValue;
private final Integer intValue;
private IntValue(BasicValue basicValue, Integer intValue) {
this.basicValue = basicValue;
this.intValue = intValue;
}
public BasicValue getBasicValue() {
return basicValue;
}
public boolean isConstant() {
return intValue != null;
}
public int getIntValue() {
Preconditions.checkState(intValue != null);
return intValue;
}
@Override
public int getSize() {
return basicValue.getSize();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
IntValue intValue1 = (IntValue) o;
return basicValue.equals(intValue1.basicValue) &&
Objects.equals(intValue, intValue1.intValue);
}
@Override
public int hashCode() {
return Objects.hash(basicValue, intValue);
}
}
Loading…
Cancel
Save