/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3.0 of the License, or * (at your option) any later version. * * EvoSuite is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ /** * */ package org.evosuite.instrumentation.coverage; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Queue; import org.evosuite.Properties; import org.evosuite.Properties.Strategy; import org.evosuite.classpath.ResourceList; import org.evosuite.coverage.branch.BranchPool; import org.evosuite.coverage.lcsaj.LCSAJ; import org.evosuite.coverage.lcsaj.LCSAJPool; import org.evosuite.graphs.GraphPool; import org.evosuite.graphs.cfg.BytecodeInstruction; import org.evosuite.graphs.cfg.BytecodeInstructionPool; import org.evosuite.graphs.cfg.RawControlFlowGraph; import org.evosuite.setup.DependencyAnalysis; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.JumpInsnNode; import org.objectweb.asm.tree.LabelNode; import org.objectweb.asm.tree.LdcInsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.TableSwitchInsnNode; import org.objectweb.asm.tree.TryCatchBlockNode; /** * <p> * LCSAJsInstrumentation class. * </p> * * @author copied from CFGMethodAdapter */ public class LCSAJsInstrumentation implements MethodInstrumentation { /* (non-Javadoc) * @see org.evosuite.cfg.MethodInstrumentation#analyze(org.objectweb.asm.tree.MethodNode, org.jgrapht.Graph, java.lang.String, java.lang.String) */ /** {@inheritDoc} */ @SuppressWarnings("unchecked") //using external lib @Override public void analyze(ClassLoader classLoader, MethodNode mn, String className, String methodName, int access) { Queue<LCSAJ> lcsaj_queue = new LinkedList<LCSAJ>(); HashSet<Integer> targets_reached = new HashSet<Integer>(); AbstractInsnNode start = mn.instructions.getFirst(); int startID = 0; // TODO: This should replace the hack below if (methodName.startsWith("<init>")) { Iterator<AbstractInsnNode> j = mn.instructions.iterator(); boolean constructorInvoked = false; while (j.hasNext()) { AbstractInsnNode in = j.next(); startID++; if(!constructorInvoked) { if (in.getOpcode() == Opcodes.INVOKESPECIAL) { MethodInsnNode cn = (MethodInsnNode) in; Collection<String> superClasses = DependencyAnalysis.getInheritanceTree().getSuperclasses(className); superClasses.add(className); String classNameWithDots = ResourceList.getClassNameFromResourcePath(cn.owner); if (superClasses.contains(classNameWithDots)) { constructorInvoked = true; break; } } else { continue; } } } } /* if (methodName.startsWith("<init>")) { if (mn.instructions.size() >= 4) { start = mn.instructions.get(4); startID = 4; } } */ LCSAJ a = new LCSAJ( className, methodName, BytecodeInstructionPool.getInstance(classLoader).getInstruction(className, methodName, startID, start)); lcsaj_queue.add(a); targets_reached.add(0); ArrayList<TryCatchBlockNode> tc_blocks = (ArrayList<TryCatchBlockNode>) mn.tryCatchBlocks; for (TryCatchBlockNode t : tc_blocks) { LCSAJ b = new LCSAJ( className, methodName, BytecodeInstructionPool.getInstance(classLoader).getInstruction(className, methodName, mn.instructions.indexOf(t.handler), t.handler)); lcsaj_queue.add(b); } while (!lcsaj_queue.isEmpty()) { LCSAJ currentLCSAJ = lcsaj_queue.poll(); int position = mn.instructions.indexOf(currentLCSAJ.getLastNodeAccessed()); // go to next bytecode instruction position++; if (position >= mn.instructions.size()) { // New LCSAJ for current + return LCSAJPool.add_lcsaj(className, methodName, currentLCSAJ); continue; } AbstractInsnNode next = mn.instructions.get(position); currentLCSAJ.lookupInstruction(position, BytecodeInstructionPool.getInstance(classLoader).getInstruction(className, methodName, position, next)); if (next instanceof JumpInsnNode) { JumpInsnNode jump = (JumpInsnNode) next; // New LCSAJ for current + jump to target LCSAJPool.add_lcsaj(className, methodName, currentLCSAJ); LabelNode target = jump.label; int targetPosition = mn.instructions.indexOf(target); if (jump.getOpcode() != Opcodes.GOTO) { LCSAJ copy = new LCSAJ(currentLCSAJ); lcsaj_queue.add(copy); } if (!targets_reached.contains(targetPosition)) { LCSAJ c = new LCSAJ( className, methodName, BytecodeInstructionPool.getInstance(classLoader).getInstruction(className, methodName, targetPosition, target)); lcsaj_queue.add(c); targets_reached.add(targetPosition); } } else if (next instanceof TableSwitchInsnNode) { TableSwitchInsnNode tswitch = (TableSwitchInsnNode) next; List<LabelNode> allTargets = tswitch.labels; for (LabelNode target : allTargets) { int targetPosition = mn.instructions.indexOf(target); if (!targets_reached.contains(targetPosition)) { LCSAJ b = new LCSAJ( className, methodName, BytecodeInstructionPool.getInstance(classLoader).getInstruction(className, methodName, targetPosition, target)); lcsaj_queue.add(b); targets_reached.add(targetPosition); } } } else if (next instanceof InsnNode) { InsnNode insn = (InsnNode) next; // New LCSAJ for current + throw / return if (insn.getOpcode() == Opcodes.ATHROW || insn.getOpcode() == Opcodes.RETURN || insn.getOpcode() == Opcodes.ARETURN || insn.getOpcode() == Opcodes.IRETURN || insn.getOpcode() == Opcodes.DRETURN || insn.getOpcode() == Opcodes.LRETURN || insn.getOpcode() == Opcodes.FRETURN) { LCSAJPool.add_lcsaj(className, methodName, currentLCSAJ); } else lcsaj_queue.add(currentLCSAJ); } else lcsaj_queue.add(currentLCSAJ); } if (Properties.STRATEGY != Strategy.EVOSUITE) addInstrumentation(classLoader, mn, className, methodName); // if (Properties.WRITE_CFG) // for (LCSAJ l : LCSAJPool.getLCSAJs(className, methodName)) { // LCSAJGraph graph = new LCSAJGraph(l, false); // String graphDestination = "evosuite-graphs/LCSAJGraphs/" + className // + "/" + methodName; // File dir = new File(graphDestination); // if (dir.mkdirs()) // graph.generate(new File(graphDestination + "/LCSAJGraph no: " // + l.getID() + ".dot")); // else if (dir.exists()) // graph.generate(new File(graphDestination + "/LCSAJGraph no: " // + l.getID() + ".dot")); // } } @SuppressWarnings("unchecked") private void addInstrumentation(ClassLoader classLoader, MethodNode mn, String className, String methodName) { RawControlFlowGraph graph = GraphPool.getInstance(classLoader).getRawCFG(className, methodName); Iterator<AbstractInsnNode> j = mn.instructions.iterator(); while (j.hasNext()) { AbstractInsnNode in = j.next(); for (BytecodeInstruction v : graph.vertexSet()) { // If this is in the CFG and it's a branch... if (in.equals(v.getASMNode())) { if (v.isForcedBranch()) { LCSAJPool.addLCSAJBranch(BranchPool.getInstance(classLoader).getBranchForInstruction(v)); int branchId = BranchPool.getInstance(classLoader).getActualBranchIdForNormalBranchInstruction(v); InsnList instrumentation = new InsnList(); instrumentation.add(new LdcInsnNode(v.getASMNode().getOpcode())); instrumentation.add(new LdcInsnNode(branchId)); instrumentation.add(new LdcInsnNode(v.getInstructionId())); instrumentation.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "org/evosuite/testcase/ExecutionTracer", "passedUnconditionalBranch", "(III)V")); if (v.isLabel()) mn.instructions.insert(v.getASMNode(), instrumentation); else mn.instructions.insertBefore(v.getASMNode(), instrumentation); } } } } } /* (non-Javadoc) * @see org.evosuite.cfg.MethodInstrumentation#executeOnExcludedMethods() */ /** {@inheritDoc} */ @Override public boolean executeOnExcludedMethods() { return false; } /* (non-Javadoc) * @see org.evosuite.cfg.MethodInstrumentation#executeOnMainMethod() */ /** {@inheritDoc} */ @Override public boolean executeOnMainMethod() { return false; } }