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