Created
March 7, 2016 12:27
-
-
Save Unh0lyTigg/47919b4afa2d16ef259b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xyz.unh0lytigg.jsoncrops.transformer.util; | |
import java.lang.reflect.*; | |
import java.util.*; | |
import java.util.concurrent.atomic.*; | |
import java.util.function.*; | |
import java.util.stream.*; | |
import org.objectweb.asm.*; | |
import org.objectweb.asm.Type; | |
import org.objectweb.asm.tree.*; | |
import com.google.common.collect.*; | |
import lombok.*; | |
@RequiredArgsConstructor | |
public final class InstructionListHelper implements Opcodes { | |
private static class NodeFunc { | |
public Predicate<AbstractInsnNode> predicate; | |
public Function<AbstractInsnNode, Boolean> function; | |
} | |
private static Field fLabelNode_label = null; | |
static { | |
try { | |
fLabelNode_label = LabelNode.class.getDeclaredField("label"); | |
fLabelNode_label.setAccessible(true); | |
} catch (NoSuchFieldException | SecurityException e) { | |
e.printStackTrace(); | |
} | |
} | |
@NonNull | |
private final ListIterator<AbstractInsnNode> iter; | |
private List<NodeFunc> mappingFuncs = Lists.newArrayList(); | |
private boolean debugAdded = false; | |
public InstructionListHelper debug() { | |
if (debugAdded) return this; | |
debugAdded = true; | |
return with(InstructionListHelper::debug_predicate, InstructionListHelper::debug_func, AbstractInsnNode.class); | |
} | |
private static boolean debug_predicate(AbstractInsnNode node) { | |
if (!(node instanceof LineNumberNode)) | |
System.out.println("\t"+node.getClass().getSimpleName() + ": " + node.getOpcode() + " (" + OPCODE_MAP.get(Integer.valueOf(node.getOpcode())) + ")"); | |
if (node instanceof LineNumberNode) { | |
LineNumberNode lnn = (LineNumberNode)node; | |
LabelNode l = lnn.start; | |
Label label = null; | |
try { | |
label = (Label) fLabelNode_label.get(l); | |
} catch (IllegalArgumentException | IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
System.out.println(String.format("\tLineNumberNode: %d (%s): %d / %s", lnn.getOpcode(), OPCODE_MAP.get(Integer.valueOf(lnn.getOpcode())), lnn.line, label == null ? "[unknown_label]" : String.valueOf(label.info))); | |
} | |
if ((node instanceof LineNumberNode) || (node instanceof FrameNode)) | |
return false; | |
return true; | |
} | |
private static String transformName(String raw) { | |
return raw == null ? "" : raw.replaceAll("[/\\\\\\Q$\\E]", "."); | |
} | |
private static boolean debug_func(AbstractInsnNode node) { | |
if (node instanceof VarInsnNode) { | |
VarInsnNode v = (VarInsnNode)node; | |
if (v.getOpcode() == ALOAD && v.var == 0) | |
System.out.println("\t\tthis"); | |
else | |
System.out.println("\t\t" + v.var); | |
} else if (node instanceof MethodInsnNode) { | |
MethodInsnNode m = (MethodInsnNode)node; | |
System.out.println("\t\t" + transformName(m.owner) + "." + m.name + m.desc); | |
} else if (node instanceof FieldInsnNode) { | |
FieldInsnNode f = (FieldInsnNode)node; | |
System.out.println("\t\t" + f.desc + " " + transformName(f.owner) + "." + f.name); | |
} else if (node instanceof InsnNode) { | |
String msg = null; | |
switch (node.getOpcode()) { | |
case ICONST_0: | |
msg = "\tConstant 0"; break; | |
case ICONST_1: | |
msg = "\tConstant 1"; break; | |
case ICONST_2: | |
msg = "\tConstant 2"; break; | |
case ICONST_3: | |
msg = "\tConstant 3"; break; | |
case ICONST_4: | |
msg = "\tConstant 4"; break; | |
case ICONST_5: | |
msg = "\tConstant 5"; break; | |
case ICONST_M1: | |
msg = "\tConstant -1"; break; | |
case DUP: | |
msg = "\tDuplicate"; break; | |
case LCONST_0: | |
msg = "\tConstant 0L"; break; | |
case LCONST_1: | |
msg = "\tConstant 1L"; break; | |
case AASTORE: | |
msg = "\tStore to array"; break; | |
} | |
if (msg != null) System.out.println("\t"+msg); | |
} else if (node instanceof TypeInsnNode) { | |
TypeInsnNode t = (TypeInsnNode)node; | |
System.out.println("\t\t" + t.desc); | |
} else if (node instanceof LdcInsnNode) { | |
LdcInsnNode ldc = (LdcInsnNode)node; | |
if (ldc.cst instanceof String) | |
System.out.println("\t\t" + ldc.cst.getClass().getName() + " \"" + ldc.cst + "\""); | |
else | |
System.out.println("\t\t" + ldc.cst.getClass().getName() + " " + ldc.cst); | |
} else if (node instanceof LabelNode) { | |
LabelNode l = (LabelNode)node; | |
Label label = null; | |
try { | |
label = (Label) fLabelNode_label.get(l); | |
} catch (IllegalArgumentException | IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
if (label != null) { | |
if (label.info instanceof String) | |
System.out.println("\t\t Label: \"" + label.info + "\""); | |
else | |
System.out.println("\t\t Label: " + label.info); | |
} | |
} else if (node instanceof JumpInsnNode) { | |
JumpInsnNode j = (JumpInsnNode)node; | |
LabelNode l = j.label; | |
Label label = null; | |
try { | |
label = (Label) fLabelNode_label.get(l); | |
System.out.println("\t\t\tlabel is " + label); | |
} catch (IllegalArgumentException | IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
String msg = null; | |
switch (node.getOpcode()) { | |
case IF_ACMPNE: | |
msg = "\tRef a != b ? branch"; break; | |
case IF_ACMPEQ: | |
msg = "\tRef a == b ? branch"; break; | |
case IF_ICMPEQ: | |
msg = "\tInt a == b ? branch"; break; | |
case IF_ICMPGE: | |
msg = "\tInt a >= b ? branch"; break; | |
case IF_ICMPGT: | |
msg = "\tInt a > b ? branch"; break; | |
case IF_ICMPLE: | |
msg = "\tInt a <= b ? branch"; break; | |
case IF_ICMPLT: | |
msg = "\tInt a < b ? branch"; break; | |
case IF_ICMPNE: | |
msg = "\tInt a != b ? branch"; break; | |
case IFEQ: | |
msg = "\tVal a == b ? branch"; break; | |
case IFGE: | |
msg = "\tVal a >= b ? branch"; break; | |
case IFGT: | |
msg = "\tVal a > b ? branch"; break; | |
case IFLE: | |
msg = "\tVal a <= b ? branch"; break; | |
case IFLT: | |
msg = "\tVal a < b ? branch"; break; | |
case IFNE: | |
msg = "\tVal a != b ? branch"; break; | |
case IFNONNULL: | |
msg = "\tVal a != null ? branch"; break; | |
case IFNULL: | |
msg = "\tVal a == null ? branch"; break; | |
} | |
if (msg != null && label != null) | |
msg = msg + " to " + label.info; | |
if (msg != null) System.out.println("\t"+msg); | |
} else if (node instanceof IntInsnNode) { | |
IntInsnNode i = (IntInsnNode)node; | |
switch (node.getOpcode()) { | |
case SIPUSH: | |
System.out.println("\t\tPush Short " + i.operand); break; | |
case NEWARRAY: | |
System.out.println("\t\tNew Array " + i.operand); break; | |
case BIPUSH: | |
System.out.println("\t\tBipush " + i.operand); break; | |
} | |
} else { | |
System.out.println("\t\tUnknown node class: " + node.getClass().getSimpleName() + " (op:" + OPCODE_MAP.get(Integer.valueOf(node.getOpcode())) + ")"); | |
} | |
return false; | |
} | |
private static Map<Integer, String> OPCODE_MAP = Maps.newHashMap(); | |
static { | |
Stream.of(Opcodes.class.getFields()).filter(f -> f.getType().isPrimitive()).forEach(f -> { | |
try { | |
int i = f.getInt(null); | |
OPCODE_MAP.put(Integer.valueOf(i), f.getName()); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
}); | |
} | |
@SuppressWarnings("unchecked") | |
public <T extends AbstractInsnNode> InstructionListHelper with(Predicate<T> p, Function<T, Boolean> f, Class<T> clazz) { | |
Function<AbstractInsnNode, Boolean> f_generic = n -> f.apply((T)n); | |
Predicate<AbstractInsnNode> p_generic = n -> { | |
if (clazz.isAssignableFrom(n.getClass())) return p.test((T)n); | |
return false; | |
}; | |
NodeFunc nf = new NodeFunc(); | |
nf.predicate = p_generic; | |
nf.function = f_generic; | |
mappingFuncs.add(nf); | |
return this; | |
} | |
public InstructionListHelper clear() { | |
mappingFuncs.clear(); | |
debugAdded = false; | |
return this; | |
} | |
public boolean run() { | |
boolean state = false; | |
iterloop: | |
while (iter.hasNext()) { | |
AbstractInsnNode node = iter.next(); | |
for (NodeFunc e : mappingFuncs) { | |
if (e.predicate.test(node)) | |
if (e.function.apply(node)) { | |
state = true; | |
break iterloop; | |
} | |
} | |
} | |
return state; | |
} | |
public static Predicate<AbstractInsnNode> opcodeCheck(int op) { | |
return n -> n.getOpcode() == op; | |
} | |
public static Predicate<AbstractInsnNode> methodName(String name) { | |
return n -> { | |
if(n instanceof MethodInsnNode) | |
return ((MethodInsnNode)n).name.equals(name); | |
return false; | |
}; | |
} | |
public static Predicate<AbstractInsnNode> atomicBoolean(AtomicBoolean b) { | |
return n -> b.get(); | |
} | |
public static <T extends AbstractInsnNode> Predicate<AbstractInsnNode> instanceCheck(Class<T> c) { | |
return n -> c.isAssignableFrom(n.getClass()); | |
} | |
public static Predicate<AbstractInsnNode> ownerExists(Predicate<String> ref) { | |
return n -> { | |
if (n instanceof FieldInsnNode) | |
return ref.test(((FieldInsnNode)n).owner); | |
else if (n instanceof MethodInsnNode) | |
return ref.test(((MethodInsnNode)n).owner); | |
return false; | |
}; | |
} | |
public static Function<LdcInsnNode, Boolean> ldcFind(String cst, AtomicBoolean b) { | |
return n -> { | |
if (n.cst instanceof String && n.cst.equals(cst)) | |
b.set(true); | |
return false; | |
}; | |
} | |
public static Function<LdcInsnNode, Boolean> ldcFind(float cst, AtomicBoolean b) { | |
return n -> { | |
if (n.cst instanceof Float && n.cst.equals(cst)) | |
b.set(true); | |
return false; | |
}; | |
} | |
public static Function<LdcInsnNode, Boolean> ldcFind(int cst, AtomicBoolean b) { | |
return n -> { | |
if (n.cst instanceof Integer && n.cst.equals(cst)) | |
b.set(true); | |
return false; | |
}; | |
} | |
public static Function<LdcInsnNode, Boolean> ldcFind(long cst, AtomicBoolean b) { | |
return n -> { | |
if (n.cst instanceof Long && n.cst.equals(cst)) | |
b.set(true); | |
return false; | |
}; | |
} | |
public static Function<LdcInsnNode, Boolean> ldcFind(Type cst, AtomicBoolean b) { | |
return n -> { | |
if (n.cst instanceof Type && n.cst.equals(cst)) | |
b.set(true); | |
return false; | |
}; | |
} | |
public static Function<AbstractInsnNode, Boolean> mapOwner(Function<String, Boolean> consumer) { | |
return n -> { | |
if (n instanceof MethodInsnNode) | |
return consumer.apply(((MethodInsnNode)n).owner); | |
else if (n instanceof FieldInsnNode) | |
return consumer.apply(((FieldInsnNode)n).owner); | |
return false; | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xyz.unh0lytigg.jsoncrops.transformer; | |
import org.objectweb.asm.*; | |
import org.objectweb.asm.tree.*; | |
public interface ITransformClass { | |
public String getTargetClass(); | |
public byte[] transform(byte[] basicClass); | |
public default ClassNode createNode(byte[] classData) { | |
ClassNode node = new ClassNode(); | |
ClassReader reader = new ClassReader(classData); | |
reader.accept(node, 0); | |
return node; | |
} | |
public default byte[] writeNode(ClassNode node) { | |
ClassWriter writer = new ClassWriter(Opcodes.ASM5); | |
node.accept(writer); | |
return writer.toByteArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment