package jqian.slicer.core;
import java.io.PrintStream;
import java.util.*;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import jqian.Global;
import jqian.slicer.plugin.*;
import jqian.slicer.view.*;
import jqian.util.*;
import jqian.util.eclipse.ConsoleUtil;
import jqian.slicer.plugin.view.*;
import jqian.sootex.dependency.pdg.DependenceGraphHelper;
import jqian.sootex.dependency.pdg.DepGraphOptions;
import jqian.sootex.dependency.pdg.SDG;
import jqian.sootex.ptsto.IPtsToQuery;
import jqian.sootex.ptsto.NaivePtsToQuery;
import jqian.sootex.ptsto.PointsToAnalysisType;
import jqian.sootex.ptsto.SparkPtsToQuery;
import jqian.sootex.ptsto.TypeBasedPointsToAnalysis;
import jqian.sootex.ptsto.TypeBasedPtsToQuery;
import jqian.sootex.sideeffect.ISideEffectAnalysis;
import jqian.sootex.sideeffect.SideEffectAnalysis;
import jqian.sootex.sideeffect.SideEffectAnalysisEx;
import jqian.sootex.util.SootUtils;
import jqian.sootex.util.callgraph.CallGraphRefiner;
import soot.*;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.CallGraphBuilder;
import soot.jimple.toolkits.pointer.DumbPointerAnalysis;
import soot.options.Options;
public class SDGConstructor implements Runnable{
private String _prjEntry;
private String _sdgEntry;
private String _classpath;
private String _temppath;
private SlicerOptions _options;
private SlithiceSlicer _slicer;
/**
* @param sdgEntry Currently, this parameter is not actually used
*/
public SDGConstructor(SlithiceSlicer slicer,String prjEntry,String sdgEntry,
String classpath, String temppath,SlicerOptions options){
this._prjEntry = prjEntry;
this._sdgEntry = sdgEntry;
this._slicer = slicer;
this._classpath = classpath;
this._temppath = temppath;
this._options = options;
}
private void loadSootClasses(){
Date startTime = new Date();
Options.v().set_whole_program(true);
Options.v().set_app(true);
Options.v().set_verbose(false);
Options.v().set_soot_classpath(_classpath);
Options.v().set_output_dir( _temppath);
Options.v().set_output_format(Options.output_format_none);
Options.v().set_keep_line_number(true);
Options.v().set_print_tags_in_output(true);
Options.v().setPhaseOption("jb", "use-original-names:true");
PhaseOptions.v().setPhaseOption("jb", "use-original-names:true");
//Options.v().set_validate(true);
//load classes for analysis
SootUtils.loadClassesForEntry(_prjEntry);
SootUtils.numberClassAndFields();
Date endTime=new Date();
Global.v().out.println("["+ID.DISPLAY_NAME+"] Load " + Scene.v().getClasses().size() +
" soot classes in "+ Utils.getTimeConsumed(startTime,endTime));
}
private IPtsToQuery doPointsToAnalysis(){
// do points-to analysis
if(_options.pointToAnalysis==PointsToAnalysisType.SPARK){
Date startTime = new Date();
Map<String,String> opt = new HashMap<String,String>();
if(_options.simplifyCallGraph){
opt.put("simulate-natives","false");
opt.put("implicit-entry","false");
}
SootUtils.doSparkPointsToAnalysis(opt);
Date endTime = new Date();
Global.v().out.println("["+ID.DISPLAY_NAME+"] Finish points-to analysis in "+ Utils.getTimeConsumed(startTime,endTime));
// simplify call graph, ignore method not reachable from main entry
// ignore implicit calls (except thread calls)
CallGraph cg = Scene.v().getCallGraph();
PointsToAnalysis ptsTo = Scene.v().getPointsToAnalysis();
CallGraphRefiner refiner = new CallGraphRefiner(ptsTo, false);
CallGraph newCg = refiner.refine(cg, new CallGraphRefiner.AggressiveCallGraphFilter());
Scene.v().setCallGraph(newCg);
Scene.v().setReachableMethods(null); //update reachable methods
return new SparkPtsToQuery();
}
else if(_options.pointToAnalysis==PointsToAnalysisType.TYPE_BASED){
// build a CHA call graph
CallGraphBuilder cg = new CallGraphBuilder( DumbPointerAnalysis.v() );
cg.build();
// use type-based points-to analysis instead
PointsToAnalysis pta = TypeBasedPointsToAnalysis.v(false);
Scene.v().setPointsToAnalysis(pta);
return new TypeBasedPtsToQuery(false);
}
else if(_options.pointToAnalysis==PointsToAnalysisType.NAIVE){
PointsToAnalysis pta = DumbPointerAnalysis.v();
// build a CHA call graph
CallGraphBuilder cg = new CallGraphBuilder(pta);
cg.build();
Scene.v().setPointsToAnalysis(pta);
return new NaivePtsToQuery();
}
else{
throw new RuntimeException("["+ID.DISPLAY_NAME+"] constructSDG() error: points-to analysis="+ _options.pointToAnalysis + " unsupported.");
}
}
public ISideEffectAnalysis doSideEffectAnalysis(IPtsToQuery ptsto, SootMethod entry){
Collection<SootMethod> entries = new ArrayList<SootMethod>(1);
entries.add(entry);
// collect method side-effects
SideEffectAnalysis se = new SideEffectAnalysis(ptsto,entries, _options.heapAbstraction);
//SideEffectAnalysisEx se = new SideEffectAnalysisEx(ptsto,entries, _options.heapAbstraction);
se.build();
return se;
}
private SDG constructSDG(){
// get entry method for SDG construction
SootMethod entry = null;
if(_sdgEntry!=null){
entry = Scene.v().getMethod(_sdgEntry);
}
else{
entry = (SootMethod)Scene.v().getEntryPoints().get(0);
}
Global.v().out.println("\n["+ID.DISPLAY_NAME+"] Constructing system dependence graph(SDG) ... ");
Date startTime = new Date();
// points-to analysis
IPtsToQuery ptsto = doPointsToAnalysis();
_slicer.setPtsToQuery(ptsto);
// side-effect analysis
ISideEffectAnalysis se = doSideEffectAnalysis(ptsto, entry);
// dependence graph construction
DepGraphOptions opts = new DepGraphOptions(true, _options.distinguishDULocInDepEdges, _options.sdgFormalActualOption);
SDG sdg = DependenceGraphHelper.constructSDG(ptsto, _options.heapAbstraction, se, entry, opts, true, _options.libTracingDepth);
Date endTime = new Date();
Global.v().out.println("["+ID.DISPLAY_NAME+"] SDG successfully constructed in "+ Utils.getTimeConsumed(startTime,endTime));
return sdg;
}
private void showSDGReadyMessage(){
class ShowMsg implements Runnable{
public void run(){
Shell shell = WorkbenchHelper.getActiveShell();
BalloonMessage.showMessage(shell,ID.DISPLAY_NAME,"Dependence graph ready, slicing can be performed now.");
}
}
IWorkbench workbench = PlatformUI.getWorkbench();
workbench.getDisplay().syncExec(new ShowMsg());
}
private void showSDG(SDG sdg){
String filename = _temppath + "/sdg.dot";
String dotpath = _options.dotpath;
Global.v().out.print("\n["+ID.DISPLAY_NAME+"] Doting SDG file (can be very slow for large SDG): "+filename+" ... ...");
DependenceGraphHelper.dotDependenceGraph(sdg, dotpath, filename, false);
//DependenceGraphHelper.showDependenceGraphByJGraph(sdg, "SDG");
Global.v().out.print("OK\n");
ImageView.showImage(filename+".jpg");
}
public void run(){
//clean soot
SootUtils.resetSoot();
// redirect output to the specified console
PrintStream out = ConsoleUtil.getConsoleOutputStream(ID.CONSOLE);
Global.v().out = out;
loadSootClasses();
// resetting previous analysis results
Global.v().reset();
Global.v().out = out;
SDG sdg = constructSDG();
//assign the constructed SDG to the slicer
_slicer.setSDG(sdg);
//show SDG ready
showSDGReadyMessage();
//show SDG
boolean showSDG = _options.showJimpleSDG;
if(showSDG){
showSDG(sdg);
}
}
}