/* * Copyright 20089 Wishnu Prasetya. * * This file is part of T2. * T2 is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License (GPL) as published by the * Free Software Foundation; either version 3 of the License, or any * later version. * * T2 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 General Public License * for more details. * * A copy of the GNU General Public License can be found in T2 distribution. * If it is missing, see http://www.gnu.org/licenses. */ package Sequenic.T2ext.Instrumenter; import org.apache.bcel.Repository; import org.apache.bcel.classfile.*; import org.apache.bcel.generic.*; import java.util.*; /** * Provide functionality to instrument a class C. Currently this means * that all the declared methods of C will be instrumented. * * We can try to extend this in the future, e.g. by instrumenting all * classes in the same package. * * Each method in-scope will be injected with sensors, and a CFG for the * method will be constructed. * * @author Wishnu Prasetya * @author Original code by Maaike Gerritsen * */ public class ClassInstrumenter { /** * The methods to instrument. */ List tmethods ; /** * The class to which the method belongs to. Note that this is not necessarily * the class that declares the method. */ Class C ; /** * Full path of the target class. */ String tpath ; /** * BCEL representation of a target class C; it allows a class file to * be analyzed, but not transformed. */ JavaClass clazz ; /** * BCEL interface to manipulate a class. */ ClassGen classGen ; /** * If true will inject sensors, else it will only generate CFG * without injecting sensors. * * The default is false. */ boolean doInject = false ; boolean debug = false ; private List instrumenters = new LinkedList() ; /** * This is the standard constructor of this class. It will set the entire * set of declared methods of the target class as targets to be * instrumented. * * @param tclass The target class to instrument. * @param path The full path to the target class. */ public ClassInstrumenter(Class tclass, String path){ C = tclass ; tpath = path ; java.lang.reflect.Method[] declaredMethods = C.getDeclaredMethods() ; tmethods = new LinkedList() ; for (int i=0; i targetmethods){ C = tclass ; tmethods = targetmethods ; // Have BCEL to read the target class and method: try { clazz = Repository.lookupClass(C); } catch (Exception e) { throw new Error(e) ; } // Set-up the class-gen to allow manipulation on the class: classGen = new ClassGen(clazz) ; for (java.lang.reflect.Method m : tmethods) { instrumenters.add(new MethodInstrumenter(m,C,classGen)) ; } } public CFGBunchFile doInstrumenting(){ if (doInject) for (MethodInstrumenter X : instrumenters) X.doInject = true ; if (debug) for (MethodInstrumenter X : instrumenters) X.debug = true ; CFGBunchFile CFGs = new CFGBunchFile() ; // Now instrument: for (MethodInstrumenter X : instrumenters) { CFGs.cfgs.add(X.doInstrumenting()) ; } done() ; saveCFGs(CFGs) ; System.out.println("Instrumenting these methods:") ; for (java.lang.reflect.Method M : tmethods) System.out.println(" " + M.getName()) ; //System.out.println("The CFGs:") ; for (CFG G : CFGs.cfgs) { G.simplePrint() ; } return CFGs ; } /** * Finalize the transformation, and save it in a new class file. */ private void done(){ if (!doInject) return ; try { classGen.getJavaClass().dump(tpath); } catch(Exception e) { throw new Error(e) ; } } private void saveCFGs(CFGBunchFile CFGs) { int N = tpath.length() ; String ext1 = ".class" ; String savefile = tpath.substring(0, N - ext1.length()) + ".cfgs" ; CFGs.save(savefile) ; System.out.println("\nSaving CFGs in " + savefile + "\n") ; } /** * Check if a Class is already instrumented. Currently only checks for * occurrences of Sequenic.T2ext.Instrumenter.Sensor.tick in the class file. */ public static boolean isInstrumented(Class C) { JavaClass clazz = null; try { // TODO check classpath stuff? clazz = Repository.lookupClass(C); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } Method[] methods = clazz.getMethods(); for(Method m : methods) { Attribute[] attributes = m.getAttributes(); //System.out.println(m); for(Attribute a : attributes) { //System.out.println(a); // FIXME: maybe a better way to determine if it's already instrumented? if(a.toString().indexOf("Sequenic.T2ext.Instrumenter.Sensor.tick") != -1) return true; } } return false; } }