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

soot.jimple.toolkits.reflection.ReflectionTraceInfo Maven / Gradle / Ivy

package soot.jimple.toolkits.reflection;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2010 Eric Bodden
 * %%
 * 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.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.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

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

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

public class ReflectionTraceInfo {
  private static final Logger logger = LoggerFactory.getLogger(ReflectionTraceInfo.class);

  public enum Kind {
    ClassForName, ClassNewInstance, ConstructorNewInstance, MethodInvoke, FieldSet, FieldGet
  }

  protected Map> classForNameReceivers;

  protected Map> classNewInstanceReceivers;

  protected Map> constructorNewInstanceReceivers;

  protected Map> methodInvokeReceivers;

  protected Map> fieldSetReceivers;

  protected Map> fieldGetReceivers;

  public ReflectionTraceInfo(String logFile) {
    classForNameReceivers = new LinkedHashMap>();
    classNewInstanceReceivers = new LinkedHashMap>();
    constructorNewInstanceReceivers = new LinkedHashMap>();
    methodInvokeReceivers = new LinkedHashMap>();
    fieldSetReceivers = new LinkedHashMap>();
    fieldGetReceivers = new LinkedHashMap>();

    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;
        Set ignoredKinds = new HashSet();
        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 possibleSourceMethods = inferSource(source, lineNumber);
          for (SootMethod sourceMethod : possibleSourceMethods) {
            if (kind.equals("Class.forName")) {
              Set receiverNames;
              if ((receiverNames = classForNameReceivers.get(sourceMethod)) == null) {
                classForNameReceivers.put(sourceMethod, receiverNames = new LinkedHashSet());
              }
              receiverNames.add(target);
            } else if (kind.equals("Class.newInstance")) {
              Set receiverNames;
              if ((receiverNames = classNewInstanceReceivers.get(sourceMethod)) == null) {
                classNewInstanceReceivers.put(sourceMethod, receiverNames = new LinkedHashSet());
              }
              receiverNames.add(target);
            } else if (kind.equals("Method.invoke")) {
              if (!Scene.v().containsMethod(target)) {
                throw new RuntimeException("Unknown method for signature: " + target);
              }

              Set receiverNames;
              if ((receiverNames = methodInvokeReceivers.get(sourceMethod)) == null) {
                methodInvokeReceivers.put(sourceMethod, receiverNames = new LinkedHashSet());
              }
              receiverNames.add(target);
            } else if (kind.equals("Constructor.newInstance")) {
              if (!Scene.v().containsMethod(target)) {
                throw new RuntimeException("Unknown method for signature: " + target);
              }

              Set receiverNames;
              if ((receiverNames = constructorNewInstanceReceivers.get(sourceMethod)) == null) {
                constructorNewInstanceReceivers.put(sourceMethod, receiverNames = new LinkedHashSet());
              }
              receiverNames.add(target);
            } else if (kind.equals("Field.set*")) {
              if (!Scene.v().containsField(target)) {
                throw new RuntimeException("Unknown method for signature: " + target);
              }

              Set receiverNames;
              if ((receiverNames = fieldSetReceivers.get(sourceMethod)) == null) {
                fieldSetReceivers.put(sourceMethod, receiverNames = new LinkedHashSet());
              }
              receiverNames.add(target);
            } else if (kind.equals("Field.get*")) {
              if (!Scene.v().containsField(target)) {
                throw new RuntimeException("Unknown method for signature: " + target);
              }

              Set receiverNames;
              if ((receiverNames = fieldGetReceivers.get(sourceMethod)) == null) {
                fieldGetReceivers.put(sourceMethod, receiverNames = new LinkedHashSet());
              }
              receiverNames.add(target);
            } else {
              ignoredKinds.add(kind);
            }
          }
          lines++;
        }
        if (!ignoredKinds.isEmpty()) {
          logger
              .debug("Encountered reflective calls entries of the following kinds that\n" + "cannot currently be handled:");
          for (String kind : ignoredKinds) {
            logger.debug("" + kind);
          }
        }
      } catch (FileNotFoundException e) {
        throw new RuntimeException("Trace file not found.", e);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
  }

  private Set 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 methodsWithRightName = new LinkedHashSet();
    for (SootMethod m : sootClass.getMethods()) {
      if (m.isConcrete() && 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.isConcrete()) {
          if (!sootMethod.hasActiveBody()) {
            sootMethod.retrieveActiveBody();
          }
          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;
        }
      }
    }
    {
      LineNumberTag tag = (LineNumberTag) host.getTag("LineNumberTag");
      if (tag != null) {
        if (tag.getLineNumber() == lineNumber) {
          return true;
        }
      }
    }
    return false;
  }

  public Set classForNameClassNames(SootMethod container) {
    if (!classForNameReceivers.containsKey(container)) {
      return Collections.emptySet();
    }
    return classForNameReceivers.get(container);
  }

  public Set classForNameClasses(SootMethod container) {
    Set result = new LinkedHashSet();
    for (String className : classForNameClassNames(container)) {
      result.add(Scene.v().getSootClass(className));
    }
    return result;
  }

  public Set classNewInstanceClassNames(SootMethod container) {
    if (!classNewInstanceReceivers.containsKey(container)) {
      return Collections.emptySet();
    }
    return classNewInstanceReceivers.get(container);
  }

  public Set classNewInstanceClasses(SootMethod container) {
    Set result = new LinkedHashSet();
    for (String className : classNewInstanceClassNames(container)) {
      result.add(Scene.v().getSootClass(className));
    }
    return result;
  }

  public Set constructorNewInstanceSignatures(SootMethod container) {
    if (!constructorNewInstanceReceivers.containsKey(container)) {
      return Collections.emptySet();
    }
    return constructorNewInstanceReceivers.get(container);
  }

  public Set constructorNewInstanceConstructors(SootMethod container) {
    Set result = new LinkedHashSet();
    for (String signature : constructorNewInstanceSignatures(container)) {
      result.add(Scene.v().getMethod(signature));
    }
    return result;
  }

  public Set methodInvokeSignatures(SootMethod container) {
    if (!methodInvokeReceivers.containsKey(container)) {
      return Collections.emptySet();
    }
    return methodInvokeReceivers.get(container);
  }

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

  public Set methodsContainingReflectiveCalls() {
    Set res = new LinkedHashSet();
    res.addAll(classForNameReceivers.keySet());
    res.addAll(classNewInstanceReceivers.keySet());
    res.addAll(constructorNewInstanceReceivers.keySet());
    res.addAll(methodInvokeReceivers.keySet());
    return res;
  }

  public Set fieldSetSignatures(SootMethod container) {
    if (!fieldSetReceivers.containsKey(container)) {
      return Collections.emptySet();
    }
    return fieldSetReceivers.get(container);
  }

  public Set fieldGetSignatures(SootMethod container) {
    if (!fieldGetReceivers.containsKey(container)) {
      return Collections.emptySet();
    }
    return fieldGetReceivers.get(container);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy