Package dk.brics.xact.analysis.soot

Source Code of dk.brics.xact.analysis.soot.Jimple2FlowGraph

package dk.brics.xact.analysis.soot;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import soot.AbstractValueBox;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Unit;
import soot.Value;
import soot.jimple.Stmt;
import soot.jimple.StringConstant;
import soot.jimple.internal.JAssignStmt;
import soot.jimple.internal.JInterfaceInvokeExpr;
import soot.jimple.internal.JInvokeStmt;
import soot.jimple.toolkits.annotation.nullcheck.NullnessAnalysis;
import soot.tagkit.LineNumberTag;
import soot.toolkits.graph.CompleteUnitGraph;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.ExceptionalUnitGraph;
import dk.brics.misc.Origin;
import dk.brics.xact.XMLException;
import dk.brics.xact.analysis.Debug;
import dk.brics.xact.analysis.ErrorHandler;
import dk.brics.xact.analysis.XMLAnalysisException;
import dk.brics.xact.analysis.config.Configuration;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.flowgraph.Method;
import dk.brics.xact.analysis.flowgraph.SchemaType;
import dk.brics.xact.analysis.flowgraph.Statement;
import dk.brics.xact.analysis.flowgraph.Variable;
import dk.brics.xact.analysis.flowgraph.VariableFilter;
import dk.brics.xact.analysis.flowgraph.statements.NopStm;

/**
* Produces flow graphs from Soot Jimple code.
*/
public class Jimple2FlowGraph {
 
  private Configuration config;
  private ErrorHandler errors;
 
  /**
   * Constructs a new flow graph producer.
   */
  public Jimple2FlowGraph(Configuration external, ErrorHandler errors) {
    this.config = external;
    this.errors = errors;
  }
 
  public TranslationResult run() {
    Map<String,String> namespaces = findNamespaces();
    config.modifyNamespaces(namespaces);
    Map<String,Origin> schemas = findSchemas();
    FlowGraph graph = new FlowGraph(schemas, namespaces);
    TranslatorContext context = new TranslatorContext(graph, errors);
    Translator translator = new Translator(context, config);
    // create methods and parse field annotations
    for (SootClass c : Scene.v().getApplicationClasses()) {
      for (SootMethod m : c.getMethods()) {
        Origin origin = new Origin(c.getName() + "." + m.getName(), 0, 0);
        Statement methodentry, methodexit;
        Variable returnVar;
        Variable[] parameters = new Variable[m.getParameterCount()];
        if (m.isConcrete()) {
          // entry
          methodentry = new NopStm(origin, "method entry");
          graph.addNode(methodentry);
          // exit
          methodexit = new NopStm(origin, "method exit");
          graph.addNode(methodexit);
          // parameters
          for (int i=0; i<m.getParameterCount(); i++) {
            parameters[i] = new Variable(context.getNextVarID(), false);
          }
          // return var
          returnVar = new Variable(context.getNextVarID(), false);
          // externally callable
          if (config.isExternallyCallable(m)) {
            graph.addEntry(methodentry);
          }
        } else {
          // non-concrete method. it must still be created for annotations to
          // be visible.
          methodentry = methodexit = null;
          returnVar = null;
        }
        // parse annotations
        SchemaType returnType;
        if (context.isAnnotatableType(m.getReturnType())) {
          returnType = context.parseSchemaType(config.getMethodReturnType(m, context.getTypeAnnotation(m)), origin);
        } else {
          returnType = null;
        }
        SchemaType[] paramTypes = new SchemaType[m.getParameterCount()];
        for (int i=0; i<m.getParameterCount(); i++) {
          if (context.isAnnotatableType(m.getParameterType(i))) {
            paramTypes[i] = context.parseSchemaType(config.getMethodParameterType(m, i, context.getTypeAnnotationForParameter(m, i)), origin);
          }
        }
        // make the method
        Method method = new Method(m.getName(), methodentry, methodexit, parameters, returnVar, returnType, paramTypes);
        context.setMethod(m, method);
      }
      for (SootField f : c.getFields()) {
        // parse annotations
        if (context.isAnnotatableType(f.getType())) {
          Origin origin = new Origin(c.getName() + "." + f.getName(), 0, 0);
          context.setFieldSchemaType(f, context.parseSchemaType(config.getFieldType(f, context.getTypeAnnotation(f)), origin));
        }
      }
    }
    // translate!
    for (SootClass c : Scene.v().getApplicationClasses()) {
      context.setCurrentClass(c);
      for (SootMethod m : c.getMethods()) {
        if (!m.isConcrete())
          continue;
        context.setCurrentSootMethod(m);
        CompleteUnitGraph unitgraph = new CompleteUnitGraph(m.retrieveActiveBody());
        context.setNullness(new NullnessAnalysis(unitgraph));
        context.setStringConstants(new StringConstantAnalysis(unitgraph));
        context.setArrayConstants(new ArrayConstantAnalysis(unitgraph));
        Method method = context.getMethod(m);
        Map<Unit,StatementPair> translated = new HashMap<Unit,StatementPair>();
        for (Unit stmt : m.getActiveBody().getUnits()) {
          context.setCurrentUnit(stmt);
          context.setCurrentLine(getLineNumber(stmt));
          translated.put(stmt, translator.translateStmt((Stmt)stmt));
        }
        for (Map.Entry<Unit, StatementPair> entry : translated.entrySet()) {
          Unit stmt = entry.getKey();
          StatementPair translation = entry.getValue();
          // add successors
          for (Unit next : unitgraph.getSuccsOf(stmt)) {
            StatementPair nextt = translated.get(next);
            graph.addEdge(translation.last, nextt.first, new VariableFilter());
          }
          // add (exceptional) return edge
          graph.addEdge(translation.last, method.getExit(), new VariableFilter());
        }
        // add entry edges
        for (Unit head : unitgraph.getHeads()) {
          graph.addEdge(method.getEntry(), translated.get(head).first, new VariableFilter(true, VariableFilter.Kind.ENTRY));
        }
      }
    }
   
    // run string analysis
    new PutStringSources(graph, context, config).analyzeStrings();
   
    // done
    return new TranslationResult(graph, context.getHotspotMap());
  }
 
