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