1 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines a '-dot-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/Compiler.h" 27 #include "llvm/Support/GraphWriter.h" 28 using namespace llvm; 29 30 namespace llvm { 31 template<> 32 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { 33 static std::string getGraphName(const Function *F) { 34 return "CFG for '" + F->getNameStr() + "' function"; 35 } 36 37 static std::string getNodeLabel(const BasicBlock *Node, 38 const Function *Graph, 39 bool ShortNames) { 40 if (ShortNames && !Node->getName().empty()) 41 return Node->getNameStr() + ":"; 42 43 std::string Str; 44 raw_string_ostream OS(Str); 45 46 if (ShortNames) { 47 WriteAsOperand(OS, Node, false); 48 return OS.str(); 49 } 50 51 if (Node->getName().empty()) { 52 WriteAsOperand(OS, Node, false); 53 OS << ":"; 54 } 55 56 OS << *Node; 57 std::string OutStr = OS.str(); 58 if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); 59 60 // Process string output to make it nicer... 61 for (unsigned i = 0; i != OutStr.length(); ++i) 62 if (OutStr[i] == '\n') { // Left justify 63 OutStr[i] = '\\'; 64 OutStr.insert(OutStr.begin()+i+1, 'l'); 65 } else if (OutStr[i] == ';') { // Delete comments! 66 unsigned Idx = OutStr.find('\n', i+1); // Find end of line 67 OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); 68 --i; 69 } 70 71 return OutStr; 72 } 73 74 static std::string getEdgeSourceLabel(const BasicBlock *Node, 75 succ_const_iterator I) { 76 // Label source of conditional branches with "T" or "F" 77 if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) 78 if (BI->isConditional()) 79 return (I == succ_begin(Node)) ? "T" : "F"; 80 return ""; 81 } 82 }; 83 } 84 85 namespace { 86 struct VISIBILITY_HIDDEN CFGViewer : public FunctionPass { 87 static char ID; // Pass identifcation, replacement for typeid 88 CFGViewer() : FunctionPass(&ID) {} 89 90 virtual bool runOnFunction(Function &F) { 91 F.viewCFG(); 92 return false; 93 } 94 95 void print(raw_ostream &OS, const Module* = 0) const {} 96 97 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 98 AU.setPreservesAll(); 99 } 100 }; 101 } 102 103 char CFGViewer::ID = 0; 104 static RegisterPass<CFGViewer> 105 V0("view-cfg", "View CFG of function", false, true); 106 107 namespace { 108 struct VISIBILITY_HIDDEN CFGOnlyViewer : public FunctionPass { 109 static char ID; // Pass identifcation, replacement for typeid 110 CFGOnlyViewer() : FunctionPass(&ID) {} 111 112 virtual bool runOnFunction(Function &F) { 113 F.viewCFG(); 114 return false; 115 } 116 117 void print(raw_ostream &OS, const Module* = 0) const {} 118 119 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 120 AU.setPreservesAll(); 121 } 122 }; 123 } 124 125 char CFGOnlyViewer::ID = 0; 126 static RegisterPass<CFGOnlyViewer> 127 V1("view-cfg-only", 128 "View CFG of function (with no function bodies)", false, true); 129 130 namespace { 131 struct VISIBILITY_HIDDEN CFGPrinter : public FunctionPass { 132 static char ID; // Pass identification, replacement for typeid 133 CFGPrinter() : FunctionPass(&ID) {} 134 explicit CFGPrinter(void *pid) : FunctionPass(pid) {} 135 136 virtual bool runOnFunction(Function &F) { 137 std::string Filename = "cfg." + F.getNameStr() + ".dot"; 138 errs() << "Writing '" << Filename << "'..."; 139 140 std::string ErrorInfo; 141 raw_fd_ostream File(Filename.c_str(), ErrorInfo); 142 143 if (ErrorInfo.empty()) 144 WriteGraph(File, (const Function*)&F); 145 else 146 errs() << " error opening file for writing!"; 147 errs() << "\n"; 148 return false; 149 } 150 151 void print(raw_ostream &OS, const Module* = 0) const {} 152 153 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 154 AU.setPreservesAll(); 155 } 156 }; 157 } 158 159 char CFGPrinter::ID = 0; 160 static RegisterPass<CFGPrinter> 161 P1("dot-cfg", "Print CFG of function to 'dot' file", false, true); 162 163 namespace { 164 struct VISIBILITY_HIDDEN CFGOnlyPrinter : public FunctionPass { 165 static char ID; // Pass identification, replacement for typeid 166 CFGOnlyPrinter() : FunctionPass(&ID) {} 167 explicit CFGOnlyPrinter(void *pid) : FunctionPass(pid) {} 168 virtual bool runOnFunction(Function &F) { 169 std::string Filename = "cfg." + F.getNameStr() + ".dot"; 170 errs() << "Writing '" << Filename << "'..."; 171 172 std::string ErrorInfo; 173 raw_fd_ostream File(Filename.c_str(), ErrorInfo); 174 175 if (ErrorInfo.empty()) 176 WriteGraph(File, (const Function*)&F, true); 177 else 178 errs() << " error opening file for writing!"; 179 errs() << "\n"; 180 return false; 181 } 182 void print(raw_ostream &OS, const Module* = 0) const {} 183 184 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 185 AU.setPreservesAll(); 186 } 187 }; 188 } 189 190 char CFGOnlyPrinter::ID = 0; 191 static RegisterPass<CFGOnlyPrinter> 192 P2("dot-cfg-only", 193 "Print CFG of function to 'dot' file (with no function bodies)", false, true); 194 195 /// viewCFG - This function is meant for use from the debugger. You can just 196 /// say 'call F->viewCFG()' and a ghostview window should pop up from the 197 /// program, displaying the CFG of the current function. This depends on there 198 /// being a 'dot' and 'gv' program in your path. 199 /// 200 void Function::viewCFG() const { 201 ViewGraph(this, "cfg" + getNameStr()); 202 } 203 204 /// viewCFGOnly - This function is meant for use from the debugger. It works 205 /// just like viewCFG, but it does not include the contents of basic blocks 206 /// into the nodes, just the label. If you are only interested in the CFG t 207 /// his can make the graph smaller. 208 /// 209 void Function::viewCFGOnly() const { 210 ViewGraph(this, "cfg" + getNameStr(), true); 211 } 212 213 FunctionPass *llvm::createCFGPrinterPass () { 214 return new CFGPrinter(); 215 } 216 217 FunctionPass *llvm::createCFGOnlyPrinterPass () { 218 return new CFGOnlyPrinter(); 219 } 220 221