Package soot

Source Code of soot.Scene

/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai
* Copyright (C) 2004 Ondrej Lhotak
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/

/*
* Modified by the Sable Research Group and others 1997-1999. 
* See the 'credits' file distributed with Soot for the complete list of
* contributors.  (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/


package soot;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.ContextSensitiveCallGraph;
import soot.jimple.toolkits.callgraph.ReachableMethods;
import soot.jimple.toolkits.pointer.DumbPointerAnalysis;
import soot.jimple.toolkits.pointer.SideEffectAnalysis;
import soot.options.CGOptions;
import soot.options.Options;
import soot.toolkits.exceptions.PedanticThrowAnalysis;
import soot.toolkits.exceptions.ThrowAnalysis;
import soot.toolkits.exceptions.UnitThrowAnalysis;
import soot.util.ArrayNumberer;
import soot.util.Chain;
import soot.util.HashChain;
import soot.util.MapNumberer;
import soot.util.Numberer;
import soot.util.SingletonList;
import soot.util.StringNumberer;

/** Manages the SootClasses of the application being analyzed. */
public class Scene  //extends AbstractHost
{
    public Scene ( Singletons.Global g )
    {
      setReservedNames();
     
        // load soot.class.path system property, if defined
        String scp = System.getProperty("soot.class.path");

        if (scp != null)
            setSootClassPath(scp);

        kindNumberer.add( Kind.INVALID );
        kindNumberer.add( Kind.STATIC );
        kindNumberer.add( Kind.VIRTUAL );
        kindNumberer.add( Kind.INTERFACE );
        kindNumberer.add( Kind.SPECIAL );
        kindNumberer.add( Kind.CLINIT );
        kindNumberer.add( Kind.THREAD );
        kindNumberer.add( Kind.FINALIZE );
        kindNumberer.add( Kind.INVOKE_FINALIZE );
        kindNumberer.add( Kind.PRIVILEGED );
        kindNumberer.add( Kind.NEWINSTANCE );

        addSootBasicClasses();
    }
    public static Scene  v() { return G.v().soot_Scene (); }
   
    Chain<SootClass> classes = new HashChain<SootClass>();
    Chain<SootClass> applicationClasses = new HashChain<SootClass>();
    Chain<SootClass> libraryClasses = new HashChain<SootClass>();
    Chain<SootClass> phantomClasses = new HashChain<SootClass>();
   
    private final Map<String,Type> nameToClass = new HashMap<String,Type>();

    ArrayNumberer kindNumberer = new ArrayNumberer();
    ArrayNumberer typeNumberer = new ArrayNumberer();
    ArrayNumberer methodNumberer = new ArrayNumberer();
    Numberer unitNumberer = new MapNumberer();
    Numberer contextNumberer = null;
    ArrayNumberer fieldNumberer = new ArrayNumberer();
    ArrayNumberer classNumberer = new ArrayNumberer();
    StringNumberer subSigNumberer = new StringNumberer();
    ArrayNumberer localNumberer = new ArrayNumberer();

    private Hierarchy activeHierarchy;
    private FastHierarchy activeFastHierarchy;
    private CallGraph activeCallGraph;
    private ReachableMethods reachableMethods;
    private PointsToAnalysis activePointsToAnalysis;
    private SideEffectAnalysis activeSideEffectAnalysis;
    private List<SootMethod> entryPoints;

    boolean allowsPhantomRefs = false;

    SootClass mainClass;
    String sootClassPath = null;

    // Two default values for constructing ExceptionalUnitGraphs:
    private ThrowAnalysis defaultThrowAnalysis = null;
   
    public void setMainClass(SootClass m)
    {
        mainClass = m;
        if(!m.declaresMethod(getSubSigNumberer().findOrAdd( "void main(java.lang.String[])" ))) {
          throw new RuntimeException("Main-class has no main method!");
        }
    }
   
    Set<String> reservedNames = new HashSet<String>();
   
    /**
        Returns a set of tokens which are reserved.  Any field, class, method, or local variable with such a name will be quoted.
     */
    
    public Set<String> getReservedNames()
    {
        return reservedNames;
    }
   
    /**
        If this name is in the set of reserved names, then return a quoted version of it.  Else pass it through.
     */
   
    public String quotedNameOf(String s)
    {
        if(reservedNames.contains(s))
            return "\'" + s + "\'";
        else
            return s;
    }
   
