Package soot.jimple.toolkits.reflection

Source Code of soot.jimple.toolkits.reflection.ReflectionTraceInfo

/* Soot - a J*va Optimization Framework
* Copyright (C) 2010 Eric Bodden
*
* 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.reflection;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import soot.Body;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
import soot.Unit;
import soot.tagkit.Host;
import soot.tagkit.SourceLnPosTag;

public class ReflectionTraceInfo {
 
  protected Map<SootMethod,Set<String>> classForNameReceivers;
 
  protected Map<SootMethod,Set<String>> classNewInstanceReceivers;

  protected Map<SootMethod,Set<String>> constructorNewInstanceReceivers;

  protected Map<SootMethod,Set<String>> methodInvokeReceivers;

  public ReflectionTraceInfo(String logFile) {
    classForNameReceivers = new HashMap<SootMethod, Set<String>>();
    classNewInstanceReceivers = new HashMap<SootMethod, Set<String>>();
    constructorNewInstanceReceivers = new HashMap<SootMethod, Set<String>>();
    methodInvokeReceivers = new HashMap<SootMethod, Set<String>>();

    if(logFile==null) {
      throw new InternalError("Trace based refection model enabled but no trace file given!?");
    } else {
      try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(logFile)));
        String line;
        int lines = 0;
        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];
          int lineNumber = portions[3].length()==0 ? -1 : Integer.parseInt(portions[3]);

          Set<SootMethod> possibleSourceMethods = inferSource(source, lineNumber);
          for (SootMethod sourceMethod : possibleSourceMethods) {
            if(kind.equals("Class.forName")) {
              Set<String> receiverNames;
              if((receiverNames=classForNameReceivers.get(sourceMethod))==null) {
                classForNameReceivers.put(sourceMethod, receiverNames = new HashSet<String>());
              }
              receiverNames.add(target);
            } else if(kind.equals("Class.newInstance")) {
              Set<String> receiverNames;
              if((receiverNames=classNewInstanceReceivers.get(sourceMethod))==null) {
                classNewInstanceReceivers.put(sourceMethod, receiverNames = new HashSet<String>());
              }
              receiverNames.add(target);
            } else if(kind.equals("Method.invoke")) {
              if(!Scene.v().containsMethod(target)) {
                throw new RuntimeException("Unknown method for signature: "+target);
              }
             
              Set<String> receiverNames;
              if((receiverNames=methodInvokeReceivers.get(sourceMethod))==null) {
                methodInvokeReceivers.put(sourceMethod, receiverNames = new HashSet<String>());
              }
              receiverNames.add(target);               
            } else if (kind.equals("Constructor.newInstance")) {
              if(!Scene.v().containsMethod(target)) {
                throw new RuntimeException("Unknown method for signature: "+target);
              }
             
              Set<String> receiverNames;
              if((receiverNames=constructorNewInstanceReceivers.get(sourceMethod))==null) {
                constructorNewInstanceReceivers.put(sourceMethod, receiverNames = new HashSet<String>());
              }
              receiverNames.add(target);               
            } else
              throw new RuntimeException("Unknown entry kind: "+kind);
          }
          lines++;
        }
      } catch (FileNotFoundException e) {
        throw new RuntimeException("Trace file not found.",e);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
  }
 
  private Set<SootMethod> inferSource(String source, int lineNumber) {
    String className = source.substring(0,source.lastIndexOf("."));
    String methodName = source.substring(source.lastIndexOf(".")+1);
    if(!Scene.v().containsClass(className)) {
      Scene.v().addBasicClass(className, SootClass.BODIES);
      Scene.v().loadBasicClasses();
      if(!Scene.v().containsClass(className)) {
        throw new RuntimeException("Trace file refers to unknown class: "+className);
      }
    }

    SootClass sootClass = Scene.v().getSootClass(className);
    Set<SootMethod> methodsWithRightName = new HashSet<SootMethod>();
    for (SootMethod m: sootClass.getMethods()) {
      if(m.getName().equals(methodName)) {
        methodsWithRightName.add(m);
      }
    }

    if(methodsWithRightName.isEmpty()) {
      throw new RuntimeException("Trace file refers to unknown method with name "+methodName+" in Class "+className);
    } else if(methodsWithRightName.size()==1) {
      return Collections.singleton(methodsWithRightName.iterator().next());
    } else {
      //more than one method with that name
      for (SootMethod sootMethod : methodsWithRightName) {
        if(coversLineNumber(lineNumber, sootMethod)) {
          return Collections.singleton(sootMethod);
        }
        if(sootMethod.hasActiveBody()) {
          Body body = sootMethod.getActiveBody();
          if(coversLineNumber(lineNumber, body)) {
            return Collections.singleton(sootMethod);
          }
          for (Unit u : body.getUnits()) {
            if(coversLineNumber(lineNumber, u)) {
              return Collections.singleton(sootMethod);
            }
          }
        }
      }
     
      //if we get here then we found no method with the right line number information;
      //be conservative and return all method that we found
      return methodsWithRightName;       
    }
  }

  private boolean coversLineNumber(int lineNumber, Host host) {
    SourceLnPosTag tag = (SourceLnPosTag) host.getTag("SourceLnPosTag");
    if(tag!=null) {
      if(tag.startLn()<=lineNumber && tag.endLn()>=lineNumber) {
        return true;
      }
    }
    return false;
  }
 
  public Set<String> classForNameClassNames(SootMethod container) {
    if(!classForNameReceivers.containsKey(container)) return Collections.emptySet();
    return classForNameReceivers.get(container);
  }

  public Set<SootClass> classForNameClasses(SootMethod container) {
    Set<SootClass> result = new HashSet<SootClass>();
    for(String className: classForNameClassNames(container)) {
      result.add(Scene.v().getSootClass(className));
    }
    return result;
  }
 
  public Set<String> classNewInstanceClassNames(SootMethod container) {
    if(!classNewInstanceReceivers.containsKey(container)) return Collections.emptySet();
    return classNewInstanceReceivers.get(container);
  }
 
  public Set<SootClass> classNewInstanceClasses(SootMethod container) {
    Set<SootClass> result = new HashSet<SootClass>();
    for(String className: classNewInstanceClassNames(container)) {
      result.add(Scene.v().getSootClass(className));
    }
    return result;
  }
 
  public Set<String> constructorNewInstanceSignatures(SootMethod container) {
    if(!constructorNewInstanceReceivers.containsKey(container)) return Collections.emptySet();
    return constructorNewInstanceReceivers.get(container);
  }
 
  public Set<SootMethod> constructorNewInstanceConstructors(SootMethod container) {
    Set<SootMethod> result = new HashSet<SootMethod>();
    for(String signature: constructorNewInstanceSignatures(container)) {
      result.add(Scene.v().getMethod(signature));
    }
    return result;
  }
 
  public Set<String> methodInvokeSignatures(SootMethod container) {
    if(!methodInvokeReceivers.containsKey(container)) return Collections.emptySet();
    return methodInvokeReceivers.get(container);
  }

  public Set<SootMethod> methodInvokeMethods(SootMethod container) {
    Set<SootMethod> result = new HashSet<SootMethod>();
    for(String signature: methodInvokeSignatures(container)) {
      result.add(Scene.v().getMethod(signature));
    }
    return result;
  }
}
TOP

Related Classes of soot.jimple.toolkits.reflection.ReflectionTraceInfo

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.