100 lines
3.7 KiB
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));
|
|
}
|
|
|
|
}
|