/** * Creates the new instructions, inlining each instantiation of each * subroutine until the code is fully elaborated. */ private void emitCode() { LinkedList<Instantiation> worklist = new LinkedList<Instantiation>(); // Create an instantiation of the "root" subroutine, which is just the // main routine worklist.add(new Instantiation(null, mainSubroutine)); // Emit instantiations of each subroutine we encounter, including the // main subroutine InsnList newInstructions = new InsnList(); List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>(); List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>(); while (!worklist.isEmpty()) { Instantiation inst = worklist.removeFirst(); emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks, newLocalVariables); } instructions = newInstructions; tryCatchBlocks = newTryCatchBlocks; localVariables = newLocalVariables; }
@SuppressWarnings(UNCHECKED) Set<LocalVariableNode> analyzeMethod() { // si seulement 1 variable locale ("this") ou si seulement des "variables locales" pour les paramètres et pour "this", // alors on passe à la méthode suivante if (localVariables.isEmpty()) { return Collections.emptySet(); } for (final Iterator<AbstractInsnNode> it = methodNode.instructions.iterator(); it .hasNext();) { analyzeInstruction(it.next()); if (localVariables.isEmpty()) { // si toutes les variables ont été utilisées, inutile de continuer à lire les instructions return Collections.emptySet(); } } return localVariables; }
@SuppressWarnings(UNCHECKED) private Set<LocalVariableNode> extractLocalVariables() { if ((methodNode.access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_SYNTHETIC)) != 0) { return Collections.emptySet(); } final int oneIfThisExists = (methodNode.access & Opcodes.ACC_STATIC) != 0 ? 0 : 1; if (methodNode.localVariables.size() <= oneIfThisExists || methodNode.localVariables .size() <= Type.getArgumentTypes(methodNode.desc).length + oneIfThisExists) { return Collections.emptySet(); } final Set<LocalVariableNode> variables = new LinkedHashSet<>(methodNode.localVariables); // on ignore les variables locales "this" et celles des paramètres // (attention les variables ne sont pas forcément dans l'ordre des index, en eclipse 3.1 ou 3.2 ?) final int nbParameters = Type.getArgumentTypes(methodNode.desc).length + oneIfThisExists; for (final Iterator<LocalVariableNode> it = variables.iterator(); it.hasNext();) { final int index = it.next().index; if (index < nbParameters) { it.remove(); } } return variables; }
@SuppressWarnings(UNCHECKED) private void filterCatchVariables() { // on supprime les variables des blocs catchs (comme eclipse, etc...), // avant de supprimer les doublons car les blocs catchs provoquent parfois des variables de même index for (final TryCatchBlockNode tryCatchBlock : (List<TryCatchBlockNode>) methodNode.tryCatchBlocks) { // TODO est-ce qu'il y a un meilleur moyen d'identifier la variable de l'exception autrement que par son type ? final String type = tryCatchBlock.type; // type est null si finally if (type != null) { for (final Iterator<LocalVariableNode> it = localVariables.iterator(); it .hasNext();) { final LocalVariableNode localVariable = it.next(); final Type typeLocalVariable = Type.getType(localVariable.desc); if (typeLocalVariable.getSort() == Type.OBJECT && type.equals(typeLocalVariable.getInternalName())) { it.remove(); break; } } } } }
private void filterDuplicates() { // et on supprime les doublons, // qui arrivent avec le code suivant : final String s; if (b) s = "t"; else s = "f";, // Rq: du coup on peut avoir des faux négatifs avec le code suivant, mais tant pis : // if (b) { Object o = new Object(); test(o); } else { Object o = new Object(); } // (attention les variables ne sont pas forcément dans l'ordre des index, en eclipse 3.1 ou 3.2 ?) for (final Iterator<LocalVariableNode> it = localVariables.iterator(); it.hasNext();) { final LocalVariableNode localVariable = it.next(); for (final LocalVariableNode localVariable2 : localVariables) { if (localVariable.index == localVariable2.index && !localVariable.equals(localVariable2)) { it.remove(); break; } } } }
@Override public void transform(ClassNode clazz, MethodNode method, InsnMatcher matcher) { AbstractInsnNode[] match = Iterators.getOnlyElement(matcher.match("BIPUSH ISTORE", m -> { IntInsnNode push = (IntInsnNode) m[0]; if (push.operand != 50) { return false; } VarInsnNode store = (VarInsnNode) m[1]; LocalVariableNode node = AsmUtils.getLocalVariable(method, store.var, store); return node != null && node.name.equals("resource") && node.desc.equals("I"); })); method.instructions.remove(match[0]); method.instructions.remove(match[1]); }
private Local getLocal(int idx) { if (idx >= maxLocals) throw new IllegalArgumentException("Invalid local index: " + idx); Integer i = idx; Local l = locals.get(i); if (l == null) { String name; if (localVars != null) { name = null; for (LocalVariableNode lvn : localVars) { if (lvn.index == idx) { name = lvn.name; break; } } /* normally for try-catch blocks */ if (name == null) name = "l" + idx; } else { name = "l" + idx; } l = Jimple.v().newLocal(name, UnknownType.v()); locals.put(i, l); } return l; }
@Override public void run() { if (mn.localVariables == null) return; for(int i = 0; i < mn.localVariables.size(); i++) { LocalVariableNode lvn = (LocalVariableNode) mn.localVariables.get(i); mn.localVariables.set ( i, new LocalVariableNode ( Main.getInstance().nameGen.get(i), lvn.desc, null, lvn.start, lvn.end, i ) ); hm.put(lvn.desc, Boolean.TRUE); } }
private List<String> getNamesByAsm( Method method, ClassNode classNode ) { List<String> names = new ArrayList<>(); MethodNode methodNode = getMethodNode( method, classNode ); if( methodNode == null ) { return getNamesByReflection( method ); } for( LocalVariableNode variableNode : (List<LocalVariableNode>) methodNode.localVariables ) { // if methodNode is not static, first local variable always be "this". if( "this".equals(variableNode.name) ) continue; names.add( variableNode.name ); } return names; }
private LocalVariableNode getLocalVariableNode(int varIdx, AbstractInsnNode insnNode, MethodNode methodNode) { int instrIdx = getInstructionIndex(insnNode); List<?> localVariables = methodNode.localVariables; for (int idx = 0; idx < localVariables.size(); idx++) { LocalVariableNode localVariableNode = (LocalVariableNode) localVariables.get(idx); if (localVariableNode.index == varIdx) { int scopeEndInstrIdx = getInstructionIndex(localVariableNode.end); if (scopeEndInstrIdx >= instrIdx) { // still valid for current line return localVariableNode; } } } throw new RuntimeException("Variable with index " + varIdx + " and end >= " + currentLine + " not found for method " + fullyQualifiedTargetClass + "#" + methodNode.name + "!"); }
private InsnList localVarValue(AbstractInsnNode insnNode, int opositeOpcode, String param) { int varIdx = -1; if (insnNode instanceof VarInsnNode) { varIdx = ((VarInsnNode) insnNode).var; } else if (insnNode instanceof IincInsnNode) { varIdx = ((IincInsnNode) insnNode).var; } else { throw new RuntimeException("Not implemented for type " + insnNode.getClass()); } InsnList instrumentation = new InsnList(); MethodNode methodNode = (MethodNode) mv; if (methodNode.localVariables.size() <= varIdx) { throw new RuntimeException("varInsnNode is pointing outside of local variables!"); } LocalVariableNode localVariableNode = getLocalVariableNode(varIdx, insnNode, methodNode); instrumentation.add(new VarInsnNode(opositeOpcode, varIdx)); instrumentation.add(new LdcInsnNode(localVariableNode.name)); instrumentation.add(new LdcInsnNode(currentLine)); instrumentation.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "org/evosuite/junit/TestRuntimeValuesDeterminer", "localVarValueChanged", "(" + param + "Ljava/lang/String;I)V")); logger.debug("Adding localVarValueChanged for var {} in line {}.", localVariableNode.name, currentLine); return instrumentation; }
/** * <p>getNextIndex</p> * * @param mn a {@link org.objectweb.asm.tree.MethodNode} object. * @return a int. */ @SuppressWarnings("rawtypes") public static int getNextIndex(MethodNode mn) { Iterator it = mn.localVariables.iterator(); int max = 0; int next = 0; while (it.hasNext()) { LocalVariableNode var = (LocalVariableNode) it.next(); int index = var.index; if (index >= max) { max = index; next = max + Type.getType(var.desc).getSize(); } } if (next == 0) next = getNextIndexFromLoad(mn); return next; }
private LocalVariableNode getLocal(MethodNode mn, AbstractInsnNode node, int index) throws VariableNotFoundException { int currentId = mn.instructions.indexOf(node); for (Object v : mn.localVariables) { LocalVariableNode localVar = (LocalVariableNode) v; int startId = mn.instructions.indexOf(localVar.start); int endId = mn.instructions.indexOf(localVar.end); logger.info("Checking " + localVar.index + " in scope " + startId + " - " + endId); if (currentId >= startId && currentId <= endId && localVar.index == index) return localVar; } throw new VariableNotFoundException("Could not find local variable " + index + " at position " + currentId + ", have variables: " + mn.localVariables.size()); }
private String guessName(final MethodNode method, final SwitchEntry se, final int local) { if (se != null) { for (LocalVariableNode node : method.localVariables) { if (node.index == local && method.instructions.indexOf(node.start) <= se.index && method.instructions.indexOf(node.end) >= se.index) { return node.name; } } } return "_local$" + local; }
@Test public void mustFindLocalVariableNodeForInstruction() { MethodNode methodNode = findMethodsWithName(classNode.methods, "localVariablesTest").get(0); List<AbstractInsnNode> insns = findInvocationsOf(methodNode.instructions, MethodUtils.getAccessibleMethod(PrintStream.class, "println", String.class)); AbstractInsnNode insnNode = insns.get(0); LocalVariableNode lvn0 = findLocalVariableNodeForInstruction(methodNode.localVariables, methodNode.instructions, insnNode, 0); LocalVariableNode lvn1 = findLocalVariableNodeForInstruction(methodNode.localVariables, methodNode.instructions, insnNode, 1); LocalVariableNode lvn2 = findLocalVariableNodeForInstruction(methodNode.localVariables, methodNode.instructions, insnNode, 2); assertEquals(lvn0.name, "this"); assertEquals(lvn1.name, "val1"); assertEquals(lvn2.name, "val2"); }
private static AbstractInsnNode getParamStartNodeOfUDClassMethodCall(MethodInsnNode node, List<LocalVariableNode> locaVariables) { String owner = node.owner; List<Integer> descriptionMatchingLocalVariables = new ArrayList<Integer>(); for (LocalVariableNode localVar : locaVariables) { if (localVar.desc.contains(owner)) { descriptionMatchingLocalVariables.add(localVar.index); } } boolean isOtherClassVariableFound = false; AbstractInsnNode previousNode = node.getPrevious(); while (previousNode != null && !isOtherClassVariableFound) { if (previousNode instanceof VarInsnNode) { VarInsnNode varInsnNode = (VarInsnNode) previousNode; Integer indexOfUDC = descriptionMatchingLocalVariables.indexOf(varInsnNode.var); if (indexOfUDC != -1) { return previousNode; } previousNode = previousNode.getPrevious(); return previousNode; } } return null; }
private static void createVarFieldArray(final CodeBlock block, final RuleMethod method) { final int count = method.getLocalVarVariables().size(); block.bipush(count).anewarray(CodegenUtils.p(Var.class)); LocalVariableNode var; String varName; for (int i = 0; i < count; i++) { var = method.getLocalVarVariables().get(i); varName = method.name + ':' + var.name; block.dup() .bipush(i) .aload(var.index) .dup() .ldc(varName) .invokevirtual(CodegenUtils.p(Var.class), "setName", CodegenUtils.sig(void.class, String.class)) .aastore(); } }
private static void patchRenderHandMethod(MethodNode mn) { System.out.println("\tPatching method renderHand in EntityRenderer"); InsnList newList = new InsnList(); mn.localVariables = new ArrayList<LocalVariableNode>(5); newList.add(new VarInsnNode(Opcodes.FLOAD, 1)); newList.add(new VarInsnNode(Opcodes.ILOAD, 2)); newList.add(new VarInsnNode(Opcodes.ALOAD, 0)); newList.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "fr/zak/cubesedge/coremod/Patch", "entityRendererRenderHandPatch", "(FIL" + className + ";)V", false)); newList.add(new InsnNode(Opcodes.RETURN)); mn.instructions = newList; }
private static void patchSetAnglesMethod(MethodNode mn) { System.out.println("\tPatching method setAngles in Entity"); InsnList newList = new InsnList(); mn.localVariables = new ArrayList<LocalVariableNode>(5); newList.add(new VarInsnNode(Opcodes.FLOAD, 1)); newList.add(new VarInsnNode(Opcodes.FLOAD, 2)); newList.add(new VarInsnNode(Opcodes.ALOAD, 0)); newList.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "fr/zak/cubesedge/coremod/Patch", "entitySetAnglesPatch", "(FFL" + className + ";)V", false)); newList.add(new InsnNode(Opcodes.RETURN)); mn.instructions = newList; }
/** * Stores the top n stack elements as local variables. Returns an array of * all of the lv indices. return[0] is the top element. * * @param n * @return */ protected LocalVariableNode[] storeToLocals(int n) { LocalVariableNode[] ret = new LocalVariableNode[n]; // System.out.println("Store to locals top " + n); // System.out.println(analyzer.stack); for (int i = 0; i < n; i++) { Type elType = null; if (analyzer.stack.get(analyzer.stack.size() - 1) == Opcodes.TOP) elType = getTypeForStackType(analyzer.stack.get(analyzer.stack.size() - 2)); else elType = getTypeForStackType(analyzer.stack.get(analyzer.stack.size() - 1)); Boolean istagged = topCarriesTaint(); ret[i] = new LocalVariableNode(null, elType.getDescriptor(), istagged.toString(), null, null, lvs.getTmpLV()); super.visitVarInsn(elType.getOpcode(ISTORE), ret[i].index); } return ret; }
/** * Will insert a NULL after the nth element from the top of the stack * * @param n */ void insertNullAt(int n) { switch (n) { case 0: super.visitInsn(ACONST_NULL); break; case 1: super.visitInsn(ACONST_NULL); super.visitInsn(SWAP); break; case 2: super.visitInsn(ACONST_NULL); super.visitInsn(DUP_X2); super.visitInsn(POP); break; default: LocalVariableNode[] d = storeToLocals(n); super.visitInsn(ACONST_NULL); for (int i = n - 1; i >= 0; i--) { loadLV(i, d); } freeLVs(d); } }
private void nameArguments() { //Labels before and after all real instructions. List<LabelNode> beginLabels = new ArrayList<>(), endLabels = new ArrayList<>(); for (AbstractInsnNode n = methodNode.instructions.getFirst(); n != null && n.getOpcode() == -1; n = n.getNext()) if (n instanceof LabelNode) beginLabels.add((LabelNode)n); for (AbstractInsnNode n = methodNode.instructions.getLast(); n != null && n.getOpcode() == -1; n = n.getPrevious()) if (n instanceof LabelNode) endLabels.add((LabelNode)n); //Get the initial frame state, which has the arguments in the proper //locals positions, and set names. Value[] locals = blocks.get(0).entryState.locals; for (LocalVariableNode lvn : methodNode.localVariables) if (beginLabels.contains(lvn.start) && endLabels.contains(lvn.end) && (!method.isConstructor() || lvn.index != 0)) locals[lvn.index].setName(lvn.name); }
private void buildLocalVariableTable() { LabelNode first = new LabelNode(), last = new LabelNode(); methodNode.instructions.insert(first); methodNode.instructions.add(last); methodNode.localVariables = new ArrayList<>(registers.size()); for (Map.Entry<Value, Integer> r : registers.entrySet()) { RegularType type = r.getKey() instanceof LocalVariable ? ((LocalVariable)r.getKey()).getType().getFieldType() : (RegularType)r.getKey().getType(); methodNode.localVariables.add(new LocalVariableNode( r.getKey().getName(), type.getDescriptor(), null, first, last, r.getValue())); } }
@SuppressWarnings("unchecked") static java.lang.reflect.Type localVariable(final ClassLoader loader, final MethodNode m, final VarInsnNode varInsn) { if (varInsn.getOpcode() == Opcodes.ALOAD) { List<LocalVariableNode> vars = m.localVariables; LocalVariableNode var = vars.stream() .filter(v -> v.index == varInsn.var) .findFirst() .orElse(null); if (var != null) { String signature = "()" + Optional.ofNullable(var.signature).orElse(var.desc); return TypeDescriptorParser.parse(loader, signature); } } return Object.class; }
public TracingMethodInstrumenter(final Tracer tracer, final ReadMethod readMethod, final ClassNode classNode, final MethodNode methodNode) { this.tracer = tracer; this.readMethod = readMethod; this.classNode = classNode; this.methodNode = methodNode; int usedLocalVars = ((readMethod.getAccess() & Opcodes.ACC_STATIC) == 0 ? 1 : 0); for (final Type t: Type.getArgumentTypes(readMethod.getDesc())) usedLocalVars += t.getSize(); if (methodNode.localVariables != null) { for (final Object locVarNode: methodNode.localVariables) { final LocalVariableNode locVar = (LocalVariableNode)locVarNode; final int index = locVar.index + Type.getType(locVar.desc).getSize(); if (usedLocalVars < index) usedLocalVars = index; } } this.tracerLocalVarIndex = usedLocalVars; ++statsMethods; if (lastClass != readMethod.getReadClass()) { lastClass = readMethod.getReadClass(); ++statsClasses; } }
public int getIndexOfVar(MethodNode m, String desc, String signature) { desc = patchDESC(desc); signature = signature == null ? null : patchDESC(signature); for (Iterator<LocalVariableNode> iterator = m.localVariables.iterator(); iterator.hasNext();) { LocalVariableNode local = iterator.next(); if (local.desc.equals(desc) && (signature == null || signature.equals(local.signature))) return local.index; } return -1; }
private static Map<LocalVariableNode, DebugLocalInfo> computeLocals( List localNodes, JarApplicationReader application) { Map<DebugLocalInfo, DebugLocalInfo> canonical = new HashMap<>(localNodes.size()); Map<LocalVariableNode, DebugLocalInfo> localVariables = new HashMap<>(localNodes.size()); for (Object o : localNodes) { LocalVariableNode node = (LocalVariableNode) o; localVariables.computeIfAbsent(node, n -> canonicalizeLocal(n, canonical, application)); } return localVariables; }
private static DebugLocalInfo canonicalizeLocal( LocalVariableNode node, Map<DebugLocalInfo, DebugLocalInfo> canonicalLocalVariables, JarApplicationReader application) { DebugLocalInfo info = new DebugLocalInfo( application.getString(node.name), application.getTypeFromDescriptor(node.desc), node.signature == null ? null : application.getString(node.signature)); DebugLocalInfo canonical = canonicalLocalVariables.putIfAbsent(info, info); return canonical != null ? canonical : info; }
public JarState(int maxLocals, Map<LocalVariableNode, DebugLocalInfo> localVariables) { int localsRegistersSize = maxLocals * 3; localsSize = maxLocals; locals = new Local[localsRegistersSize]; startOfStack = localsRegistersSize; topOfStack = startOfStack; this.localVariables = localVariables; localVariableStartPoints = HashMultimap.create(); localVariableEndPoints = HashMultimap.create(); populateLocalTables(); }
private void populateLocalTables() { for (LocalVariableNode node : localVariables.keySet()) { if (node.start != node.end) { localVariableStartPoints.put(node.start, node); localVariableEndPoints.put(node.end, node); } } }
public List<Local> openLocals(LabelNode label) { Collection<LocalVariableNode> nodes = localVariableStartPoints.get(label); ArrayList<Local> locals = new ArrayList<>(nodes.size()); for (LocalVariableNode node : nodes) { locals.add(setLocalInfo(node.index, Type.getType(node.desc), localVariables.get(node))); } // Sort to ensure deterministic instruction ordering (correctness is unaffected). locals.sort(Comparator.comparingInt(local -> local.slot.register)); return locals; }