From bb2f72c4f0b8340ec5a8842782668f216cfa8439 Mon Sep 17 00:00:00 2001 From: Graham Date: Fri, 30 Aug 2019 19:09:00 +0100 Subject: [PATCH] Add ConstSourceInterpreter It is akin to SourceInterpreter, but more efficient as it only tracks the sources of integer constants and it doesn't track sources through copy instructions. --- .../deob/analysis/ConstSourceInterpreter.java | 117 ++++++++++++++++++ .../deob/analysis/ConstSourceValue.java | 78 ++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceInterpreter.java create mode 100644 deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceValue.java diff --git a/deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceInterpreter.java b/deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceInterpreter.java new file mode 100644 index 0000000000..77514fd0f2 --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceInterpreter.java @@ -0,0 +1,117 @@ +package dev.openrs2.deob.analysis; + +import java.util.List; + +import com.google.common.collect.ImmutableList; +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.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 ConstSourceInterpreter extends Interpreter { + private final Interpreter basicInterpreter = new BasicInterpreter(); + + public ConstSourceInterpreter() { + super(Opcodes.ASM7); + } + + @Override + public ConstSourceValue newValue(Type type) { + var basicValue = basicInterpreter.newValue(type); + if (basicValue == null) { + return null; + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public ConstSourceValue newOperation(AbstractInsnNode insn) throws AnalyzerException { + var basicValue = basicInterpreter.newOperation(insn); + if (basicValue == null) { + return null; + } + + if (InsnNodeUtils.isIntConstant(insn)) { + return ConstSourceValue.createSingleSourceConstant(basicValue, insn); + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public ConstSourceValue copyOperation(AbstractInsnNode insn, ConstSourceValue value) throws AnalyzerException { + var basicValue = basicInterpreter.copyOperation(insn, value.getBasicValue()); + if (basicValue == null) { + return null; + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public ConstSourceValue unaryOperation(AbstractInsnNode insn, ConstSourceValue value) throws AnalyzerException { + var basicValue = basicInterpreter.unaryOperation(insn, value.getBasicValue()); + if (basicValue == null) { + return null; + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public ConstSourceValue binaryOperation(AbstractInsnNode insn, ConstSourceValue value1, ConstSourceValue value2) throws AnalyzerException { + var basicValue = basicInterpreter.binaryOperation(insn, value1.getBasicValue(), value2.getBasicValue()); + if (basicValue == null) { + return null; + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public ConstSourceValue ternaryOperation(AbstractInsnNode insn, ConstSourceValue value1, ConstSourceValue value2, ConstSourceValue value3) throws AnalyzerException { + var basicValue = basicInterpreter.ternaryOperation(insn, value1.getBasicValue(), value2.getBasicValue(), value3.getBasicValue()); + if (basicValue == null) { + return null; + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public ConstSourceValue naryOperation(AbstractInsnNode insn, List values) throws AnalyzerException { + var args = values.stream() + .map(ConstSourceValue::getBasicValue) + .collect(ImmutableList.toImmutableList()); + var basicValue = basicInterpreter.naryOperation(insn, args); + if (basicValue == null) { + return null; + } + + return ConstSourceValue.createUnknown(basicValue); + } + + @Override + public void returnOperation(AbstractInsnNode insn, ConstSourceValue value, ConstSourceValue expected) throws AnalyzerException { + basicInterpreter.returnOperation(insn, value.getBasicValue(), expected.getBasicValue()); + } + + @Override + public ConstSourceValue merge(ConstSourceValue value1, ConstSourceValue value2) { + var basicValue = basicInterpreter.merge(value1.getBasicValue(), value2.getBasicValue()); + if (basicValue == null) { + return null; + } + + if (value1.isSingleSourceConstant() && value1.equals(value2)) { + return value1; + } + + return ConstSourceValue.createUnknown(basicValue); + } +} diff --git a/deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceValue.java b/deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceValue.java new file mode 100644 index 0000000000..7a791a33e3 --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/analysis/ConstSourceValue.java @@ -0,0 +1,78 @@ +package dev.openrs2.deob.analysis; + +import java.util.Objects; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.analysis.BasicValue; +import org.objectweb.asm.tree.analysis.Value; + +public final class ConstSourceValue implements Value { + public static ConstSourceValue createUnknown(BasicValue basicValue) { + Preconditions.checkNotNull(basicValue); + return new ConstSourceValue(basicValue, null); + } + + public static ConstSourceValue createSingleSourceConstant(BasicValue basicValue, AbstractInsnNode source) { + Preconditions.checkArgument(basicValue == BasicValue.INT_VALUE); + Preconditions.checkNotNull(source); + return new ConstSourceValue(basicValue, source); + } + + private final BasicValue basicValue; + private final AbstractInsnNode source; + + private ConstSourceValue(BasicValue basicValue, AbstractInsnNode source) { + this.basicValue = basicValue; + this.source = source; + } + + public BasicValue getBasicValue() { + return basicValue; + } + + public boolean isUnknown() { + return source == null; + } + + public boolean isSingleSourceConstant() { + return source != null; + } + + public AbstractInsnNode getSource() { + Preconditions.checkState(source != null); + return source; + } + + @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; + } + ConstSourceValue that = (ConstSourceValue) o; + return basicValue.equals(that.basicValue) && + Objects.equals(source, that.source); + } + + @Override + public int hashCode() { + return Objects.hash(basicValue, source); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("basicValue", basicValue) + .add("source", source) + .toString(); + } +}