Package soot.jimple.toolkits.callgraph

Source Code of soot.jimple.toolkits.callgraph.OnFlyCallGraphBuilder

/* Soot - a J*va Optimization Framework
* Copyright (C) 2003 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.
*/

package soot.jimple.toolkits.callgraph;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import soot.ArrayType;
import soot.Body;
import soot.Context;
import soot.EntryPoints;
import soot.FastHierarchy;
import soot.G;
import soot.Kind;
import soot.Local;
import soot.MethodContext;
import soot.MethodOrMethodContext;
import soot.PackManager;
import soot.PhaseOptions;
import soot.RefType;
import soot.Scene;
import soot.SceneTransformer;
import soot.SootClass;
import soot.SootMethod;
import soot.SootMethodRef;
import soot.Transform;
import soot.Type;
import soot.Unit;
import soot.Value;
import soot.javaToJimple.LocalGenerator;
import soot.jimple.AssignStmt;
import soot.jimple.FieldRef;
import soot.jimple.InstanceInvokeExpr;
import soot.jimple.InvokeExpr;
import soot.jimple.InvokeStmt;
import soot.jimple.Jimple;
import soot.jimple.NewArrayExpr;
import soot.jimple.NewExpr;
import soot.jimple.NewMultiArrayExpr;
import soot.jimple.SpecialInvokeExpr;
import soot.jimple.StaticFieldRef;
import soot.jimple.StaticInvokeExpr;
import soot.jimple.Stmt;
import soot.jimple.StringConstant;
import soot.jimple.VirtualInvokeExpr;
import soot.jimple.spark.pag.PAG;
import soot.jimple.toolkits.reflection.ReflectionTraceInfo;
import soot.options.CGOptions;
import soot.tagkit.Host;
import soot.tagkit.SourceLnPosTag;
import soot.util.LargeNumberedMap;
import soot.util.NumberedString;
import soot.util.SmallNumberedMap;
import soot.util.queue.ChunkedQueue;
import soot.util.queue.QueueReader;

/** Models the call graph.
* @author Ondrej Lhotak
*/
public final class OnFlyCallGraphBuilder
{
  public class DefaultReflectionModel implements ReflectionModel {
   
      protected CGOptions options = new CGOptions( PhaseOptions.v().getPhaseOptions("cg") );
     
      protected HashSet<SootMethod> warnedAlready = new HashSet<SootMethod>();

    public void classForName(SootMethod source, Stmt s) {
          List<Local> stringConstants = (List<Local>) methodToStringConstants.get(source);
          if( stringConstants == null )
              methodToStringConstants.put(source, stringConstants = new ArrayList<Local>());
      InvokeExpr ie = s.getInvokeExpr();
          Value className = ie.getArg(0);
          if( className instanceof StringConstant ) {
              String cls = ((StringConstant) className ).value;
              constantForName( cls, source, s );
          } else {
              Local constant = (Local) className;
              if( options.safe_forname() ) {
                  for (SootMethod tgt : EntryPoints.v().clinits()) {
                      addEdge( source, s, tgt, Kind.CLINIT );
                  }
              } else {
                  for (SootClass cls : Scene.v().dynamicClasses()) {
                      for (SootMethod clinit : EntryPoints.v().clinitsOf(cls)) {
                          addEdge( source, s, clinit, Kind.CLINIT);
                      }
                  }
                  VirtualCallSite site = new VirtualCallSite( s, source, null, null, Kind.CLINIT );
                  List<VirtualCallSite> sites = (List<VirtualCallSite>) stringConstToSites.get(constant);
                  if (sites == null) {
                      stringConstToSites.put(constant, sites = new ArrayList<VirtualCallSite>());
                      stringConstants.add(constant);
                  }
                  sites.add(site);
              }
          }       
    }

