Store stack context with variable context, and pass up stack contexts when invoking methods. I don't think iirc is right?

This commit is contained in:
Adam
2015-08-22 17:54:39 -04:00
parent 8ff2f4776a
commit e478a4b1f9
36 changed files with 222 additions and 130 deletions

View File

@@ -47,66 +47,66 @@ public class Deob
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("rename unique took " + bdur/1000L + " seconds");
// // remove except RuntimeException
// bstart = System.currentTimeMillis();
// new RuntimeExceptions().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("runtime exception took " + bdur/1000L + " seconds");
//
// // remove unused methods
// bstart = System.currentTimeMillis();
// new UnusedMethods().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused methods took " + bdur/1000L + " seconds");
//
// new UnreachedCode().run(group);
//
// // remove illegal state exceptions, frees up some parameters
// bstart = System.currentTimeMillis();
// new IllegalStateExceptions().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("illegal state exception took " + bdur/1000L + " seconds");
//
// // remove constant logically dead parameters
// bstart = System.currentTimeMillis();
// new ConstantParameter().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("constant param took " + bdur/1000L + " seconds");
//
// // remove unhit blocks
// bstart = System.currentTimeMillis();
// new UnreachedCode().run(group);
// //new UnusedBlocks().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused blocks took " + bdur/1000L + " seconds");
//
// // remove unused parameters
// bstart = System.currentTimeMillis();
// new UnusedParameters().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused params took " + bdur/1000L + " seconds");
//
// // remove jump obfuscation
// //new Jumps().run(group);
//
// // remove unused fields
// bstart = System.currentTimeMillis();
// new UnusedFields().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused fields took " + bdur/1000L + " seconds");
//
// // remove unused methods, again?
// bstart = System.currentTimeMillis();
// new UnusedMethods().run(group);
// bdur = System.currentTimeMillis() - bstart;
// System.out.println("unused methods took " + bdur/1000L + " seconds");
//
//
// new MethodInliner().run(group);
//
// new MethodMover().run(group);
//
// new FieldInliner().run(group);
// remove except RuntimeException
bstart = System.currentTimeMillis();
new RuntimeExceptions().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("runtime exception took " + bdur/1000L + " seconds");
// remove unused methods
bstart = System.currentTimeMillis();
new UnusedMethods().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("unused methods took " + bdur/1000L + " seconds");
new UnreachedCode().run(group);
// remove illegal state exceptions, frees up some parameters
bstart = System.currentTimeMillis();
new IllegalStateExceptions().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("illegal state exception took " + bdur/1000L + " seconds");
// remove constant logically dead parameters
bstart = System.currentTimeMillis();
new ConstantParameter().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("constant param took " + bdur/1000L + " seconds");
// remove unhit blocks
bstart = System.currentTimeMillis();
new UnreachedCode().run(group);
//new UnusedBlocks().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("unused blocks took " + bdur/1000L + " seconds");
// remove unused parameters
bstart = System.currentTimeMillis();
new UnusedParameters().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("unused params took " + bdur/1000L + " seconds");
// remove jump obfuscation
//new Jumps().run(group);
// remove unused fields
bstart = System.currentTimeMillis();
new UnusedFields().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("unused fields took " + bdur/1000L + " seconds");
// remove unused methods, again?
bstart = System.currentTimeMillis();
new UnusedMethods().run(group);
bdur = System.currentTimeMillis() - bstart;
System.out.println("unused methods took " + bdur/1000L + " seconds");
new MethodInliner().run(group);
new MethodMover().run(group);
new FieldInliner().run(group);
// XXX this is broken because when moving clinit around, some fields can depend on other fields
// (like multianewarray)

View File