    public SootClass getMainClass()
    {
        if(mainClass == null) {
          setMainClassFromOptions();
        }
        if(mainClass == null)
            throw new RuntimeException("There is no main class set!");
           
        return mainClass;
    }
    public SootMethod getMainMethod() {
        if(mainClass==null) {
            throw new RuntimeException("There is no main class set!");
        }
        if (!mainClass.declaresMethod ("main", new SingletonList( ArrayType.v(RefType.v("java.lang.String"), 1) ), VoidType.v())) {
            throw new RuntimeException("Main class declares no main method!");
        }
        return mainClass.getMethod ("main", new SingletonList( ArrayType.v(RefType.v("java.lang.String"), 1) ), VoidType.v());  
    }
   
   
    public void setSootClassPath(String p)
    {
        sootClassPath = p;
        SourceLocator.v().invalidateClassPath();
    }
   
    public String getSootClassPath()
    {
        if( sootClassPath == null ) {
            String optionscp = Options.v().soot_classpath();
            if( optionscp.length() > 0 )
                sootClassPath = optionscp;

            String defaultSootClassPath = defaultClassPath();
 
          //if no classpath is given on the command line, take the default
          if( sootClassPath == null ) {
            sootClassPath = defaultSootClassPath;
          } else {
            //if one is given...
              if(Options.v().prepend_classpath()) {
                //if the prepend flag is set, append the default classpath
                sootClassPath += File.pathSeparator + defaultSootClassPath;
              }
              //else, leave it as it is
          }       
        }

        return sootClassPath;
    }
   
  public String defaultClassPath() {
    StringBuffer sb = new StringBuffer();
    sb.append(System.getProperty("java.class.path")+File.pathSeparator);
        if(System.getProperty("os.name").equals("Mac OS X")) {
          //in Mac OS X, rt.jar is split into classes.jar and ui.jar
          sb.append(File.pathSeparator);
          sb.append(System.getProperty("java.home"));
          sb.append(File.separator);
          sb.append("..");
          sb.append(File.separator);
          sb.append("Classes");
          sb.append(File.separator);
          sb.append("classes.jar");
 
          sb.append(File.pathSeparator);
          sb.append(System.getProperty("java.home"));
          sb.append(File.separator);
          sb.append("..");
          sb.append(File.separator);
          sb.append("Classes");
          sb.append(File.separator);
          sb.append("ui.jar");


        } else {
            sb.append(File.pathSeparator);
            sb.append(System.getProperty("java.home"));
            sb.append(File.separator);
            sb.append("lib");
            sb.append(File.separator);
            sb.append("rt.jar");
        }
       
    if(Options.v().whole_program() || Options.v().output_format()==Options.output_format_dava) {
      //add jce.jar, which is necessary for whole program mode
      //(java.security.Signature from rt.jar import javax.crypto.Cipher from jce.jar             
      sb.append(File.pathSeparator+
        System.getProperty("java.home")+File.separator+"lib"+File.separator+"jce.jar");
    }
   
    return sb.toString();
  }


    private int stateCount;
    public int getState() { return this.stateCount; }
    private void modifyHierarchy() {
        stateCount++;
        activeHierarchy = null;
        activeFastHierarchy = null;
        activeSideEffectAnalysis = null;
        activePointsToAnalysis = null;
    }

    public void addClass(SootClass c)
    {
        if(c.isInScene())
            throw new RuntimeException("already managed: "+c.getName());

        if(containsClass(c.getName()))
            throw new RuntimeException("duplicate class: "+c.getName());

        classes.add(c);
        c.setLibraryClass();

        nameToClass.put(c.getName(), c.getType());
        c.getType().setSootClass(c);
        c.setInScene(true);
        modifyHierarchy();
    }

    public void removeClass(SootClass c)
    {
        if(!c.isInScene())
            throw new RuntimeException();

        classes.remove(c);
       
        if(c.isLibraryClass()) {
            libraryClasses.remove(c);
        } else if(c.isPhantomClass()) {
            phantomClasses.remove(c);
        } else if(c.isApplicationClass()) {
            applicationClasses.remove(c);
        }
       
        c.getType().setSootClass(null);
        c.setInScene(false);
        modifyHierarchy();
    }

    public boolean containsClass(String className)
    {
        RefType type = (RefType) nameToClass.get(className);
        if( type == null ) return false;
        if( !type.hasSootClass() ) return false;
        SootClass c = type.getSootClass();
        return c.isInScene();
    }
   
    public boolean containsType(String className)
    {
        return nameToClass.containsKey(className);
    }

    public String signatureToClass(String sig) {
        if( sig.charAt(0) != '<' ) throw new RuntimeException("oops "+sig);
        if( sig.charAt(sig.length()-1) != '>' ) throw new RuntimeException("oops "+sig);
        int index = sig.indexOf( ":" );
        if( index < 0 ) throw new RuntimeException("oops "+sig);
        return sig.substring(1,index);
    }

