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