    public void classNewInstance(SootMethod source, Stmt s) {
      if( options.safe_newinstance() ) {
        for (SootMethod tgt : EntryPoints.v().inits()) {
          addEdge( source, s, tgt, Kind.NEWINSTANCE );
        }
      } else {
        for (SootClass cls : Scene.v().dynamicClasses()) {
          if( cls.declaresMethod(sigInit) ) {
            addEdge( source, s, cls.getMethod(sigInit), Kind.NEWINSTANCE );
          }
        }

        if( options.verbose() ) {
          G.v().out.println( "Warning: Method "+source+
              " is reachable, and calls Class.newInstance;"+
              " graph will be incomplete!"+
          " Use safe-newinstance option for a conservative result." );
        }
      }
    }

    public void contructorNewInstance(SootMethod source, Stmt s) {
      if( options.safe_newinstance() ) {
        for (SootMethod tgt : EntryPoints.v().allInits()) {
          addEdge( source, s, tgt, Kind.NEWINSTANCE );
        }
      } else {
        for (SootClass cls : Scene.v().dynamicClasses()) {
          for(SootMethod m: cls.getMethods()) {
            if(m.getName().equals("<init>")) {
              addEdge( source, s, m, Kind.NEWINSTANCE );
            }
          }
        }
        if( options.verbose() ) {
          G.v().out.println( "Warning: Method "+source+
              " is reachable, and calls Constructor.newInstance;"+
              " graph will be incomplete!"+
          " Use safe-newinstance option for a conservative result." );
        }
      }
    }

    public void methodInvoke(SootMethod container, Stmt invokeStmt) {
      if( !warnedAlready(container) ) {
        if( options.verbose() ) {
          G.v().out.println( "Warning: call to "+
              "java.lang.reflect.Method: invoke() from "+container+
          "; graph will be incomplete!" );
        }
        markWarned(container);
      }
    }

    private void markWarned(SootMethod m) {
      warnedAlready.add(m);
    }

    private boolean warnedAlready(SootMethod m) {
      return warnedAlready.contains(m);
    }

  }

 
  public class TraceBasedReflectionModel implements ReflectionModel {
   
    class Guard {
      public Guard(SootMethod container, Stmt stmt, String message) {
        this.container = container;
        this.stmt = stmt;
        this.message = message;
      }
      final SootMethod container;
      final Stmt stmt;
      final String message;
    }
   
    protected Set<Guard> guards;
   
    protected ReflectionTraceInfo reflectionInfo;

    private boolean registeredTransformation = false;
   
    private TraceBasedReflectionModel() {
      guards = new HashSet<Guard>();
     
      String logFile = options.reflection_log();
      if(logFile==null) {
        throw new InternalError("Trace based refection model enabled but no trace file given!?");
      } else {
        reflectionInfo = new ReflectionTraceInfo(logFile);
      }
    }

    /**
     * Adds an edge to all class initializers of all possible receivers
     * of Class.forName() calls within source.
     */
    public void classForName(SootMethod container, Stmt forNameInvokeStmt) {
      Set<String> classNames = reflectionInfo.classForNameClassNames(container);
      if(classNames==null || classNames.isEmpty()) {
        registerGuard(container, forNameInvokeStmt, "Class.forName() call site; Soot did not expect this site to be reached");
      } else {
        for (String clsName : classNames) {
                constantForName( clsName, container, forNameInvokeStmt );
        }
      }
    }

    /**
     * Adds an edge to the constructor of the target class from this call to
     * {@link Class#newInstance()}.
     */
    public void classNewInstance(SootMethod container, Stmt newInstanceInvokeStmt) {
      Set<String> classNames = reflectionInfo.classNewInstanceClassNames(container);
      if(classNames==null || classNames.isEmpty()) {
        registerGuard(container, newInstanceInvokeStmt, "Class.newInstance() call site; Soot did not expect this site to be reached");
      } else {
        for (String clsName : classNames) {
          SootClass cls = Scene.v().getSootClass(clsName);
          if( cls.declaresMethod(sigInit) ) {
            SootMethod constructor = cls.getMethod(sigInit);
            addEdge( container, newInstanceInvokeStmt, constructor, Kind.REFL_CLASS_NEWINSTANCE );
          }
        }
      }
    }