    public String signatureToSubsignature(String sig) {
        if( sig.charAt(0) != '<' ) throw new RuntimeException("oops "+sig);
        if( sig.charAt(sig.length()-1) != '>' ) throw new RuntimeException("oops "+sig);
        int index = sig.indexOf( ":" );
        if( index < 0 ) throw new RuntimeException("oops "+sig);
        return sig.substring(index+2,sig.length()-1);
    }

    private SootField grabField(String fieldSignature)
    {
        String cname = signatureToClass( fieldSignature );
        String fname = signatureToSubsignature( fieldSignature );
        if( !containsClass(cname) ) return null;
        SootClass c = getSootClass(cname);
        if( !c.declaresField( fname ) ) return null;
        return c.getField( fname );
    }

    public boolean containsField(String fieldSignature)
    {
        return grabField(fieldSignature) != null;
    }
   
    private SootMethod grabMethod(String methodSignature)
    {
        String cname = signatureToClass( methodSignature );
        String mname = signatureToSubsignature( methodSignature );
        if( !containsClass(cname) ) return null;
        SootClass c = getSootClass(cname);
        if( !c.declaresMethod( mname ) ) return null;
        return c.getMethod( mname );
    }

    public boolean containsMethod(String methodSignature)
    {
        return grabMethod(methodSignature) != null;
    }

    public SootField getField(String fieldSignature)
    {
        SootField f = grabField( fieldSignature );
        if (f != null)
            return f;

        throw new RuntimeException("tried to get nonexistent field "+fieldSignature);
    }

    public SootMethod getMethod(String methodSignature)
    {
        SootMethod m = grabMethod( methodSignature );
        if (m != null)
            return m;
        throw new RuntimeException("tried to get nonexistent method "+methodSignature);
    }

    /**
     * Attempts to load the given class and all of the required support classes.
     * Returns the original class if it was loaded, or null otherwise.
     */
    
    public SootClass tryLoadClass(String className, int desiredLevel)
    {  
        /*
        if(Options.v().time())
            Main.v().resolveTimer.start();
        */
       
        setPhantomRefs(true);
        //SootResolver resolver = new SootResolver();
        if( !getPhantomRefs()
        && SourceLocator.v().getClassSource(className) == null ) {
            setPhantomRefs(false);
            return null;
        }
        SootResolver resolver = SootResolver.v();
        SootClass toReturn = resolver.resolveClass(className, desiredLevel);
        setPhantomRefs(false);

        return toReturn;
       
        /*
        if(Options.v().time())
            Main.v().resolveTimer.end(); */
    }
   
    /**
     * Loads the given class and all of the required support classes.  Returns the first class.
     */
    
    public SootClass loadClassAndSupport(String className)
    {
        SootClass ret = loadClass(className, SootClass.SIGNATURES);
        if( !ret.isPhantom() ) ret = loadClass(className, SootClass.BODIES);
        return ret;
    }

    public SootClass loadClass(String className, int desiredLevel)
    {  
        /*
        if(Options.v().time())
            Main.v().resolveTimer.start();
        */
       
        setPhantomRefs(true);
        //SootResolver resolver = new SootResolver();
        SootResolver resolver = SootResolver.v();
        SootClass toReturn = resolver.resolveClass(className, desiredLevel);
        setPhantomRefs(false);

        return toReturn;
       
        /*
        if(Options.v().time())
            Main.v().resolveTimer.end(); */
    }
   
    /**
     * Returns the RefType with the given className. 
     * @throws IllegalStateException if the RefType for this class cannot be found.
     * Use {@link #containsType(String)} to check if type is registered
     */
    public RefType getRefType(String className)
    {
        RefType refType = (RefType) nameToClass.get(className);
        if(refType==null) {
          throw new IllegalStateException("RefType "+className+" not loaded. " +
              "If you tried to get the RefType of a library class, did you call loadNecessaryClasses()? " +
              "Otherwise please check Soot's classpath.");
        }
    return refType;
    }
   
    /**
     * Returns the {@link RefType} for {@link Object}.
     */
    public RefType getObjectType() {
      return getRefType("java.lang.Object");
    }

    /**
     * Returns the RefType with the given className. 
     */
    public void addRefType(RefType type)
    {
        nameToClass.put(type.getClassName(), type);
    }

    /**
     * Returns the SootClass with the given className. 
     */

  public SootClass getSootClass(String className) {
    RefType type = (RefType) nameToClass.get(className);
    SootClass toReturn = null;
    if (type != null)
      toReturn = type.getSootClass();

    if (toReturn != null) {
      return toReturn;
    } else if (allowsPhantomRefs()) {
      SootClass c = new SootClass(className);
      c.setPhantom(true);
      addClass(c);
      return c;
    } else {
      throw new RuntimeException(System.getProperty("line.separator")
          + "Aborting: can't find classfile " + className);
    }
  }

