sp-04/src/ch/usi/inf/sp/cfg/App.java

100 lines
3.7 KiB
Java

package ch.usi.inf.sp.cfg;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import ch.usi.inf.sp.bytecode.Disassembler;
import ch.usi.inf.sp.dom.DominatorAnalyzer;
import ch.usi.inf.sp.dom.DominatorTree;
import ch.usi.inf.sp.dom.DominatorTreeRenderer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
public final class App {
/**
* Invoke like this...
* <p>
* java App test-input/java10/ExampleClass.class test-output
* <p>
* to produce one disassembly, one CFG, one dominator tree,
* and one combined graph (CFG with additional dotted dominance edges)
* for each method in ExampleClass.
* Afterwards, go to the test-output folder, and call...
* <p>
* dot -Tpdf -oall.pdf *.dot
* <p>
* ...to produce a file all.pdf containing one page for each graph, or...
* <p>
* dot -Tpdf -oall.combined.pdf *.combined.pdf
* </p>
* ...to produce a file all.combined.pdf with just the combined graphs.
*
* MAKE SURE YOU MANUALLY VERIFY FOR EACH METHOD THAT THE DOMINATORS ARE CORRECT.
*/
public static void main(final String[] args) throws IOException {
final File classFile = new File(args[0]);
final File outputDirectory = new File(args[1]);
final App app = new App(classFile, outputDirectory);
app.execute();
}
private final File classFile;
private final File outputDirectory;
public App(final File classFile, final File outputDirectory) {
this.classFile = classFile;
this.outputDirectory = outputDirectory;
}
/**
* Save the given contents into a file with the given fileName in the outputDirectory.
*/
private void save(final String fileName, final String contents) throws IOException {
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}
final File file = new File(outputDirectory, fileName);
final FileWriter writer = new FileWriter(file);
writer.write(contents);
writer.close();
}
public void execute() throws IOException {
final ClassReader cr = new ClassReader(new FileInputStream(classFile));
// create an empty ClassNode (in-memory representation of a class)
final ClassNode cn = new ClassNode();
// have the ClassReader read the class file and populate the ClassNode with the corresponding information
cr.accept(cn, 0);
// disassemble and perform control-flow analysis
processClass(cn);
}
private void processClass(final ClassNode cn) throws IOException {
System.out.println("Class: " + cn.name);
// get the list of all methods in that class
final List<MethodNode> methods = cn.methods;
for (int m = 0; m < methods.size(); m++) {
final MethodNode method = methods.get(m);
processMethod(method);
}
}
private void processMethod(final MethodNode method) throws IOException {
System.out.println(" Method: " + method.name + method.desc);
save(method.name + ".asm.txt", Disassembler.disassembleMethod(method));
final ControlFlowGraph cfg = ControlFlowGraphBuilder.createControlFlowGraph(method);
save(method.name + ".cfg.dot", ControlFlowGraphRenderer.renderControlFlowGraph(method.name, cfg));
final DominatorTree dt = DominatorAnalyzer.analyze(cfg);
save(method.name + ".dt.dot", DominatorTreeRenderer.renderDominatorTree(method.name, dt));
save(method.name + ".combined.dot", DominatorTreeRenderer.renderCombined(method.name, cfg, dt));
}
}