
soot.SootResolver.orig Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
/* Soot - a J*va Optimization Framework
* Copyright (C) 2000 Patrice Pominville
* Copyright (C) 2004 Ondrej Lhotak, Ganesh Sittampalam
*
* 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.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.JastAddJ.BytecodeParser;
import soot.JastAddJ.CompilationUnit;
import soot.JastAddJ.JastAddJavaParser;
import soot.JastAddJ.JavaParser;
import soot.JastAddJ.Program;
import soot.javaToJimple.IInitialResolver.Dependencies;
import soot.options.Options;
import soot.util.ConcurrentHashMultiMap;
import soot.util.MultiMap;
/**
* Loads symbols for SootClasses from either class files or jimple files.
*/
public class SootResolver {
<<<<<<< HEAD
/**
* Maps each resolved class to a list of all references in it.
*/
protected MultiMap classToTypesSignature = new ConcurrentHashMultiMap();
/**
* Maps each resolved class to a list of all references in it.
*/
protected MultiMap classToTypesHierarchy = new ConcurrentHashMultiMap();
/**
* SootClasses waiting to be resolved.
*/
@SuppressWarnings("unchecked")
private final Deque[] worklist = new Deque[4];
private Program program = null;
public SootResolver(Singletons.Global g) {
worklist[SootClass.HIERARCHY] = new ArrayDeque();
worklist[SootClass.SIGNATURES] = new ArrayDeque();
worklist[SootClass.BODIES] = new ArrayDeque();
}
protected void initializeProgram() {
if (Options.v().src_prec() != Options.src_prec_apk_c_j) {
program = new Program();
program.state().reset();
program.initBytecodeReader(new BytecodeParser());
program.initJavaParser(new JavaParser() {
@Override
public CompilationUnit parse(InputStream is, String fileName)
throws IOException, beaver.Parser.Exception {
return new JastAddJavaParser().parse(is, fileName);
}
});
program.options().initOptions();
program.options().addKeyValueOption("-classpath");
program.options().setValueForOption(Scene.v().getSootClassPath(), "-classpath");
if (Options.v().src_prec() == Options.src_prec_java)
program.setSrcPrec(Program.SRC_PREC_JAVA);
else if (Options.v().src_prec() == Options.src_prec_class)
program.setSrcPrec(Program.SRC_PREC_CLASS);
else if (Options.v().src_prec() == Options.src_prec_only_class)
program.setSrcPrec(Program.SRC_PREC_CLASS);
program.initPaths();
}
}
public static SootResolver v() {
if (ModuleUtil.module_mode())
return G.v().soot_SootModuleResolver();
return G.v().soot_SootResolver();
}
/**
* Returns true if we are resolving all class refs recursively.
*/
protected boolean resolveEverything() {
if (Options.v().on_the_fly())
return false;
return (Options.v().whole_program() || Options.v().whole_shimple() || Options.v().full_resolver()
|| Options.v().output_format() == Options.output_format_dava);
}
/**
* Returns a (possibly not yet resolved) SootClass to be used in references
* to a class. If/when the class is resolved, it will be resolved into this
* SootClass.
*/
public SootClass makeClassRef(String className) {
if (Scene.v().containsClass(className))
return Scene.v().getSootClass(className);
SootClass newClass;
if (className.endsWith(SootModuleInfo.MODULE_INFO)) {
newClass = new SootModuleInfo(className, null);
} else {
newClass = new SootClass(className);
}
newClass.setResolvingLevel(SootClass.DANGLING);
Scene.v().addClass(newClass);
return newClass;
}
/**
* Resolves the given class. Depending on the resolver settings, may decide
* to resolve other classes as well. If the class has already been resolved,
* just returns the class that was already resolved.
*/
public SootClass resolveClass(String className, int desiredLevel) {
SootClass resolvedClass = null;
try {
resolvedClass = makeClassRef(className);
addToResolveWorklist(resolvedClass, desiredLevel);
processResolveWorklist();
return resolvedClass;
} catch (SootClassNotFoundException e) {
// remove unresolved class and rethrow
if (resolvedClass != null) {
assert resolvedClass.resolvingLevel() == SootClass.DANGLING;
Scene.v().removeClass(resolvedClass);
}
throw e;
}
}
/**
* Resolve all classes on toResolveWorklist.
*/
protected void processResolveWorklist() {
for (int i = SootClass.BODIES; i >= SootClass.HIERARCHY; i--) {
while (!worklist[i].isEmpty()) {
SootClass sc = worklist[i].pop();
if (resolveEverything()) { // Whole program mode
boolean onlySignatures = sc.isPhantom() || (Options.v().no_bodies_for_excluded()
&& Scene.v().isExcluded(sc) && !Scene.v().getBasicClasses().contains(sc.getName()));
if (onlySignatures) {
bringToSignatures(sc);
sc.setPhantomClass();
for (SootMethod m : sc.getMethods()) {
m.setPhantom(true);
}
for (SootField f : sc.getFields()) {
f.setPhantom(true);
}
} else
bringToBodies(sc);
} else { // No transitive
switch (i) {
case SootClass.BODIES:
bringToBodies(sc);
break;
case SootClass.SIGNATURES:
bringToSignatures(sc);
break;
case SootClass.HIERARCHY:
bringToHierarchy(sc);
break;
}
}
}
}
}
protected void addToResolveWorklist(Type type, int level) {
// We go from Type -> SootClass directly, since RefType.getSootClass
// calls makeClassRef anyway
if (type instanceof RefType)
addToResolveWorklist(((RefType) type).getSootClass(), level);
else if (type instanceof ArrayType)
addToResolveWorklist(((ArrayType) type).baseType, level);
// Other types ignored
}
protected void addToResolveWorklist(SootClass sc, int desiredLevel) {
if (sc.resolvingLevel() >= desiredLevel)
return;
worklist[desiredLevel].add(sc);
}
/**
* Hierarchy - we know the hierarchy of the class and that's it requires at
* least Hierarchy for all supertypes and enclosing types.
*/
protected void bringToHierarchy(SootClass sc) {
if (sc.resolvingLevel() >= SootClass.HIERARCHY)
return;
if (Options.v().debug_resolver())
G.v().out.println("bringing to HIERARCHY: " + sc);
sc.setResolvingLevel(SootClass.HIERARCHY);
bringToHierarchyUnchecked(sc);
}
protected void bringToHierarchyUnchecked(SootClass sc) {
String className = sc.getName();
ClassSource is;
if (ModuleUtil.module_mode()) {
is = ModulePathSourceLocator.v().getClassSource(className, com.google.common.base.Optional.fromNullable(sc.moduleName));
} else {
is = SourceLocator.v().getClassSource(className);
}
try {
boolean modelAsPhantomRef = is == null;
if (modelAsPhantomRef) {
if (!Scene.v().allowsPhantomRefs()) {
String suffix = "";
if (className.equals("java.lang.Object")) {
suffix = " Try adding rt.jar to Soot's classpath, e.g.:\n"
+ "java -cp sootclasses.jar soot.Main -cp "
+ ".:/path/to/jdk/jre/lib/rt.jar ";
} else if (className.equals("javax.crypto.Cipher")) {
suffix = " Try adding jce.jar to Soot's classpath, e.g.:\n"
+ "java -cp sootclasses.jar soot.Main -cp "
+ ".:/path/to/jdk/jre/lib/rt.jar:/path/to/jdk/jre/lib/jce.jar ";
}
throw new SootClassNotFoundException(
"couldn't find class: " + className + " (is your soot-class-path set properly?)" + suffix);
} else {
// G.v().out.println("Warning: " + className + " is a
// phantom class!");
sc.setPhantomClass();
}
} else {
Dependencies dependencies = is.resolve(sc);
if (!dependencies.typesToSignature.isEmpty())
classToTypesSignature.putAll(sc, dependencies.typesToSignature);
if (!dependencies.typesToHierarchy.isEmpty())
classToTypesHierarchy.putAll(sc, dependencies.typesToHierarchy);
}
} finally {
if (is != null)
is.close();
}
reResolveHierarchy(sc);
}
public void reResolveHierarchy(SootClass sc) {
// Bring superclasses to hierarchy
if (sc.hasSuperclass())
addToResolveWorklist(sc.getSuperclass(), SootClass.HIERARCHY);
if (sc.hasOuterClass())
addToResolveWorklist(sc.getOuterClass(), SootClass.HIERARCHY);
for (SootClass iface : sc.getInterfaces()) {
addToResolveWorklist(iface, SootClass.HIERARCHY);
}
}
/**
* Signatures - we know the signatures of all methods and fields requires at
* least Hierarchy for all referred to types in these signatures.
*/
protected void bringToSignatures(SootClass sc) {
if (sc.resolvingLevel() >= SootClass.SIGNATURES)
return;
bringToHierarchy(sc);
if (Options.v().debug_resolver())
G.v().out.println("bringing to SIGNATURES: " + sc);
sc.setResolvingLevel(SootClass.SIGNATURES);
bringToSignaturesUnchecked(sc);
}
protected void bringToSignaturesUnchecked(SootClass sc) {
for (SootField f : sc.getFields()) {
addToResolveWorklist(f.getType(), SootClass.HIERARCHY);
}
for (SootMethod m : sc.getMethods()) {
addToResolveWorklist(m.getReturnType(), SootClass.HIERARCHY);
for (Type ptype : m.getParameterTypes()) {
addToResolveWorklist(ptype, SootClass.HIERARCHY);
}
List exceptions = m.getExceptionsUnsafe();
if (exceptions != null) {
for (SootClass exception : exceptions) {
addToResolveWorklist(exception, SootClass.HIERARCHY);
}
}
}
// Bring superclasses to signatures
if (sc.hasSuperclass())
addToResolveWorklist(sc.getSuperclass(), SootClass.SIGNATURES);
for (SootClass iface : sc.getInterfaces()) {
addToResolveWorklist(iface, SootClass.SIGNATURES);
}
}
/**
* Bodies - we can now start loading the bodies of methods for all referred
* to methods and fields in the bodies, requires signatures for the method
* receiver and field container, and hierarchy for all other classes
* referenced in method references. Current implementation does not
* distinguish between the receiver and other references. Therefore, it is
* conservative and brings all of them to signatures. But this could/should
* be improved.
*/
protected void bringToBodies(SootClass sc) {
if (sc.resolvingLevel() >= SootClass.BODIES)
return;
bringToSignatures(sc);
if (Options.v().debug_resolver())
G.v().out.println("bringing to BODIES: " + sc);
sc.setResolvingLevel(SootClass.BODIES);
bringToBodiesUnchecked(sc);
}
protected void bringToBodiesUnchecked(SootClass sc) {
{
Collection references = classToTypesHierarchy.get(sc);
if (references != null) {
// This must be an iterator, not a for-all since the underlying
// collection may change as we go
Iterator it = references.iterator();
while (it.hasNext()) {
final Type t = it.next();
addToResolveWorklist(t, SootClass.HIERARCHY);
}
}
}
{
Collection references = classToTypesSignature.get(sc);
if (references != null) {
// This must be an iterator, not a for-all since the underlying
// collection may change as we go
Iterator it = references.iterator();
while (it.hasNext()) {
final Type t = it.next();
addToResolveWorklist(t, SootClass.SIGNATURES);
}
}
}
}
public void reResolve(SootClass cl, int newResolvingLevel) {
int resolvingLevel = cl.resolvingLevel();
if (resolvingLevel >= newResolvingLevel)
return;
reResolveHierarchy(cl);
cl.setResolvingLevel(newResolvingLevel);
addToResolveWorklist(cl, resolvingLevel);
processResolveWorklist();
}
public void reResolve(SootClass cl) {
reResolve(cl, SootClass.HIERARCHY);
}
public Program getProgram() {
if (program == null)
initializeProgram();
return program;
}
protected class SootClassNotFoundException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1563461446590293827L;
private SootClassNotFoundException(String s) {
super(s);
}
}
=======
private static final Logger logger = LoggerFactory.getLogger(SootResolver.class);
/** Maps each resolved class to a list of all references in it. */
protected MultiMap classToTypesSignature = new ConcurrentHashMultiMap();
/** Maps each resolved class to a list of all references in it. */
protected MultiMap classToTypesHierarchy = new ConcurrentHashMultiMap();
/** SootClasses waiting to be resolved. */
@SuppressWarnings("unchecked")
private final Deque[] worklist = new Deque[4];
private Program program = null;
public SootResolver(Singletons.Global g) {
worklist[SootClass.HIERARCHY] = new ArrayDeque();
worklist[SootClass.SIGNATURES] = new ArrayDeque();
worklist[SootClass.BODIES] = new ArrayDeque();
}
protected void initializeProgram() {
if (Options.v().src_prec() != Options.src_prec_apk_c_j) {
program = new Program();
program.state().reset();
program.initBytecodeReader(new BytecodeParser());
program.initJavaParser(new JavaParser() {
@Override
public CompilationUnit parse(InputStream is, String fileName)
throws IOException, beaver.Parser.Exception {
return new JastAddJavaParser().parse(is, fileName);
}
});
program.options().initOptions();
program.options().addKeyValueOption("-classpath");
program.options().setValueForOption(Scene.v().getSootClassPath(), "-classpath");
if (Options.v().src_prec() == Options.src_prec_java)
program.setSrcPrec(Program.SRC_PREC_JAVA);
else if (Options.v().src_prec() == Options.src_prec_class)
program.setSrcPrec(Program.SRC_PREC_CLASS);
else if (Options.v().src_prec() == Options.src_prec_only_class)
program.setSrcPrec(Program.SRC_PREC_CLASS);
program.initPaths();
}
}
public static SootResolver v() {
return G.v().soot_SootResolver();
}
/** Returns true if we are resolving all class refs recursively. */
protected boolean resolveEverything() {
if (Options.v().on_the_fly())
return false;
return (Options.v().whole_program() || Options.v().whole_shimple() || Options.v().full_resolver()
|| Options.v().output_format() == Options.output_format_dava);
}
/**
* Returns a (possibly not yet resolved) SootClass to be used in references to a
* class. If/when the class is resolved, it will be resolved into this
* SootClass.
*/
public SootClass makeClassRef(String className) {
if (Scene.v().containsClass(className))
return Scene.v().getSootClass(className);
SootClass newClass;
newClass = new SootClass(className);
newClass.setResolvingLevel(SootClass.DANGLING);
Scene.v().addClass(newClass);
return newClass;
}
/**
* Resolves the given class. Depending on the resolver settings, may decide to
* resolve other classes as well. If the class has already been resolved, just
* returns the class that was already resolved.
*/
public SootClass resolveClass(String className, int desiredLevel) {
SootClass resolvedClass = null;
try {
resolvedClass = makeClassRef(className);
addToResolveWorklist(resolvedClass, desiredLevel);
processResolveWorklist();
return resolvedClass;
} catch (SootClassNotFoundException e) {
// remove unresolved class and rethrow
if (resolvedClass != null) {
assert resolvedClass.resolvingLevel() == SootClass.DANGLING;
Scene.v().removeClass(resolvedClass);
}
throw e;
}
}
/** Resolve all classes on toResolveWorklist. */
protected void processResolveWorklist() {
for (int i = SootClass.BODIES; i >= SootClass.HIERARCHY; i--) {
while (!worklist[i].isEmpty()) {
SootClass sc = worklist[i].pop();
if (resolveEverything()) { // Whole program mode
boolean onlySignatures = sc.isPhantom() || (Options.v().no_bodies_for_excluded()
&& Scene.v().isExcluded(sc) && !Scene.v().getBasicClasses().contains(sc.getName()));
if (onlySignatures) {
bringToSignatures(sc);
sc.setPhantomClass();
for (SootMethod m : sc.getMethods()) {
m.setPhantom(true);
}
for (SootField f : sc.getFields()) {
f.setPhantom(true);
}
} else
bringToBodies(sc);
} else { // No transitive
switch (i) {
case SootClass.BODIES:
bringToBodies(sc);
break;
case SootClass.SIGNATURES:
bringToSignatures(sc);
break;
case SootClass.HIERARCHY:
bringToHierarchy(sc);
break;
}
}
}
}
}
protected void addToResolveWorklist(Type type, int level) {
// We go from Type -> SootClass directly, since RefType.getSootClass
// calls makeClassRef anyway
if (type instanceof RefType)
addToResolveWorklist(((RefType) type).getSootClass(), level);
else if (type instanceof ArrayType)
addToResolveWorklist(((ArrayType) type).baseType, level);
// Other types ignored
}
protected void addToResolveWorklist(SootClass sc, int desiredLevel) {
if (sc.resolvingLevel() >= desiredLevel)
return;
worklist[desiredLevel].add(sc);
}
/**
* Hierarchy - we know the hierarchy of the class and that's it requires at
* least Hierarchy for all supertypes and enclosing types.
*/
protected void bringToHierarchy(SootClass sc) {
if (sc.resolvingLevel() >= SootClass.HIERARCHY)
return;
if (Options.v().debug_resolver())
logger.debug("bringing to HIERARCHY: " + sc);
sc.setResolvingLevel(SootClass.HIERARCHY);
bringToHierarchyUnchecked(sc);
}
protected void bringToHierarchyUnchecked(SootClass sc) {
String className = sc.getName();
ClassSource is = SourceLocator.v().getClassSource(className);
try {
boolean modelAsPhantomRef = is == null;
if (modelAsPhantomRef) {
if (!Scene.v().allowsPhantomRefs()) {
String suffix = "";
if (className.equals("java.lang.Object")) {
suffix = " Try adding rt.jar to Soot's classpath, e.g.:\n"
+ "java -cp sootclasses.jar soot.Main -cp "
+ ".:/path/to/jdk/jre/lib/rt.jar ";
} else if (className.equals("javax.crypto.Cipher")) {
suffix = " Try adding jce.jar to Soot's classpath, e.g.:\n"
+ "java -cp sootclasses.jar soot.Main -cp "
+ ".:/path/to/jdk/jre/lib/rt.jar:/path/to/jdk/jre/lib/jce.jar ";
}
throw new SootClassNotFoundException(
"couldn't find class: " + className + " (is your soot-class-path set properly?)" + suffix);
} else {
// logger.warn("" + className + " is a
// phantom class!");
sc.setPhantomClass();
}
} else {
Dependencies dependencies = is.resolve(sc);
if (!dependencies.typesToSignature.isEmpty())
classToTypesSignature.putAll(sc, dependencies.typesToSignature);
if (!dependencies.typesToHierarchy.isEmpty())
classToTypesHierarchy.putAll(sc, dependencies.typesToHierarchy);
}
} finally {
if (is != null)
is.close();
}
reResolveHierarchy(sc);
}
public void reResolveHierarchy(SootClass sc) {
// Bring superclasses to hierarchy
SootClass superClass = sc.getSuperclassUnsafe();
if (superClass != null)
addToResolveWorklist(superClass, SootClass.HIERARCHY);
SootClass outerClass = sc.getOuterClassUnsafe();
if (outerClass != null)
addToResolveWorklist(outerClass, SootClass.HIERARCHY);
for (SootClass iface : sc.getInterfaces()) {
addToResolveWorklist(iface, SootClass.HIERARCHY);
}
}
/**
* Signatures - we know the signatures of all methods and fields requires at
* least Hierarchy for all referred to types in these signatures.
*/
protected void bringToSignatures(SootClass sc) {
if (sc.resolvingLevel() >= SootClass.SIGNATURES)
return;
bringToHierarchy(sc);
if (Options.v().debug_resolver())
logger.debug("bringing to SIGNATURES: " + sc);
sc.setResolvingLevel(SootClass.SIGNATURES);
bringToSignaturesUnchecked(sc);
}
protected void bringToSignaturesUnchecked(SootClass sc) {
for (SootField f : sc.getFields()) {
addToResolveWorklist(f.getType(), SootClass.HIERARCHY);
}
for (SootMethod m : sc.getMethods()) {
addToResolveWorklist(m.getReturnType(), SootClass.HIERARCHY);
for (Type ptype : m.getParameterTypes()) {
addToResolveWorklist(ptype, SootClass.HIERARCHY);
}
List exceptions = m.getExceptionsUnsafe();
if (exceptions != null) {
for (SootClass exception : exceptions) {
addToResolveWorklist(exception, SootClass.HIERARCHY);
}
}
}
// Bring superclasses to signatures
reResolveHierarchy(sc);
}
/**
* Bodies - we can now start loading the bodies of methods for all referred to
* methods and fields in the bodies, requires signatures for the method receiver
* and field container, and hierarchy for all other classes referenced in method
* references. Current implementation does not distinguish between the receiver
* and other references. Therefore, it is conservative and brings all of them to
* signatures. But this could/should be improved.
*/
protected void bringToBodies(SootClass sc) {
if (sc.resolvingLevel() >= SootClass.BODIES)
return;
bringToSignatures(sc);
if (Options.v().debug_resolver())
logger.debug("bringing to BODIES: " + sc);
sc.setResolvingLevel(SootClass.BODIES);
bringToBodiesUnchecked(sc);
}
protected void bringToBodiesUnchecked(SootClass sc) {
{
Collection references = classToTypesHierarchy.get(sc);
if (references != null) {
// This must be an iterator, not a for-all since the underlying
// collection may change as we go
Iterator it = references.iterator();
while (it.hasNext()) {
final Type t = it.next();
addToResolveWorklist(t, SootClass.HIERARCHY);
}
}
}
{
Collection references = classToTypesSignature.get(sc);
if (references != null) {
// This must be an iterator, not a for-all since the underlying
// collection may change as we go
Iterator it = references.iterator();
while (it.hasNext()) {
final Type t = it.next();
addToResolveWorklist(t, SootClass.SIGNATURES);
}
}
}
}
public void reResolve(SootClass cl, int newResolvingLevel) {
int resolvingLevel = cl.resolvingLevel();
if (resolvingLevel >= newResolvingLevel)
return;
reResolveHierarchy(cl);
cl.setResolvingLevel(newResolvingLevel);
addToResolveWorklist(cl, resolvingLevel);
processResolveWorklist();
}
public void reResolve(SootClass cl) {
reResolve(cl, SootClass.HIERARCHY);
}
public Program getProgram() {
if (program == null)
initializeProgram();
return program;
}
public class SootClassNotFoundException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1563461446590293827L;
private SootClassNotFoundException(String s) {
super(s);
}
}
>>>>>>> origin/develop
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy