package test;
import java.io.*;
import java.util.*;
import soot.*;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.CallGraphBuilder;
import soot.jimple.toolkits.pointer.DumbPointerAnalysis;
import soot.options.Options;
import soot.toolkits.graph.BriefUnitGraph;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.UnitGraph;
import jqian.sootex.CFGProvider;
import jqian.sootex.Cache;
import jqian.sootex.dependency.pdg.*;
import jqian.sootex.dependency.pdg.builder.AbstractPDGBuilder;
import jqian.sootex.dependency.pdg.builder.UnsafePDGBuilder;
import jqian.sootex.du.DUBuilder;
import jqian.sootex.du.IGlobalDUQuery;
import jqian.sootex.du.IReachingDUQuery;
import jqian.sootex.location.HeapAbstraction;
import jqian.sootex.ptsto.IPtsToQuery;
import jqian.sootex.sideeffect.*;
import jqian.sootex.util.CFGViewer;
import jqian.sootex.util.HammockCFG;
import jqian.sootex.util.SootUtils;
import jqian.sootex.util.callgraph.CallGraphRefiner;
import jqian.sootex.util.callgraph.DirectedCallGraph;
import jqian.sootex.util.graph.GraphHelper;
import jqian.util.Configurator;
import jqian.util.PathUtils;
import jqian.util.Utils;
import jqian.util.CollectionUtils;
import jqian.util.dot.DotViewer;
import jqian.util.dot.GrappaGraph;
import jqian.util.graph.Graph;
import jqian.util.jgraphx.GraphViewer;
/**
* @author bruteforce
*
*/
public class Test {
public static Properties _config;
public static boolean _debug;
public static boolean _verbose;
public static PrintStream out = System.out;
public final static String DEFAULT_CONFIG_FILE = "/config.xml";
public static Properties loadConfig(String configFile){
Configurator conf = new Configurator();
File file = new File(configFile);
if(file.isAbsolute()){
_config = conf.parse(configFile);
}
else{
InputStream is = Test.class.getResourceAsStream(configFile);
_config = conf.parse(is);
}
_debug = Boolean.valueOf(_config.getProperty("debug"));
_verbose = Boolean.valueOf(_config.getProperty("verbose"));
return _config;
}
public static void setDefaultSootOptions(Properties config, boolean isWholeProgramAnalysis, boolean inShimple){
String jdkPath = _config.getProperty("jdk_path");
String classpath = _config.getProperty("classpath");
String outputDir = "./output/soot";
File file = new File(outputDir);
file.mkdirs();
//clearDirectory(outputDir);
classpath = PathUtils.getJreClasspath(jdkPath) + ";" + classpath;
if(isWholeProgramAnalysis){
if(inShimple){
Options.v().set_whole_shimple(true);
Options.v().set_via_shimple(true);
}
else{
Options.v().set_whole_program(isWholeProgramAnalysis);
}
}
Options.v().set_verbose(false);
Options.v().set_soot_classpath(classpath);
Options.v().set_output_dir(outputDir);
Options.v().set_output_format(Options.output_format_none);
Options.v().set_keep_line_number(true);
//Options.v().print_tags_in_output();
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);
}
public static Collection<SootClass> loadClasses(boolean isWholeProgramAnalysis){
Date startTime = new Date();
setDefaultSootOptions(_config, isWholeProgramAnalysis, false);
//load classes for analysis
String entryClass = _config.getProperty("entry_class");
SootUtils.loadClassesForEntry(entryClass);
Date endTime=new Date();
Test.out.println("Load " + Scene.v().getClasses().size() + " soot classes in "+ Utils.getTimeConsumed(startTime,endTime));
SootUtils.numberClassAndFields();
return Scene.v().getClasses();
}
public static void printCollection(Iterator<?> first,String separator){
String str = CollectionUtils.toString(first,separator);
Test.out.print(str);
}
public static void dotView(String dotfilename){
DotViewer dotView = new DotViewer(_config.getProperty("dot"),dotfilename);
dotView.dotIt();
dotView.view();
}
public static void showGraph(Graph graph, String tool){
if(tool.equals("dot")){
String dotfilename= "./output/dot/"+graph.getTitle()+".dot";
dotfilename = PathUtils.toValidFilepath(dotfilename);
GrappaGraph ggraph = new GrappaGraph(graph);
ggraph.saveToDot(dotfilename);
DotViewer dotView = new DotViewer(_config.getProperty("dot"),dotfilename);
dotView.dotIt();
dotView.view();
}
else if(tool.equals("jgraph")){
GraphViewer frame = new GraphViewer(graph);
frame.setSize(1000, 700);
frame.setVisible(true);
}
}
public static void showCFG(SootMethod m, DirectedGraph<Unit> ucfg, String tool){
CFGViewer viewer = new CFGViewer(m,ucfg);
Graph cfg = viewer.makeJimpleCFG();
cfg.setTitle("jimple_"+m.getName());
showGraph(cfg, tool);
}
public static void showCFG(SootMethod m, String tool){
Body body = m.getActiveBody();
DirectedGraph<Unit> ucfg=new BriefUnitGraph(body);
showCFG(m, ucfg, tool);
}
public static void showCFG(SootMethod m){
showCFG(m, "jgraph");
}
public static void printBody(Body body){
for(Unit s: body.getUnits()){
int line = SootUtils.getLine(s);
Test.out.println(""+line+": " + s);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void showCallGraph(CallGraph cg){
List entries = Scene.v().getEntryPoints();
DirectedGraph dcg = new DirectedCallGraph(cg, entries);
Graph displayedCallgraph = GraphHelper.toDisplayGraph(dcg, "Call Graph");
showGraph(displayedCallgraph, "jgraph");
}
public static void buildCHACallGraph(){
List<SootMethod> entries = EntryPoints.v().application();
entries = entries.subList(0, 1);
Scene.v().setEntryPoints(entries);
//PhaseOptions.v().setPhaseOption("cg", "implicit-entry:false");
//PhaseOptions.v().setPhaseOption("cg.spark", "simulate-natives:false");
Date startTime = new Date();
CallGraphBuilder cg = new CallGraphBuilder( DumbPointerAnalysis.v() );
cg.build();
Date endTime=new Date();
System.out.println("[Call Graph] Call graph built in "+ Utils.getTimeConsumed(startTime,endTime)
+ ", " + Scene.v().getReachableMethods().size() +" methods reachable.");
}
public static void doFastSparkPointsToAnalysis() {
Map<String,String> opt = new HashMap<String,String>();
opt.put("simulate-natives","false");
opt.put("implicit-entry","false");
SootUtils.doSparkPointsToAnalysis(opt);
}
public static PDG buildUnsafePDG(SootMethod m,IPtsToQuery pt2Query,IReachingDUQuery rd,boolean withCtrlDep){
DepGraphOptions options = new DepGraphOptions(withCtrlDep,false,HeapAbstraction.FIELD_SENSITIVE);
UnitGraph cfg = new HammockCFG(m.retrieveActiveBody());
AbstractPDGBuilder pdgbd = new UnsafePDGBuilder(m,cfg,options,pt2Query, HeapAbstraction.FIELD_SENSITIVE, rd);
pdgbd.build();
PDG depGraph = pdgbd.getPDG();
Graph graph = GraphHelper.toDisplayGraph(depGraph.toDirectedGraph(), "PDG_"+m.getName());
showGraph(graph, "jgraph");
return depGraph;
}
public static ISideEffectAnalysis loadSideEffector(IPtsToQuery query){
SideEffectAnalysis se = new SideEffectAnalysis(query,EntryPoints.v().application(), HeapAbstraction.FIELD_SENSITIVE);
se.build();
return se;
}
public static String getEntrySignature(String mainClass){
return "<"+mainClass+": void main(java.lang.String[])>";
}
public static CallGraph simplifyCallGraph(){
CallGraph cg = Scene.v().getCallGraph();
PointsToAnalysis ptsTo = Scene.v().getPointsToAnalysis();
CallGraphRefiner refiner = new CallGraphRefiner(ptsTo, true);
CallGraph newCg = refiner.refine(cg, new CallGraphRefiner.AggressiveCallGraphFilter());
Scene.v().setCallGraph(newCg);
Scene.v().setReachableMethods(null); //update reachable methods
return newCg;
}
static IGlobalDUQuery createDUQuery(IPtsToQuery ptsto, CFGProvider cfgProvider, boolean buildAll){
ISideEffectAnalysis sideEffector = loadSideEffector(ptsto);
Date startTime = new Date();
DUBuilder du = new DUBuilder(cfgProvider, ptsto, HeapAbstraction.FIELD_SENSITIVE, sideEffector, true);
IGlobalDUQuery duQuery = du.getGlobalDUQuery();
if(buildAll){
List<MethodOrMethodContext> rm = Cache.v().getTopologicalOrder();
for(Iterator<MethodOrMethodContext> it = rm.iterator();it.hasNext();){
SootMethod m = (SootMethod)it.next();
if(m.isConcrete()){
duQuery.getRDQuery(m);
duQuery.getRUQuery(m);
}
}
Date endTime=new Date();
Test.out.println("Test finish in "+ Utils.getTimeConsumed(startTime,endTime));
}
return duQuery;
}
}