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 CFGDomTree dom; 39 dom.buildDominatorTree(AC->getCFG()); 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 // PostDominatorsTreeDumper 56 //===----------------------------------------------------------------------===// 57 58 namespace { 59 class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> { 60 public: 61 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 62 BugReporter &BR) const { 63 if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 64 CFGPostDomTree dom; 65 dom.buildDominatorTree(AC->getCFG()); 66 dom.dump(); 67 } 68 } 69 }; 70 } 71 72 void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { 73 mgr.registerChecker<PostDominatorsTreeDumper>(); 74 } 75 76 bool ento::shouldRegisterPostDominatorsTreeDumper(const LangOptions &LO) { 77 return true; 78 } 79 80 //===----------------------------------------------------------------------===// 81 // LiveVariablesDumper 82 //===----------------------------------------------------------------------===// 83 84 namespace { 85 class LiveVariablesDumper : public Checker<check::ASTCodeBody> { 86 public: 87 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 88 BugReporter &BR) const { 89 if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { 90 L->dumpBlockLiveness(mgr.getSourceManager()); 91 } 92 } 93 }; 94 } 95 96 void ento::registerLiveVariablesDumper(CheckerManager &mgr) { 97 mgr.registerChecker<LiveVariablesDumper>(); 98 } 99 100 bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { 101 return true; 102 } 103 104 //===----------------------------------------------------------------------===// 105 // LiveStatementsDumper 106 //===----------------------------------------------------------------------===// 107 108 namespace { 109 class LiveStatementsDumper : public Checker<check::ASTCodeBody> { 110 public: 111 void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, 112 BugReporter &BR) const { 113 if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) 114 L->dumpStmtLiveness(Mgr.getSourceManager()); 115 } 116 }; 117 } 118 119 void ento::registerLiveStatementsDumper(CheckerManager &mgr) { 120 mgr.registerChecker<LiveStatementsDumper>(); 121 } 122 123 bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { 124 return true; 125 } 126 127 //===----------------------------------------------------------------------===// 128 // CFGViewer 129 //===----------------------------------------------------------------------===// 130 131 namespace { 132 class CFGViewer : public Checker<check::ASTCodeBody> { 133 public: 134 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 135 BugReporter &BR) const { 136 if (CFG *cfg = mgr.getCFG(D)) { 137 cfg->viewCFG(mgr.getLangOpts()); 138 } 139 } 140 }; 141 } 142 143 void ento::registerCFGViewer(CheckerManager &mgr) { 144 mgr.registerChecker<CFGViewer>(); 145 } 146 147 bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { 148 return true; 149 } 150 151 //===----------------------------------------------------------------------===// 152 // CFGDumper 153 //===----------------------------------------------------------------------===// 154 155 namespace { 156 class CFGDumper : public Checker<check::ASTCodeBody> { 157 public: 158 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 159 BugReporter &BR) const { 160 PrintingPolicy Policy(mgr.getLangOpts()); 161 Policy.TerseOutput = true; 162 Policy.PolishForDeclaration = true; 163 D->print(llvm::errs(), Policy); 164 165 if (CFG *cfg = mgr.getCFG(D)) { 166 cfg->dump(mgr.getLangOpts(), 167 llvm::sys::Process::StandardErrHasColors()); 168 } 169 } 170 }; 171 } 172 173 void ento::registerCFGDumper(CheckerManager &mgr) { 174 mgr.registerChecker<CFGDumper>(); 175 } 176 177 bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { 178 return true; 179 } 180 181 //===----------------------------------------------------------------------===// 182 // CallGraphViewer 183 //===----------------------------------------------------------------------===// 184 185 namespace { 186 class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { 187 public: 188 void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 189 BugReporter &BR) const { 190 CallGraph CG; 191 CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 192 CG.viewGraph(); 193 } 194 }; 195 } 196 197 void ento::registerCallGraphViewer(CheckerManager &mgr) { 198 mgr.registerChecker<CallGraphViewer>(); 199 } 200 201 bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { 202 return true; 203 } 204 205 //===----------------------------------------------------------------------===// 206 // CallGraphDumper 207 //===----------------------------------------------------------------------===// 208 209 namespace { 210 class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { 211 public: 212 void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 213 BugReporter &BR) const { 214 CallGraph CG; 215 CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 216 CG.dump(); 217 } 218 }; 219 } 220 221 void ento::registerCallGraphDumper(CheckerManager &mgr) { 222 mgr.registerChecker<CallGraphDumper>(); 223 } 224 225 bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { 226 return true; 227 } 228 229 //===----------------------------------------------------------------------===// 230 // ConfigDumper 231 //===----------------------------------------------------------------------===// 232 233 namespace { 234 class ConfigDumper : public Checker< check::EndOfTranslationUnit > { 235 typedef AnalyzerOptions::ConfigTable Table; 236 237 static int compareEntry(const Table::MapEntryTy *const *LHS, 238 const Table::MapEntryTy *const *RHS) { 239 return (*LHS)->getKey().compare((*RHS)->getKey()); 240 } 241 242 public: 243 void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, 244 AnalysisManager& mgr, 245 BugReporter &BR) const { 246 const Table &Config = mgr.options.Config; 247 248 SmallVector<const Table::MapEntryTy *, 32> Keys; 249 for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; 250 ++I) 251 Keys.push_back(&*I); 252 llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); 253 254 llvm::errs() << "[config]\n"; 255 for (unsigned I = 0, E = Keys.size(); I != E; ++I) 256 llvm::errs() << Keys[I]->getKey() << " = " 257 << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second) 258 << '\n'; 259 260 llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; 261 } 262 }; 263 } 264 265 void ento::registerConfigDumper(CheckerManager &mgr) { 266 mgr.registerChecker<ConfigDumper>(); 267 } 268 269 bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { 270 return true; 271 } 272 273 //===----------------------------------------------------------------------===// 274 // ExplodedGraph Viewer 275 //===----------------------------------------------------------------------===// 276 277 namespace { 278 class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 279 public: 280 ExplodedGraphViewer() {} 281 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 282 Eng.ViewGraph(0); 283 } 284 }; 285 286 } 287 288 void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 289 mgr.registerChecker<ExplodedGraphViewer>(); 290 } 291 292 bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { 293 return true; 294 } 295 296 //===----------------------------------------------------------------------===// 297 // Emits a report for every Stmt that the analyzer visits. 298 //===----------------------------------------------------------------------===// 299 300 namespace { 301 302 class ReportStmts : public Checker<check::PreStmt<Stmt>> { 303 BuiltinBug BT_stmtLoc{this, "Statement"}; 304 305 public: 306 void checkPreStmt(const Stmt *S, CheckerContext &C) const { 307 ExplodedNode *Node = C.generateNonFatalErrorNode(); 308 if (!Node) 309 return; 310 311 auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node); 312 313 C.emitReport(std::move(Report)); 314 } 315 }; 316 317 } // end of anonymous namespace 318 319 void ento::registerReportStmts(CheckerManager &mgr) { 320 mgr.registerChecker<ReportStmts>(); 321 } 322 323 bool ento::shouldRegisterReportStmts(const LangOptions &LO) { 324 return true; 325 } 326