  public int getLineNumber(Unit s) {
    LineNumberTag tag = (LineNumberTag)s.getTag("LineNumberTag");
    if (tag != null)
      return tag.getLineNumber();
    return -1;
  }
 
  /**
   * Locates the namespace declarations in application classes.
   * Recognizes the pattern <code>XML.getNamespaceMap().put("foo", "bar");</code>
   * (and similarly for <code>getThreadNamespaceMap</code>).
   */
  private Map<String,String> findNamespaces() { // TODO: need better namespace declaration recognizer?
    Map<String,String> namespaces = new HashMap<String,String>();
    for (SootClass c : Scene.v().getApplicationClasses()) {
      for (SootMethod m : c.getMethods()) {
        if (!m.isConcrete())
          continue;
        DirectedGraph<Unit> mbug = new ExceptionalUnitGraph(m.retrieveActiveBody());
        for (Unit u : mbug) {
          Stmt s1 = (Stmt) u;
          List<Unit> succs = mbug.getSuccsOf(s1);
          if (succs.size() == 1) {
            Stmt s2 = (Stmt) succs.get(0);
            if (s1 instanceof JAssignStmt && s2 instanceof JInvokeStmt && mbug.getPredsOf(s2).size() == 1) {
              JAssignStmt js1 = (JAssignStmt) s1;
              JInvokeStmt js2 = (JInvokeStmt) s2;
              if (js1.containsInvokeExpr()
                  && (js1.getInvokeExpr().getMethod().getSignature().equals("<dk.brics.xact.XML: java.util.Map getNamespaceMap()>")
                      || js1.getInvokeExpr().getMethod().getSignature().equals("<dk.brics.xact.XML: java.util.Map getThreadNamespaceMap()>"))
                  && js2.getInvokeExpr().getMethod().getSignature().equals("<java.util.Map: java.lang.Object put(java.lang.Object,java.lang.Object)>")
                  && js1.getDefBoxes().size() == 1 && js1.getDefBoxes().get(0) instanceof AbstractValueBox
                  && js2.getInvokeExpr() instanceof JInterfaceInvokeExpr) {
                Value v = ((AbstractValueBox) js1.getDefBoxes().get(0)).getValue();
                JInterfaceInvokeExpr put = (JInterfaceInvokeExpr) js2.getInvokeExpr();
                if (put.getBase().equivTo(v)) {
                  Origin origin = new Origin(m.getDeclaringClass().getName() + "." + m.getName(), getLineNumber(u), 0);
                  String prefix = getConstantString(put.getArg(0), origin);
                  String uri = getConstantString(put.getArg(1), origin);
                  String oldUri = namespaces.put(prefix, uri);
                  if (oldUri != null && !uri.equals(oldUri)) {
                      throw new XMLException("Conflicting namespace bindings of prefix " + prefix + " at " + origin, origin);
                  }
                  Debug.println(1, true, "Detected namespace declaration: " + prefix + " -> " + uri);
                }
              }
            }
          }
        }
      }
    }
    return namespaces;
  }
 
  /**
   * Locates schemas in application classes.
   * Recognizes the pattern <code>XML.loadXMLSchema("foo")</code>.
   * @return map from schema URLs to origins
   */
  public Map<String,Origin> findSchemas() {
    Map<String,Origin> schemas = new LinkedHashMap<String,Origin>();
    for (SootClass c : Scene.v().getApplicationClasses()) {
      for (SootMethod m : c.getMethods()) {
        if (!m.isConcrete())
          continue;
        DirectedGraph<Unit> mbug = new ExceptionalUnitGraph(m.retrieveActiveBody());
        for (Unit u : mbug) {
          Stmt s = (Stmt) u;
          if (s instanceof JInvokeStmt) {
            JInvokeStmt js = (JInvokeStmt) s;
            if (js.getInvokeExpr().getMethod().getSignature().equals("<dk.brics.xact.XML: void loadXMLSchema(java.lang.String)>")) {
              Origin origin = new Origin(m.getDeclaringClass().getName() + "." + m.getName(), getLineNumber(s), 0);
              String schema = getConstantString(js.getInvokeExpr().getArg(0), origin);
              schema = config.translateSchemaLocation(schema);
              Debug.println(1, true, "Using schema: " + schema);
              schemas.put(schema, origin);
            }
          }
        }
      }
    }
    return schemas;
  }
  private String getConstantString(Value v, Origin orig) {
    if (v instanceof StringConstant)
      return ((StringConstant)v).value;
    else
      throw new XMLAnalysisException("Constant string expected", orig);
  }
}
TOP

Related Classes of dk.brics.xact.analysis.soot.Jimple2FlowGraph

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.