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 // `<prefix>.<fnname>.dot` file for each function in the program, with a graph 12 // of the CFG for that function. The default value for `<prefix>` is `cfg` but 13 // can be customized as needed. 14 // 15 // The other main feature of this file is that it implements the 16 // Function::viewCFG method, which is useful for debugging passes which operate 17 // on the CFG. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #include "llvm/Analysis/CFGPrinter.h" 22 #include "llvm/Pass.h" 23 #include "llvm/Support/FileSystem.h" 24 using namespace llvm; 25 26 static cl::opt<std::string> CFGFuncName( 27 "cfg-func-name", cl::Hidden, 28 cl::desc("The name of a function (or its substring)" 29 " whose CFG is viewed/printed.")); 30 31 static cl::opt<std::string> CFGDotFilenamePrefix( 32 "cfg-dot-filename-prefix", cl::Hidden, 33 cl::desc("The prefix used for the CFG dot file names.")); 34 35 namespace { 36 struct CFGViewerLegacyPass : public FunctionPass { 37 static char ID; // Pass identifcation, replacement for typeid 38 CFGViewerLegacyPass() : FunctionPass(ID) { 39 initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry()); 40 } 41 42 bool runOnFunction(Function &F) override { 43 F.viewCFG(); 44 return false; 45 } 46 47 void print(raw_ostream &OS, const Module* = nullptr) const override {} 48 49 void getAnalysisUsage(AnalysisUsage &AU) const override { 50 AU.setPreservesAll(); 51 } 52 }; 53 } 54 55 char CFGViewerLegacyPass::ID = 0; 56 INITIALIZE_PASS(CFGViewerLegacyPass, "view-cfg", "View CFG of function", false, true) 57 58 PreservedAnalyses CFGViewerPass::run(Function &F, 59 FunctionAnalysisManager &AM) { 60 F.viewCFG(); 61 return PreservedAnalyses::all(); 62 } 63 64 65 namespace { 66 struct CFGOnlyViewerLegacyPass : public FunctionPass { 67 static char ID; // Pass identifcation, replacement for typeid 68 CFGOnlyViewerLegacyPass() : FunctionPass(ID) { 69 initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry()); 70 } 71 72 bool runOnFunction(Function &F) override { 73 F.viewCFGOnly(); 74 return false; 75 } 76 77 void print(raw_ostream &OS, const Module* = nullptr) const override {} 78 79 void getAnalysisUsage(AnalysisUsage &AU) const override { 80 AU.setPreservesAll(); 81 } 82 }; 83 } 84 85 char CFGOnlyViewerLegacyPass::ID = 0; 86 INITIALIZE_PASS(CFGOnlyViewerLegacyPass, "view-cfg-only", 87 "View CFG of function (with no function bodies)", false, true) 88 89 PreservedAnalyses CFGOnlyViewerPass::run(Function &F, 90 FunctionAnalysisManager &AM) { 91 F.viewCFGOnly(); 92 return PreservedAnalyses::all(); 93 } 94 95 static void writeCFGToDotFile(Function &F, bool CFGOnly = false) { 96 if (!CFGFuncName.empty() && !F.getName().contains(CFGFuncName)) 97 return; 98 std::string Filename = 99 (CFGDotFilenamePrefix + "." + F.getName() + ".dot").str(); 100 errs() << "Writing '" << Filename << "'..."; 101 102 std::error_code EC; 103 raw_fd_ostream File(Filename, EC, sys::fs::F_Text); 104 105 if (!EC) 106 WriteGraph(File, (const Function*)&F, CFGOnly); 107 else 108 errs() << " error opening file for writing!"; 109 errs() << "\n"; 110 } 111 112 namespace { 113 struct CFGPrinterLegacyPass : public FunctionPass { 114 static char ID; // Pass identification, replacement for typeid 115 CFGPrinterLegacyPass() : FunctionPass(ID) { 116 initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); 117 } 118 119 bool runOnFunction(Function &F) override { 120 writeCFGToDotFile(F); 121 return false; 122 } 123 124 void print(raw_ostream &OS, const Module* = nullptr) const override {} 125 126 void getAnalysisUsage(AnalysisUsage &AU) const override { 127 AU.setPreservesAll(); 128 } 129 }; 130 } 131 132 char CFGPrinterLegacyPass::ID = 0; 133 INITIALIZE_PASS(CFGPrinterLegacyPass, "dot-cfg", "Print CFG of function to 'dot' file", 134 false, true) 135 136 PreservedAnalyses CFGPrinterPass::run(Function &F, 137 FunctionAnalysisManager &AM) { 138 writeCFGToDotFile(F); 139 return PreservedAnalyses::all(); 140 } 141 142 namespace { 143 struct CFGOnlyPrinterLegacyPass : public FunctionPass { 144 static char ID; // Pass identification, replacement for typeid 145 CFGOnlyPrinterLegacyPass() : FunctionPass(ID) { 146 initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry()); 147 } 148 149 bool runOnFunction(Function &F) override { 150 writeCFGToDotFile(F, /*CFGOnly=*/true); 151 return false; 152 } 153 void print(raw_ostream &OS, const Module* = nullptr) const override {} 154 155 void getAnalysisUsage(AnalysisUsage &AU) const override { 156 AU.setPreservesAll(); 157 } 158 }; 159 } 160 161 char CFGOnlyPrinterLegacyPass::ID = 0; 162 INITIALIZE_PASS(CFGOnlyPrinterLegacyPass, "dot-cfg-only", 163 "Print CFG of function to 'dot' file (with no function bodies)", 164 false, true) 165 166 PreservedAnalyses CFGOnlyPrinterPass::run(Function &F, 167 FunctionAnalysisManager &AM) { 168 writeCFGToDotFile(F, /*CFGOnly=*/true); 169 return PreservedAnalyses::all(); 170 } 171 172 /// viewCFG - This function is meant for use from the debugger. You can just 173 /// say 'call F->viewCFG()' and a ghostview window should pop up from the 174 /// program, displaying the CFG of the current function. This depends on there 175 /// being a 'dot' and 'gv' program in your path. 176 /// 177 void Function::viewCFG() const { 178 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) 179 return; 180 ViewGraph(this, "cfg" + getName()); 181 } 182 183 /// viewCFGOnly - This function is meant for use from the debugger. It works 184 /// just like viewCFG, but it does not include the contents of basic blocks 185 /// into the nodes, just the label. If you are only interested in the CFG 186 /// this can make the graph smaller. 187 /// 188 void Function::viewCFGOnly() const { 189 if (!CFGFuncName.empty() && !getName().contains(CFGFuncName)) 190 return; 191 ViewGraph(this, "cfg" + getName(), true); 192 } 193 194 FunctionPass *llvm::createCFGPrinterLegacyPassPass () { 195 return new CFGPrinterLegacyPass(); 196 } 197 198 FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () { 199 return new CFGOnlyPrinterLegacyPass(); 200 } 201 202