Convert IntValue to a sealed class

master
Graham 5 years ago
parent 84f18c4d10
commit 0f78c9582c
  1. 58
      deob/src/main/java/dev/openrs2/deob/analysis/IntInterpreter.kt
  2. 88
      deob/src/main/java/dev/openrs2/deob/analysis/IntValue.java
  3. 25
      deob/src/main/java/dev/openrs2/deob/analysis/IntValue.kt
  4. 21
      deob/src/main/java/dev/openrs2/deob/transform/DummyArgTransformer.kt

@ -1,7 +1,5 @@
package dev.openrs2.deob.analysis package dev.openrs2.deob.analysis
import com.google.common.collect.ImmutableSet
import com.google.common.collect.Sets
import dev.openrs2.asm.intConstant import dev.openrs2.asm.intConstant
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type import org.objectweb.asm.Type
@ -16,7 +14,7 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
override fun newValue(type: Type?): IntValue? { override fun newValue(type: Type?): IntValue? {
val basicValue = basicInterpreter.newValue(type) ?: return null val basicValue = basicInterpreter.newValue(type) ?: return null
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): IntValue { override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): IntValue {
@ -24,18 +22,18 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
if (parameters != null) { if (parameters != null) {
val parameterIndex = when { val parameterIndex = when {
isInstanceMethod && local == 0 -> return IntValue.newUnknown(basicValue) isInstanceMethod && local == 0 -> return IntValue.Unknown(basicValue)
isInstanceMethod -> local - 1 isInstanceMethod -> local - 1
else -> local else -> local
} }
val parameter = parameters[parameterIndex] val parameter = parameters[parameterIndex]
if (parameter != null) { if (parameter != null) {
return IntValue.newConstant(basicValue, parameter) return IntValue.Constant(basicValue, parameter)
} }
} }
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
@Throws(AnalyzerException::class) @Throws(AnalyzerException::class)
@ -43,9 +41,9 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
val basicValue = basicInterpreter.newOperation(insn) val basicValue = basicInterpreter.newOperation(insn)
val v = insn.intConstant val v = insn.intConstant
return if (v != null) { return if (v != null) {
IntValue.newConstant(basicValue, v) IntValue.Constant(basicValue, v)
} else { } else {
IntValue.newUnknown(basicValue) IntValue.Unknown(basicValue)
} }
} }
@ -57,49 +55,49 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
override fun unaryOperation(insn: AbstractInsnNode, value: IntValue): IntValue? { override fun unaryOperation(insn: AbstractInsnNode, value: IntValue): IntValue? {
val basicValue = basicInterpreter.unaryOperation(insn, value.basicValue) ?: return null val basicValue = basicInterpreter.unaryOperation(insn, value.basicValue) ?: return null
if (value.isUnknown) { if (value !is IntValue.Constant) {
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
val set = ImmutableSet.builder<Int>() val set = mutableSetOf<Int>()
for (v in value.intValues) { for (v in value.values) {
val result = when { val result = when {
insn.opcode == Opcodes.INEG -> -v insn.opcode == Opcodes.INEG -> -v
insn is IincInsnNode -> v + insn.incr insn is IincInsnNode -> v + insn.incr
insn.opcode == Opcodes.I2B -> v.toByte().toInt() insn.opcode == Opcodes.I2B -> v.toByte().toInt()
insn.opcode == Opcodes.I2C -> v.toChar().toInt() insn.opcode == Opcodes.I2C -> v.toChar().toInt()
insn.opcode == Opcodes.I2S -> v.toShort().toInt() insn.opcode == Opcodes.I2S -> v.toShort().toInt()
else -> return IntValue.newUnknown(basicValue) else -> return IntValue.Unknown(basicValue)
} }
set.add(result) set.add(result)
} }
return IntValue.newConstant(basicValue, set.build()) return IntValue.Constant(basicValue, set)
} }
@Throws(AnalyzerException::class) @Throws(AnalyzerException::class)
override fun binaryOperation(insn: AbstractInsnNode, value1: IntValue, value2: IntValue): IntValue? { override fun binaryOperation(insn: AbstractInsnNode, value1: IntValue, value2: IntValue): IntValue? {
val basicValue = basicInterpreter.binaryOperation(insn, value1.basicValue, value2.basicValue) ?: return null val basicValue = basicInterpreter.binaryOperation(insn, value1.basicValue, value2.basicValue) ?: return null
if (value1.isUnknown || value2.isUnknown) { if (value1 !is IntValue.Constant || value2 !is IntValue.Constant) {
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
val set = ImmutableSet.builder<Int>() val set = mutableSetOf<Int>()
for (v1 in value1.intValues) { for (v1 in value1.values) {
for (v2 in value2.intValues) { for (v2 in value2.values) {
val result = when (insn.opcode) { val result = when (insn.opcode) {
Opcodes.IADD -> v1 + v2 Opcodes.IADD -> v1 + v2
Opcodes.ISUB -> v1 - v2 Opcodes.ISUB -> v1 - v2
Opcodes.IMUL -> v1 * v2 Opcodes.IMUL -> v1 * v2
Opcodes.IDIV -> { Opcodes.IDIV -> {
if (v2 == 0) { if (v2 == 0) {
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
v1 / v2 v1 / v2
} }
Opcodes.IREM -> { Opcodes.IREM -> {
if (v2 == 0) { if (v2 == 0) {
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
v1 % v2 v1 % v2
} }
@ -109,12 +107,12 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
Opcodes.IAND -> v1 and v2 Opcodes.IAND -> v1 and v2
Opcodes.IOR -> v1 or v2 Opcodes.IOR -> v1 or v2
Opcodes.IXOR -> v1 xor v2 Opcodes.IXOR -> v1 xor v2
else -> return IntValue.newUnknown(basicValue) else -> return IntValue.Unknown(basicValue)
} }
set.add(result) set.add(result)
} }
} }
return IntValue.newConstant(basicValue, set.build()) return IntValue.Constant(basicValue, set)
} }
@Throws(AnalyzerException::class) @Throws(AnalyzerException::class)
@ -127,14 +125,14 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
val basicValue = val basicValue =
basicInterpreter.ternaryOperation(insn, value1.basicValue, value2.basicValue, value3.basicValue) basicInterpreter.ternaryOperation(insn, value1.basicValue, value2.basicValue, value3.basicValue)
?: return null ?: return null
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
@Throws(AnalyzerException::class) @Throws(AnalyzerException::class)
override fun naryOperation(insn: AbstractInsnNode, values: List<IntValue>): IntValue? { override fun naryOperation(insn: AbstractInsnNode, values: List<IntValue>): IntValue? {
val args = values.map { it.basicValue }.toList() val args = values.map { it.basicValue }.toList()
val basicValue = basicInterpreter.naryOperation(insn, args) ?: return null val basicValue = basicInterpreter.naryOperation(insn, args) ?: return null
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
@Throws(AnalyzerException::class) @Throws(AnalyzerException::class)
@ -149,15 +147,15 @@ class IntInterpreter(private val parameters: Array<Set<Int>?>?) : Interpreter<In
return value1 return value1
} }
if (value1.isUnknown || value2.isUnknown) { if (value1 !is IntValue.Constant || value2 !is IntValue.Constant) {
return IntValue.newUnknown(basicValue) return IntValue.Unknown(basicValue)
} }
val set = ImmutableSet.copyOf(Sets.union(value1.intValues, value2.intValues)) val set = value1.values.union(value2.values)
return if (set.size > MAX_TRACKED_VALUES) { return if (set.size > MAX_TRACKED_VALUES) {
IntValue.newUnknown(basicValue) IntValue.Unknown(basicValue)
} else { } else {
IntValue.newConstant(basicValue, set) IntValue.Constant(basicValue, set)
} }
} }

@ -1,88 +0,0 @@
package dev.openrs2.deob.analysis;
import java.util.Objects;
import java.util.Set;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
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) {
return newConstant(basicValue, ImmutableSet.of(intValue));
}
public static IntValue newConstant(BasicValue basicValue, Set<Integer> intValues) {
Preconditions.checkArgument(basicValue == BasicValue.INT_VALUE);
Preconditions.checkArgument(!intValues.isEmpty());
return new IntValue(basicValue, intValues);
}
public static IntValue newUnknown(BasicValue basicValue) {
Preconditions.checkNotNull(basicValue);
return new IntValue(basicValue, ImmutableSet.of());
}
private final BasicValue basicValue;
private final Set<Integer> intValues;
private IntValue(BasicValue basicValue, Set<Integer> intValues) {
this.basicValue = basicValue;
this.intValues = intValues;
}
public BasicValue getBasicValue() {
return basicValue;
}
public boolean isUnknown() {
return intValues.isEmpty();
}
public boolean isSingleConstant() {
return intValues.size() == 1;
}
public int getIntValue() {
Preconditions.checkState(isSingleConstant());
return intValues.iterator().next();
}
public Set<Integer> getIntValues() {
Preconditions.checkArgument(!isUnknown());
return intValues;
}
@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(intValues, intValue1.intValues);
}
@Override
public int hashCode() {
return Objects.hash(basicValue, intValues);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("basicValue", basicValue)
.add("intValues", intValues)
.toString();
}
}

@ -0,0 +1,25 @@
package dev.openrs2.deob.analysis
import org.objectweb.asm.tree.analysis.BasicValue
import org.objectweb.asm.tree.analysis.Value
sealed class IntValue : Value {
data class Unknown(override val basicValue: BasicValue) : IntValue()
data class Constant(override val basicValue: BasicValue, val values: Set<Int>) : IntValue() {
val singleton: Int?
init {
require(values.isNotEmpty())
singleton = if (values.size == 1) values.first() else null
}
constructor(basicValue: BasicValue, value: Int) : this(basicValue, setOf(value))
}
abstract val basicValue: BasicValue
override fun getSize(): Int {
return basicValue.size
}
}

@ -10,6 +10,7 @@ import dev.openrs2.asm.transform.Transformer
import dev.openrs2.common.collect.DisjointSet import dev.openrs2.common.collect.DisjointSet
import dev.openrs2.deob.ArgRef import dev.openrs2.deob.ArgRef
import dev.openrs2.deob.analysis.IntInterpreter import dev.openrs2.deob.analysis.IntInterpreter
import dev.openrs2.deob.analysis.IntValue
import dev.openrs2.deob.analysis.SourcedIntValue import dev.openrs2.deob.analysis.SourcedIntValue
import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type import org.objectweb.asm.Type
@ -106,7 +107,7 @@ class DummyArgTransformer : Transformer() {
val set = mutableSetOf<Int>() val set = mutableSetOf<Int>()
for ((source, intValue) in intValues) { for ((source, intValue) in intValues) {
if (intValue.isUnknown) { if (intValue !is IntValue.Constant) {
return null return null
} }
@ -114,13 +115,13 @@ class DummyArgTransformer : Transformer() {
continue continue
} }
if (intValue.isSingleConstant) { if (intValue.singleton != null) {
if (isMutuallyRecursiveDummy(method, arg, source, intValue.intValue)) { if (isMutuallyRecursiveDummy(method, arg, source, intValue.singleton)) {
continue continue
} }
} }
set.addAll(intValue.intValues) set.addAll(intValue.values)
} }
return if (set.isEmpty()) { return if (set.isEmpty()) {
@ -237,11 +238,11 @@ class DummyArgTransformer : Transformer() {
} }
Opcodes.IFEQ, Opcodes.IFNE -> { Opcodes.IFEQ, Opcodes.IFNE -> {
val value = frame.getStack(stackSize - 1) val value = frame.getStack(stackSize - 1)
if (value.isUnknown) { if (value !is IntValue.Constant) {
continue@frame continue@frame
} }
val result = evaluateUnaryBranch(insn.opcode, value.intValues) val result = evaluateUnaryBranch(insn.opcode, value.values)
@Suppress("NON_EXHAUSTIVE_WHEN") @Suppress("NON_EXHAUSTIVE_WHEN")
when (result) { when (result) {
BranchResult.ALWAYS_TAKEN -> alwaysTakenBranches.add(insn as JumpInsnNode) BranchResult.ALWAYS_TAKEN -> alwaysTakenBranches.add(insn as JumpInsnNode)
@ -251,11 +252,11 @@ class DummyArgTransformer : Transformer() {
Opcodes.IF_ICMPEQ, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPLT, Opcodes.IF_ICMPGE, Opcodes.IF_ICMPGT, Opcodes.IF_ICMPLE -> { Opcodes.IF_ICMPEQ, Opcodes.IF_ICMPNE, Opcodes.IF_ICMPLT, Opcodes.IF_ICMPGE, Opcodes.IF_ICMPGT, Opcodes.IF_ICMPLE -> {
val value1 = frame.getStack(stackSize - 2) val value1 = frame.getStack(stackSize - 2)
val value2 = frame.getStack(stackSize - 1) val value2 = frame.getStack(stackSize - 1)
if (value1.isUnknown || value2.isUnknown) { if (value1 !is IntValue.Constant || value2 !is IntValue.Constant) {
continue@frame continue@frame
} }
val result = evaluateBinaryBranch(insn.opcode, value1.intValues, value2.intValues) val result = evaluateBinaryBranch(insn.opcode, value1.values, value2.values)
@Suppress("NON_EXHAUSTIVE_WHEN") @Suppress("NON_EXHAUSTIVE_WHEN")
when (result) { when (result) {
BranchResult.ALWAYS_TAKEN -> alwaysTakenBranches.add(insn as JumpInsnNode) BranchResult.ALWAYS_TAKEN -> alwaysTakenBranches.add(insn as JumpInsnNode)
@ -276,8 +277,8 @@ class DummyArgTransformer : Transformer() {
val nextFrame = frames[nextInsnIndex] val nextFrame = frames[nextInsnIndex]
val value = nextFrame.getStack(nextFrame.stackSize - 1) val value = nextFrame.getStack(nextFrame.stackSize - 1)
if (value.isSingleConstant) { if (value is IntValue.Constant && value.singleton != null) {
constInsns[insn] = value.intValue constInsns[insn] = value.singleton
} }
} }
} }

Loading…
Cancel
Save