Java tutorial
/* * SootClassLoader.java * Jun 30, 2011 * * CriticAL : A Critic for APIs and Libraries * * Copyright (C) 2011 Chandan Raj Rupakheti & Daqing Hou, Clarkson University * * This program 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 of the License, or any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Contact Us: * Chandan Raj Rupakheti (rupakhcr@clarkson.edu) * Daqing Hou (dhou@clarkson.edu) * Clarkson University * PO Box 5722 * Potsdam * NY 13699-5722 * http://critical.sourceforge.net */ package cfgrecognition.loader; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import soot.Scene; import soot.SootClass; import soot.SootMethod; import soot.options.Options; import astrecognition.Activator; /** * This class uses JDT API to traverse through all of the project types * including the inner types and loads them in Soot. It is designed as a * singleton class. * * @author <a href="http://clarkson.edu/~rupakhcr">Chandan R. Rupakheti</a> * (rupakhcr@clarkson.edu) */ public class SootClassLoader { private final static String DUMMY_MAIN_CLASS = "zdummy.Main"; private final static String DUMMY_ENTRY_METHOD = "main"; private static SootClassLoader instance; /** * Gets the instance of class loader. * * @return */ public static synchronized SootClassLoader instance() { if (instance == null) instance = new SootClassLoader(); return instance; } /** * Resets the instance to null, releasing all of the occupied resources. */ public static synchronized void reset() { instance = null; } private Map<String, SootClass> nameToClassMap; private SootClassLoader() { nameToClassMap = Collections.synchronizedMap(new HashMap<String, SootClass>()); configureSoot(); } private synchronized void configureSoot() { // TODO, get this from the plugin class String classPath = SootClasspath.urlsToString(SootClasspath.projectClassPath2(Activator.getIJavaProject())); // Set up all the options for soot soot.G.reset(); Options options = soot.options.Options.v(); options.set_soot_classpath(classPath); options.set_prepend_classpath(true); options.allow_phantom_refs(); options.set_keep_line_number(true); options.set_whole_program(true); options.setPhaseOption("jb", "use-original-names:true"); options.setPhaseOption("cg", "verbose:false"); // Let soot parse user option and set it // options.parse(Activator.getPreferences().getSootOptionArray()); // Load dummy main class. This is requirement for all the project being // analyzed SootClass mainClass = this.load(DUMMY_MAIN_CLASS, true); List<SootMethod> entryPointList = new ArrayList<SootMethod>(); entryPointList.add(mainClass.getMethodByName(DUMMY_ENTRY_METHOD)); soot.Scene.v().setEntryPoints(entryPointList); } /** * Loads a class to the soot. * * @param name * The qualified name of the class to be loaded in Soot. * @return {@link SootClass} after loading. */ public synchronized SootClass load(String name) { SootClass sootClass = load(name, false); if (sootClass != null) { this.nameToClassMap.put(name, sootClass); } return sootClass; } // Load class here returns null so we might expect a null pointer exception // somewhere private synchronized SootClass load(String name, boolean main) { try { SootClass c = Scene.v().loadClassAndSupport(name); c.setApplicationClass(); if (main) Scene.v().setMainClass(c); return c; } catch (Exception e) { Activator.log(Status.ERROR, "Unable to load " + name + " in Soot.", e); return null; } } /** * Returns the class loaded in Soot corresponding to the supplied name. Null * is returned if the class with the given name is not present. * * @param name * @return */ public SootClass getSootClass(String name) { return this.nameToClassMap.get(name); } /** * Gets all of the classes loaded in soot. Note modifying this collection * will change the internal structure of the backing map. * * @return */ public Collection<SootClass> getAllSootClasses() { return this.nameToClassMap.values(); } /** * Checks if the supplied name of the class is an application class that was * loaded in soot. * * @param className * The name of the class to be checked. * @return <tt>true</tt> if loaded as an application class and * <tt>false</tt> otherwise. */ public boolean contains(String className) { return this.nameToClassMap.containsKey(className); } /** * Checks if the supplied class is an application class that was loaded in * soot. * * @param clazz * The class to be checked. * @return <tt>true</tt> if loaded as an application class and * <tt>false</tt> otherwise. */ public boolean contains(SootClass clazz) { return this.nameToClassMap.containsKey(clazz.getName()); } /** * The method traverses all of the project types in depth-first order * including inner and anonymous types and loads them in Soot. * * * @param monitor * The progress monitor. * @throws Exception * Propagated from JDT APIs. */ public void process() throws Exception { IJavaProject project = Activator.getIJavaProject(); IPackageFragmentRoot[] packageFragmentRoots = project.getPackageFragmentRoots(); // subMonitor.beginTask("Loading " + project.getElementName() + " ...", 2); // // SubProgressMonitor monitor = new SubProgressMonitor(subMonitor, 1); // monitor.beginTask("Loading packages ... ", // packageFragmentRoots.length + 1); for (IPackageFragmentRoot pkgFragRoot : packageFragmentRoots) { if (pkgFragRoot.getKind() == IPackageFragmentRoot.K_SOURCE) { IJavaElement[] pkgFrags = (IJavaElement[]) pkgFragRoot.getChildren(); for (IJavaElement pkgFrag : pkgFrags) { // if (monitor.isCanceled()) // return; // // monitor.subTask("Loading classes in " // + pkgFrag.getElementName()); if (pkgFrag.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { IPackageFragment pkgFragment = (IPackageFragment) pkgFrag; IJavaElement[] children = pkgFragment.getChildren(); for (IJavaElement anElement : children) { // if (monitor.isCanceled()) // return; // Make sure its a java file if (anElement.getElementType() == IJavaElement.COMPILATION_UNIT) { this.dfsDomTree(anElement); // this.dfsDomTree(anElement, monitor); } } } } } // monitor.worked(1); } // Load the necessary classes after all of the classes have been loaded. Scene.v().loadNecessaryClasses(); // monitor.done(); // Create an instance of Interpreter before we process anything further // Interpreter.instance(); // monitor = new SubProgressMonitor(subMonitor, 1); // monitor.beginTask("Configuring entry points ... ", this // .getAllSootClasses().size()); // for (SootClass c : this.getAllSootClasses()) { // // ExtensionManager manager = ExtensionManager.instance(); // // Configure entry methods for extension plugin // for (SootMethod method : c.getMethods()) { // if (monitor.isCanceled()) // return; // // TODO: later down the road, this specifies the entry points // // (characteristics for different algorithms) // // manager.checkEntryMethod(method, monitor); // monitor.worked(1); // } // } // monitor.done(); } protected void dfsDomTree(IJavaElement element) throws Exception { // if (monitor.isCanceled()) { // return; // } if (element.isReadOnly()) return; int elementType = element.getElementType(); if (elementType == IJavaElement.COMPILATION_UNIT) { ICompilationUnit cu = (ICompilationUnit) element; IType[] allTypes = cu.getTypes(); for (IType aType : allTypes) { dfsDomTree(aType); } } else if (elementType == IJavaElement.TYPE) { IType aType = (IType) element; if (aType.isClass()) { // Load a type in Soot load(aType.getFullyQualifiedName()); } // Go inside the methods to look for Anonymous Inner Class for (IMethod m : aType.getMethods()) { IJavaElement[] elems = m.getChildren(); for (IJavaElement elem : elems) { if (elem.getElementType() == IJavaElement.TYPE) { dfsDomTree(elem); } } } // For inner classes IType[] allTypes = aType.getTypes(); for (IType childType : allTypes) { dfsDomTree(childType); } } } /** * This is a debug method to check all of the classes loaded in Soot through * this loader. * * @param oStream */ public void printLoadedClasses(OutputStream oStream) { PrintStream out = new PrintStream(oStream); out.println("#################################################"); out.println("Loaded Classes in Soot:"); out.println("#################################################"); for (SootClass aClass : this.nameToClassMap.values()) { String superClassString = "NONE"; if (aClass.hasSuperclass()) { superClassString = aClass.getSuperclass().getName(); } out.println(aClass.getName() + " extends " + superClassString); } out.println("#################################################"); out.println(); out.flush(); } }