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
CFGViewerLegacyPass__anon52f097dc0111::CFGViewerLegacyPass38     CFGViewerLegacyPass() : FunctionPass(ID) {
39       initializeCFGViewerLegacyPassPass(*PassRegistry::getPassRegistry());
40     }
41 
runOnFunction__anon52f097dc0111::CFGViewerLegacyPass42     bool runOnFunction(Function &F) override {
43       F.viewCFG();
44       return false;
45     }
46 
print__anon52f097dc0111::CFGViewerLegacyPass47     void print(raw_ostream &OS, const Module* = nullptr) const override {}
48 
getAnalysisUsage__anon52f097dc0111::CFGViewerLegacyPass49     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 
run(Function & F,FunctionAnalysisManager & AM)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
CFGOnlyViewerLegacyPass__anon52f097dc0211::CFGOnlyViewerLegacyPass68     CFGOnlyViewerLegacyPass() : FunctionPass(ID) {
69       initializeCFGOnlyViewerLegacyPassPass(*PassRegistry::getPassRegistry());
70     }
71 
runOnFunction__anon52f097dc0211::CFGOnlyViewerLegacyPass72     bool runOnFunction(Function &F) override {
73       F.viewCFGOnly();
74       return false;
75     }
76 
print__anon52f097dc0211::CFGOnlyViewerLegacyPass77     void print(raw_ostream &OS, const Module* = nullptr) const override {}
78 
getAnalysisUsage__anon52f097dc0211::CFGOnlyViewerLegacyPass79     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 
run(Function & F,FunctionAnalysisManager & AM)89 PreservedAnalyses CFGOnlyViewerPass::run(Function &F,
90                                          FunctionAnalysisManager &AM) {
91   F.viewCFGOnly();
92   return PreservedAnalyses::all();
93 }
94 
writeCFGToDotFile(Function & F,bool CFGOnly=false)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
CFGPrinterLegacyPass__anon52f097dc0311::CFGPrinterLegacyPass115     CFGPrinterLegacyPass() : FunctionPass(ID) {
116       initializeCFGPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
117     }
118 
runOnFunction__anon52f097dc0311::CFGPrinterLegacyPass119     bool runOnFunction(Function &F) override {
120       writeCFGToDotFile(F);
121       return false;
122     }
123 
print__anon52f097dc0311::CFGPrinterLegacyPass124     void print(raw_ostream &OS, const Module* = nullptr) const override {}
125 
getAnalysisUsage__anon52f097dc0311::CFGPrinterLegacyPass126     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 
run(Function & F,FunctionAnalysisManager & AM)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
CFGOnlyPrinterLegacyPass__anon52f097dc0411::CFGOnlyPrinterLegacyPass145     CFGOnlyPrinterLegacyPass() : FunctionPass(ID) {
146       initializeCFGOnlyPrinterLegacyPassPass(*PassRegistry::getPassRegistry());
147     }
148 
runOnFunction__anon52f097dc0411::CFGOnlyPrinterLegacyPass149     bool runOnFunction(Function &F) override {
150       writeCFGToDotFile(F, /*CFGOnly=*/true);
151       return false;
152     }
print__anon52f097dc0411::CFGOnlyPrinterLegacyPass153     void print(raw_ostream &OS, const Module* = nullptr) const override {}
154 
getAnalysisUsage__anon52f097dc0411::CFGOnlyPrinterLegacyPass155     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 
run(Function & F,FunctionAnalysisManager & AM)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 ///
viewCFG() const177 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 ///
viewCFGOnly() const188 void Function::viewCFGOnly() const {
189   if (!CFGFuncName.empty() && !getName().contains(CFGFuncName))
190      return;
191   ViewGraph(this, "cfg" + getName(), true);
192 }
193 
createCFGPrinterLegacyPassPass()194 FunctionPass *llvm::createCFGPrinterLegacyPassPass () {
195   return new CFGPrinterLegacyPass();
196 }
197 
createCFGOnlyPrinterLegacyPassPass()198 FunctionPass *llvm::createCFGOnlyPrinterLegacyPassPass () {
199   return new CFGOnlyPrinterLegacyPass();
200 }
201 
202