forked from openrs2/openrs2
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.master
parent
71d1b8d435
commit
bb2f72c4f0
@ -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<ConstSourceValue> { |
||||||
|
private final Interpreter<BasicValue> 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<? extends ConstSourceValue> 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); |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue