0001: /* Soot - a J*va Optimization Framework
0002: * Copyright (C) 1997-1999 Raja Vallee-Rai
0003: * Copyright (C) 2004 Ondrej Lhotak
0004: *
0005: * This library is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU Lesser General Public
0007: * License as published by the Free Software Foundation; either
0008: * version 2.1 of the License, or (at your option) any later version.
0009: *
0010: * This library is distributed in the hope that it will be useful,
0011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013: * Lesser General Public License for more details.
0014: *
0015: * You should have received a copy of the GNU Lesser General Public
0016: * License along with this library; if not, write to the
0017: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
0018: * Boston, MA 02111-1307, USA.
0019: */
0020:
0021: /*
0022: * Modified by the Sable Research Group and others 1997-1999.
0023: * See the 'credits' file distributed with Soot for the complete list of
0024: * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
0025: */
0026:
0027: package soot;
0028:
0029: import soot.options.*;
0030:
0031: import soot.util.*;
0032:
0033: import java.util.*;
0034: import java.io.*;
0035: import soot.jimple.toolkits.callgraph.*;
0036: import soot.jimple.toolkits.pointer.*;
0037: import soot.toolkits.exceptions.ThrowAnalysis;
0038: import soot.toolkits.exceptions.PedanticThrowAnalysis;
0039: import soot.toolkits.exceptions.UnitThrowAnalysis;
0040:
0041: /** Manages the SootClasses of the application being analyzed. */
0042: public class Scene //extends AbstractHost
0043: {
0044: public Scene(Singletons.Global g) {
0045: setReservedNames();
0046:
0047: // load soot.class.path system property, if defined
0048: String scp = System.getProperty("soot.class.path");
0049:
0050: if (scp != null)
0051: setSootClassPath(scp);
0052:
0053: kindNumberer.add(Kind.INVALID);
0054: kindNumberer.add(Kind.STATIC);
0055: kindNumberer.add(Kind.VIRTUAL);
0056: kindNumberer.add(Kind.INTERFACE);
0057: kindNumberer.add(Kind.SPECIAL);
0058: kindNumberer.add(Kind.CLINIT);
0059: kindNumberer.add(Kind.THREAD);
0060: kindNumberer.add(Kind.FINALIZE);
0061: kindNumberer.add(Kind.INVOKE_FINALIZE);
0062: kindNumberer.add(Kind.PRIVILEGED);
0063: kindNumberer.add(Kind.NEWINSTANCE);
0064:
0065: addSootBasicClasses();
0066: }
0067:
0068: public static Scene v() {
0069: return G.v().soot_Scene();
0070: }
0071:
0072: Chain<SootClass> classes = new HashChain<SootClass>();
0073: Chain<SootClass> applicationClasses = new HashChain<SootClass>();
0074: Chain<SootClass> libraryClasses = new HashChain<SootClass>();
0075: Chain<SootClass> phantomClasses = new HashChain<SootClass>();
0076:
0077: private final Map<String, Type> nameToClass = new HashMap<String, Type>();
0078:
0079: ArrayNumberer kindNumberer = new ArrayNumberer();
0080: ArrayNumberer typeNumberer = new ArrayNumberer();
0081: ArrayNumberer methodNumberer = new ArrayNumberer();
0082: Numberer unitNumberer = new MapNumberer();
0083: Numberer contextNumberer = null;
0084: ArrayNumberer fieldNumberer = new ArrayNumberer();
0085: ArrayNumberer classNumberer = new ArrayNumberer();
0086: StringNumberer subSigNumberer = new StringNumberer();
0087: ArrayNumberer localNumberer = new ArrayNumberer();
0088:
0089: private Hierarchy activeHierarchy;
0090: private FastHierarchy activeFastHierarchy;
0091: private CallGraph activeCallGraph;
0092: private ReachableMethods reachableMethods;
0093: private PointsToAnalysis activePointsToAnalysis;
0094: private SideEffectAnalysis activeSideEffectAnalysis;
0095: private List<SootMethod> entryPoints;
0096:
0097: boolean allowsPhantomRefs = false;
0098:
0099: SootClass mainClass;
0100: String sootClassPath = null;
0101:
0102: // Two default values for constructing ExceptionalUnitGraphs:
0103: private ThrowAnalysis defaultThrowAnalysis = null;
0104:
0105: public void setMainClass(SootClass m) {
0106: mainClass = m;
0107: if (!m.declaresMethod(Scene.v().getSubSigNumberer().findOrAdd(
0108: "void main(java.lang.String[])"))) {
0109: throw new RuntimeException("Main-class has no main method!");
0110: }
0111: }
0112:
0113: Set<String> reservedNames = new HashSet<String>();
0114:
0115: /**
0116: Returns a set of tokens which are reserved. Any field, class, method, or local variable with such a name will be quoted.
0117: */
0118:
0119: public Set<String> getReservedNames() {
0120: return reservedNames;
0121: }
0122:
0123: /**
0124: If this name is in the set of reserved names, then return a quoted version of it. Else pass it through.
0125: */
0126:
0127: public String quotedNameOf(String s) {
0128: if (reservedNames.contains(s))
0129: return "\'" + s + "\'";
0130: else
0131: return s;
0132: }
0133:
0134: public SootClass getMainClass() {
0135: if (mainClass == null) {
0136: setMainClassFromOptions();
0137: }
0138: if (mainClass == null)
0139: throw new RuntimeException("There is no main class set!");
0140:
0141: return mainClass;
0142: }
0143:
0144: public SootMethod getMainMethod() {
0145: if (mainClass == null) {
0146: throw new RuntimeException("There is no main class set!");
0147: }
0148: if (!mainClass.declaresMethod("main", new SingletonList(
0149: ArrayType.v(RefType.v("java.lang.String"), 1)),
0150: VoidType.v())) {
0151: throw new RuntimeException(
0152: "Main class declares no main method!");
0153: }
0154: return mainClass.getMethod("main", new SingletonList(ArrayType
0155: .v(RefType.v("java.lang.String"), 1)), VoidType.v());
0156: }
0157:
0158: public void setSootClassPath(String p) {
0159: sootClassPath = p;
0160: SourceLocator.v().invalidateClassPath();
0161: }
0162:
0163: public String getSootClassPath() {
0164: if (sootClassPath == null) {
0165: String optionscp = Options.v().soot_classpath();
0166: if (optionscp.length() > 0)
0167: sootClassPath = optionscp;
0168:
0169: String defaultSootClassPath = defaultClassPath();
0170:
0171: //if no classpath is given on the command line, take the default
0172: if (sootClassPath == null) {
0173: sootClassPath = defaultSootClassPath;
0174: } else {
0175: //if one is given...
0176: if (Options.v().prepend_classpath()) {
0177: //if the prepend flag is set, append the default classpath
0178: sootClassPath += File.pathSeparator
0179: + defaultSootClassPath;
0180: }
0181: //else, leave it as it is
0182: }
0183: }
0184:
0185: return sootClassPath;
0186: }
0187:
0188: public String defaultClassPath() {
0189: String defaultSootClassPath = System
0190: .getProperty("java.class.path")
0191: + File.pathSeparator
0192: + System.getProperty("java.home")
0193: + File.separator + "lib" + File.separator + "rt.jar";
0194: if (Options.v().whole_program()) {
0195: //add jce.jar, which is necessary for whole program mode
0196: //(java.security.Signature from rt.jar import javax.crypto.Cipher from jce.jar
0197: defaultSootClassPath += File.pathSeparator
0198: + System.getProperty("java.home") + File.separator
0199: + "lib" + File.separator + "jce.jar";
0200: }
0201: return defaultSootClassPath;
0202: }
0203:
0204: private int stateCount;
0205:
0206: public int getState() {
0207: return this .stateCount;
0208: }
0209:
0210: private void modifyHierarchy() {
0211: stateCount++;
0212: activeHierarchy = null;
0213: activeFastHierarchy = null;
0214: activeSideEffectAnalysis = null;
0215: activePointsToAnalysis = null;
0216: }
0217:
0218: public void addClass(SootClass c) {
0219: if (c.isInScene())
0220: throw new RuntimeException("already managed: "
0221: + c.getName());
0222:
0223: if (containsClass(c.getName()))
0224: throw new RuntimeException("duplicate class: "
0225: + c.getName());
0226:
0227: classes.add(c);
0228: c.setLibraryClass();
0229:
0230: nameToClass.put(c.getName(), c.getType());
0231: c.getType().setSootClass(c);
0232: c.setInScene(true);
0233: modifyHierarchy();
0234: }
0235:
0236: public void removeClass(SootClass c) {
0237: if (!c.isInScene())
0238: throw new RuntimeException();
0239:
0240: classes.remove(c);
0241:
0242: if (c.isLibraryClass()) {
0243: libraryClasses.remove(c);
0244: } else if (c.isPhantomClass()) {
0245: phantomClasses.remove(c);
0246: } else if (c.isApplicationClass()) {
0247: applicationClasses.remove(c);
0248: }
0249:
0250: c.getType().setSootClass(null);
0251: c.setInScene(false);
0252: modifyHierarchy();
0253: }
0254:
0255: public boolean containsClass(String className) {
0256: RefType type = (RefType) nameToClass.get(className);
0257: if (type == null)
0258: return false;
0259: if (!type.hasSootClass())
0260: return false;
0261: SootClass c = type.getSootClass();
0262: return c.isInScene();
0263: }
0264:
0265: public String signatureToClass(String sig) {
0266: if (sig.charAt(0) != '<')
0267: throw new RuntimeException("oops " + sig);
0268: if (sig.charAt(sig.length() - 1) != '>')
0269: throw new RuntimeException("oops " + sig);
0270: int index = sig.indexOf(":");
0271: if (index < 0)
0272: throw new RuntimeException("oops " + sig);
0273: return sig.substring(1, index);
0274: }
0275:
0276: public String signatureToSubsignature(String sig) {
0277: if (sig.charAt(0) != '<')
0278: throw new RuntimeException("oops " + sig);
0279: if (sig.charAt(sig.length() - 1) != '>')
0280: throw new RuntimeException("oops " + sig);
0281: int index = sig.indexOf(":");
0282: if (index < 0)
0283: throw new RuntimeException("oops " + sig);
0284: return sig.substring(index + 2, sig.length() - 1);
0285: }
0286:
0287: private SootField grabField(String fieldSignature) {
0288: String cname = signatureToClass(fieldSignature);
0289: String fname = signatureToSubsignature(fieldSignature);
0290: if (!containsClass(cname))
0291: return null;
0292: SootClass c = getSootClass(cname);
0293: if (!c.declaresField(fname))
0294: return null;
0295: return c.getField(fname);
0296: }
0297:
0298: public boolean containsField(String fieldSignature) {
0299: return grabField(fieldSignature) != null;
0300: }
0301:
0302: private SootMethod grabMethod(String methodSignature) {
0303: String cname = signatureToClass(methodSignature);
0304: String mname = signatureToSubsignature(methodSignature);
0305: if (!containsClass(cname))
0306: return null;
0307: SootClass c = getSootClass(cname);
0308: if (!c.declaresMethod(mname))
0309: return null;
0310: return c.getMethod(mname);
0311: }
0312:
0313: public boolean containsMethod(String methodSignature) {
0314: return grabMethod(methodSignature) != null;
0315: }
0316:
0317: public SootField getField(String fieldSignature) {
0318: SootField f = grabField(fieldSignature);
0319: if (f != null)
0320: return f;
0321:
0322: throw new RuntimeException("tried to get nonexistent field "
0323: + fieldSignature);
0324: }
0325:
0326: public SootMethod getMethod(String methodSignature) {
0327: SootMethod m = grabMethod(methodSignature);
0328: if (m != null)
0329: return m;
0330: throw new RuntimeException("tried to get nonexistent method "
0331: + methodSignature);
0332: }
0333:
0334: /**
0335: * Attempts to load the given class and all of the required support classes.
0336: * Returns the original class if it was loaded, or null otherwise.
0337: */
0338:
0339: public SootClass tryLoadClass(String className, int desiredLevel) {
0340: /*
0341: if(Options.v().time())
0342: Main.v().resolveTimer.start();
0343: */
0344:
0345: Scene.v().setPhantomRefs(true);
0346: //SootResolver resolver = new SootResolver();
0347: if (!getPhantomRefs()
0348: && SourceLocator.v().getClassSource(className) == null) {
0349: Scene.v().setPhantomRefs(false);
0350: return null;
0351: }
0352: SootResolver resolver = SootResolver.v();
0353: SootClass toReturn = resolver.resolveClass(className,
0354: desiredLevel);
0355: Scene.v().setPhantomRefs(false);
0356:
0357: return toReturn;
0358:
0359: /*
0360: if(Options.v().time())
0361: Main.v().resolveTimer.end(); */
0362: }
0363:
0364: /**
0365: * Loads the given class and all of the required support classes. Returns the first class.
0366: */
0367:
0368: public SootClass loadClassAndSupport(String className) {
0369: SootClass ret = loadClass(className, SootClass.SIGNATURES);
0370: if (!ret.isPhantom())
0371: ret = loadClass(className, SootClass.BODIES);
0372: return ret;
0373: }
0374:
0375: public SootClass loadClass(String className, int desiredLevel) {
0376: /*
0377: if(Options.v().time())
0378: Main.v().resolveTimer.start();
0379: */
0380:
0381: Scene.v().setPhantomRefs(true);
0382: //SootResolver resolver = new SootResolver();
0383: SootResolver resolver = SootResolver.v();
0384: SootClass toReturn = resolver.resolveClass(className,
0385: desiredLevel);
0386: Scene.v().setPhantomRefs(false);
0387:
0388: return toReturn;
0389:
0390: /*
0391: if(Options.v().time())
0392: Main.v().resolveTimer.end(); */
0393: }
0394:
0395: /**
0396: * Returns the RefType with the given className.
0397: */
0398: public RefType getRefType(String className) {
0399: return (RefType) nameToClass.get(className);
0400: }
0401:
0402: /**
0403: * Returns the RefType with the given className.
0404: */
0405: public void addRefType(RefType type) {
0406: nameToClass.put(type.getClassName(), type);
0407: }
0408:
0409: /**
0410: * Returns the SootClass with the given className.
0411: */
0412:
0413: public SootClass getSootClass(String className) {
0414: RefType type = (RefType) nameToClass.get(className);
0415: SootClass toReturn = null;
0416: if (type != null)
0417: toReturn = type.getSootClass();
0418:
0419: if (toReturn != null) {
0420: return toReturn;
0421: } else if (Scene.v().allowsPhantomRefs()) {
0422: SootClass c = new SootClass(className);
0423: c.setPhantom(true);
0424: addClass(c);
0425: return c;
0426: } else {
0427: throw new RuntimeException(System
0428: .getProperty("line.separator")
0429: + "Aborting: can't find classfile " + className);
0430: }
0431: }
0432:
0433: /**
0434: * Returns an backed chain of the classes in this manager.
0435: */
0436:
0437: public Chain<SootClass> getClasses() {
0438: return classes;
0439: }
0440:
0441: /* The four following chains are mutually disjoint. */
0442:
0443: /**
0444: * Returns a chain of the application classes in this scene.
0445: * These classes are the ones which can be freely analysed & modified.
0446: */
0447: public Chain<SootClass> getApplicationClasses() {
0448: return applicationClasses;
0449: }
0450:
0451: /**
0452: * Returns a chain of the library classes in this scene.
0453: * These classes can be analysed but not modified.
0454: */
0455: public Chain<SootClass> getLibraryClasses() {
0456: return libraryClasses;
0457: }
0458:
0459: /**
0460: * Returns a chain of the phantom classes in this scene.
0461: * These classes are referred to by other classes, but cannot be loaded.
0462: */
0463: public Chain<SootClass> getPhantomClasses() {
0464: return phantomClasses;
0465: }
0466:
0467: Chain<SootClass> getContainingChain(SootClass c) {
0468: if (c.isApplicationClass())
0469: return getApplicationClasses();
0470: else if (c.isLibraryClass())
0471: return getLibraryClasses();
0472: else if (c.isPhantomClass())
0473: return getPhantomClasses();
0474:
0475: return null;
0476: }
0477:
0478: /****************************************************************************/
0479: /**
0480: Retrieves the active side-effect analysis
0481: */
0482:
0483: public SideEffectAnalysis getSideEffectAnalysis() {
0484: if (!hasSideEffectAnalysis()) {
0485: setSideEffectAnalysis(new SideEffectAnalysis(
0486: getPointsToAnalysis(), getCallGraph()));
0487: }
0488:
0489: return activeSideEffectAnalysis;
0490: }
0491:
0492: /**
0493: Sets the active side-effect analysis
0494: */
0495:
0496: public void setSideEffectAnalysis(SideEffectAnalysis sea) {
0497: activeSideEffectAnalysis = sea;
0498: }
0499:
0500: public boolean hasSideEffectAnalysis() {
0501: return activeSideEffectAnalysis != null;
0502: }
0503:
0504: public void releaseSideEffectAnalysis() {
0505: activeSideEffectAnalysis = null;
0506: }
0507:
0508: /****************************************************************************/
0509: /**
0510: Retrieves the active pointer analysis
0511: */
0512:
0513: public PointsToAnalysis getPointsToAnalysis() {
0514: if (!hasPointsToAnalysis()) {
0515: return DumbPointerAnalysis.v();
0516: }
0517:
0518: return activePointsToAnalysis;
0519: }
0520:
0521: /**
0522: Sets the active pointer analysis
0523: */
0524:
0525: public void setPointsToAnalysis(PointsToAnalysis pa) {
0526: activePointsToAnalysis = pa;
0527: }
0528:
0529: public boolean hasPointsToAnalysis() {
0530: return activePointsToAnalysis != null;
0531: }
0532:
0533: public void releasePointsToAnalysis() {
0534: activePointsToAnalysis = null;
0535: }
0536:
0537: /****************************************************************************/
0538: /** Makes a new fast hierarchy is none is active, and returns the active
0539: * fast hierarchy. */
0540: public FastHierarchy getOrMakeFastHierarchy() {
0541: if (!hasFastHierarchy()) {
0542: setFastHierarchy(new FastHierarchy());
0543: }
0544: return getFastHierarchy();
0545: }
0546:
0547: /**
0548: Retrieves the active fast hierarchy
0549: */
0550:
0551: public FastHierarchy getFastHierarchy() {
0552: if (!hasFastHierarchy())
0553: throw new RuntimeException(
0554: "no active FastHierarchy present for scene");
0555:
0556: return activeFastHierarchy;
0557: }
0558:
0559: /**
0560: Sets the active hierarchy
0561: */
0562:
0563: public void setFastHierarchy(FastHierarchy hierarchy) {
0564: activeFastHierarchy = hierarchy;
0565: }
0566:
0567: public boolean hasFastHierarchy() {
0568: return activeFastHierarchy != null;
0569: }
0570:
0571: public void releaseFastHierarchy() {
0572: activeFastHierarchy = null;
0573: }
0574:
0575: /****************************************************************************/
0576: /**
0577: Retrieves the active hierarchy
0578: */
0579:
0580: public Hierarchy getActiveHierarchy() {
0581: if (!hasActiveHierarchy())
0582: //throw new RuntimeException("no active Hierarchy present for scene");
0583: setActiveHierarchy(new Hierarchy());
0584:
0585: return activeHierarchy;
0586: }
0587:
0588: /**
0589: Sets the active hierarchy
0590: */
0591:
0592: public void setActiveHierarchy(Hierarchy hierarchy) {
0593: activeHierarchy = hierarchy;
0594: }
0595:
0596: public boolean hasActiveHierarchy() {
0597: return activeHierarchy != null;
0598: }
0599:
0600: public void releaseActiveHierarchy() {
0601: activeHierarchy = null;
0602: }
0603:
0604: /** Get the set of entry points that are used to build the call graph. */
0605: public List<SootMethod> getEntryPoints() {
0606: if (entryPoints == null) {
0607: entryPoints = EntryPoints.v().all();
0608: }
0609: return entryPoints;
0610: }
0611:
0612: /** Change the set of entry point methods used to build the call graph. */
0613: public void setEntryPoints(List<SootMethod> entryPoints) {
0614: this .entryPoints = entryPoints;
0615: }
0616:
0617: private ContextSensitiveCallGraph cscg;
0618:
0619: public ContextSensitiveCallGraph getContextSensitiveCallGraph() {
0620: if (cscg == null)
0621: throw new RuntimeException(
0622: "No context-sensitive call graph present in Scene. You can bulid one with Paddle.");
0623: return cscg;
0624: }
0625:
0626: public void setContextSensitiveCallGraph(
0627: ContextSensitiveCallGraph cscg) {
0628: this .cscg = cscg;
0629: }
0630:
0631: public CallGraph getCallGraph() {
0632: if (!hasCallGraph()) {
0633: throw new RuntimeException(
0634: "No call graph present in Scene. Maybe you want Whole Program mode (-w).");
0635: }
0636:
0637: return activeCallGraph;
0638: }
0639:
0640: public void setCallGraph(CallGraph cg) {
0641: reachableMethods = null;
0642: activeCallGraph = cg;
0643: }
0644:
0645: public boolean hasCallGraph() {
0646: return activeCallGraph != null;
0647: }
0648:
0649: public void releaseCallGraph() {
0650: activeCallGraph = null;
0651: reachableMethods = null;
0652: }
0653:
0654: public ReachableMethods getReachableMethods() {
0655: if (reachableMethods == null) {
0656: reachableMethods = new ReachableMethods(getCallGraph(),
0657: new ArrayList<MethodOrMethodContext>(
0658: getEntryPoints()));
0659: }
0660: reachableMethods.update();
0661: return reachableMethods;
0662: }
0663:
0664: public void setReachableMethods(ReachableMethods rm) {
0665: reachableMethods = rm;
0666: }
0667:
0668: public boolean hasReachableMethods() {
0669: return reachableMethods != null;
0670: }
0671:
0672: public void releaseReachableMethods() {
0673: reachableMethods = null;
0674: }
0675:
0676: public boolean getPhantomRefs() {
0677: if (!Options.v().allow_phantom_refs())
0678: return false;
0679: return allowsPhantomRefs;
0680: }
0681:
0682: public void setPhantomRefs(boolean value) {
0683: allowsPhantomRefs = value;
0684: }
0685:
0686: public boolean allowsPhantomRefs() {
0687: return getPhantomRefs();
0688: }
0689:
0690: public Numberer kindNumberer() {
0691: return kindNumberer;
0692: }
0693:
0694: public ArrayNumberer getTypeNumberer() {
0695: return typeNumberer;
0696: }
0697:
0698: public ArrayNumberer getMethodNumberer() {
0699: return methodNumberer;
0700: }
0701:
0702: public Numberer getContextNumberer() {
0703: return contextNumberer;
0704: }
0705:
0706: public Numberer getUnitNumberer() {
0707: return unitNumberer;
0708: }
0709:
0710: public ArrayNumberer getFieldNumberer() {
0711: return fieldNumberer;
0712: }
0713:
0714: public ArrayNumberer getClassNumberer() {
0715: return classNumberer;
0716: }
0717:
0718: public StringNumberer getSubSigNumberer() {
0719: return subSigNumberer;
0720: }
0721:
0722: public ArrayNumberer getLocalNumberer() {
0723: return localNumberer;
0724: }
0725:
0726: public void setContextNumberer(Numberer n) {
0727: if (contextNumberer != null)
0728: throw new RuntimeException(
0729: "Attempt to set context numberer when it is already set.");
0730: contextNumberer = n;
0731: }
0732:
0733: /**
0734: * Returns the {@link ThrowAnalysis} to be used by default when
0735: * constructing CFGs which include exceptional control flow.
0736: *
0737: * @return the default {@link ThrowAnalysis}
0738: */
0739: public ThrowAnalysis getDefaultThrowAnalysis() {
0740: if (defaultThrowAnalysis == null) {
0741: int optionsThrowAnalysis = Options.v().throw_analysis();
0742: switch (optionsThrowAnalysis) {
0743: case Options.throw_analysis_pedantic:
0744: defaultThrowAnalysis = PedanticThrowAnalysis.v();
0745: break;
0746: case Options.throw_analysis_unit:
0747: defaultThrowAnalysis = UnitThrowAnalysis.v();
0748: break;
0749: default:
0750: throw new IllegalStateException(
0751: "Options.v().throw_analysi() == "
0752: + Options.v().throw_analysis());
0753: }
0754: }
0755: return defaultThrowAnalysis;
0756: }
0757:
0758: /**
0759: * Sets the {@link ThrowAnalysis} to be used by default when
0760: * constructing CFGs which include exceptional control flow.
0761: *
0762: * @param the default {@link ThrowAnalysis}.
0763: */
0764: public void setDefaultThrowAnalysis(ThrowAnalysis ta) {
0765: defaultThrowAnalysis = ta;
0766: }
0767:
0768: private void setReservedNames() {
0769: Set<String> rn = getReservedNames();
0770: rn.add("newarray");
0771: rn.add("newmultiarray");
0772: rn.add("nop");
0773: rn.add("ret");
0774: rn.add("specialinvoke");
0775: rn.add("staticinvoke");
0776: rn.add("tableswitch");
0777: rn.add("virtualinvoke");
0778: rn.add("null_type");
0779: rn.add("unknown");
0780: rn.add("cmp");
0781: rn.add("cmpg");
0782: rn.add("cmpl");
0783: rn.add("entermonitor");
0784: rn.add("exitmonitor");
0785: rn.add("interfaceinvoke");
0786: rn.add("lengthof");
0787: rn.add("lookupswitch");
0788: rn.add("neg");
0789: rn.add("if");
0790: rn.add("abstract");
0791: rn.add("boolean");
0792: rn.add("break");
0793: rn.add("byte");
0794: rn.add("case");
0795: rn.add("catch");
0796: rn.add("char");
0797: rn.add("class");
0798: rn.add("final");
0799: rn.add("native");
0800: rn.add("public");
0801: rn.add("protected");
0802: rn.add("private");
0803: rn.add("static");
0804: rn.add("synchronized");
0805: rn.add("transient");
0806: rn.add("volatile");
0807: rn.add("interface");
0808: rn.add("void");
0809: rn.add("short");
0810: rn.add("int");
0811: rn.add("long");
0812: rn.add("float");
0813: rn.add("double");
0814: rn.add("extends");
0815: rn.add("implements");
0816: rn.add("breakpoint");
0817: rn.add("default");
0818: rn.add("goto");
0819: rn.add("instanceof");
0820: rn.add("new");
0821: rn.add("return");
0822: rn.add("throw");
0823: rn.add("throws");
0824: rn.add("null");
0825: rn.add("from");
0826: rn.add("to");
0827: }
0828:
0829: private final Set<String>[] basicclasses = new Set[4];
0830:
0831: private void addSootBasicClasses() {
0832: basicclasses[SootClass.HIERARCHY] = new HashSet<String>();
0833: basicclasses[SootClass.SIGNATURES] = new HashSet<String>();
0834: basicclasses[SootClass.BODIES] = new HashSet<String>();
0835:
0836: addBasicClass("java.lang.Object");
0837: addBasicClass("java.lang.Class", SootClass.SIGNATURES);
0838:
0839: addBasicClass("java.lang.Void", SootClass.SIGNATURES);
0840: addBasicClass("java.lang.Boolean", SootClass.SIGNATURES);
0841: addBasicClass("java.lang.Byte", SootClass.SIGNATURES);
0842: addBasicClass("java.lang.Character", SootClass.SIGNATURES);
0843: addBasicClass("java.lang.Short", SootClass.SIGNATURES);
0844: addBasicClass("java.lang.Integer", SootClass.SIGNATURES);
0845: addBasicClass("java.lang.Long", SootClass.SIGNATURES);
0846: addBasicClass("java.lang.Float", SootClass.SIGNATURES);
0847: addBasicClass("java.lang.Double", SootClass.SIGNATURES);
0848:
0849: addBasicClass("java.lang.String");
0850: addBasicClass("java.lang.StringBuffer", SootClass.SIGNATURES);
0851:
0852: addBasicClass("java.lang.Error");
0853: addBasicClass("java.lang.AssertionError", SootClass.SIGNATURES);
0854: addBasicClass("java.lang.Throwable", SootClass.SIGNATURES);
0855: addBasicClass("java.lang.NoClassDefFoundError",
0856: SootClass.SIGNATURES);
0857: addBasicClass("java.lang.ExceptionInInitializerError");
0858: addBasicClass("java.lang.RuntimeException");
0859: addBasicClass("java.lang.ClassNotFoundException");
0860: addBasicClass("java.lang.ArithmeticException");
0861: addBasicClass("java.lang.ArrayStoreException");
0862: addBasicClass("java.lang.ClassCastException");
0863: addBasicClass("java.lang.IllegalMonitorStateException");
0864: addBasicClass("java.lang.IndexOutOfBoundsException");
0865: addBasicClass("java.lang.ArrayIndexOutOfBoundsException");
0866: addBasicClass("java.lang.NegativeArraySizeException");
0867: addBasicClass("java.lang.NullPointerException");
0868: addBasicClass("java.lang.InstantiationError");
0869: addBasicClass("java.lang.InternalError");
0870: addBasicClass("java.lang.OutOfMemoryError");
0871: addBasicClass("java.lang.StackOverflowError");
0872: addBasicClass("java.lang.UnknownError");
0873: addBasicClass("java.lang.ThreadDeath");
0874: addBasicClass("java.lang.ClassCircularityError");
0875: addBasicClass("java.lang.ClassFormatError");
0876: addBasicClass("java.lang.IllegalAccessError");
0877: addBasicClass("java.lang.IncompatibleClassChangeError");
0878: addBasicClass("java.lang.LinkageError");
0879: addBasicClass("java.lang.VerifyError");
0880: addBasicClass("java.lang.NoSuchFieldError");
0881: addBasicClass("java.lang.AbstractMethodError");
0882: addBasicClass("java.lang.NoSuchMethodError");
0883: addBasicClass("java.lang.UnsatisfiedLinkError");
0884:
0885: addBasicClass("java.lang.Thread");
0886: addBasicClass("java.lang.Runnable");
0887: addBasicClass("java.lang.Cloneable");
0888:
0889: addBasicClass("java.io.Serializable");
0890:
0891: addBasicClass("java.lang.ref.Finalizer");
0892: }
0893:
0894: public void addBasicClass(String name) {
0895: addBasicClass(name, SootClass.HIERARCHY);
0896: }
0897:
0898: public void addBasicClass(String name, int level) {
0899: basicclasses[level].add(name);
0900: }
0901:
0902: /** Load just the set of basic classes soot needs, ignoring those
0903: * specified on the command-line. You don't need to use both this and
0904: * loadNecessaryClasses, though it will only waste time.
0905: */
0906: public void loadBasicClasses() {
0907: Iterator it;
0908:
0909: for (int i = SootClass.BODIES; i >= SootClass.HIERARCHY; i--) {
0910: it = basicclasses[i].iterator();
0911: while (it.hasNext()) {
0912: String name = (String) it.next();
0913: tryLoadClass(name, i);
0914: }
0915: }
0916: }
0917:
0918: private List<SootClass> dynamicClasses;
0919:
0920: public Collection<SootClass> dynamicClasses() {
0921: return dynamicClasses;
0922: }
0923:
0924: private void loadNecessaryClass(String name) {
0925: SootClass c;
0926:
0927: c = Scene.v().loadClassAndSupport(name);
0928:
0929: if (mainClass == null) {
0930: mainClass = c;
0931: Scene.v().setMainClass(c);
0932: }
0933: c.setApplicationClass();
0934: }
0935:
0936: /** Load the set of classes that soot needs, including those specified on the
0937: * command-line. This is the standard way of initialising the list of
0938: * classes soot should use.
0939: */
0940: public void loadNecessaryClasses() {
0941: loadBasicClasses();
0942:
0943: Iterator<String> it = Options.v().classes().iterator();
0944:
0945: while (it.hasNext()) {
0946: String name = (String) it.next();
0947: loadNecessaryClass(name);
0948: }
0949:
0950: loadDynamicClasses();
0951:
0952: for (Iterator<String> pathIt = Options.v().process_dir()
0953: .iterator(); pathIt.hasNext();) {
0954:
0955: final String path = (String) pathIt.next();
0956: for (String cl : SourceLocator.v().getClassesUnder(path)) {
0957: Scene.v().loadClassAndSupport(cl).setApplicationClass();
0958: }
0959: }
0960:
0961: prepareClasses();
0962: setDoneResolving();
0963: }
0964:
0965: public void loadDynamicClasses() {
0966: dynamicClasses = new ArrayList<SootClass>();
0967: HashSet<String> dynClasses = new HashSet<String>();
0968: dynClasses.addAll(Options.v().dynamic_class());
0969:
0970: for (Iterator<String> pathIt = Options.v().dynamic_dir()
0971: .iterator(); pathIt.hasNext();) {
0972:
0973: final String path = (String) pathIt.next();
0974: dynClasses.addAll(SourceLocator.v().getClassesUnder(path));
0975: }
0976:
0977: for (Iterator<String> pkgIt = Options.v().dynamic_package()
0978: .iterator(); pkgIt.hasNext();) {
0979:
0980: final String pkg = (String) pkgIt.next();
0981: dynClasses.addAll(SourceLocator.v()
0982: .classesInDynamicPackage(pkg));
0983: }
0984:
0985: for (String className : dynClasses) {
0986:
0987: dynamicClasses
0988: .add(Scene.v().loadClassAndSupport(className));
0989: }
0990: }
0991:
0992: /* Generate classes to process, adding or removing package marked by
0993: * command line options.
0994: */
0995: private void prepareClasses() {
0996:
0997: LinkedList<String> excludedPackages = new LinkedList<String>();
0998: if (Options.v().exclude() != null)
0999: excludedPackages.addAll(Options.v().exclude());
1000:
1001: if (!Options.v().include_all()) {
1002: excludedPackages.add("java.");
1003: excludedPackages.add("sun.");
1004: excludedPackages.add("javax.");
1005: excludedPackages.add("com.sun.");
1006: excludedPackages.add("com.ibm.");
1007: excludedPackages.add("org.xml.");
1008: excludedPackages.add("org.w3c.");
1009: excludedPackages.add("org.apache.");
1010: }
1011:
1012: // Remove/add all classes from packageInclusionMask as per -i option
1013: Set<SootClass> processedClasses = new HashSet<SootClass>();
1014: while (true) {
1015: Set<SootClass> unprocessedClasses = new HashSet<SootClass>(
1016: Scene.v().getClasses());
1017: unprocessedClasses.removeAll(processedClasses);
1018: if (unprocessedClasses.isEmpty())
1019: break;
1020: processedClasses.addAll(unprocessedClasses);
1021: for (SootClass s : unprocessedClasses) {
1022: if (s.isPhantom())
1023: continue;
1024: if (Options.v().app()) {
1025: s.setApplicationClass();
1026: }
1027: if (Options.v().classes().contains(s.getName())) {
1028: s.setApplicationClass();
1029: continue;
1030: }
1031: for (Iterator<String> pkgIt = excludedPackages
1032: .iterator(); pkgIt.hasNext();) {
1033: final String pkg = (String) pkgIt.next();
1034: if (s.isApplicationClass()
1035: && s.getPackageName().startsWith(pkg)) {
1036: s.setLibraryClass();
1037: }
1038: }
1039: for (Iterator<String> pkgIt = Options.v().include()
1040: .iterator(); pkgIt.hasNext();) {
1041: final String pkg = (String) pkgIt.next();
1042: if (s.getPackageName().startsWith(pkg))
1043: s.setApplicationClass();
1044: }
1045: if (s.isApplicationClass()) {
1046: // make sure we have the support
1047: Scene.v().loadClassAndSupport(s.getName());
1048: }
1049: }
1050: }
1051: }
1052:
1053: ArrayList<String> pkgList;
1054:
1055: public void setPkgList(ArrayList<String> list) {
1056: pkgList = list;
1057: }
1058:
1059: public ArrayList<String> getPkgList() {
1060: return pkgList;
1061: }
1062:
1063: /** Create an unresolved reference to a method. */
1064: public SootMethodRef makeMethodRef(SootClass declaringClass,
1065: String name, List<Type> parameterTypes, Type returnType,
1066: boolean isStatic) {
1067: return new AbstractSootMethodRef(declaringClass, name,
1068: parameterTypes, returnType, isStatic);
1069: }
1070:
1071: /** Create an unresolved reference to a constructor. */
1072: public SootMethodRef makeConstructorRef(SootClass declaringClass,
1073: List<Type> parameterTypes) {
1074: return makeMethodRef(declaringClass,
1075: SootMethod.constructorName, parameterTypes, VoidType
1076: .v(), false);
1077: }
1078:
1079: /** Create an unresolved reference to a field. */
1080: public SootFieldRef makeFieldRef(SootClass declaringClass,
1081: String name, Type type, boolean isStatic) {
1082: return new AbstractSootFieldRef(declaringClass, name, type,
1083: isStatic);
1084: }
1085:
1086: /** Returns the list of SootClasses that have been resolved at least to
1087: * the level specified. */
1088: public List/*SootClass*/<SootClass> getClasses(int desiredLevel) {
1089: List<SootClass> ret = new ArrayList<SootClass>();
1090: for (Iterator<SootClass> clIt = getClasses().iterator(); clIt
1091: .hasNext();) {
1092: final SootClass cl = (SootClass) clIt.next();
1093: if (cl.resolvingLevel() >= desiredLevel)
1094: ret.add(cl);
1095: }
1096: return ret;
1097: }
1098:
1099: private boolean doneResolving = false;
1100:
1101: public boolean doneResolving() {
1102: return doneResolving;
1103: }
1104:
1105: public void setDoneResolving() {
1106: doneResolving = true;
1107: }
1108:
1109: public void setMainClassFromOptions() {
1110: if (mainClass != null)
1111: return;
1112: if (Options.v().main_class() != null
1113: && Options.v().main_class().length() > 0) {
1114: setMainClass(getSootClass(Options.v().main_class()));
1115: } else {
1116: // try to infer a main class if none is given
1117: for (Iterator<SootClass> classIter = getApplicationClasses()
1118: .iterator(); classIter.hasNext();) {
1119: SootClass c = (SootClass) classIter.next();
1120: if (c.declaresMethod("main", new SingletonList(
1121: ArrayType.v(RefType.v("java.lang.String"), 1)),
1122: VoidType.v())) {
1123: G.v().out.println("No main class given. Inferred '"
1124: + c.getName() + "' as main class.");
1125: setMainClass(c);
1126: break;
1127: }
1128: }
1129: }
1130: }
1131: }
|