@@ -1,6 +1,5 @@
package net.runelite.deob.attributes.code.instructions;
import net.runelite.deob.ClassFile;
import net.runelite.deob.attributes.code.Instruction;
import net.runelite.deob.attributes.code.InstructionType;
import net.runelite.deob.attributes.code.Instructions;
@@ -12,7 +11,6 @@ import net.runelite.deob.execution.Stack;
import net.runelite.deob.execution.StackContext;
import net.runelite.deob.execution.VariableContext;
import net.runelite.deob.execution.Variables;
import net.runelite.deob.pool.Class;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -55,7 +53,7 @@ public class AStore extends Instruction implements LVTInstruction, WideInstructi
StackContext object = stack.pop();
ins.pop(object);
variables.set(index, new VariableContext(ins, object.getType()));
variables.set(index, new VariableContext(ins, object));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class AStore_0 extends Instruction implements LVTInstruction
StackContext object = stack.pop();
ins.pop(object);
variables.set(0, new VariableContext(ins, object.getType()));
variables.set(0, new VariableContext(ins, object));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class AStore_1 extends Instruction implements LVTInstruction
StackContext object = stack.pop();
ins.pop(object);
variables.set(1, new VariableContext(ins, object.getType()));
variables.set(1, new VariableContext(ins, object));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class AStore_2 extends Instruction implements LVTInstruction
StackContext object = stack.pop();
ins.pop(object);
variables.set(2, new VariableContext(ins, object.getType()));
variables.set(2, new VariableContext(ins, object));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class AStore_3 extends Instruction implements LVTInstruction
StackContext object = stack.pop();
ins.pop(object);
variables.set(3, new VariableContext(ins, object.getType()));
variables.set(3, new VariableContext(ins, object));
frame.addInstructionContext(ins);
}

View File

@@ -53,7 +53,7 @@ public class DStore extends Instruction implements LVTInstruction, WideInstructi
StackContext value = stack.pop();
ins.pop(value);
variables.set(index, new VariableContext(ins, value.getType()));
variables.set(index, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class DStore_0 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(0, new VariableContext(ins, value.getType()));
variables.set(0, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class DStore_1 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(1, new VariableContext(ins, value.getType()));
variables.set(1, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class DStore_2 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(2, new VariableContext(ins, value.getType()));
variables.set(2, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class DStore_3 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(3, new VariableContext(ins, value.getType()));
variables.set(3, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -53,7 +53,7 @@ public class FStore extends Instruction implements LVTInstruction, WideInstructi
StackContext value = stack.pop();
ins.pop(value);
variables.set(index, new VariableContext(ins, value.getType()));
variables.set(index, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class FStore_0 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(0, new VariableContext(ins, value.getType()));
variables.set(0, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class FStore_1 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(1, new VariableContext(ins, value.getType()));
variables.set(1, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class FStore_2 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(2, new VariableContext(ins, value.getType()));
variables.set(2, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -30,7 +30,7 @@ public class FStore_3 extends Instruction implements LVTInstruction
StackContext value = stack.pop();
ins.pop(value);
variables.set(3, new VariableContext(ins, value.getType()));
variables.set(3, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -58,7 +58,7 @@ public class IInc extends Instruction implements LVTInstruction, WideInstruction
assert vctx.getType().equals(new Type(int.class.getCanonicalName()));
ins.read(vctx);
vctx = new VariableContext(ins, vctx.getType());
vctx = new VariableContext(ins, vctx.getStackContext()); // XXX this is probably not right.
var.set(index, vctx);
frame.addInstructionContext(ins);

View File

@@ -64,7 +64,7 @@ public class IStore extends Instruction implements LVTInstruction, WideInstructi
assert value.getType().equals(new Type(int.class.getName()));
ins.pop(value);
variables.set(index, new VariableContext(ins, value.getType()));
variables.set(index, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class IStore_0 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(int.class.getName()));
ins.pop(value);
variables.set(0, new VariableContext(ins, value.getType()));
variables.set(0, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class IStore_1 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(int.class.getName()));
ins.pop(value);
variables.set(1, new VariableContext(ins, value.getType()));
variables.set(1, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class IStore_2 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(int.class.getName()));
ins.pop(value);
variables.set(2, new VariableContext(ins, value.getType()));
variables.set(2, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class IStore_3 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(int.class.getName()));
ins.pop(value);
variables.set(3, new VariableContext(ins, value.getType()));
variables.set(3, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -23,6 +23,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.runelite.deob.execution.Execution;
public class InvokeInterface extends Instruction implements InvokeInstruction
{
@@ -102,8 +103,16 @@ public class InvokeInterface extends Instruction implements InvokeInstruction
for (net.runelite.deob.Method method : getMethods())
{
ins.invoke(method);
if (method.getCode() == null)
{
frame.getExecution().methods.add(method);
continue;
}
// add possible method call to execution
frame.getExecution().addMethod(method);
Execution execution = frame.getExecution();
execution.invoke(ins, method);
}
frame.addInstructionContext(ins);

View File

@@ -22,6 +22,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.runelite.deob.execution.Execution;
public class InvokeSpecial extends Instruction implements InvokeInstruction
{
@@ -88,8 +89,16 @@ public class InvokeSpecial extends Instruction implements InvokeInstruction
for (net.runelite.deob.Method method : getMethods())
{
ins.invoke(method);
if (method.getCode() == null)
{
frame.getExecution().methods.add(method);
continue;
}
// add possible method call to execution
frame.getExecution().addMethod(method);
Execution execution = frame.getExecution();
execution.invoke(ins, method);
}
frame.addInstructionContext(ins);

View File

@@ -22,6 +22,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.runelite.deob.execution.Execution;
public class InvokeStatic extends Instruction implements InvokeInstruction
{
@@ -85,8 +86,16 @@ public class InvokeStatic extends Instruction implements InvokeInstruction
for (net.runelite.deob.Method method : getMethods())
{
ins.invoke(method);
if (method.getCode() == null)
{
frame.getExecution().methods.add(method);
continue;
}
// add possible method call to execution
frame.getExecution().addMethod(method);
Execution execution = frame.getExecution();
execution.invoke(ins, method);
}
frame.addInstructionContext(ins);

View File

@@ -22,6 +22,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.runelite.deob.execution.Execution;
public class InvokeVirtual extends Instruction implements InvokeInstruction
{
@@ -71,8 +72,16 @@ public class InvokeVirtual extends Instruction implements InvokeInstruction
for (net.runelite.deob.Method method : getMethods())
{
ins.invoke(method);
if (method.getCode() == null)
{
frame.getExecution().methods.add(method);
continue;
}
// add possible method call to execution
frame.getExecution().addMethod(method);
Execution execution = frame.getExecution();
execution.invoke(ins, method);
}
frame.addInstructionContext(ins);

View File

@@ -55,7 +55,7 @@ public class LStore extends Instruction implements LVTInstruction, WideInstructi
assert value.getType().equals(new Type(long.class.getName()));
ins.pop(value);
variables.set(index, new VariableContext(ins, value.getType()));
variables.set(index, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class LStore_0 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(long.class.getName()));
ins.pop(value);
variables.set(0, new VariableContext(ins, value.getType()));
variables.set(0, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class LStore_1 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(long.class.getName()));
ins.pop(value);
variables.set(1, new VariableContext(ins, value.getType()));
variables.set(1, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class LStore_2 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(long.class.getName()));
ins.pop(value);
variables.set(2, new VariableContext(ins, value.getType()));
variables.set(2, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -32,7 +32,7 @@ public class LStore_3 extends Instruction implements LVTInstruction
assert value.getType().equals(new Type(long.class.getName()));
ins.pop(value);
variables.set(3, new VariableContext(ins, value.getType()));
variables.set(3, new VariableContext(ins, value));
frame.addInstructionContext(ins);
}

View File

@@ -7,18 +7,20 @@ import net.runelite.deob.Method;
import net.runelite.deob.attributes.code.Instruction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.collections4.map.MultiValueMap;
public class Execution
{
private ClassGroup group;
public List<Frame> frames = new ArrayList<>(),
processedFrames = new ArrayList<>();
private List<Method> pendingMethods = new ArrayList<>(); // pending methods
public Set<Method> methods = new HashSet<>(); // all methods
public Set<Instruction> executed = new HashSet<>(); // executed instructions
private MultiValueMap<InstructionContext, Method> invokes = new MultiValueMap<>();
public Execution(ClassGroup group)
{
@@ -30,58 +32,62 @@ public class Execution
for (ClassFile cf : group.getClasses())
{
for (Method m : cf.getMethods().getMethods())
{
{
if (!Deob.isObfuscated(m.getName()) && !m.getName().equals("<init>"))
{
addMethod(m); // I guess this method name is overriding a jre interface (init, run, ?).
if (m.getCode() == null)
{
methods.add(m);
continue;
}
Frame frame = new Frame(this, m);
frame.initialize();
addFrame(frame); // I guess this method name is overriding a jre interface (init, run, ?).
}
}
}
}
public void addMethod(Method method)
private boolean hasInvoked(InstructionContext from, Method to)
{
assert method != null;
Collection<Method> methods = invokes.getCollection(from);
if (methods != null && methods.contains(to))
return true;
if (methods.contains(method))
return; // already processed
invokes.put(from, to);
return false;
}
private void addFrame(Frame frame)
{
frames.add(frame);
}
public void invoke(InstructionContext from, Method to)
{
if (hasInvoked(from, to))
return;
pendingMethods.add(method);
methods.add(method);
Frame f = new Frame(this, to);
f.initialize(from);
this.addFrame(f);
}
public void run()
{
int count = 0, fcount = 0;
while (!pendingMethods.isEmpty())
{
Method method = pendingMethods.remove(0);
if (method.getCode() == null)
continue;
Frame f = new Frame(this, method);
frames.add(f);
fcount += this.runFrames();
++count;
}
System.out.println("Processed " + count + " methods and " + fcount + " paths");
}
private int runFrames()
{
int fcount = 0;
while (!frames.isEmpty())
{
Frame frame = frames.remove(0);
methods.add(frame.getMethod());
++fcount;
frame.execute();
processedFrames.add(frame);
}
return fcount;
System.out.println("Processed " + fcount + " frames");
}
}

View File

@@ -1,5 +1,6 @@
package net.runelite.deob.execution;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -15,6 +16,7 @@ import net.runelite.deob.attributes.code.instructions.TableSwitch;
import net.runelite.deob.pool.NameAndType;
import java.util.HashSet;
import java.util.Set;
import net.runelite.deob.attributes.code.instruction.types.InvokeInstruction;
import org.apache.commons.collections4.MultiMap;
import org.apache.commons.collections4.map.MultiValueMap;
@@ -38,19 +40,52 @@ public class Frame
stack = new Stack(code.getMaxStack());
variables = new Variables(code.getMaxLocals());
}
public void initialize()
{
// initialize LVT
int pos = 0;
if (!method.isStatic())
variables.set(pos++, new VariableContext(null, new Type(method.getMethods().getClassFile().getName())));
variables.set(pos++, new VariableContext(new Type(method.getMethods().getClassFile().getName())));
NameAndType nat = method.getNameAndType();
for (int i = 0; i < nat.getNumberOfArgs(); ++i)
{
variables.set(pos, new VariableContext(null, new Type(nat.getDescriptor().getTypeOfArg(i)).toStackType()));
variables.set(pos, new VariableContext(new Type(nat.getDescriptor().getTypeOfArg(i)).toStackType()));
pos += nat.getDescriptor().getTypeOfArg(i).getSlots();
}
Code code = method.getCode();
cur = code.getInstructions().getInstructions().get(0);
}
public void initialize(InstructionContext ctx)
{
// initialize frame from invoking context
assert ctx.getInstruction() instanceof InvokeInstruction;
// initialize LVT. the last argument is popped first, and is at arguments[0]
List<StackContext> pops = ctx.getPops();
pops = Lists.reverse(new ArrayList<>(pops)); // reverse the list so first argument is at index 0
int lvtOffset = 0;
if (!method.isStatic())
variables.set(lvtOffset++, new VariableContext(ctx, pops.remove(0)));
NameAndType nat = method.getNameAndType();
for (int i = 0; i < nat.getNumberOfArgs(); ++i)
{
StackContext argument = pops.remove(0);
variables.set(lvtOffset, new VariableContext(ctx, argument));//new Type(nat.getDescriptor().getTypeOfArg(i)).toStackType()));
lvtOffset += nat.getDescriptor().getTypeOfArg(i).getSlots();
}
assert pops.isEmpty();
Code code = method.getCode();
cur = code.getInstructions().getInstructions().get(0);
}

View File

@@ -102,7 +102,7 @@ public class InstructionContext
Stack ours = new Stack(this.getStack()), // copy stacks since we destroy them
theirs = new Stack(ic.getStack());
if (ours.getSize() != theirs.getSize())
if (ours.getSize() != theirs.getSize()) // is this possible?
return false;
while (ours.getSize() > 0)

View File

@@ -2,13 +2,25 @@ package net.runelite.deob.execution;
public class VariableContext
{
private InstructionContext ic;
private StackContext ctx; // the value stored
private InstructionContext ic; // the instruction which stored it. also ctx.popped?
private Type type;
public VariableContext(InstructionContext i, Type t)
public VariableContext(InstructionContext i, StackContext ctx)
{
ic = i;
type = t;
this.ctx = ctx;
type = ctx.getType();
}
public VariableContext(Type type) // for entrypoints
{
this.type = type;
}
public StackContext getStackContext()
{
return ctx;
}
public Type getType()