    /**
     * Adds a special edge of kind {@link Kind#REFL_CONSTR_NEWINSTANCE} to all possible target constructors
     * of this call to {@link Constructor#newInstance(Object...)}.
     * Those kinds of edges are treated specially in terms of how parameters are assigned,
     * as parameters to the reflective call are passed into the argument array of
     * {@link Constructor#newInstance(Object...)}.
     * @see PAG#addCallTarget(Edge)
     */
    public void contructorNewInstance(SootMethod container, Stmt newInstanceInvokeStmt) {
      Set<String> constructorSignatures = reflectionInfo.constructorNewInstanceSignatures(container);
      if(constructorSignatures==null || constructorSignatures.isEmpty()) {
        registerGuard(container, newInstanceInvokeStmt, "Constructor.newInstance(..) call site; Soot did not expect this site to be reached");
      } else {
        for (String constructorSignature : constructorSignatures) {
          SootMethod constructor = Scene.v().getMethod(constructorSignature);
          addEdge( container, newInstanceInvokeStmt, constructor, Kind.REFL_CONSTR_NEWINSTANCE );
        }
      }
    }

    /**
     * Adds a special edge of kind {@link Kind#REFL_INVOKE} to all possible target methods
     * of this call to {@link Method#invoke(Object, Object...)}.
     * Those kinds of edges are treated specially in terms of how parameters are assigned,
     * as parameters to the reflective call are passed into the argument array of
     * {@link Method#invoke(Object, Object...)}.
     * @see PAG#addCallTarget(Edge)
     */
    public void methodInvoke(SootMethod container, Stmt invokeStmt) {
      Set<String> methodSignatures = reflectionInfo.methodInvokeSignatures(container);
      if (methodSignatures == null || methodSignatures.isEmpty()) {
        registerGuard(container, invokeStmt, "Method.invoke(..) call site; Soot did not expect this site to be reached");
      } else {
        for (String methodSignature : methodSignatures) {
          SootMethod method = Scene.v().getMethod(methodSignature);
          addEdge( container, invokeStmt, method, Kind.REFL_INVOKE );
        }
      }
    }

    private void registerGuard(SootMethod container, Stmt stmt, String string) {
      guards.add(new Guard(container,stmt,string));

      if(options.verbose()) {
        G.v().out.println("Incomplete trace file: Class.forName() is called in method '" +
            container+"' but trace contains no information about the receiver class of this call.");
        if(options.guards().equals("ignore")) {
          G.v().out.println("Guarding strategy is set to 'ignore'. Will ignore this problem.");
        } else if(options.guards().equals("print")) {
          G.v().out.println("Guarding strategy is set to 'print'. " +
              "Program will print a stack trace if this location is reached during execution.");
        } else if(options.guards().equals("throw")) {
          G.v().out.println("Guarding strategy is set to 'throw'. Program will throw an " +
              "Error if this location is reached during execution.");
        } else {
          throw new RuntimeException("Invalid value for phase option (guarding): "+options.guards());
        }
      }
     
      if(!registeredTransformation) {
        registeredTransformation=true;
        PackManager.v().getPack("wjap").add(new Transform("wjap.guards",new SceneTransformer() {
         
          @Override
          protected void internalTransform(String phaseName, Map options) {
            for (Guard g : guards) {
              insertGuard(g);
            }
          }
        }));
        PhaseOptions.v().setPhaseOption("wjap.guards", "enabled");
      }
    }
   