    /**
     * Returns an backed chain of the classes in this manager.
     */
    
    public Chain<SootClass> getClasses()
    {
        return classes;
    }

    /* The four following chains are mutually disjoint. */

    /**
     * Returns a chain of the application classes in this scene.
     * These classes are the ones which can be freely analysed & modified.
     */
    public Chain<SootClass> getApplicationClasses()
    {
        return applicationClasses;
    }

    /**
     * Returns a chain of the library classes in this scene.
     * These classes can be analysed but not modified.
     */
    public Chain<SootClass> getLibraryClasses()
    {
        return libraryClasses;
    }

    /**
     * Returns a chain of the phantom classes in this scene.
     * These classes are referred to by other classes, but cannot be loaded.
     */
    public Chain<SootClass> getPhantomClasses()
    {
        return phantomClasses;
    }

    Chain<SootClass> getContainingChain(SootClass c)
    {
        if (c.isApplicationClass())
            return getApplicationClasses();
        else if (c.isLibraryClass())
            return getLibraryClasses();
        else if (c.isPhantomClass())
            return getPhantomClasses();

        return null;
    }

    /****************************************************************************/
    /**
        Retrieves the active side-effect analysis
     */

    public SideEffectAnalysis getSideEffectAnalysis()
    {
        if(!hasSideEffectAnalysis()) {
      setSideEffectAnalysis( new SideEffectAnalysis(
      getPointsToAnalysis(),
      getCallGraph() ) );
  }
           
        return activeSideEffectAnalysis;
    }
   
    /**
        Sets the active side-effect analysis
     */
    
    public void setSideEffectAnalysis(SideEffectAnalysis sea)
    {
        activeSideEffectAnalysis = sea;
    }

    public boolean hasSideEffectAnalysis()
    {
        return activeSideEffectAnalysis != null;
    }
   
    public void releaseSideEffectAnalysis()
    {
        activeSideEffectAnalysis = null;
    }

    /****************************************************************************/
    /**
        Retrieves the active pointer analysis
     */

    public PointsToAnalysis getPointsToAnalysis()
    {
        if(!hasPointsToAnalysis()) {
      return DumbPointerAnalysis.v();
  }
           
        return activePointsToAnalysis;
    }
   
    /**
        Sets the active pointer analysis
     */
    
    public void setPointsToAnalysis(PointsToAnalysis pa)
    {
        activePointsToAnalysis = pa;
    }

    public boolean hasPointsToAnalysis()
    {
        return activePointsToAnalysis != null;
    }
   
    public void releasePointsToAnalysis()
    {
        activePointsToAnalysis = null;
    }

    /****************************************************************************/
    /** Makes a new fast hierarchy is none is active, and returns the active
     * fast hierarchy. */
    public FastHierarchy getOrMakeFastHierarchy() {
  if(!hasFastHierarchy() ) {
      setFastHierarchy( new FastHierarchy() );
  }
  return getFastHierarchy();
    }
    /**
        Retrieves the active fast hierarchy
     */

    public FastHierarchy getFastHierarchy()
    {
        if(!hasFastHierarchy())
            throw new RuntimeException("no active FastHierarchy present for scene");
           
        return activeFastHierarchy;
    }
   
    /**
        Sets the active hierarchy
     */
    
    public void setFastHierarchy(FastHierarchy hierarchy)
    {
        activeFastHierarchy = hierarchy;
    }

    public boolean hasFastHierarchy()
    {
        return activeFastHierarchy != null;
    }
   
    public void releaseFastHierarchy()
    {
        activeFastHierarchy = null;
    }

    /****************************************************************************/
    /**
        Retrieves the active hierarchy
     */

    public Hierarchy getActiveHierarchy()
    {
        if(!hasActiveHierarchy())
            //throw new RuntimeException("no active Hierarchy present for scene");
            setActiveHierarchy( new Hierarchy() );
           
        return activeHierarchy;
    }
   
    /**
        Sets the active hierarchy
     */
    
    public void setActiveHierarchy(Hierarchy hierarchy)
    {
        activeHierarchy = hierarchy;
    }

    public boolean hasActiveHierarchy()
    {
        return activeHierarchy != null;
    }
   
    public void releaseActiveHierarchy()
    {
        activeHierarchy = null;
    }

    /** Get the set of entry points that are used to build the call graph. */
    public List<SootMethod> getEntryPoints() {
        if( entryPoints == null ) {
            entryPoints = EntryPoints.v().all();
        }
        return entryPoints;
    }

    /** Change the set of entry point methods used to build the call graph. */
    public void setEntryPoints( List<SootMethod> entryPoints ) {
        this.entryPoints = entryPoints;
    }

