package org.jglrxavpok.jlsl; import static org.objectweb.asm.Opcodes.*; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Stack; import org.jglrxavpok.jlsl.fragments.AccessPolicy; import org.jglrxavpok.jlsl.fragments.AddFragment; import org.jglrxavpok.jlsl.fragments.AndFragment; import org.jglrxavpok.jlsl.fragments.AnnotationFragment; import org.jglrxavpok.jlsl.fragments.ArrayOfArrayLoadFragment; import org.jglrxavpok.jlsl.fragments.ArrayStoreFragment; import org.jglrxavpok.jlsl.fragments.CastFragment; import org.jglrxavpok.jlsl.fragments.CodeFragment; import org.jglrxavpok.jlsl.fragments.CompareFragment; import org.jglrxavpok.jlsl.fragments.DivFragment; import org.jglrxavpok.jlsl.fragments.DuplicateFragment; import org.jglrxavpok.jlsl.fragments.ElseStatementFragment; import org.jglrxavpok.jlsl.fragments.EndOfBlockFragment; import org.jglrxavpok.jlsl.fragments.EndOfMethodFragment; import org.jglrxavpok.jlsl.fragments.EqualCheckFragment; import org.jglrxavpok.jlsl.fragments.FieldFragment; import org.jglrxavpok.jlsl.fragments.GetFieldFragment; import org.jglrxavpok.jlsl.fragments.IfNotStatementFragment; import org.jglrxavpok.jlsl.fragments.IfStatementFragment; import org.jglrxavpok.jlsl.fragments.IntPushFragment; import org.jglrxavpok.jlsl.fragments.LdcFragment; import org.jglrxavpok.jlsl.fragments.LeftShiftFragment; import org.jglrxavpok.jlsl.fragments.LineNumberFragment; import org.jglrxavpok.jlsl.fragments.LoadConstantFragment; import org.jglrxavpok.jlsl.fragments.LoadVariableFragment; import org.jglrxavpok.jlsl.fragments.MethodCallFragment; import org.jglrxavpok.jlsl.fragments.MethodCallFragment.InvokeTypes; import org.jglrxavpok.jlsl.fragments.ModFragment; import org.jglrxavpok.jlsl.fragments.MulFragment; import org.jglrxavpok.jlsl.fragments.NewArrayFragment; import org.jglrxavpok.jlsl.fragments.NewClassFragment; import org.jglrxavpok.jlsl.fragments.NewInstanceFragment; import org.jglrxavpok.jlsl.fragments.NewMultiArrayFragment; import org.jglrxavpok.jlsl.fragments.NewPrimitiveArrayFragment; import org.jglrxavpok.jlsl.fragments.NotEqualCheckFragment; import org.jglrxavpok.jlsl.fragments.OrFragment; import org.jglrxavpok.jlsl.fragments.PopFragment; import org.jglrxavpok.jlsl.fragments.PutFieldFragment; import org.jglrxavpok.jlsl.fragments.ReturnFragment; import org.jglrxavpok.jlsl.fragments.ReturnValueFragment; import org.jglrxavpok.jlsl.fragments.RightShiftFragment; import org.jglrxavpok.jlsl.fragments.StartOfMethodFragment; import org.jglrxavpok.jlsl.fragments.StoreVariableFragment; import org.jglrxavpok.jlsl.fragments.SubFragment; import org.jglrxavpok.jlsl.fragments.XorFragment; import org.objectweb.asm.ClassReader; import org.objectweb.asm.Label; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AnnotationNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldInsnNode; import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.FrameNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.IntInsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.LineNumberNode; import org.objectweb.asm.tree.LocalVariableNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.MultiANewArrayInsnNode; import org.objectweb.asm.tree.TypeInsnNode; import org.objectweb.asm.tree.VarInsnNode; import org.objectweb.asm.util.Printer; import org.objectweb.asm.util.TraceClassVisitor; public class BytecodeDecoder extends CodeDecoder { public static boolean DEBUG = false; public BytecodeDecoder() { } public BytecodeDecoder addInstructionsFromInterfaces(boolean add) { this.instructionsFromInterfaces = add; return this; } private boolean instructionsFromInterfaces = false; public void handleClass(ClassNode classNode, List out) { NewClassFragment classFragment = new NewClassFragment(); classFragment.className = classNode.name.replace("/", ".").replace("$", "."); classFragment.superclass = classNode.superName.replace("/", ".").replace("$", "."); classFragment.access = new AccessPolicy(classNode.access); if (classNode.sourceFile != null) classFragment.sourceFile = classNode.sourceFile; classFragment.classVersion = classNode.version; List interfaces = classNode.interfaces; classFragment.interfaces = interfaces.toArray(new String[0]); if (instructionsFromInterfaces) for (String interfaceInst : interfaces) { ArrayList fragments = new ArrayList(); handleClass(interfaceInst.replace("/", "."), fragments); out.addAll(fragments); } out.add(classFragment); List methodNodes = classNode.methods; List fieldNodes = classNode.fields; List list = classNode.visibleAnnotations; if (list != null) for (AnnotationNode annotNode : list) { AnnotationFragment annotFragment = createFromNode(annotNode); classFragment.addChild(annotFragment); } for (FieldNode field : fieldNodes) { String name = field.name; String type = typesFromDesc(field.desc)[0]; FieldFragment fieldFragment = new FieldFragment(); fieldFragment.name = name; fieldFragment.type = type; fieldFragment.initialValue = field.value; fieldFragment.access = new AccessPolicy(field.access); List annotations = field.visibleAnnotations; if (annotations != null) for (AnnotationNode annotNode : annotations) { AnnotationFragment annotFragment = createFromNode(annotNode); fieldFragment.addChild(annotFragment); } out.add(fieldFragment); } Collections.sort(methodNodes, new Comparator() { public int compare(MethodNode arg0, MethodNode arg1) { if (arg0.name.equals("main")) return 1; if (arg1.name.equals("main")) return -1; return 0; } }); // TODO: Better the method sorting for (MethodNode node : methodNodes) { List localVariables = node.localVariables; StartOfMethodFragment startOfMethodFragment = new StartOfMethodFragment(); startOfMethodFragment.access = new AccessPolicy(node.access); startOfMethodFragment.name = node.name; startOfMethodFragment.owner = classNode.name.replace("/", "."); startOfMethodFragment.returnType = typesFromDesc(node.desc.substring(node.desc.indexOf(")") + 1))[0]; ArrayList localNames = new ArrayList(); for (LocalVariableNode var : localVariables) { startOfMethodFragment.varNameMap.put(var.index, var.name); startOfMethodFragment.varTypeMap.put(var.index, typesFromDesc(var.desc)[0]); startOfMethodFragment.varName2TypeMap.put(var.name, typesFromDesc(var.desc)[0]); if (var.index == 0 && !startOfMethodFragment.access.isStatic()) { ; } else { localNames.add(var.name); } } String[] argsTypes = typesFromDesc( node.desc.substring(node.desc.indexOf('(') + 1, node.desc.indexOf(')'))); int argIndex = 0; for (String argType : argsTypes) { startOfMethodFragment.argumentsTypes.add(argType); String name = localNames.isEmpty() ? "var" + argIndex : localNames.get(argIndex); startOfMethodFragment.argumentsNames.add(name); argIndex++; } List annots = node.visibleAnnotations; if (node.visibleAnnotations != null) for (AnnotationNode annotNode : annots) { startOfMethodFragment.addChild(createFromNode(annotNode)); } out.add(startOfMethodFragment); addAnnotFragments(startOfMethodFragment.owner, node.name, node.desc, startOfMethodFragment); handleMethodNode(node, startOfMethodFragment.varTypeMap, startOfMethodFragment.varNameMap, out); EndOfMethodFragment endOfMethodFragment = new EndOfMethodFragment(); endOfMethodFragment.access = startOfMethodFragment.access; endOfMethodFragment.name = startOfMethodFragment.name; endOfMethodFragment.owner = startOfMethodFragment.owner; endOfMethodFragment.argumentsNames = startOfMethodFragment.argumentsNames; endOfMethodFragment.argumentsTypes = startOfMethodFragment.argumentsTypes; endOfMethodFragment.returnType = startOfMethodFragment.returnType; endOfMethodFragment.varNameMap = startOfMethodFragment.varNameMap; endOfMethodFragment.varTypeMap = startOfMethodFragment.varTypeMap; endOfMethodFragment.varName2TypeMap = startOfMethodFragment.varName2TypeMap; endOfMethodFragment.getChildren().addAll(startOfMethodFragment.getChildren()); addAnnotFragments(endOfMethodFragment.owner, node.name, node.desc, endOfMethodFragment); out.add(endOfMethodFragment); } } @Override public void handleClass(Object data, List out) { if (data instanceof ClassNode) { this.handleClass((ClassNode) data, out); return; } else if (data == null) { return; } try { ClassReader reader; if (data instanceof byte[]) { reader = new ClassReader((byte[]) data); } else if (data instanceof InputStream) { reader = new ClassReader((InputStream) data); } else if (data instanceof String) { this.handleClass(Class.forName((String) data), out); return; } else if (data instanceof Class) { Class clazz = (Class) data; ClassLoader loader = clazz.getClassLoader(); reader = new ClassReader(loader.getResourceAsStream(clazz.getName().replace('.', '/') + ".class")); } else { throw new JLSLException("Invalid type: " + data.getClass().getCanonicalName()); } ClassNode classNode = new ClassNode(); reader.accept(classNode, 0); if (BytecodeDecoder.DEBUG) { reader.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0); } this.handleClass(classNode, out); } catch (Exception e) { throw new JLSLException(e); } } private static AnnotationFragment createFromNode(AnnotationNode annotNode) { AnnotationFragment annotFragment = new AnnotationFragment(); annotFragment.name = typesFromDesc(annotNode.desc)[0].replace("/", ".").replace("$", "."); List values = annotNode.values; if (values != null) for (int index = 0; index < values.size(); index += 2) { String key = (String) values.get(index); Object value = values.get(index + 1); annotFragment.values.put(key, value); } return annotFragment; } private static void handleMethodNode(MethodNode node, HashMap varTypeMap, HashMap varNameMap, List out) { int lastFrameType = 0; int frames = 0; int framesToSkip = 0; Stack toJump = new Stack(); Stack