Loading pom.xml +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ <groupId>tfm</groupId> <artifactId>tfm</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <properties> Loading @@ -16,5 +17,6 @@ <modules> <module>sdg-core</module> <module>sdg-cli</module> <module>sdg-gui</module> </modules> </project> sdg-cli/pom.xml +2 −2 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ <groupId>tfm</groupId> <artifactId>sdg-cli</artifactId> <version>1.0-SNAPSHOT</version> <version>1.0.0</version> <properties> <maven.compiler.source>11</maven.compiler.source> Loading @@ -27,7 +27,7 @@ <dependency> <groupId>tfm</groupId> <artifactId>sdg-core</artifactId> <version>1.0-SNAPSHOT</version> <version>1.0.0</version> <scope>compile</scope> </dependency> </dependencies> Loading sdg-cli/src/main/java/tfm/cli/GraphLog.java +24 −14 Original line number Diff line number Diff line package tfm.cli; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.graphs.Graph; import tfm.nodes.GraphNode; import tfm.utils.FileUtil; import tfm.utils.Logger; Loading @@ -21,15 +24,12 @@ public abstract class GraphLog<G extends Graph> { } } static final String CFG = "cfg"; static final String PDG = "pdg"; static final String SDG = "sdg"; G graph; protected G graph; protected String imageName; protected Format format; protected String format; protected boolean generated = false; protected File outputDir = new File("./out/"); public GraphLog() { this(null); Loading @@ -39,6 +39,10 @@ public abstract class GraphLog<G extends Graph> { this.graph = graph; } public void setDirectory(File outputDir) { this.outputDir = outputDir; } public void log() throws IOException { Logger.log( "****************************\n" + Loading @@ -52,7 +56,7 @@ public abstract class GraphLog<G extends Graph> { "****************************" ); try (StringWriter stringWriter = new StringWriter()) { graph.getDOTExporter().exportGraph(graph, stringWriter); getDOTExporter(graph).exportGraph(graph, stringWriter); stringWriter.append('\n'); Logger.log(stringWriter.toString()); } Loading @@ -63,22 +67,24 @@ public abstract class GraphLog<G extends Graph> { } public void generateImages(String imageName) throws IOException { generateImages(imageName, Format.PNG); generateImages(imageName, "pdf"); } public void generateImages(String imageName, Format format) throws IOException { this.imageName = imageName + "-" + graph.getClass().getName(); public void generateImages(String imageName, String format) throws IOException { this.imageName = imageName + "-" + graph.getClass().getSimpleName(); this.format = format; generated = true; File tmpDot = File.createTempFile("graph-source-", ".dot"); tmpDot.getParentFile().mkdirs(); getImageFile().getParentFile().mkdirs(); // Graph -> DOT -> file try (Writer w = new FileWriter(tmpDot)) { graph.getDOTExporter().exportGraph(graph, w); getDOTExporter(graph).exportGraph(graph, w); } // Execute dot ProcessBuilder pb = new ProcessBuilder("dot", tmpDot.getAbsolutePath(), "-T" + format.getExt(), tmpDot.getAbsolutePath(), "-T" + format, "-o", getImageFile().getAbsolutePath()); try { int result = pb.start().waitFor(); Loading @@ -96,7 +102,11 @@ public abstract class GraphLog<G extends Graph> { FileUtil.open(getImageFile()); } protected File getImageFile() { return new File("./out/" + imageName + "." + format.getExt()); public File getImageFile() { return new File(outputDir, imageName + "." + format); } protected DOTExporter<GraphNode<?>, Arc> getDOTExporter(G graph) { return graph.getDOTExporter(); } } sdg-cli/src/main/java/tfm/cli/PDGLog.java +3 −5 Original line number Diff line number Diff line Loading @@ -31,18 +31,16 @@ public class PDGLog extends GraphLog<PDG> { Logger.log(graph.vertexSet().stream() .sorted(Comparator.comparingLong(GraphNode::getId)) .map(node -> String.format("GraphNode { id: %s, instruction: %s, declared: %s, defined: %s, used: %s }", String.format("GraphNode { id: %s, instruction: %s, variables: %s}", node.getId(), node.getInstruction(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables()) node.getVariableActions()) ).collect(Collectors.joining(System.lineSeparator())) ); } @Override public void generateImages(String imageName, Format format) throws IOException { public void generateImages(String imageName, String format) throws IOException { super.generateImages(imageName, format); if (cfgLog != null) cfgLog.generateImages(imageName, format); Loading sdg-cli/src/main/java/tfm/cli/PHPSlice.java 0 → 100644 +143 −0 Original line number Diff line number Diff line package tfm.cli; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.symbolsolver.JavaSymbolSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import org.apache.commons.cli.*; import tfm.graphs.cfg.CFG; import tfm.graphs.exceptionsensitive.ESSDG; import tfm.graphs.sdg.SDG; import tfm.nodes.GraphNode; import tfm.slicing.NodeIdSlicingCriterion; import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; public class PHPSlice { protected static final Options OPTIONS = new Options(); static { OPTIONS.addOption(Option .builder("f") .hasArg().argName("CriterionFile.java").type(File.class) .required() .desc("The file that contains the slicing criterion.") .build()); OPTIONS.addOption(Option .builder("i") .hasArg().argName("node_id") .required() .desc("The slicing criterion, in the form of a node id (a positive integer).") .build()); OPTIONS.addOption(Option .builder("o") .hasArg().argName("output_file") .required() .desc("The folder where the slice and the graphs should be placed") .build()); OPTIONS.addOption("es", "exception-sensitive", false, "Enable exception-sensitive analysis"); OPTIONS.addOption(Option .builder("h").longOpt("help") .desc("Shows this text") .build()); } private final File outputDir; private File scFile; private int scId; private final CommandLine cliOpts; public PHPSlice(String... cliArgs) throws ParseException { cliOpts = new DefaultParser().parse(OPTIONS, cliArgs); if (cliOpts.hasOption('h')) throw new ParseException(OPTIONS.toString()); setScId(Integer.parseInt(cliOpts.getOptionValue("i"))); setScFile(cliOpts.getOptionValue("f")); outputDir = new File(cliOpts.getOptionValue("o")); if (!outputDir.isDirectory()) throw new ParseException("The output directory is not a directory or not readable by us!"); } private void setScFile(String fileName) throws ParseException { File file = new File(fileName); if (!(file.exists() && file.isFile())) throw new ParseException("Slicing criterion file is not an existing file."); scFile = file; } private void setScId(int line) throws ParseException { if (line < 0) throw new ParseException("The line of the slicing criterion must be strictly greater than zero."); scId = line; } public void slice() throws ParseException, IOException { // Configure JavaParser CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); combinedTypeSolver.add(new ReflectionTypeSolver(true)); JavaParser.getStaticConfiguration().setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); JavaParser.getStaticConfiguration().setAttributeComments(false); // Build the SDG NodeList<CompilationUnit> units = new NodeList<>(); try { units.add(JavaParser.parse(scFile)); } catch (FileNotFoundException e) { throw new ParseException(e.getMessage()); } SDG sdg = cliOpts.hasOption("exception-sensitive") ? new ESSDG() : new SDG(); sdg.build(units); // Slice the SDG SlicingCriterion sc = new NodeIdSlicingCriterion(scId, ""); Slice slice = sdg.slice(sc); // Convert the slice to code and output the result to `outputDir` for (CompilationUnit cu : slice.toAst()) { if (cu.getStorage().isEmpty()) throw new IllegalStateException("A synthetic CompilationUnit was discovered, with no file associated to it."); File javaFile = new File(outputDir, cu.getStorage().get().getFileName()); try (PrintWriter pw = new PrintWriter(javaFile)) { pw.print(new BlockComment(getDisclaimer(cu.getStorage().get()))); pw.print(cu); } catch (FileNotFoundException e) { System.err.println("Could not write file " + javaFile); } } File imageDir = new File(outputDir, "images"); imageDir.mkdir(); // Output the sliced graph to the output directory SDGLog sdgLog = new SlicedSDGLog(sdg, slice, sc); sdgLog.setDirectory(outputDir); sdgLog.generateImages("graph", "svg"); for (CFG cfg : sdg.getCFGs()) { CFGLog log = new CFGLog(cfg); log.setDirectory(imageDir); log.generateImages("root" + cfg.getRootNode().map(GraphNode::getId).orElse(-1L), "svg"); } } protected String getDisclaimer(CompilationUnit.Storage s) { return String.format("\n\tThis file was automatically generated as part of a slice with criterion" + "\n\tnode id: %d\n\tOriginal file: %s\n", scId, s.getPath()); } public static void main(String... args) { try { new PHPSlice(args).slice(); } catch (Exception e) { System.err.println("Error!\n" + e.getMessage()); } } } Loading
pom.xml +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ <groupId>tfm</groupId> <artifactId>tfm</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <properties> Loading @@ -16,5 +17,6 @@ <modules> <module>sdg-core</module> <module>sdg-cli</module> <module>sdg-gui</module> </modules> </project>
sdg-cli/pom.xml +2 −2 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ <groupId>tfm</groupId> <artifactId>sdg-cli</artifactId> <version>1.0-SNAPSHOT</version> <version>1.0.0</version> <properties> <maven.compiler.source>11</maven.compiler.source> Loading @@ -27,7 +27,7 @@ <dependency> <groupId>tfm</groupId> <artifactId>sdg-core</artifactId> <version>1.0-SNAPSHOT</version> <version>1.0.0</version> <scope>compile</scope> </dependency> </dependencies> Loading
sdg-cli/src/main/java/tfm/cli/GraphLog.java +24 −14 Original line number Diff line number Diff line package tfm.cli; import org.jgrapht.io.DOTExporter; import tfm.arcs.Arc; import tfm.graphs.Graph; import tfm.nodes.GraphNode; import tfm.utils.FileUtil; import tfm.utils.Logger; Loading @@ -21,15 +24,12 @@ public abstract class GraphLog<G extends Graph> { } } static final String CFG = "cfg"; static final String PDG = "pdg"; static final String SDG = "sdg"; G graph; protected G graph; protected String imageName; protected Format format; protected String format; protected boolean generated = false; protected File outputDir = new File("./out/"); public GraphLog() { this(null); Loading @@ -39,6 +39,10 @@ public abstract class GraphLog<G extends Graph> { this.graph = graph; } public void setDirectory(File outputDir) { this.outputDir = outputDir; } public void log() throws IOException { Logger.log( "****************************\n" + Loading @@ -52,7 +56,7 @@ public abstract class GraphLog<G extends Graph> { "****************************" ); try (StringWriter stringWriter = new StringWriter()) { graph.getDOTExporter().exportGraph(graph, stringWriter); getDOTExporter(graph).exportGraph(graph, stringWriter); stringWriter.append('\n'); Logger.log(stringWriter.toString()); } Loading @@ -63,22 +67,24 @@ public abstract class GraphLog<G extends Graph> { } public void generateImages(String imageName) throws IOException { generateImages(imageName, Format.PNG); generateImages(imageName, "pdf"); } public void generateImages(String imageName, Format format) throws IOException { this.imageName = imageName + "-" + graph.getClass().getName(); public void generateImages(String imageName, String format) throws IOException { this.imageName = imageName + "-" + graph.getClass().getSimpleName(); this.format = format; generated = true; File tmpDot = File.createTempFile("graph-source-", ".dot"); tmpDot.getParentFile().mkdirs(); getImageFile().getParentFile().mkdirs(); // Graph -> DOT -> file try (Writer w = new FileWriter(tmpDot)) { graph.getDOTExporter().exportGraph(graph, w); getDOTExporter(graph).exportGraph(graph, w); } // Execute dot ProcessBuilder pb = new ProcessBuilder("dot", tmpDot.getAbsolutePath(), "-T" + format.getExt(), tmpDot.getAbsolutePath(), "-T" + format, "-o", getImageFile().getAbsolutePath()); try { int result = pb.start().waitFor(); Loading @@ -96,7 +102,11 @@ public abstract class GraphLog<G extends Graph> { FileUtil.open(getImageFile()); } protected File getImageFile() { return new File("./out/" + imageName + "." + format.getExt()); public File getImageFile() { return new File(outputDir, imageName + "." + format); } protected DOTExporter<GraphNode<?>, Arc> getDOTExporter(G graph) { return graph.getDOTExporter(); } }
sdg-cli/src/main/java/tfm/cli/PDGLog.java +3 −5 Original line number Diff line number Diff line Loading @@ -31,18 +31,16 @@ public class PDGLog extends GraphLog<PDG> { Logger.log(graph.vertexSet().stream() .sorted(Comparator.comparingLong(GraphNode::getId)) .map(node -> String.format("GraphNode { id: %s, instruction: %s, declared: %s, defined: %s, used: %s }", String.format("GraphNode { id: %s, instruction: %s, variables: %s}", node.getId(), node.getInstruction(), node.getDeclaredVariables(), node.getDefinedVariables(), node.getUsedVariables()) node.getVariableActions()) ).collect(Collectors.joining(System.lineSeparator())) ); } @Override public void generateImages(String imageName, Format format) throws IOException { public void generateImages(String imageName, String format) throws IOException { super.generateImages(imageName, format); if (cfgLog != null) cfgLog.generateImages(imageName, format); Loading
sdg-cli/src/main/java/tfm/cli/PHPSlice.java 0 → 100644 +143 −0 Original line number Diff line number Diff line package tfm.cli; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.symbolsolver.JavaSymbolSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import org.apache.commons.cli.*; import tfm.graphs.cfg.CFG; import tfm.graphs.exceptionsensitive.ESSDG; import tfm.graphs.sdg.SDG; import tfm.nodes.GraphNode; import tfm.slicing.NodeIdSlicingCriterion; import tfm.slicing.Slice; import tfm.slicing.SlicingCriterion; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; public class PHPSlice { protected static final Options OPTIONS = new Options(); static { OPTIONS.addOption(Option .builder("f") .hasArg().argName("CriterionFile.java").type(File.class) .required() .desc("The file that contains the slicing criterion.") .build()); OPTIONS.addOption(Option .builder("i") .hasArg().argName("node_id") .required() .desc("The slicing criterion, in the form of a node id (a positive integer).") .build()); OPTIONS.addOption(Option .builder("o") .hasArg().argName("output_file") .required() .desc("The folder where the slice and the graphs should be placed") .build()); OPTIONS.addOption("es", "exception-sensitive", false, "Enable exception-sensitive analysis"); OPTIONS.addOption(Option .builder("h").longOpt("help") .desc("Shows this text") .build()); } private final File outputDir; private File scFile; private int scId; private final CommandLine cliOpts; public PHPSlice(String... cliArgs) throws ParseException { cliOpts = new DefaultParser().parse(OPTIONS, cliArgs); if (cliOpts.hasOption('h')) throw new ParseException(OPTIONS.toString()); setScId(Integer.parseInt(cliOpts.getOptionValue("i"))); setScFile(cliOpts.getOptionValue("f")); outputDir = new File(cliOpts.getOptionValue("o")); if (!outputDir.isDirectory()) throw new ParseException("The output directory is not a directory or not readable by us!"); } private void setScFile(String fileName) throws ParseException { File file = new File(fileName); if (!(file.exists() && file.isFile())) throw new ParseException("Slicing criterion file is not an existing file."); scFile = file; } private void setScId(int line) throws ParseException { if (line < 0) throw new ParseException("The line of the slicing criterion must be strictly greater than zero."); scId = line; } public void slice() throws ParseException, IOException { // Configure JavaParser CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); combinedTypeSolver.add(new ReflectionTypeSolver(true)); JavaParser.getStaticConfiguration().setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); JavaParser.getStaticConfiguration().setAttributeComments(false); // Build the SDG NodeList<CompilationUnit> units = new NodeList<>(); try { units.add(JavaParser.parse(scFile)); } catch (FileNotFoundException e) { throw new ParseException(e.getMessage()); } SDG sdg = cliOpts.hasOption("exception-sensitive") ? new ESSDG() : new SDG(); sdg.build(units); // Slice the SDG SlicingCriterion sc = new NodeIdSlicingCriterion(scId, ""); Slice slice = sdg.slice(sc); // Convert the slice to code and output the result to `outputDir` for (CompilationUnit cu : slice.toAst()) { if (cu.getStorage().isEmpty()) throw new IllegalStateException("A synthetic CompilationUnit was discovered, with no file associated to it."); File javaFile = new File(outputDir, cu.getStorage().get().getFileName()); try (PrintWriter pw = new PrintWriter(javaFile)) { pw.print(new BlockComment(getDisclaimer(cu.getStorage().get()))); pw.print(cu); } catch (FileNotFoundException e) { System.err.println("Could not write file " + javaFile); } } File imageDir = new File(outputDir, "images"); imageDir.mkdir(); // Output the sliced graph to the output directory SDGLog sdgLog = new SlicedSDGLog(sdg, slice, sc); sdgLog.setDirectory(outputDir); sdgLog.generateImages("graph", "svg"); for (CFG cfg : sdg.getCFGs()) { CFGLog log = new CFGLog(cfg); log.setDirectory(imageDir); log.generateImages("root" + cfg.getRootNode().map(GraphNode::getId).orElse(-1L), "svg"); } } protected String getDisclaimer(CompilationUnit.Storage s) { return String.format("\n\tThis file was automatically generated as part of a slice with criterion" + "\n\tnode id: %d\n\tOriginal file: %s\n", scId, s.getPath()); } public static void main(String... args) { try { new PHPSlice(args).slice(); } catch (Exception e) { System.err.println("Error!\n" + e.getMessage()); } } }