    private ContextSensitiveCallGraph cscg;
    public ContextSensitiveCallGraph getContextSensitiveCallGraph() {
        if(cscg == null) throw new RuntimeException("No context-sensitive call graph present in Scene. You can bulid one with Paddle.");
        return cscg;
    }

    public void setContextSensitiveCallGraph(ContextSensitiveCallGraph cscg) {
        this.cscg = cscg;
    }

    public CallGraph getCallGraph()
    {
        if(!hasCallGraph()) {
            throw new RuntimeException( "No call graph present in Scene. Maybe you want Whole Program mode (-w)." );
        }
           
        return activeCallGraph;
    }
   
    public void setCallGraph(CallGraph cg)
    {
        reachableMethods = null;
        activeCallGraph = cg;
    }

    public boolean hasCallGraph()
    {
        return activeCallGraph != null;
    }
   
    public void releaseCallGraph()
    {
        activeCallGraph = null;
        reachableMethods = null;
    }
    public ReachableMethods getReachableMethods() {
        if( reachableMethods == null ) {
            reachableMethods = new ReachableMethods(
                    getCallGraph(), new ArrayList<MethodOrMethodContext>(getEntryPoints()) );
        }
        reachableMethods.update();
        return reachableMethods;
    }
    public void setReachableMethods( ReachableMethods rm ) {
        reachableMethods = rm;
    }
    public boolean hasReachableMethods() {
        return reachableMethods != null;
    }
    public void releaseReachableMethods() {
        reachableMethods = null;
    }
  
    public boolean getPhantomRefs()
    {
        //if( !Options.v().allow_phantom_refs() ) return false;
        //return allowsPhantomRefs;
      return Options.v().allow_phantom_refs();
    }

    public void setPhantomRefs(boolean value)
    {
        allowsPhantomRefs = value;
    }
   
    public boolean allowsPhantomRefs()
    {
        return getPhantomRefs();
    }
    public Numberer kindNumberer() { return kindNumberer; }
    public ArrayNumberer getTypeNumberer() { return typeNumberer; }
    public ArrayNumberer getMethodNumberer() { return methodNumberer; }
    public Numberer getContextNumberer() { return contextNumberer; }
    public Numberer getUnitNumberer() { return unitNumberer; }
    public ArrayNumberer getFieldNumberer() { return fieldNumberer; }
    public ArrayNumberer getClassNumberer() { return classNumberer; }
    public StringNumberer getSubSigNumberer() { return subSigNumberer; }
    public ArrayNumberer getLocalNumberer() { return localNumberer; }

    public void setContextNumberer( Numberer n ) {
        if( contextNumberer != null )
            throw new RuntimeException(
                    "Attempt to set context numberer when it is already set." );
        contextNumberer = n;
    }

    /**
     * Returns the {@link ThrowAnalysis} to be used by default when
     * constructing CFGs which include exceptional control flow.
     *
     * @return the default {@link ThrowAnalysis}
     */
    public ThrowAnalysis getDefaultThrowAnalysis()
    {
  if( defaultThrowAnalysis == null ) {
      int optionsThrowAnalysis = Options.v().throw_analysis();
      switch (optionsThrowAnalysis) {
      case Options.throw_analysis_pedantic:
    defaultThrowAnalysis = PedanticThrowAnalysis.v();
    break;
      case Options.throw_analysis_unit:
    defaultThrowAnalysis = UnitThrowAnalysis.v();
    break;
      default:
    throw new IllegalStateException("Options.v().throw_analysi() == " +
            Options.v().throw_analysis());
      }
  }
  return defaultThrowAnalysis;
    }

    /**
     * Sets the {@link ThrowAnalysis} to be used by default when
     * constructing CFGs which include exceptional control flow.
     *
     * @param the default {@link ThrowAnalysis}.
     */
    public void setDefaultThrowAnalysis(ThrowAnalysis ta)
    {
  defaultThrowAnalysis = ta;
    }

    private void setReservedNames()
    {
        Set<String> rn = getReservedNames();       
        rn.add("newarray");
        rn.add("newmultiarray");
        rn.add("nop");
        rn.add("ret");
        rn.add("specialinvoke");
        rn.add("staticinvoke");
        rn.add("tableswitch");
        rn.add("virtualinvoke");
        rn.add("null_type");
        rn.add("unknown");
        rn.add("cmp");
        rn.add("cmpg");
        rn.add("cmpl");
        rn.add("entermonitor");
        rn.add("exitmonitor");
        rn.add("interfaceinvoke");
        rn.add("lengthof");
        rn.add("lookupswitch");
        rn.add("neg");
        rn.add("if");
        rn.add("abstract");
        rn.add("annotation");
        rn.add("boolean");
        rn.add("break");
        rn.add("byte");
        rn.add("case");
        rn.add("catch");
        rn.add("char");
        rn.add("class");
        rn.add("final");
        rn.add("native");
        rn.add("public");
        rn.add("protected");
        rn.add("private");
        rn.add("static");
        rn.add("synchronized");
        rn.add("transient");
        rn.add("volatile");
        rn.add("interface");
        rn.add("void");
        rn.add("short");
        rn.add("int");
        rn.add("long");
        rn.add("float");
        rn.add("double");
        rn.add("extends");
        rn.add("implements");
        rn.add("breakpoint");
        rn.add("default");
        rn.add("goto");
        rn.add("instanceof");
        rn.add("new");
        rn.add("return");
        rn.add("throw");
        rn.add("throws");
        rn.add("null");
        rn.add("from");
        rn.add("to");
    }

