1 //==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines checkers that display debugging information.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14 #include "clang/Analysis/Analyses/Dominators.h"
15 #include "clang/Analysis/Analyses/LiveVariables.h"
16 #include "clang/Analysis/CallGraph.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
23 #include "llvm/Support/Process.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 //===----------------------------------------------------------------------===//
29 // DominatorsTreeDumper
30 //===----------------------------------------------------------------------===//
31 
32 namespace {
33 class DominatorsTreeDumper : public Checker<check::ASTCodeBody> {
34 public:
35   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
36                         BugReporter &BR) const {
37     if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
38       DominatorTree dom;
39       dom.buildDominatorTree(*AC);
40       dom.dump();
41     }
42   }
43 };
44 }
45 
46 void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
47   mgr.registerChecker<DominatorsTreeDumper>();
48 }
49 
50 bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) {
51   return true;
52 }
53 
54 //===----------------------------------------------------------------------===//
55 // LiveVariablesDumper
56 //===----------------------------------------------------------------------===//
57 
58 namespace {
59 class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
60 public:
61   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
62                         BugReporter &BR) const {
63     if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
64       L->dumpBlockLiveness(mgr.getSourceManager());
65     }
66   }
67 };
68 }
69 
70 void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
71   mgr.registerChecker<LiveVariablesDumper>();
72 }
73 
74 bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) {
75   return true;
76 }
77 
78 //===----------------------------------------------------------------------===//
79 // LiveStatementsDumper
80 //===----------------------------------------------------------------------===//
81 
82 namespace {
83 class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
84 public:
85   void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
86                         BugReporter &BR) const {
87     if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
88       L->dumpStmtLiveness(Mgr.getSourceManager());
89   }
90 };
91 }
92 
93 void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
94   mgr.registerChecker<LiveStatementsDumper>();
95 }
96 
97 bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) {
98   return true;
99 }
100 
101 //===----------------------------------------------------------------------===//
102 // CFGViewer
103 //===----------------------------------------------------------------------===//
104 
105 namespace {
106 class CFGViewer : public Checker<check::ASTCodeBody> {
107 public:
108   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
109                         BugReporter &BR) const {
110     if (CFG *cfg = mgr.getCFG(D)) {
111       cfg->viewCFG(mgr.getLangOpts());
112     }
113   }
114 };
115 }
116 
117 void ento::registerCFGViewer(CheckerManager &mgr) {
118   mgr.registerChecker<CFGViewer>();
119 }
120 
121 bool ento::shouldRegisterCFGViewer(const LangOptions &LO) {
122   return true;
123 }
124 
125 //===----------------------------------------------------------------------===//
126 // CFGDumper
127 //===----------------------------------------------------------------------===//
128 
129 namespace {
130 class CFGDumper : public Checker<check::ASTCodeBody> {
131 public:
132   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
133                         BugReporter &BR) const {
134     PrintingPolicy Policy(mgr.getLangOpts());
135     Policy.TerseOutput = true;
136     Policy.PolishForDeclaration = true;
137     D->print(llvm::errs(), Policy);
138 
139     if (CFG *cfg = mgr.getCFG(D)) {
140       cfg->dump(mgr.getLangOpts(),
141                 llvm::sys::Process::StandardErrHasColors());
142     }
143   }
144 };
145 }
146 
147 void ento::registerCFGDumper(CheckerManager &mgr) {
148   mgr.registerChecker<CFGDumper>();
149 }
150 
151 bool ento::shouldRegisterCFGDumper(const LangOptions &LO) {
152   return true;
153 }
154 
155 //===----------------------------------------------------------------------===//
156 // CallGraphViewer
157 //===----------------------------------------------------------------------===//
158 
159 namespace {
160 class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
161 public:
162   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
163                     BugReporter &BR) const {
164     CallGraph CG;
165     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
166     CG.viewGraph();
167   }
168 };
169 }
170 
171 void ento::registerCallGraphViewer(CheckerManager &mgr) {
172   mgr.registerChecker<CallGraphViewer>();
173 }
174 
175 bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) {
176   return true;
177 }
178 
179 //===----------------------------------------------------------------------===//
180 // CallGraphDumper
181 //===----------------------------------------------------------------------===//
182 
183 namespace {
184 class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
185 public:
186   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
187                     BugReporter &BR) const {
188     CallGraph CG;
189     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
190     CG.dump();
191   }
192 };
193 }
194 
195 void ento::registerCallGraphDumper(CheckerManager &mgr) {
196   mgr.registerChecker<CallGraphDumper>();
197 }
198 
199 bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) {
200   return true;
201 }
202 
203 //===----------------------------------------------------------------------===//
204 // ConfigDumper
205 //===----------------------------------------------------------------------===//
206 
207 namespace {
208 class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
209   typedef AnalyzerOptions::ConfigTable Table;
210 
211   static int compareEntry(const Table::MapEntryTy *const *LHS,
212                           const Table::MapEntryTy *const *RHS) {
213     return (*LHS)->getKey().compare((*RHS)->getKey());
214   }
215 
216 public:
217   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
218                                  AnalysisManager& mgr,
219                                  BugReporter &BR) const {
220     const Table &Config = mgr.options.Config;
221 
222     SmallVector<const Table::MapEntryTy *, 32> Keys;
223     for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
224          ++I)
225       Keys.push_back(&*I);
226     llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
227 
228     llvm::errs() << "[config]\n";
229     for (unsigned I = 0, E = Keys.size(); I != E; ++I)
230       llvm::errs() << Keys[I]->getKey() << " = "
231                    << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
232                    << '\n';
233 
234     llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
235   }
236 };
237 }
238 
239 void ento::registerConfigDumper(CheckerManager &mgr) {
240   mgr.registerChecker<ConfigDumper>();
241 }
242 
243 bool ento::shouldRegisterConfigDumper(const LangOptions &LO) {
244   return true;
245 }
246 
247 //===----------------------------------------------------------------------===//
248 // ExplodedGraph Viewer
249 //===----------------------------------------------------------------------===//
250 
251 namespace {
252 class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
253 public:
254   ExplodedGraphViewer() {}
255   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
256     Eng.ViewGraph(0);
257   }
258 };
259 
260 }
261 
262 void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
263   mgr.registerChecker<ExplodedGraphViewer>();
264 }
265 
266 bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) {
267   return true;
268 }
269 
270 //===----------------------------------------------------------------------===//
271 // Emits a report for every Stmt that the analyzer visits.
272 //===----------------------------------------------------------------------===//
273 
274 namespace {
275 
276 class ReportStmts : public Checker<check::PreStmt<Stmt>> {
277   BuiltinBug BT_stmtLoc{this, "Statement"};
278 
279 public:
280   void checkPreStmt(const Stmt *S, CheckerContext &C) const {
281     ExplodedNode *Node = C.generateNonFatalErrorNode();
282     if (!Node)
283       return;
284 
285     auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node);
286 
287     C.emitReport(std::move(Report));
288   }
289 };
290 
291 } // end of anonymous namespace
292 
293 void ento::registerReportStmts(CheckerManager &mgr) {
294   mgr.registerChecker<ReportStmts>();
295 }
296 
297 bool ento::shouldRegisterReportStmts(const LangOptions &LO) {
298   return true;
299 }
300