    private void insertGuard(Guard guard) {
      if(options.guards().equals("ignore")) return;
     
      SootMethod container = guard.container;
      Stmt insertionPoint = guard.stmt;
      if(!container.hasActiveBody()) {
        G.v().out.println("WARNING: Tried to insert guard into "+container+" but couldn't because method has no body.");
      } else {
        Body body = container.getActiveBody();
       
        //exc = new Error
        RefType runtimeExceptionType = RefType.v("java.lang.Error");
        NewExpr newExpr = Jimple.v().newNewExpr(runtimeExceptionType);
        LocalGenerator lg = new LocalGenerator(body);
        Local exceptionLocal = lg.generateLocal(runtimeExceptionType);
        AssignStmt assignStmt = Jimple.v().newAssignStmt(exceptionLocal, newExpr);
        body.getUnits().insertBefore(assignStmt, insertionPoint);
       
        //exc.<init>(message)
        SootMethodRef cref = runtimeExceptionType.getSootClass().getMethod("<init>", Collections.singletonList(RefType.v("java.lang.String"))).makeRef();
        SpecialInvokeExpr constructorInvokeExpr = Jimple.v().newSpecialInvokeExpr(exceptionLocal, cref, StringConstant.v(guard.message));
        InvokeStmt initStmt = Jimple.v().newInvokeStmt(constructorInvokeExpr);
        body.getUnits().insertAfter(initStmt, assignStmt);
       
        if(options.guards().equals("print")) {
          //exc.printStackTrace();
          VirtualInvokeExpr printStackTraceExpr = Jimple.v().newVirtualInvokeExpr(exceptionLocal, Scene.v().getSootClass("java.lang.Throwable").getMethod("printStackTrace", Collections.emptyList()).makeRef());
          InvokeStmt printStackTraceStmt = Jimple.v().newInvokeStmt(printStackTraceExpr);
          body.getUnits().insertAfter(printStackTraceStmt, initStmt);
        } else if(options.guards().equals("throw")) {
          body.getUnits().insertAfter(Jimple.v().newThrowStmt(exceptionLocal), initStmt);
        } else {
          throw new RuntimeException("Invalid value for phase option (guarding): "+options.guards());
        }
      }
    }

  }
 
    /** context-insensitive stuff */
    private final CallGraph cicg = new CallGraph();
    private final HashSet<SootMethod> analyzedMethods = new HashSet<SootMethod>();

    private final LargeNumberedMap receiverToSites = new LargeNumberedMap( Scene.v().getLocalNumberer() ); // Local -> List(VirtualCallSite)
    private final LargeNumberedMap methodToReceivers = new LargeNumberedMap( Scene.v().getMethodNumberer() ); // SootMethod -> List(Local)
    public LargeNumberedMap methodToReceivers() { return methodToReceivers; }

    private final SmallNumberedMap stringConstToSites = new SmallNumberedMap( Scene.v().getLocalNumberer() ); // Local -> List(VirtualCallSite)
    private final LargeNumberedMap methodToStringConstants = new LargeNumberedMap( Scene.v().getMethodNumberer() ); // SootMethod -> List(Local)
    public LargeNumberedMap methodToStringConstants() { return methodToStringConstants; }

    private CGOptions options;

    private boolean appOnly;

    /** context-sensitive stuff */
    private ReachableMethods rm;
    private QueueReader worklist;

    private ContextManager cm;

    private final ChunkedQueue targetsQueue = new ChunkedQueue();
    private final QueueReader targets = targetsQueue.reader();