    private final Set<String>[] basicclasses=new Set[4];

    private void addSootBasicClasses() {
        basicclasses[SootClass.HIERARCHY] = new HashSet<String>();
        basicclasses[SootClass.SIGNATURES] = new HashSet<String>();
        basicclasses[SootClass.BODIES] = new HashSet<String>();

  addBasicClass("java.lang.Object");
  addBasicClass("java.lang.Class", SootClass.SIGNATURES);

  addBasicClass("java.lang.Void", SootClass.SIGNATURES);
  addBasicClass("java.lang.Boolean", SootClass.SIGNATURES);
  addBasicClass("java.lang.Byte", SootClass.SIGNATURES);
  addBasicClass("java.lang.Character", SootClass.SIGNATURES);
  addBasicClass("java.lang.Short", SootClass.SIGNATURES);
  addBasicClass("java.lang.Integer", SootClass.SIGNATURES);
  addBasicClass("java.lang.Long", SootClass.SIGNATURES);
  addBasicClass("java.lang.Float", SootClass.SIGNATURES);
  addBasicClass("java.lang.Double", SootClass.SIGNATURES);

  addBasicClass("java.lang.String");
  addBasicClass("java.lang.StringBuffer", SootClass.SIGNATURES);

  addBasicClass("java.lang.Error");
  addBasicClass("java.lang.AssertionError", SootClass.SIGNATURES);
  addBasicClass("java.lang.Throwable", SootClass.SIGNATURES);
  addBasicClass("java.lang.NoClassDefFoundError", SootClass.SIGNATURES);
  addBasicClass("java.lang.ExceptionInInitializerError");
  addBasicClass("java.lang.RuntimeException");
  addBasicClass("java.lang.ClassNotFoundException");
  addBasicClass("java.lang.ArithmeticException");
  addBasicClass("java.lang.ArrayStoreException");
  addBasicClass("java.lang.ClassCastException");
  addBasicClass("java.lang.IllegalMonitorStateException");
  addBasicClass("java.lang.IndexOutOfBoundsException");
  addBasicClass("java.lang.ArrayIndexOutOfBoundsException");
  addBasicClass("java.lang.NegativeArraySizeException");
  addBasicClass("java.lang.NullPointerException");
  addBasicClass("java.lang.InstantiationError");
  addBasicClass("java.lang.InternalError");
  addBasicClass("java.lang.OutOfMemoryError");
  addBasicClass("java.lang.StackOverflowError");
  addBasicClass("java.lang.UnknownError");
  addBasicClass("java.lang.ThreadDeath");
  addBasicClass("java.lang.ClassCircularityError");
  addBasicClass("java.lang.ClassFormatError");
  addBasicClass("java.lang.IllegalAccessError");
  addBasicClass("java.lang.IncompatibleClassChangeError");
  addBasicClass("java.lang.LinkageError");
  addBasicClass("java.lang.VerifyError");
  addBasicClass("java.lang.NoSuchFieldError");
  addBasicClass("java.lang.AbstractMethodError");
  addBasicClass("java.lang.NoSuchMethodError");
  addBasicClass("java.lang.UnsatisfiedLinkError");

  addBasicClass("java.lang.Thread");
  addBasicClass("java.lang.Runnable");
  addBasicClass("java.lang.Cloneable");

  addBasicClass("java.io.Serializable")

  addBasicClass("java.lang.ref.Finalizer");
    }

    public void addBasicClass(String name) {
  addBasicClass(name,SootClass.HIERARCHY);
    }
   
    public void addBasicClass(String name,int level) {
  basicclasses[level].add(name);
    }

    /** Load just the set of basic classes soot needs, ignoring those
     *  specified on the command-line. You don't need to use both this and
     *  loadNecessaryClasses, though it will only waste time.
     */
    public void loadBasicClasses() {
      addReflectionTraceClasses();
     
    for(int i=SootClass.BODIES;i>=SootClass.HIERARCHY;i--) {
        for(String name: basicclasses[i]) {
          tryLoadClass(name,i);
        }
    }
    }

