package fr.lifl.stc.stan.analyser;
//import java.util.Vector;
import java.io.IOException;
import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.antlr.runtime.RecognitionException;
import fr.lifl.stc.stan.classAnnoter.LinkMapClassAnnoter;
import fr.lifl.stc.stan.implicitFlow.QuineMcCluskey.Minimization;
import fr.lifl.stc.stan.link.LinkFactory;
import fr.lifl.stc.stan.link.TableLink;
import fr.lifl.stc.stan.link.defaultLink.DefaultLinkFactory;
import fr.lifl.stc.stan.policy.Policy;
import fr.lifl.stc.stan.policy.defaultPolicy.DefaultPolicy;
import fr.lifl.stc.stan.signature.SignatureDictionary;
import fr.lifl.stc.stan.tools.HTMLOutput;
import fr.lifl.stc.stan.tools.NativesAnnoter;
import fr.lifl.stc.stan.util.Printer;
import fr.lifl.stc.stan.dsl.DSLReader;
import fr.lifl.stc.stan.dsl.PolicyManager;
import fr.lifl.stc.stan.dsl.FlowChecker;
/**
* @author Julien Graziano
* @author Dorina
*/
public class GlobalAnalyser {
private SignatureDictionary dictionary;
private Policy policy;
private FlowChecker flowchecker; /** Checker for dsl policies */
private JavaClass classes[];
public static LinkFactory linkFactory = new DefaultLinkFactory();
/**
* Creates a new GlobalAnalyser
instance.
*
* @param classes
* set of classfiles to analyse
* @throws ClassNotFoundException
* @throws IOException
*
*/
public GlobalAnalyser(JavaClass[] classes) throws IOException,
ClassNotFoundException {
/**
* loading dictionary
*/
System.out.println("[init] Loading dictionary "+Config.getDictionary());
dictionary = new SignatureDictionary(Config.getDictionary());
/**
* adds initial dictionary (e.g. api dictionary) content to main dictionary
*/
if (Config.getInitialDictionary() != null) {
System.out.println("[init] Adding initial dictionary "+Config.getInitialDictionary());
dictionary.addContent(Config.getInitialDictionary());
}
/**
* loads policy file
*/
if(Config.getPolicy()!=null) {
System.out.println("[init] Loading policy file "+Config.getPolicy());
policy = new DefaultPolicy(Config.getPolicy());
}
else{
policy = new DefaultPolicy();
}
/**
* loads DSL policies file
*/
if(Config.getDSLFile()!=null) {
System.out.println("[init] Loading DSL policies file "+Config.getDSLFile());
DSLReader dsl=null;
try {
dsl = new DSLReader(Config.getDSLFile());
} catch(RecognitionException e) {
System.out.println("[init] There was an error reading the DSL file, ignoring it : " + e.getMessage());
} catch(IOException e) {
System.out.println("[init] There was an error while trying to open DSL file, ignoring it : " + e.getMessage());
}
if ( dsl == null )
flowchecker = new FlowChecker(new PolicyManager());
else
flowchecker = new FlowChecker(dsl.policies);
}
else{
flowchecker = new FlowChecker(new PolicyManager());
}
/**
* creates the class hierarchy
*/
System.out.println("[init] Register classes");
System.out.println("no of classes "+classes.length);
//Printer.println("no of classes "+classes.length);
for (int i = 0; i < classes.length; i++) {
policy.registerClass(classes[i]);
dictionary.registerClass(classes[i]);
}
/**
* registers methods in the class hierarchy
*/
System.out.println("[init] Register methods");
for (int i = 0; i < classes.length; i++) {
dictionary.registerMethods(classes[i]);
}
/**
* registers manual annotations
*/
if(Config.getHandAnnotationsFile()!=null) {
System.out.println("[init] Add hand-annotations");
NativesAnnoter na = new NativesAnnoter(dictionary, Config.getHandAnnotationsFile(), classes);
na.addToDico();
}
this.classes = classes;
}
/**
* @see fr.lifl.stc.stan.analyser.Analyser#analyse() Analyse le
* groupe de classes par passes successives tant qu'un changement
* apparait dans le dictionnaire
*/
public void analyse() throws IOException {
ClassAnalyser canalyser;
int noCycles = 0;
do {
Stats.initIteration();
StatsEscape.init();
System.out.println("\n\n[run] START cycle "+noCycles+"\n");
//Printer.println("\n\n[run] START cycle "+noCycles+"\n");
dictionary.setUnChanged();
for (int i = 0; i < classes.length; i++) {
Printer.println("\n[run] Analysing class "+ classes[i].getFileName());
HTMLOutput.openHTMLOutput(Config.htmlRep()
+ classes[i].getClassName());
canalyser = new ClassAnalyser(dictionary, policy, flowchecker, classes[i]);
canalyser.analyse();
HTMLOutput.closeHTMLOutput();
}
Stats.endIteration();
noCycles++;
} while (dictionary.isChanged());
/**
* writes dictionary to file
*/
dictionary.dump();
/**
* prints statistics
*/
System.out.println("noCycles:\t" + noCycles);
if (Config.statisticsEnabled()) {
Stats.println("noCycles:\t" + noCycles +" \n ProofSize:\t" + Stats.sizeOfProof +
"\n max table link L = " + TableLink.maxL + "\n max table link C = " + TableLink.maxC);
Stats.printStats();
StatsEscape.print();
}
if (Config.implicitFlowEnabled()) {
Minimization.stats.printStats();
}
// annotated classes with signatures
if (Config.annotateEnabled())
this.annotate();
}
/**
* annotates classes with link map attribute
* @throws IOException
*/
private void annotate() throws IOException {
for (int i = 0; i < classes.length; i++) {
LinkMapClassAnnoter la = new LinkMapClassAnnoter(classes[i],
dictionary);
la.annotateClass();
}
}
/**
* prints help
*
*/
private static void printHelp() {
System.out.println("Usage : if_analyze ");
System.out.println("where possible options include: ");
System.out.println(" -h/--help : print this help");
System.out.println(" -v/--verbose : verbose mode");
System.out.println(" -d/--dictionary : use as dictionary");
System.out.println(" -p/--path : use as path for files below");
System.out.println(" -i/--initial-dictionary : use as initial dictionary (for hand annotations)");
System.out.println(" -H/--hand-annotations : use as file containing hand written annotations");
System.out.println(" -P/--policy : use as file policy (e.g. containing secret attributes)");
System.out.println(" -a/--annotate : annotate the .class files ");
System.out.println(" -r/--annotate-rep : use as a basis for annotated class dumps");
System.out.println(" -s/--statistics : produce statistics");
System.out.println(" -o/--statistics-file : use as statistics output");
System.out.println(" -t/--html : produce html dumps");
System.out.println(" -b/--html-rep : use as a basis for html dumps");
System.out.println(" -c/--configuration : use configuration from config.xml");
System.out.println(" -w/--worst-signature : use the worst signature as global signature for abstract methods");
System.out.println(" -x/--directory : analyze all .class files in and its subdirectories");
System.out.println(" -f/--file : analyze all .class in file");
}
/**
* Loads, from bcel, classes passed as line arguments and launches the
* analyzer
*/
public static void main(String args[]) {
int error, i;
long time1, time2;
GlobalAnalyser ganalyser;
JavaClass classes[];
time1 = System.currentTimeMillis();
error = i = 0;
int c;
LongOpt[] longopts = new LongOpt[16];
longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
longopts[1] = new LongOpt("dictionary", LongOpt.REQUIRED_ARGUMENT, null, 'd');
longopts[2] = new LongOpt("initial-dictionary", LongOpt.REQUIRED_ARGUMENT, null, 'i');
longopts[3] = new LongOpt("policy", LongOpt.REQUIRED_ARGUMENT, null, 'P');
longopts[4] = new LongOpt("annotate", LongOpt.NO_ARGUMENT, null, 'a');
longopts[5] = new LongOpt("annotate-rep", LongOpt.REQUIRED_ARGUMENT, null, 'r');
longopts[6] = new LongOpt("statistics", LongOpt.NO_ARGUMENT, null, 's');
longopts[7] = new LongOpt("statistics-file", LongOpt.REQUIRED_ARGUMENT, null, 'o');
longopts[8] = new LongOpt("html", LongOpt.NO_ARGUMENT, null, 't');
longopts[9] = new LongOpt("html-rep", LongOpt.REQUIRED_ARGUMENT, null, 'b');
longopts[10] = new LongOpt("configuration", LongOpt.REQUIRED_ARGUMENT, null, 'c');
longopts[11] = new LongOpt("worst-signature", LongOpt.NO_ARGUMENT, null, 'w');
longopts[12] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null, 'v');
longopts[13] = new LongOpt("path", LongOpt.REQUIRED_ARGUMENT, null, 'p');
longopts[14] = new LongOpt("hand-annotations", LongOpt.REQUIRED_ARGUMENT, null, 'H');
longopts[15] = new LongOpt("file", LongOpt.REQUIRED_ARGUMENT, null, 'f');
Getopt g = new Getopt("GlobalAnalyzer", args, "hvp:d:i:H:P:ar:so:tb:c:f:wvW;", longopts);
try {
while ((c = g.getopt()) != -1) {
switch (c) {
case 'h':
printHelp();
System.exit(0);
break;
case 'v':
Config.setEnableVerbose(true);
break;
case 'p':
Config.setPath(g.getOptarg());
break;
case 'c':
Config.loadXMLConfigFile(g.getOptarg());
break;
case 'd':
Config.setDictionary(g.getOptarg());
break;
case 'i':
Config.setInitialDictionary(g.getOptarg());
break;
case 'P':
Config.setPolicy(g.getOptarg());
break;
case 'H':
Config.setHandAnnotationsFile(g.getOptarg());
break;
case 'a':
Config.setEnableAnnotate(true);
break;
case 'r':
Config.setAnnotationRep(g.getOptarg());
break;
case 's':
Config.setEnableStatistics(true);
break;
case 'o':
Config.setStatisticsFile(g.getOptarg());
break;
case 't':
Config.setEnableHtml(true);
break;
case 'b':
Config.setHtmlRep(g.getOptarg());
break;
case 'w':
Config.setEnableWorstSignature(true);
break;
case 'f':
Config.setInputFile(g.getOptarg());
break;
case 'W':
System.out.println("You tried a -W with an incorrect long option name");
break;
case ':':
System.out.println("You need an argument for option " + (char) g.getOptopt());
break;
case '?':
System.out.println("The option '" + (char) g.getOptopt() + "' is not valid");
break;
default:
System.out.println("getopt(): unknown option " + c);
break;
}
}
if(Config.getDictionary() == null) {
Config.setDictionary("dico.txt");
}
int from = g.getOptind();
String[] files = Config.getInputFiles();
int filesLength = (files==null)?0:files.length;
classes = new JavaClass[args.length - from + filesLength];
for (i = 0; i < filesLength; i++) {
classes[i] = (new ClassParser((String)files[i])).parse();
}
for (int j = 0; j < args.length - from; j++)
classes[i+j] = (new ClassParser(args[j + from])).parse();
ganalyser = new GlobalAnalyser(classes);
ganalyser.analyse();
} catch (IOException e) {
System.err.println(" E: File "+" does not exist or you don't have permission on it: "+e);
e.printStackTrace();
error = 1;
} catch (ClassNotFoundException e) {
System.err.println("E: Internal error:"+e.toString());
error = 1;
}
time2 = System.currentTimeMillis();
System.out.println("Analyse took: ");
System.out.println((time2 - time1) + "ms");
if (time2 - time1 < 1000)
System.out.println((time2 - time1) + "ms");
else
System.out.println(((time2 - time1) / 1000) + "s");
if (ClassAnalyser.memory < (1 << 10))
System.out.println(ClassAnalyser.memory + "octets");
else if (ClassAnalyser.memory < (1 << 20))
System.out.println((ClassAnalyser.memory >> 10) + "Ko");
else
System.out.println((ClassAnalyser.memory >> 20) + "Mo");
Stats.printMemory();
System.exit(error);
}
}