LLVM API Documentation
00001 //===- CFGPrinter.cpp - DOT printer for the control flow graph ------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by the LLVM research group and is distributed under 00006 // the University of Illinois Open Source License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a '-print-cfg' analysis pass, which emits the 00011 // cfg.<fnname>.dot file for each function in the program, with a graph of the 00012 // CFG for that function. 00013 // 00014 // The other main feature of this file is that it implements the 00015 // Function::viewCFG method, which is useful for debugging passes which operate 00016 // on the CFG. 00017 // 00018 //===----------------------------------------------------------------------===// 00019 00020 #include "llvm/Function.h" 00021 #include "llvm/Instructions.h" 00022 #include "llvm/Pass.h" 00023 #include "llvm/Analysis/CFGPrinter.h" 00024 #include "llvm/Assembly/Writer.h" 00025 #include "llvm/Support/CFG.h" 00026 #include "llvm/Support/GraphWriter.h" 00027 #include <sstream> 00028 #include <fstream> 00029 using namespace llvm; 00030 00031 /// CFGOnly flag - This is used to control whether or not the CFG graph printer 00032 /// prints out the contents of basic blocks or not. This is acceptable because 00033 /// this code is only really used for debugging purposes. 00034 /// 00035 static bool CFGOnly = false; 00036 00037 namespace llvm { 00038 template<> 00039 struct DOTGraphTraits<const Function*> : public DefaultDOTGraphTraits { 00040 static std::string getGraphName(const Function *F) { 00041 return "CFG for '" + F->getName() + "' function"; 00042 } 00043 00044 static std::string getNodeLabel(const BasicBlock *Node, 00045 const Function *Graph) { 00046 if (CFGOnly && !Node->getName().empty()) 00047 return Node->getName() + ":"; 00048 00049 std::ostringstream Out; 00050 if (CFGOnly) { 00051 WriteAsOperand(Out, Node, false, true); 00052 return Out.str(); 00053 } 00054 00055 if (Node->getName().empty()) { 00056 WriteAsOperand(Out, Node, false, true); 00057 Out << ":"; 00058 } 00059 00060 Out << *Node; 00061 std::string OutStr = Out.str(); 00062 if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); 00063 00064 // Process string output to make it nicer... 00065 for (unsigned i = 0; i != OutStr.length(); ++i) 00066 if (OutStr[i] == '\n') { // Left justify 00067 OutStr[i] = '\\'; 00068 OutStr.insert(OutStr.begin()+i+1, 'l'); 00069 } else if (OutStr[i] == ';') { // Delete comments! 00070 unsigned Idx = OutStr.find('\n', i+1); // Find end of line 00071 OutStr.erase(OutStr.begin()+i, OutStr.begin()+Idx); 00072 --i; 00073 } 00074 00075 return OutStr; 00076 } 00077 00078 static std::string getEdgeSourceLabel(const BasicBlock *Node, 00079 succ_const_iterator I) { 00080 // Label source of conditional branches with "T" or "F" 00081 if (const BranchInst *BI = dyn_cast<BranchInst>(Node->getTerminator())) 00082 if (BI->isConditional()) 00083 return (I == succ_begin(Node)) ? "T" : "F"; 00084 return ""; 00085 } 00086 }; 00087 } 00088 00089 namespace { 00090 struct CFGPrinter : public FunctionPass { 00091 virtual bool runOnFunction(Function &F) { 00092 std::string Filename = "cfg." + F.getName() + ".dot"; 00093 std::cerr << "Writing '" << Filename << "'..."; 00094 std::ofstream File(Filename.c_str()); 00095 00096 if (File.good()) 00097 WriteGraph(File, (const Function*)&F); 00098 else 00099 std::cerr << " error opening file for writing!"; 00100 std::cerr << "\n"; 00101 return false; 00102 } 00103 00104 void print(std::ostream &OS) const {} 00105 00106 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 00107 AU.setPreservesAll(); 00108 } 00109 }; 00110 00111 RegisterAnalysis<CFGPrinter> P1("print-cfg", 00112 "Print CFG of function to 'dot' file"); 00113 00114 struct CFGOnlyPrinter : public CFGPrinter { 00115 virtual bool runOnFunction(Function &F) { 00116 bool OldCFGOnly = CFGOnly; 00117 CFGOnly = true; 00118 CFGPrinter::runOnFunction(F); 00119 CFGOnly = OldCFGOnly; 00120 return false; 00121 } 00122 void print(std::ostream &OS) const {} 00123 00124 virtual void getAnalysisUsage(AnalysisUsage &AU) const { 00125 AU.setPreservesAll(); 00126 } 00127 }; 00128 00129 RegisterAnalysis<CFGOnlyPrinter> 00130 P2("print-cfg-only", 00131 "Print CFG of function to 'dot' file (with no function bodies)"); 00132 } 00133 00134 /// viewCFG - This function is meant for use from the debugger. You can just 00135 /// say 'call F->viewCFG()' and a ghostview window should pop up from the 00136 /// program, displaying the CFG of the current function. This depends on there 00137 /// being a 'dot' and 'gv' program in your path. 00138 /// 00139 void Function::viewCFG() const { 00140 std::string Filename = "/tmp/cfg." + getName() + ".dot"; 00141 std::cerr << "Writing '" << Filename << "'... "; 00142 std::ofstream F(Filename.c_str()); 00143 00144 if (!F.good()) { 00145 std::cerr << " error opening file for writing!\n"; 00146 return; 00147 } 00148 00149 WriteGraph(F, this); 00150 F.close(); 00151 std::cerr << "\n"; 00152 00153 std::cerr << "Running 'dot' program... " << std::flush; 00154 if (system(("dot -Tps -Nfontname=Courier -Gsize=7.5,10 " + Filename 00155 + " > /tmp/cfg.tempgraph.ps").c_str())) { 00156 std::cerr << "Error running dot: 'dot' not in path?\n"; 00157 } else { 00158 std::cerr << "\n"; 00159 system("gv /tmp/cfg.tempgraph.ps"); 00160 } 00161 system(("rm " + Filename + " /tmp/cfg.tempgraph.ps").c_str()); 00162 } 00163 00164 /// viewCFGOnly - This function is meant for use from the debugger. It works 00165 /// just like viewCFG, but it does not include the contents of basic blocks 00166 /// into the nodes, just the label. If you are only interested in the CFG t 00167 /// his can make the graph smaller. 00168 /// 00169 void Function::viewCFGOnly() const { 00170 CFGOnly = true; 00171 viewCFG(); 00172 CFGOnly = false; 00173 } 00174 00175 FunctionPass *llvm::createCFGPrinterPass () { 00176 return new CFGPrinter(); 00177 } 00178 00179 FunctionPass *llvm::createCFGOnlyPrinterPass () { 00180 return new CFGOnlyPrinter(); 00181 } 00182