1 19 20 25 26 27 package soot.util; 28 29 import java.io.File ; 30 import java.io.IOException ; 31 import java.io.PrintWriter ; 32 import java.util.Collections ; 33 import java.util.ArrayList ; 34 import java.util.Iterator ; 35 import java.util.List ; 36 import java.util.Map ; 37 import java.util.StringTokenizer ; 38 import soot.Body; 39 import soot.G; 40 import soot.PhaseOptions; 41 import soot.Printer; 42 import soot.Scene; 43 import soot.Singletons; 44 import soot.SootClass; 45 import soot.SootMethod; 46 import soot.options.Options; 47 import soot.toolkits.graph.ExceptionalGraph; 48 import soot.toolkits.graph.DirectedGraph; 49 import soot.util.Chain; 50 import soot.util.cfgcmd.CFGToDotGraph; 51 import soot.util.dot.DotGraph; 52 53 54 64 65 public class PhaseDumper { 66 private List bodyDumpingPhases; 67 private List cfgDumpingPhases; 68 69 private class PhaseStack extends ArrayList { 70 72 private final static int initialCapacity = 4; 73 final static String EMPTY_STACK_PHASE_NAME = "NOPHASE"; 74 75 PhaseStack() { 76 super(initialCapacity); 77 } 78 79 boolean empty() { 80 return (this.size() == 0); 81 } 82 83 String currentPhase() { 84 if (this.size() <= 0) { 85 return EMPTY_STACK_PHASE_NAME; 86 } else { 87 return (String ) this.get(this.size() - 1); 88 } 89 } 90 91 String pop() { 92 return (String ) this.remove(this.size() - 1); 93 } 94 95 String push(String phaseName) { 96 this.add(phaseName); 97 return phaseName; 98 } 99 } 100 private PhaseStack phaseStack = new PhaseStack(); 101 final static String allWildcard = "ALL"; 102 103 104 public PhaseDumper(Singletons.Global g) { 105 bodyDumpingPhases = Options.v().dump_body(); 106 cfgDumpingPhases = Options.v().dump_cfg(); 107 } 108 109 110 115 public static PhaseDumper v() { 116 return G.v().soot_util_PhaseDumper(); 117 } 118 119 120 private boolean isBodyDumpingPhase(String phaseName) { 121 return bodyDumpingPhases.contains(phaseName) || 122 bodyDumpingPhases.contains(allWildcard); 123 } 124 125 126 private boolean isCFGDumpingPhase(String phaseName) { 127 return cfgDumpingPhases.contains(phaseName) || 128 cfgDumpingPhases.contains(allWildcard); 129 } 130 131 132 private static java.io.File makeDirectoryIfMissing(Body b) 133 throws java.io.IOException { 134 StringBuffer buf = 135 new StringBuffer (soot.SourceLocator.v().getOutputDir()); 136 buf.append(File.separatorChar); 137 String className = b.getMethod().getDeclaringClass().getName(); 138 buf.append(className); 139 buf.append(File.separatorChar); 140 buf.append(b.getMethod().getSubSignature()); 141 java.io.File dir = new java.io.File (buf.toString()); 142 if (dir.exists()) { 143 if (! dir.isDirectory()) { 144 throw new java.io.IOException (dir.getPath() + " exists but is not a directory."); 145 } 146 } else { 147 if (! dir.mkdirs()) { 148 throw new java.io.IOException ("Unable to mkdirs " + dir.getPath()); 149 } 150 } 151 return dir; 152 } 153 154 155 private static PrintWriter openBodyFile(Body b, String baseName) 156 throws java.io.IOException { 157 File dir = makeDirectoryIfMissing(b); 158 String filePath = dir.toString() + File.separatorChar + baseName; 159 return 160 new PrintWriter (new java.io.FileOutputStream (filePath)); 161 } 162 163 164 167 168 private static String nextGraphFileName(Body b, String baseName) 169 throws java.io.IOException { 170 File dir = makeDirectoryIfMissing(b); 172 final String prefix = dir.toString() + File.separatorChar + baseName; 173 String filename = null; 174 File file = null; 175 int fileNumber = 0; 176 do { 177 file = new File (prefix + fileNumber + DotGraph.DOT_EXTENSION); 178 fileNumber++; 179 } while (file.exists()); 180 return file.toString(); 181 } 182 183 184 private static void deleteOldGraphFiles(final Body b, 185 final String phaseName) { 186 try { 187 final File dir = makeDirectoryIfMissing(b); 188 final File [] toDelete = dir.listFiles(new java.io.FilenameFilter () { 189 public boolean accept(File dir, String name) { 190 return name.startsWith(phaseName) && 191 name.endsWith(DotGraph.DOT_EXTENSION); 192 } 193 }); 194 for (int i = 0; i < toDelete.length ; i++) { 195 toDelete[i].delete(); 196 } 197 } catch (java.io.IOException e) { 198 G.v().out.println("PhaseDumper.dumpBody() caught: " + e.toString()); 201 e.printStackTrace(G.v().out); 202 } 203 } 204 205 206 private boolean alreadyDumping = false; 216 217 private void dumpBody(Body b, String baseName) { 218 try { 219 alreadyDumping = true; 220 java.io.PrintWriter out = openBodyFile(b, baseName); 221 soot.Printer.v().setOption(Printer.USE_ABBREVIATIONS); 222 soot.Printer.v().printTo(b, out); 223 out.close(); 224 } catch (java.io.IOException e) { 225 G.v().out.println("PhaseDumper.dumpBody() caught: " + e.toString()); 228 e.printStackTrace(G.v().out); 229 } finally { 230 alreadyDumping = false; 231 } 232 } 233 234 private void dumpAllBodies(String baseName, 235 boolean deleteGraphFiles) { 236 List classes = Scene.v().getClasses(SootClass.BODIES); 237 for (Iterator c = classes.iterator(); c.hasNext(); ) { 238 SootClass cls = (SootClass) c.next(); 239 for (Iterator m = cls.getMethods().iterator(); m.hasNext(); ) { 240 SootMethod method = (SootMethod) m.next(); 241 if (method.hasActiveBody()) { 242 Body body = method.getActiveBody(); 243 if (deleteGraphFiles) { 244 deleteOldGraphFiles(body, baseName); 245 } 246 dumpBody(body, baseName); 247 } 248 } 249 } 250 } 251 252 253 263 public void dumpBefore(Body b, String phaseName) { 264 phaseStack.push(phaseName); 265 if (isBodyDumpingPhase(phaseName)) { 266 deleteOldGraphFiles(b, phaseName); 267 dumpBody(b, phaseName + ".in"); 268 } 269 } 270 271 272 284 public void dumpAfter(Body b, String phaseName) { 285 String poppedPhaseName = phaseStack.pop(); 286 if (poppedPhaseName != phaseName) { 287 throw new IllegalArgumentException ("dumpAfter(" + phaseName + 288 ") when poppedPhaseName == " + 289 poppedPhaseName); 290 } 291 if (isBodyDumpingPhase(phaseName)) { 292 dumpBody(b, phaseName + ".out"); 293 } 294 } 295 296 297 306 public void dumpBefore(String phaseName) { 307 phaseStack.push(phaseName); 308 if (isBodyDumpingPhase(phaseName)) { 309 dumpAllBodies(phaseName + ".in", true); 310 } 311 } 312 313 314 324 public void dumpAfter(String phaseName) { 325 String poppedPhaseName = phaseStack.pop(); 326 if (poppedPhaseName != phaseName) { 327 throw new IllegalArgumentException ("dumpAfter(" + phaseName + 328 ") when poppedPhaseName == " + 329 poppedPhaseName); 330 } 331 if (isBodyDumpingPhase(phaseName)) { 332 dumpAllBodies(phaseName + ".out", false); 333 } 334 } 335 336 337 345 public void dumpGraph(DirectedGraph g, Body b) { 346 if (alreadyDumping) { 347 return; 348 } 349 try { 350 alreadyDumping = true; 351 String phaseName = phaseStack.currentPhase(); 352 if (isCFGDumpingPhase(phaseName)) { 353 try { 354 String outputFile = nextGraphFileName(b, phaseName + "-" + 355 getClassIdent(g) + "-"); 356 DotGraph dotGraph = new CFGToDotGraph().drawCFG(g, b); 357 dotGraph.plot(outputFile); 358 359 } catch (java.io.IOException e) { 360 G.v().out.println("PhaseDumper.dumpBody() caught: " + 363 e.toString()); 364 e.printStackTrace(G.v().out); 365 } 366 } 367 } finally { 368 alreadyDumping = false; 369 } 370 } 371 372 373 379 public void dumpGraph(ExceptionalGraph g) { 380 if (alreadyDumping) { 381 return; 382 } 383 try { 384 alreadyDumping = true; 385 String phaseName = phaseStack.currentPhase(); 386 if (isCFGDumpingPhase(phaseName)) { 387 try { 388 String outputFile = nextGraphFileName(g.getBody(), 389 phaseName + "-" + 390 getClassIdent(g) + "-"); 391 CFGToDotGraph drawer = new CFGToDotGraph(); 392 drawer.setShowExceptions(Options.v().show_exception_dests()); 393 DotGraph dotGraph = drawer.drawCFG(g); 394 dotGraph.plot(outputFile); 395 396 } catch (java.io.IOException e) { 397 G.v().out.println("PhaseDumper.dumpBody() caught: " + 400 e.toString()); 401 e.printStackTrace(G.v().out); 402 } 403 } 404 } finally { 405 alreadyDumping = false; 406 } 407 } 408 409 415 private String getClassIdent(Object obj) { 416 String qualifiedName = obj.getClass().getName(); 417 int lastDotIndex = qualifiedName.lastIndexOf('.'); 418 return qualifiedName.substring(lastDotIndex+1); 419 } 420 421 422 429 public void printCurrentStackTrace() { 430 try { 431 throw new java.io.IOException ("FAKE"); 432 } catch (java.io.IOException e) { 433 e.printStackTrace(G.v().out); 434 } 435 } 436 } 437 | Popular Tags |