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 //===----------------------------------------------------------------------===// 51 // LiveVariablesDumper 52 //===----------------------------------------------------------------------===// 53 54 namespace { 55 class LiveVariablesDumper : public Checker<check::ASTCodeBody> { 56 public: 57 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 58 BugReporter &BR) const { 59 if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { 60 L->dumpBlockLiveness(mgr.getSourceManager()); 61 } 62 } 63 }; 64 } 65 66 void ento::registerLiveVariablesDumper(CheckerManager &mgr) { 67 mgr.registerChecker<LiveVariablesDumper>(); 68 } 69 70 //===----------------------------------------------------------------------===// 71 // LiveStatementsDumper 72 //===----------------------------------------------------------------------===// 73 74 namespace { 75 class LiveStatementsDumper : public Checker<check::ASTCodeBody> { 76 public: 77 void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, 78 BugReporter &BR) const { 79 if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) 80 L->dumpStmtLiveness(Mgr.getSourceManager()); 81 } 82 }; 83 } 84 85 void ento::registerLiveStatementsDumper(CheckerManager &mgr) { 86 mgr.registerChecker<LiveStatementsDumper>(); 87 } 88 89 //===----------------------------------------------------------------------===// 90 // CFGViewer 91 //===----------------------------------------------------------------------===// 92 93 namespace { 94 class CFGViewer : public Checker<check::ASTCodeBody> { 95 public: 96 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 97 BugReporter &BR) const { 98 if (CFG *cfg = mgr.getCFG(D)) { 99 cfg->viewCFG(mgr.getLangOpts()); 100 } 101 } 102 }; 103 } 104 105 void ento::registerCFGViewer(CheckerManager &mgr) { 106 mgr.registerChecker<CFGViewer>(); 107 } 108 109 //===----------------------------------------------------------------------===// 110 // CFGDumper 111 //===----------------------------------------------------------------------===// 112 113 namespace { 114 class CFGDumper : public Checker<check::ASTCodeBody> { 115 public: 116 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 117 BugReporter &BR) const { 118 PrintingPolicy Policy(mgr.getLangOpts()); 119 Policy.TerseOutput = true; 120 Policy.PolishForDeclaration = true; 121 D->print(llvm::errs(), Policy); 122 123 if (CFG *cfg = mgr.getCFG(D)) { 124 cfg->dump(mgr.getLangOpts(), 125 llvm::sys::Process::StandardErrHasColors()); 126 } 127 } 128 }; 129 } 130 131 void ento::registerCFGDumper(CheckerManager &mgr) { 132 mgr.registerChecker<CFGDumper>(); 133 } 134 135 //===----------------------------------------------------------------------===// 136 // CallGraphViewer 137 //===----------------------------------------------------------------------===// 138 139 namespace { 140 class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { 141 public: 142 void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 143 BugReporter &BR) const { 144 CallGraph CG; 145 CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 146 CG.viewGraph(); 147 } 148 }; 149 } 150 151 void ento::registerCallGraphViewer(CheckerManager &mgr) { 152 mgr.registerChecker<CallGraphViewer>(); 153 } 154 155 //===----------------------------------------------------------------------===// 156 // CallGraphDumper 157 //===----------------------------------------------------------------------===// 158 159 namespace { 160 class CallGraphDumper : 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.dump(); 167 } 168 }; 169 } 170 171 void ento::registerCallGraphDumper(CheckerManager &mgr) { 172 mgr.registerChecker<CallGraphDumper>(); 173 } 174 175 176 //===----------------------------------------------------------------------===// 177 // ConfigDumper 178 //===----------------------------------------------------------------------===// 179 180 namespace { 181 class ConfigDumper : public Checker< check::EndOfTranslationUnit > { 182 typedef AnalyzerOptions::ConfigTable Table; 183 184 static int compareEntry(const Table::MapEntryTy *const *LHS, 185 const Table::MapEntryTy *const *RHS) { 186 return (*LHS)->getKey().compare((*RHS)->getKey()); 187 } 188 189 public: 190 void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, 191 AnalysisManager& mgr, 192 BugReporter &BR) const { 193 const Table &Config = mgr.options.Config; 194 195 SmallVector<const Table::MapEntryTy *, 32> Keys; 196 for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; 197 ++I) 198 Keys.push_back(&*I); 199 llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); 200 201 llvm::errs() << "[config]\n"; 202 for (unsigned I = 0, E = Keys.size(); I != E; ++I) 203 llvm::errs() << Keys[I]->getKey() << " = " 204 << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second) 205 << '\n'; 206 207 llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; 208 } 209 }; 210 } 211 212 void ento::registerConfigDumper(CheckerManager &mgr) { 213 mgr.registerChecker<ConfigDumper>(); 214 } 215 216 //===----------------------------------------------------------------------===// 217 // ExplodedGraph Viewer 218 //===----------------------------------------------------------------------===// 219 220 namespace { 221 class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 222 public: 223 ExplodedGraphViewer() {} 224 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 225 Eng.ViewGraph(0); 226 } 227 }; 228 229 } 230 231 void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 232 mgr.registerChecker<ExplodedGraphViewer>(); 233 } 234 235