DebugCheckers.cpp revision 1.1.1.1
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 25using namespace clang; 26using namespace ento; 27 28//===----------------------------------------------------------------------===// 29// DominatorsTreeDumper 30//===----------------------------------------------------------------------===// 31 32namespace { 33class DominatorsTreeDumper : public Checker<check::ASTCodeBody> { 34public: 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 46void ento::registerDominatorsTreeDumper(CheckerManager &mgr) { 47 mgr.registerChecker<DominatorsTreeDumper>(); 48} 49 50bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) { 51 return true; 52} 53 54//===----------------------------------------------------------------------===// 55// PostDominatorsTreeDumper 56//===----------------------------------------------------------------------===// 57 58namespace { 59class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> { 60public: 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 72void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { 73 mgr.registerChecker<PostDominatorsTreeDumper>(); 74} 75 76bool ento::shouldRegisterPostDominatorsTreeDumper(const LangOptions &LO) { 77 return true; 78} 79 80//===----------------------------------------------------------------------===// 81// ControlDependencyTreeDumper 82//===----------------------------------------------------------------------===// 83 84namespace { 85class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> { 86public: 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 97void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) { 98 mgr.registerChecker<ControlDependencyTreeDumper>(); 99} 100 101bool ento::shouldRegisterControlDependencyTreeDumper(const LangOptions &LO) { 102 return true; 103} 104 105//===----------------------------------------------------------------------===// 106// LiveVariablesDumper 107//===----------------------------------------------------------------------===// 108 109namespace { 110class LiveVariablesDumper : public Checker<check::ASTCodeBody> { 111public: 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 121void ento::registerLiveVariablesDumper(CheckerManager &mgr) { 122 mgr.registerChecker<LiveVariablesDumper>(); 123} 124 125bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { 126 return true; 127} 128 129//===----------------------------------------------------------------------===// 130// LiveStatementsDumper 131//===----------------------------------------------------------------------===// 132 133namespace { 134class LiveStatementsDumper : public Checker<check::ASTCodeBody> { 135public: 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 144void ento::registerLiveStatementsDumper(CheckerManager &mgr) { 145 mgr.registerChecker<LiveStatementsDumper>(); 146} 147 148bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { 149 return true; 150} 151 152//===----------------------------------------------------------------------===// 153// CFGViewer 154//===----------------------------------------------------------------------===// 155 156namespace { 157class CFGViewer : public Checker<check::ASTCodeBody> { 158public: 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 168void ento::registerCFGViewer(CheckerManager &mgr) { 169 mgr.registerChecker<CFGViewer>(); 170} 171 172bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { 173 return true; 174} 175 176//===----------------------------------------------------------------------===// 177// CFGDumper 178//===----------------------------------------------------------------------===// 179 180namespace { 181class CFGDumper : public Checker<check::ASTCodeBody> { 182public: 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 198void ento::registerCFGDumper(CheckerManager &mgr) { 199 mgr.registerChecker<CFGDumper>(); 200} 201 202bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { 203 return true; 204} 205 206//===----------------------------------------------------------------------===// 207// CallGraphViewer 208//===----------------------------------------------------------------------===// 209 210namespace { 211class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { 212public: 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 222void ento::registerCallGraphViewer(CheckerManager &mgr) { 223 mgr.registerChecker<CallGraphViewer>(); 224} 225 226bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { 227 return true; 228} 229 230//===----------------------------------------------------------------------===// 231// CallGraphDumper 232//===----------------------------------------------------------------------===// 233 234namespace { 235class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { 236public: 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 246void ento::registerCallGraphDumper(CheckerManager &mgr) { 247 mgr.registerChecker<CallGraphDumper>(); 248} 249 250bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { 251 return true; 252} 253 254//===----------------------------------------------------------------------===// 255// ConfigDumper 256//===----------------------------------------------------------------------===// 257 258namespace { 259class 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 267public: 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 290void ento::registerConfigDumper(CheckerManager &mgr) { 291 mgr.registerChecker<ConfigDumper>(); 292} 293 294bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { 295 return true; 296} 297 298//===----------------------------------------------------------------------===// 299// ExplodedGraph Viewer 300//===----------------------------------------------------------------------===// 301 302namespace { 303class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 304public: 305 ExplodedGraphViewer() {} 306 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 307 Eng.ViewGraph(0); 308 } 309}; 310 311} 312 313void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 314 mgr.registerChecker<ExplodedGraphViewer>(); 315} 316 317bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { 318 return true; 319} 320 321//===----------------------------------------------------------------------===// 322// Emits a report for every Stmt that the analyzer visits. 323//===----------------------------------------------------------------------===// 324 325namespace { 326 327class ReportStmts : public Checker<check::PreStmt<Stmt>> { 328 BuiltinBug BT_stmtLoc{this, "Statement"}; 329 330public: 331 void checkPreStmt(const Stmt *S, CheckerContext &C) const { 332 ExplodedNode *Node = C.generateNonFatalErrorNode(); 333 if (!Node) 334 return; 335 336 auto Report = 337 std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node); 338 339 C.emitReport(std::move(Report)); 340 } 341}; 342 343} // end of anonymous namespace 344 345void ento::registerReportStmts(CheckerManager &mgr) { 346 mgr.registerChecker<ReportStmts>(); 347} 348 349bool ento::shouldRegisterReportStmts(const LangOptions &LO) { 350 return true; 351} 352