forked from openrs2/openrs2
parent
2cde631fca
commit
751ae183c1
@ -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…
Reference in new issue