All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.toolkits.callgraph.CallGraphBuilder Maven / Gradle / Ivy

package soot.jimple.toolkits.callgraph;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2002 Ondrej Lhotak
 * %%
 * 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 2.1 of the
 * License, or (at your option) 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.EntryPoints;
import soot.Local;
import soot.MethodOrMethodContext;
import soot.PointsToAnalysis;
import soot.PointsToSet;
import soot.Scene;
import soot.Type;
import soot.Value;
import soot.jimple.IntConstant;
import soot.jimple.NewArrayExpr;
import soot.jimple.spark.pag.AllocNode;
import soot.jimple.spark.pag.ArrayElement;
import soot.jimple.spark.pag.Node;
import soot.jimple.spark.sets.P2SetVisitor;
import soot.jimple.spark.sets.PointsToSetInternal;
import soot.util.queue.QueueReader;

/**
 * Models the call graph.
 *
 * @author Ondrej Lhotak
 */
public final class CallGraphBuilder {
  private static final Logger logger = LoggerFactory.getLogger(CallGraphBuilder.class);
  private PointsToAnalysis pa;
  private final ReachableMethods reachables;
  private final OnFlyCallGraphBuilder ofcgb;
  private final CallGraph cg;

  public CallGraph getCallGraph() {
    return cg;
  }

  public ReachableMethods reachables() {
    return reachables;
  }

  public static ContextManager makeContextManager(CallGraph cg) {
    return new ContextInsensitiveContextManager(cg);
  }

  /**
   * This constructor builds a complete call graph using the given PointsToAnalysis to resolve virtual calls.
   */
  public CallGraphBuilder(PointsToAnalysis pa) {
    this.pa = pa;
    cg = Scene.v().internalMakeCallGraph();
    Scene.v().setCallGraph(cg);
    reachables = Scene.v().getReachableMethods();
    ContextManager cm = makeContextManager(cg);
    ofcgb = new OnFlyCallGraphBuilder(cm, reachables);
  }

  /**
   * This constructor builds the incomplete hack call graph for the Dava ThrowFinder. It uses all application class methods
   * as entry points, and it ignores any calls by non-application class methods. Don't use this constructor if you need a
   * real call graph.
   */
  public CallGraphBuilder() {
    logger.warn("using incomplete callgraph containing " + "only application classes.");
    pa = soot.jimple.toolkits.pointer.DumbPointerAnalysis.v();
    cg = Scene.v().internalMakeCallGraph();
    Scene.v().setCallGraph(cg);
    List entryPoints = new ArrayList();
    entryPoints.addAll(EntryPoints.v().methodsOfApplicationClasses());
    entryPoints.addAll(EntryPoints.v().implicit());
    reachables = new ReachableMethods(cg, entryPoints);
    ContextManager cm = new ContextInsensitiveContextManager(cg);
    ofcgb = new OnFlyCallGraphBuilder(cm, reachables, true);
  }

  public void build() {
    QueueReader worklist = reachables.listener();
    while (true) {
      ofcgb.processReachables();
      reachables.update();
      if (!worklist.hasNext()) {
        break;
      }
      final MethodOrMethodContext momc = worklist.next();
      List receivers = ofcgb.methodToReceivers().get(momc.method());
      if (receivers != null) {
        for (Iterator receiverIt = receivers.iterator(); receiverIt.hasNext();) {
          final Local receiver = receiverIt.next();
          final PointsToSet p2set = pa.reachingObjects(receiver);
          for (Iterator typeIt = p2set.possibleTypes().iterator(); typeIt.hasNext();) {
            final Type type = typeIt.next();
            ofcgb.addType(receiver, momc.context(), type, null);
          }
        }
      }
      List bases = ofcgb.methodToInvokeArgs().get(momc.method());
      if (bases != null) {
        for (Local base : bases) {
          PointsToSet pts = pa.reachingObjects(base);
          for (Type ty : pts.possibleTypes()) {
            ofcgb.addBaseType(base, momc.context(), ty);
          }
        }
      }
      List argArrays = ofcgb.methodToInvokeBases().get(momc.method());
      if (argArrays != null) {
        for (final Local argArray : argArrays) {
          PointsToSet pts = pa.reachingObjects(argArray);
          if (pts instanceof PointsToSetInternal) {
            PointsToSetInternal ptsi = (PointsToSetInternal) pts;
            ptsi.forall(new P2SetVisitor() {
              @Override
              public void visit(Node n) {
                assert n instanceof AllocNode;
                AllocNode an = (AllocNode) n;
                Object newExpr = an.getNewExpr();
                ofcgb.addInvokeArgDotField(argArray, an.dot(ArrayElement.v()));
                if (newExpr instanceof NewArrayExpr) {
                  NewArrayExpr nae = (NewArrayExpr) newExpr;
                  Value size = nae.getSize();
                  if (size instanceof IntConstant) {
                    IntConstant arrSize = (IntConstant) size;
                    ofcgb.addPossibleArgArraySize(argArray, arrSize.value, momc.context());
                  } else {
                    ofcgb.setArgArrayNonDetSize(argArray, momc.context());
                  }
                }
              }
            });
          }
          for (Type t : pa.reachingObjectsOfArrayElement(pts).possibleTypes()) {
            ofcgb.addInvokeArgType(argArray, momc.context(), t);
          }
        }
      }
      List stringConstants = ofcgb.methodToStringConstants().get(momc.method());
      if (stringConstants != null) {
        for (Iterator stringConstantIt = stringConstants.iterator(); stringConstantIt.hasNext();) {
          final Local stringConstant = stringConstantIt.next();
          PointsToSet p2set = pa.reachingObjects(stringConstant);
          Collection possibleStringConstants = p2set.possibleStringConstants();
          if (possibleStringConstants == null) {
            ofcgb.addStringConstant(stringConstant, momc.context(), null);
          } else {
            for (Iterator constantIt = possibleStringConstants.iterator(); constantIt.hasNext();) {
              final String constant = constantIt.next();
              ofcgb.addStringConstant(stringConstant, momc.context(), constant);
            }
          }
        }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy