WALA/com.ibm.wala.core/src/com/ibm/wala/client/AbstractAnalysisEngine.java

312 lines
9.2 KiB
Java

/*******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.client;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.jar.JarFile;
import com.ibm.wala.analysis.pointers.BasicHeapGraph;
import com.ibm.wala.analysis.pointers.HeapGraph;
import com.ibm.wala.classLoader.ClassLoaderFactory;
import com.ibm.wala.classLoader.ClassLoaderFactoryImpl;
import com.ibm.wala.classLoader.JarFileModule;
import com.ibm.wala.classLoader.Module;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.CallGraphBuilder;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.impl.Util;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.DefaultIRFactory;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
import com.ibm.wala.util.config.AnalysisScopeReader;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.io.FileProvider;
/**
* Abstract base class for analysis engine implementations
*
* Some clients choose to build on this, but many don't. I usually don't in new code; I usually don't find the re-use enabled by
* this class compelling. I would probably nuke this except for some legacy code that uses it.
*/
public abstract class AbstractAnalysisEngine implements AnalysisEngine {
public interface EntrypointBuilder {
Iterable<Entrypoint> createEntrypoints(AnalysisScope scope, IClassHierarchy cha);
}
public final static String SYNTHETIC_J2SE_MODEL = "SyntheticJ2SEModel.txt";
/**
* DEBUG_LEVEL:
* <ul>
* <li>0 No output
* <li>1 Print some simple stats and warning information
* <li>2 Detailed debugging
* </ul>
*/
protected static final int DEBUG_LEVEL = 1;
/**
* Name of the file which holds the class hierarchy exclusions directives for this analysis.
*/
private String exclusionsFile = "J2SEClassHierarchyExclusions.txt";
/**
* The modules to analyze
*/
protected Collection<Module> moduleFiles;
/**
* A representation of the analysis scope
*/
protected AnalysisScope scope;
/**
* A representation of the analysis options
*/
private AnalysisOptions options;
/**
* A cache of IRs and stuff
*/
private AnalysisCache cache = makeDefaultCache();
/**
* The standard J2SE libraries to analyze
*/
protected Module[] j2seLibs;
/**
* Whether to perform closed-world analysis of an application
*/
private boolean closedWorld = false;
/**
* Governing class hierarchy
*/
private IClassHierarchy cha;
/**
* Governing call graph
*/
protected CallGraph cg;
/**
* Results of pointer analysis
*/
protected PointerAnalysis pointerAnalysis;
/**
* Graph view of flow of pointers between heap abstractions
*/
private HeapGraph heapGraph;
private EntrypointBuilder entrypointBuilder = new EntrypointBuilder() {
public Iterable<Entrypoint> createEntrypoints(AnalysisScope scope, IClassHierarchy cha) {
return makeDefaultEntrypoints(scope, cha);
}
};
protected abstract CallGraphBuilder getCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache);
protected CallGraphBuilder buildCallGraph(IClassHierarchy cha, AnalysisOptions options, boolean savePointerAnalysis,
IProgressMonitor monitor) throws IllegalArgumentException, CancelException {
CallGraphBuilder builder = getCallGraphBuilder(cha, options, cache);
cg = builder.makeCallGraph(options, monitor);
if (savePointerAnalysis) {
pointerAnalysis = builder.getPointerAnalysis();
}
return builder;
}
public void setModuleFiles(Collection moduleFiles) {
this.moduleFiles = moduleFiles;
}
/**
* Set up the AnalysisScope object
*
* @throws IOException
*/
public void buildAnalysisScope() throws IOException {
if (j2seLibs == null) {
Assertions.UNREACHABLE("no j2selibs specified. You probably did not call AppAnalysisEngine.setJ2SELibrary.");
}
scope = AnalysisScopeReader.readJavaScope(SYNTHETIC_J2SE_MODEL, (new FileProvider()).getFile(getExclusionsFile()), getClass()
.getClassLoader());
// add standard libraries
for (int i = 0; i < j2seLibs.length; i++) {
scope.addToScope(scope.getPrimordialLoader(), j2seLibs[i]);
}
// add user stuff
addApplicationModulesToScope();
}
/**
* @return a IClassHierarchy object for this analysis scope
*/
public IClassHierarchy buildClassHierarchy() {
IClassHierarchy cha = null;
ClassLoaderFactory factory = new ClassLoaderFactoryImpl(getScope().getExclusions());
try {
cha = ClassHierarchy.make(getScope(), factory);
} catch (ClassHierarchyException e) {
System.err.println("Class Hierarchy construction failed");
System.err.println(e.toString());
e.printStackTrace();
}
return cha;
}
public IClassHierarchy getClassHierarchy() {
return cha;
}
protected void setClassHierarchy(IClassHierarchy cha) {
this.cha = cha;
}
/**
* @return Returns the call graph
*/
protected CallGraph getCallGraph() {
return cg;
}
/**
* Add the application modules to the analysis scope.
*/
protected void addApplicationModulesToScope() {
ClassLoaderReference app = scope.getApplicationLoader();
for (Iterator it = moduleFiles.iterator(); it.hasNext();) {
Object o = it.next();
if (!(o instanceof Module)) {
Assertions.UNREACHABLE("Unexpected type: " + o.getClass());
}
Module M = (Module) o;
scope.addToScope(app, M);
}
}
public void setJ2SELibraries(JarFile[] libs) {
if (libs == null) {
throw new IllegalArgumentException("libs is null");
}
this.j2seLibs = new Module[libs.length];
for (int i = 0; i < libs.length; i++) {
j2seLibs[i] = new JarFileModule(libs[i]);
}
}
public void setJ2SELibraries(Module[] libs) {
if (libs == null) {
throw new IllegalArgumentException("libs is null");
}
this.j2seLibs = new Module[libs.length];
for (int i = 0; i < libs.length; i++) {
j2seLibs[i] = libs[i];
}
}
public void setClosedWorld(boolean b) {
this.closedWorld = b;
}
public boolean isClosedWorld() {
return closedWorld;
}
protected AnalysisScope getScope() {
return scope;
}
public PointerAnalysis getPointerAnalysis() {
return pointerAnalysis;
}
public HeapGraph getHeapGraph() {
if (heapGraph == null) {
heapGraph = new BasicHeapGraph(getPointerAnalysis(), cg);
}
return heapGraph;
}
public String getExclusionsFile() {
return exclusionsFile;
}
public void setExclusionsFile(String exclusionsFile) {
this.exclusionsFile = exclusionsFile;
}
public AnalysisOptions getDefaultOptions(Iterable<Entrypoint> entrypoints) {
return new AnalysisOptions(getScope(), entrypoints);
}
public AnalysisCache makeDefaultCache() {
return new AnalysisCache(new DefaultIRFactory());
}
protected Iterable<Entrypoint> makeDefaultEntrypoints(AnalysisScope scope, IClassHierarchy cha) {
return Util.makeMainEntrypoints(scope, cha);
}
public void setEntrypointBuilder(EntrypointBuilder builder) {
entrypointBuilder = builder;
}
/**
* Builds the call graph for the analysis scope in effect, using all of the given entry points.
*
* @throws CancelException
* @throws IllegalArgumentException
* @throws IOException
*/
public CallGraphBuilder defaultCallGraphBuilder() throws IllegalArgumentException, CancelException, IOException {
buildAnalysisScope();
IClassHierarchy cha = buildClassHierarchy();
setClassHierarchy(cha);
Iterable<Entrypoint> eps = entrypointBuilder.createEntrypoints(scope, cha);
options = getDefaultOptions(eps);
cache = makeDefaultCache();
return buildCallGraph(cha, options, true, null);
}
public CallGraph buildDefaultCallGraph() throws IllegalArgumentException, CancelException, IOException {
return defaultCallGraphBuilder().makeCallGraph(options, null);
}
public AnalysisCache getCache() {
return cache;
}
public AnalysisOptions getOptions() {
return options;
}
}