    private void addReflectionTraceClasses() {
      CGOptions options = new CGOptions( PhaseOptions.v().getPhaseOptions("cg") );
      String log = options.reflection_log();
     
      Set<String> classNames = new HashSet<String>();
      if(log!=null && log.length()>0) {
      BufferedReader reader;
      String line="";
      try {
        reader = new BufferedReader(new InputStreamReader(new FileInputStream(log)));
        while((line=reader.readLine())!=null) {
          if(line.length()==0) continue;
          String[] portions = line.split(";",-1);
          String kind = portions[0];
          String target = portions[1];
          String source = portions[2];
          String sourceClassName = source.substring(0,source.lastIndexOf("."));
          classNames.add(sourceClassName);
          if(kind.equals("Class.forName")) {
            classNames.add(target);
          } else if(kind.equals("Class.newInstance")) {
            classNames.add(target);
          } else if(kind.equals("Method.invoke") || kind.equals("Constructor.newInstance")) {
            classNames.add(signatureToClass(target));
          } else throw new RuntimeException("Unknown entry kind: "+kind);
        }
      } catch (Exception e) {
        throw new RuntimeException("Line: '"+line+"'", e);
      }
      }
     
      for (String c : classNames) {
        addBasicClass(c, SootClass.BODIES);
    }
  }

  private List<SootClass> dynamicClasses;
    public Collection<SootClass> dynamicClasses() {
      if(dynamicClasses==null) {
        throw new IllegalStateException("Have to call loadDynamicClasses() first!");
      }
        return dynamicClasses;
    }

    private void loadNecessaryClass(String name) {
        SootClass c;
        c = loadClassAndSupport(name);
        c.setApplicationClass();
    }
    /** Load the set of classes that soot needs, including those specified on the
     *  command-line. This is the standard way of initialising the list of
     *  classes soot should use.
     */
    public void loadNecessaryClasses() {
  loadBasicClasses();

        Iterator<String> it = Options.v().classes().iterator();

        while (it.hasNext()) {
            String name = (String) it.next();
            loadNecessaryClass(name);
        }

        loadDynamicClasses();

        for( Iterator<String> pathIt = Options.v().process_dir().iterator(); pathIt.hasNext(); ) {

            final String path = (String) pathIt.next();
            for (String cl : SourceLocator.v().getClassesUnder(path)) {
                loadClassAndSupport(cl).setApplicationClass();
            }
        }

        prepareClasses();
        setDoneResolving();
    }

    public void loadDynamicClasses() {
        dynamicClasses = new ArrayList<SootClass>();
        HashSet<String> dynClasses = new HashSet<String>();
        dynClasses.addAll(Options.v().dynamic_class());

        for( Iterator<String> pathIt = Options.v().dynamic_dir().iterator(); pathIt.hasNext(); ) {

            final String path = (String) pathIt.next();
            dynClasses.addAll(SourceLocator.v().getClassesUnder(path));
        }

        for( Iterator<String> pkgIt = Options.v().dynamic_package().iterator(); pkgIt.hasNext(); ) {

            final String pkg = (String) pkgIt.next();
            dynClasses.addAll(SourceLocator.v().classesInDynamicPackage(pkg));
        }

        for (String className : dynClasses) {

            dynamicClasses.add( loadClassAndSupport(className) );
        }
       
        //remove non-concrete classes that may accidentally have been loaded
        for (Iterator<SootClass> iterator = dynamicClasses.iterator(); iterator.hasNext();) {
      SootClass c = iterator.next();
      if(!c.isConcrete()) {
        if(Options.v().verbose()) {
          G.v().out.println("Warning: dynamic class "+c.getName()+" is abstract or an interface, and it will not be considered.");
        }
        iterator.remove();
      }
    }
    }