    public OnFlyCallGraphBuilder( ContextManager cm, ReachableMethods rm ) {
        this.cm = cm;
        this.rm = rm;
        worklist = rm.listener();
        options = new CGOptions( PhaseOptions.v().getPhaseOptions("cg") );
        if( !options.verbose() ) {
            G.v().out.println( "[Call Graph] For information on where the call graph may be incomplete, use the verbose option to the cg phase." );
        }
       
        if(options.reflection_log()==null || options.reflection_log().length()==0) {
          reflectionModel = new DefaultReflectionModel();
        } else {
          reflectionModel = new TraceBasedReflectionModel();
        }
    }
    public OnFlyCallGraphBuilder( ContextManager cm, ReachableMethods rm, boolean appOnly ) {
        this( cm, rm );
        this.appOnly = appOnly;
    }
    public void processReachables() {
        while(true) {
            if( !worklist.hasNext() ) {
                rm.update();
                if( !worklist.hasNext() ) break;
            }
            MethodOrMethodContext momc = (MethodOrMethodContext) worklist.next();
            SootMethod m = momc.method();
            if( appOnly && !m.getDeclaringClass().isApplicationClass() ) continue;
            if( analyzedMethods.add( m ) ) processNewMethod( m );
            processNewMethodContext( momc );
        }
    }
    public boolean wantTypes( Local receiver ) {
        return receiverToSites.get(receiver) != null;
    }
    public void addType( Local receiver, Context srcContext, Type type, Context typeContext ) {
        FastHierarchy fh = Scene.v().getOrMakeFastHierarchy();
        for( Iterator siteIt = ((Collection) receiverToSites.get( receiver )).iterator(); siteIt.hasNext(); ) {
            final VirtualCallSite site = (VirtualCallSite) siteIt.next();
            InstanceInvokeExpr iie = site.iie();
            if( site.kind() == Kind.THREAD
            && !fh.canStoreType( type, clRunnable ) )
                continue;

            if( site.iie() instanceof SpecialInvokeExpr && site.kind != Kind.THREAD ) {
              targetsQueue.add( VirtualCalls.v().resolveSpecial(
                            (SpecialInvokeExpr) site.iie(),
                            site.subSig(),
                            site.container() ) );
            } else {
                VirtualCalls.v().resolve( type,
                        receiver.getType(),
                        site.subSig(),
                        site.container(),
                        targetsQueue );
            }
            while(targets.hasNext()) {
                SootMethod target = (SootMethod) targets.next();
                cm.addVirtualEdge(
                        MethodContext.v( site.container(), srcContext ),
                        site.stmt(),
                        target,
                        site.kind(),
                        typeContext );
            }
        }
    }
    public boolean wantStringConstants( Local stringConst ) {
        return stringConstToSites.get(stringConst) != null;
    }
    public void addStringConstant( Local l, Context srcContext, String constant ) {
        for( Iterator siteIt = ((Collection) stringConstToSites.get( l )).iterator(); siteIt.hasNext(); ) {
            final VirtualCallSite site = (VirtualCallSite) siteIt.next();
            if( constant == null ) {
                if( options.verbose() ) {
                    G.v().out.println( "Warning: Method "+site.container()+
                        " is reachable, and calls Class.forName on a"+
                        " non-constant String; graph will be incomplete!"+
                        " Use safe-forname option for a conservative result." );
                }
            } else {
                if( constant.length() > 0 && constant.charAt(0) == '[' ) {
                    if( constant.length() > 1 && constant.charAt(1) == 'L'
                    && constant.charAt(constant.length()-1) == ';' ) {
                        constant = constant.substring(2,constant.length()-1);
                    } else continue;
                }
                if( !Scene.v().containsClass( constant ) ) {
                    if( options.verbose() ) {
                        G.v().out.println( "Warning: Class "+constant+" is"+
                            " a dynamic class, and you did not specify"+
                            " it as such; graph will be incomplete!" );
                    }
                } else {
                    SootClass sootcls = Scene.v().getSootClass( constant );
                    if( !sootcls.isApplicationClass() ) {
                        sootcls.setLibraryClass();
                    }
                    for (SootMethod clinit : EntryPoints.v().clinitsOf(sootcls)) {
                        cm.addStaticEdge(
                                MethodContext.v( site.container(), srcContext ),
                                site.stmt(),
                                clinit,
                                Kind.CLINIT );
                    }
                }
            }
        }
    }

    /* End of public methods. */

