1 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file was developed by the LLVM research group and is distributed under 6 // the University of Illinois Open Source License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines a '-print-cfg' analysis pass, which emits the 11 // cfg.<fnname>.dot file for each function in the program, with a graph of the 12 // CFG for that function. 13 // 14 // The other main feature of this file is that it implements the 15 // Function::viewCFG method, which is useful for debugging passes which operate 16 // on the CFG. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "llvm/Function.h" 21 #include "llvm/Instructions.h" 22 #include "llvm/Pass.h" 23 #include "llvm/Analysis/CFGPrinter.h" 24 #include "llvm/Assembly/Writer.h" 25 #include "llvm/Support/CFG.h" 26 #include "llvm/Support/GraphWriter.h" 27 #include <sstream> 28 #include <fstream> 29 using namespace llvm; 30 31 /// CFGOnly flag - This is used to control whether or not the CFG graph printer 32 /// prints out the contents of basic blocks or not. This is acceptable because 33 /// this code is only really used for debugging purposes. 34 /// 35 static bool CFGOnly = false; 36 37 namespace llvm { 38 template<> 39 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { 40 static std::string getGraphName(const Function *F) { 41 return "CFG for '" + F->getName() + "' function"; 42 } 43 44 static std::string getNodeLabel(const BasicBlock *Node, 45 const Function *Graph) { 46 if (CFGOnly && !Node->getName().empty()) 47 return Node->getName() + ":"; 48 49 std::ostringstream Out; 50 if (CFGOnly) { 51 WriteAsOperand(Out, Node, false, true); 52 return Out.str(); 53 } 54 55 if (Node->getName().empty()) { 56 WriteAsOperand(Out, Node, false, true); 57 Out << ":"; 58 } 59 60 Out << *Node; 61 std::string OutStr = Out.str(); 62 if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); 63 64 // Process string output to make it nicer... 65 for (unsigned i = 0; i != OutStr.length(); ++i) 66 if (OutStr[i] == '\n') { // Left justify 67 OutStr[i] = '\\'; 68 OutStr.insert(OutStr.begin()+i+1, 'l'); 69 } else if (OutStr[i] == ';') { // Delete comments! 70 unsigned Idx = OutStr.find('\n', i+1); // Find end of line 71 OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); 72 --i; 73 } 74 75 return OutStr; 76 } 77 78 static std::string getEdgeSourceLabel(const BasicBlock *Node, 79 succ_const_iterator I) { 80 // Label source of conditional branches with "T" or "F" 81 if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) 82 if (BI->isConditional()) 83 return (I == succ_begin(Node)) ? "T" : "F"; 84 return ""; 85 } 86 }; 87 } 88 89 namespace { 90 struct CFGPrinter : public FunctionPass { 91 virtual bool runOnFunction(Function &F) { 92 std::string Filename = "cfg." + F.getName() + ".dot"; 93 std::cerr << "Writing '" << Filename << "'..."; 94 std::ofstream File(Filename.c_str()); 95 96 if (File.good()) 97 WriteGraph(File, (const Function*)&F); 98 else 99 std::cerr << " error opening file for writing!"; 100 std::cerr << "\n"; 101 return false; 102 } 103 104 void print(std::ostream &OS, const Module* = 0) const {} 105 106 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 107 AU.setPreservesAll(); 108 } 109 }; 110 111 RegisterAnalysis<CFGPrinter> P1("print-cfg", 112 "Print CFG of function to 'dot' file"); 113 114 struct CFGOnlyPrinter : public CFGPrinter { 115 virtual bool runOnFunction(Function &F) { 116 bool OldCFGOnly = CFGOnly; 117 CFGOnly = true; 118 CFGPrinter::runOnFunction(F); 119 CFGOnly = OldCFGOnly; 120 return false; 121 } 122 void print(std::ostream &OS, const Module* = 0) const {} 123 124 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 125 AU.setPreservesAll(); 126 } 127 }; 128 129 RegisterAnalysis<CFGOnlyPrinter> 130 P2("print-cfg-only", 131 "Print CFG of function to 'dot' file (with no function bodies)"); 132 } 133 134 /// viewCFG - This function is meant for use from the debugger. You can just 135 /// say 'call F->viewCFG()' and a ghostview window should pop up from the 136 /// program, displaying the CFG of the current function. This depends on there 137 /// being a 'dot' and 'gv' program in your path. 138 /// 139 void Function::viewCFG() const { 140 std::string Filename = "/tmp/cfg." + getName() + ".dot"; 141 std::cerr << "Writing '" << Filename << "'... "; 142 std::ofstream F(Filename.c_str()); 143 144 if (!F.good()) { 145 std::cerr << " error opening file for writing!\n"; 146 return; 147 } 148 149 WriteGraph(F, this); 150 F.close(); 151 std::cerr << "\n"; 152 153 std::cerr << "Running 'dot' program... " << std::flush; 154 if (system(("dot -Tps -Nfontname=Courier -Gsize=7.5,10 " + Filename 155 + " > /tmp/cfg.tempgraph.ps").c_str())) { 156 std::cerr << "Error running dot: 'dot' not in path?\n"; 157 } else { 158 std::cerr << "\n"; 159 system("gv /tmp/cfg.tempgraph.ps"); 160 } 161 system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str()); 162 } 163 164 /// viewCFGOnly - This function is meant for use from the debugger. It works 165 /// just like viewCFG, but it does not include the contents of basic blocks 166 /// into the nodes, just the label. If you are only interested in the CFG t 167 /// his can make the graph smaller. 168 /// 169 void Function::viewCFGOnly() const { 170 CFGOnly = true; 171 viewCFG(); 172 CFGOnly = false; 173 } 174 175 FunctionPass *llvm::createCFGPrinterPass () { 176 return new CFGPrinter(); 177 } 178 179 FunctionPass *llvm::createCFGOnlyPrinterPass () { 180 return new CFGOnlyPrinter(); 181 } 182 183