    /* Generate classes to process, adding or removing package marked by
     * command line options.
     */
    private void prepareClasses() {

        LinkedList<String> excludedPackages = new LinkedList<String>();
        if (Options.v().exclude() != null)
            excludedPackages.addAll(Options.v().exclude());

        if( !Options.v().include_all() ) {
            excludedPackages.add("java.");
            excludedPackages.add("sun.");
            excludedPackages.add("javax.");
            excludedPackages.add("com.sun.");
            excludedPackages.add("com.ibm.");
            excludedPackages.add("org.xml.");
            excludedPackages.add("org.w3c.");
            excludedPackages.add("org.apache.");
            excludedPackages.add("apple.awt.");
            excludedPackages.add("com.apple.");
        }

        // Remove/add all classes from packageInclusionMask as per -i option
        Chain<SootClass> processedClasses = new HashChain<SootClass>();
        while(true) {
            Chain<SootClass> unprocessedClasses = new HashChain<SootClass>(getClasses());
            unprocessedClasses.removeAll(processedClasses);
            if( unprocessedClasses.isEmpty() ) break;
            processedClasses.addAll(unprocessedClasses);
            for (SootClass s : unprocessedClasses) {
                if( s.isPhantom() ) continue;
                if(Options.v().app()) {
                    s.setApplicationClass();
                }
                if (Options.v().classes().contains(s.getName())) {
                    s.setApplicationClass();
                    continue;
                }
                for( Iterator<String> pkgIt = excludedPackages.iterator(); pkgIt.hasNext(); ) {
                    final String pkg = (String) pkgIt.next();
                    if (s.isApplicationClass()
                    && (s.getPackageName()+".").startsWith(pkg)) {
                            s.setLibraryClass();
                    }
                }
                for( Iterator<String> pkgIt = Options.v().include().iterator(); pkgIt.hasNext(); ) {
                    final String pkg = (String) pkgIt.next();
                    if ((s.getPackageName()+".").startsWith(pkg))
                        s.setApplicationClass();
                }
                if(s.isApplicationClass()) {
                    // make sure we have the support
                    loadClassAndSupport(s.getName());
                }
            }
        }
    }

    ArrayList<String> pkgList;

    public void setPkgList(ArrayList<String> list){
        pkgList = list;
    }

    public ArrayList<String> getPkgList(){
        return pkgList;
    }


    /** Create an unresolved reference to a method. */
    public SootMethodRef makeMethodRef(
            SootClass declaringClass,
            String name,
            List<Type> parameterTypes,
            Type returnType,
            boolean isStatic ) {
        return new SootMethodRefImpl(declaringClass, name, parameterTypes,
                returnType, isStatic);
    }

    /** Create an unresolved reference to a constructor. */
    public SootMethodRef makeConstructorRef(
            SootClass declaringClass,
            List<Type> parameterTypes) {
        return makeMethodRef(declaringClass, SootMethod.constructorName,
                                         parameterTypes, VoidType.v(), false );
    }


    /** Create an unresolved reference to a field. */
    public SootFieldRef makeFieldRef(
            SootClass declaringClass,
            String name,
            Type type,
            boolean isStatic) {
        return new AbstractSootFieldRef(declaringClass, name, type, isStatic);
    }
    /** Returns the list of SootClasses that have been resolved at least to
     * the level specified. */
    public List/*SootClass*/<SootClass> getClasses(int desiredLevel) {
        List<SootClass> ret = new ArrayList<SootClass>();
        for( Iterator<SootClass> clIt = getClasses().iterator(); clIt.hasNext(); ) {
            final SootClass cl = (SootClass) clIt.next();
            if( cl.resolvingLevel() >= desiredLevel ) ret.add(cl);
        }
        return ret;
    }
    private boolean doneResolving = false;
  private boolean incrementalBuild;
    public boolean doneResolving() { return doneResolving; }
    public void setDoneResolving() { doneResolving = true; }
    public void setMainClassFromOptions() {
        if(mainClass != null) return;
        if( Options.v().main_class() != null
                && Options.v().main_class().length() > 0 ) {
            setMainClass(getSootClass(Options.v().main_class()));
        } else {              
          // try to infer a main class from the command line if none is given
          for (Iterator<String> classIter = Options.v().classes().iterator(); classIter.hasNext();) {
                    SootClass c = getSootClass(classIter.next());
                    if (c.declaresMethod ("main", new SingletonList( ArrayType.v(RefType.v("java.lang.String"), 1) ), VoidType.v()))
                    {
                        G.v().out.println("No main class given. Inferred '"+c.getName()+"' as main class.");         
                        setMainClass(c);
                        return;
                    }
            }
         
          // try to infer a main class from the usual classpath if none is given
          for (Iterator<SootClass> classIter = getApplicationClasses().iterator(); classIter.hasNext();) {
                    SootClass c = (SootClass) classIter.next();
                    if (c.declaresMethod ("main", new SingletonList( ArrayType.v(RefType.v("java.lang.String"), 1) ), VoidType.v()))
                    {
                        G.v().out.println("No main class given. Inferred '"+c.getName()+"' as main class.");         
                        setMainClass(c);
                        return;
                    }
            }
        }
    }
   
    /**
     * This method returns true when in incremental build mode.
     * Other classes can query this flag and change the way in which they use the Scene,
     * depending on the flag's value.
     */
    public boolean isIncrementalBuild() {
      return incrementalBuild;
    }
   
    public void initiateIncrementalBuild() {
      this.incrementalBuild = true;
    }

    public void incrementalBuildFinished() {
      this.incrementalBuild = false;
    }
}
TOP

Related Classes of soot.Scene

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.