    private void addVirtualCallSite( Stmt s, SootMethod m, Local receiver,
            InstanceInvokeExpr iie, NumberedString subSig, Kind kind ) {
        List<VirtualCallSite> sites = (List<VirtualCallSite>) receiverToSites.get(receiver);
        if (sites == null) {
            receiverToSites.put(receiver, sites = new ArrayList<VirtualCallSite>());
            List<Local> receivers = (List<Local>) methodToReceivers.get(m);
            if( receivers == null )
                methodToReceivers.put(m, receivers = new ArrayList<Local>());
            receivers.add(receiver);
        }
        sites.add(new VirtualCallSite(s, m, iie, subSig, kind));
    }
    private void processNewMethod( SootMethod m ) {
        if( m.isNative() || m.isPhantom() ) {
            return;
        }
        Body b = m.retrieveActiveBody();
        getImplicitTargets( m );
        findReceivers(m, b);
    }
    private void findReceivers(SootMethod m, Body b) {
        for( Iterator sIt = b.getUnits().iterator(); sIt.hasNext(); ) {
            final Stmt s = (Stmt) sIt.next();
            if (s.containsInvokeExpr()) {
                InvokeExpr ie = s.getInvokeExpr();

                if (ie instanceof InstanceInvokeExpr) {
                    InstanceInvokeExpr iie = (InstanceInvokeExpr) ie;
                    Local receiver = (Local) iie.getBase();
                    NumberedString subSig =
                        iie.getMethodRef().getSubSignature();
                    addVirtualCallSite( s, m, receiver, iie, subSig,
                            Edge.ieToKind(iie) );
                    if( subSig == sigStart ) {
                        addVirtualCallSite( s, m, receiver, iie, sigRun,
                                Kind.THREAD );
                    }
                } else {
                  SootMethod tgt = ie.getMethod();
                  addEdge(m, s, tgt);
                  if( tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction)>" )
                      ||  tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction)>" )
                      ||  tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)>" )
                      ||  tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext)>" ) ) {
                   
                    Local receiver = (Local) ie.getArg(0);
                    addVirtualCallSite( s, m, receiver, null, sigObjRun,
                        Kind.PRIVILEGED );
                  }                     
                }
            }
        }
    }
   
    ReflectionModel reflectionModel;
   
    private void getImplicitTargets( SootMethod source ) {
        final SootClass scl = source.getDeclaringClass();
        if( source.isNative() || source.isPhantom() ) return;
        if( source.getSubSignature().indexOf( "<init>" ) >= 0 ) {
            handleInit(source, scl);
        }
        Body b = source.retrieveActiveBody();
        for( Iterator sIt = b.getUnits().iterator(); sIt.hasNext(); ) {
            final Stmt s = (Stmt) sIt.next();
            if( s.containsInvokeExpr() ) {
                InvokeExpr ie = s.getInvokeExpr();
                if( ie.getMethodRef().getSignature().equals( "<java.lang.reflect.Method: java.lang.Object invoke(java.lang.Object,java.lang.Object[])>" ) ) {
                  reflectionModel.methodInvoke(source,s);
                }
                if( ie.getMethodRef().getSignature().equals( "<java.lang.Class: java.lang.Object newInstance()>" ) ) {
                  reflectionModel.classNewInstance(source,s);
                }
                if( ie.getMethodRef().getSignature().equals( "<java.lang.reflect.Constructor: java.lang.Object newInstance(java.lang.Object[])>" ) ) {
                  reflectionModel.contructorNewInstance(source, s);
                }
                if( ie.getMethodRef().getSubSignature() == sigForName ) {
                  reflectionModel.classForName(source,s);
                }
                if( ie instanceof StaticInvokeExpr ) {
                  SootClass cl = ie.getMethodRef().declaringClass();
                  for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                    addEdge( source, s, clinit, Kind.CLINIT );
                  }
                }
            }
            if( s.containsFieldRef() ) {
                FieldRef fr = s.getFieldRef();
                if( fr instanceof StaticFieldRef ) {
                    SootClass cl = fr.getFieldRef().declaringClass();
                    for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                        addEdge( source, s, clinit, Kind.CLINIT );
                    }
                }
            }
            if( s instanceof AssignStmt ) {
                Value rhs = ((AssignStmt)s).getRightOp();
                if( rhs instanceof NewExpr ) {
                    NewExpr r = (NewExpr) rhs;
                    SootClass cl = r.getBaseType().getSootClass();
                    for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                        addEdge( source, s, clinit, Kind.CLINIT );
                    }
                } else if( rhs instanceof NewArrayExpr || rhs instanceof NewMultiArrayExpr ) {
                    Type t = rhs.getType();
                    if( t instanceof ArrayType ) t = ((ArrayType)t).baseType;
                    if( t instanceof RefType ) {
                        SootClass cl = ((RefType) t).getSootClass();
                        for (SootMethod clinit : EntryPoints.v().clinitsOf(cl)) {
                            addEdge( source, s, clinit, Kind.CLINIT );
                        }
                    }
                }
            }
        }
    }

    private void processNewMethodContext( MethodOrMethodContext momc ) {
        SootMethod m = momc.method();
        Object ctxt = momc.context();
        Iterator it = cicg.edgesOutOf(m);
        while( it.hasNext() ) {
            Edge e = (Edge) it.next();
            cm.addStaticEdge( momc, e.srcUnit(), e.tgt(), e.kind() );
        }
    }

    private void handleInit(SootMethod source, final SootClass scl) {
        addEdge( source, null, scl, sigFinalize, Kind.FINALIZE );
    }
    private void constantForName( String cls, SootMethod src, Stmt srcUnit ) {
        if( cls.length() > 0 && cls.charAt(0) == '[' ) {
            if( cls.length() > 1 && cls.charAt(1) == 'L' && cls.charAt(cls.length()-1) == ';' ) {
                cls = cls.substring(2,cls.length()-1);
                constantForName( cls, src, srcUnit );
            }
        } else {
            if( !Scene.v().containsClass( cls ) ) {
                if( options.verbose() ) {
                    G.v().out.println( "Warning: Class "+cls+" is"+
                        " a dynamic class, and you did not specify"+
                        " it as such; graph will be incomplete!" );
                }
            } else {
                SootClass sootcls = Scene.v().getSootClass( cls );
                if( !sootcls.isApplicationClass() ) {
                    sootcls.setLibraryClass();
                }
                for (SootMethod clinit : EntryPoints.v().clinitsOf(sootcls)) {
                    addEdge( src, srcUnit, clinit, Kind.CLINIT );
                }

            }
        }
    }

    private void addEdge( SootMethod src, Stmt stmt, SootMethod tgt,
            Kind kind ) {
        cicg.addEdge( new Edge( src, stmt, tgt, kind ) );
    }

    private void addEdgeSootMethod src, Stmt stmt, SootClass cls, NumberedString methodSubSig, Kind kind ) {
        if( cls.declaresMethod( methodSubSig ) ) {
            addEdge( src, stmt, cls.getMethod( methodSubSig ), kind );
        }
    }
    private void addEdge( SootMethod src, Stmt stmt, SootMethod tgt ) {
        InvokeExpr ie = stmt.getInvokeExpr();
        addEdge( src, stmt, tgt, Edge.ieToKind(ie) );
    }

    protected final NumberedString sigFinalize = Scene.v().getSubSigNumberer().
        findOrAdd( "void finalize()" );
    protected final NumberedString sigInit = Scene.v().getSubSigNumberer().
        findOrAdd( "void <init>()" );
    protected final NumberedString sigStart = Scene.v().getSubSigNumberer().
        findOrAdd( "void start()" );
    protected final NumberedString sigRun = Scene.v().getSubSigNumberer().
        findOrAdd( "void run()" );
    protected final NumberedString sigObjRun = Scene.v().getSubSigNumberer().
        findOrAdd( "java.lang.Object run()" );
    protected final NumberedString sigForName = Scene.v().getSubSigNumberer().
        findOrAdd( "java.lang.Class forName(java.lang.String)" );
    protected final RefType clRunnable = RefType.v("java.lang.Runnable");
   
}
TOP

Related Classes of soot.jimple.toolkits.callgraph.OnFlyCallGraphBuilder

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.