1 //==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines checkers that display debugging information. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "ClangSACheckers.h" 15 #include "clang/Analysis/Analyses/Dominators.h" 16 #include "clang/Analysis/Analyses/LiveVariables.h" 17 #include "clang/Analysis/CallGraph.h" 18 #include "clang/StaticAnalyzer/Core/Checker.h" 19 #include "clang/StaticAnalyzer/Core/IssueHash.h" 20 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 24 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 25 #include "llvm/Support/Process.h" 26 27 using namespace clang; 28 using namespace ento; 29 30 //===----------------------------------------------------------------------===// 31 // DominatorsTreeDumper 32 //===----------------------------------------------------------------------===// 33 34 namespace { 35 class DominatorsTreeDumper : public Checker<check::ASTCodeBody> { 36 public: 37 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 38 BugReporter &BR) const { 39 if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 40 DominatorTree dom; 41 dom.buildDominatorTree(*AC); 42 dom.dump(); 43 } 44 } 45 }; 46 } 47 48 void ento::registerDominatorsTreeDumper(CheckerManager &mgr) { 49 mgr.registerChecker<DominatorsTreeDumper>(); 50 } 51 52 //===----------------------------------------------------------------------===// 53 // LiveVariablesDumper 54 //===----------------------------------------------------------------------===// 55 56 namespace { 57 class LiveVariablesDumper : public Checker<check::ASTCodeBody> { 58 public: 59 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 60 BugReporter &BR) const { 61 if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { 62 L->dumpBlockLiveness(mgr.getSourceManager()); 63 } 64 } 65 }; 66 } 67 68 void ento::registerLiveVariablesDumper(CheckerManager &mgr) { 69 mgr.registerChecker<LiveVariablesDumper>(); 70 } 71 72 //===----------------------------------------------------------------------===// 73 // CFGViewer 74 //===----------------------------------------------------------------------===// 75 76 namespace { 77 class CFGViewer : public Checker<check::ASTCodeBody> { 78 public: 79 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 80 BugReporter &BR) const { 81 if (CFG *cfg = mgr.getCFG(D)) { 82 cfg->viewCFG(mgr.getLangOpts()); 83 } 84 } 85 }; 86 } 87 88 void ento::registerCFGViewer(CheckerManager &mgr) { 89 mgr.registerChecker<CFGViewer>(); 90 } 91 92 //===----------------------------------------------------------------------===// 93 // CFGDumper 94 //===----------------------------------------------------------------------===// 95 96 namespace { 97 class CFGDumper : public Checker<check::ASTCodeBody> { 98 public: 99 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 100 BugReporter &BR) const { 101 PrintingPolicy Policy(mgr.getLangOpts()); 102 Policy.TerseOutput = true; 103 Policy.PolishForDeclaration = true; 104 D->print(llvm::errs(), Policy); 105 106 if (CFG *cfg = mgr.getCFG(D)) { 107 cfg->dump(mgr.getLangOpts(), 108 llvm::sys::Process::StandardErrHasColors()); 109 } 110 } 111 }; 112 } 113 114 void ento::registerCFGDumper(CheckerManager &mgr) { 115 mgr.registerChecker<CFGDumper>(); 116 } 117 118 //===----------------------------------------------------------------------===// 119 // CallGraphViewer 120 //===----------------------------------------------------------------------===// 121 122 namespace { 123 class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { 124 public: 125 void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 126 BugReporter &BR) const { 127 CallGraph CG; 128 CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 129 CG.viewGraph(); 130 } 131 }; 132 } 133 134 void ento::registerCallGraphViewer(CheckerManager &mgr) { 135 mgr.registerChecker<CallGraphViewer>(); 136 } 137 138 //===----------------------------------------------------------------------===// 139 // CallGraphDumper 140 //===----------------------------------------------------------------------===// 141 142 namespace { 143 class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { 144 public: 145 void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 146 BugReporter &BR) const { 147 CallGraph CG; 148 CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 149 CG.dump(); 150 } 151 }; 152 } 153 154 void ento::registerCallGraphDumper(CheckerManager &mgr) { 155 mgr.registerChecker<CallGraphDumper>(); 156 } 157 158 159 //===----------------------------------------------------------------------===// 160 // ConfigDumper 161 //===----------------------------------------------------------------------===// 162 163 namespace { 164 class ConfigDumper : public Checker< check::EndOfTranslationUnit > { 165 typedef AnalyzerOptions::ConfigTable Table; 166 167 static int compareEntry(const Table::MapEntryTy *const *LHS, 168 const Table::MapEntryTy *const *RHS) { 169 return (*LHS)->getKey().compare((*RHS)->getKey()); 170 } 171 172 public: 173 void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, 174 AnalysisManager& mgr, 175 BugReporter &BR) const { 176 const Table &Config = mgr.options.Config; 177 178 SmallVector<const Table::MapEntryTy *, 32> Keys; 179 for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; 180 ++I) 181 Keys.push_back(&*I); 182 llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); 183 184 llvm::errs() << "[config]\n"; 185 for (unsigned I = 0, E = Keys.size(); I != E; ++I) 186 llvm::errs() << Keys[I]->getKey() << " = " << Keys[I]->second << '\n'; 187 188 llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; 189 } 190 }; 191 } 192 193 void ento::registerConfigDumper(CheckerManager &mgr) { 194 mgr.registerChecker<ConfigDumper>(); 195 } 196 197 //===----------------------------------------------------------------------===// 198 // ExplodedGraph Viewer 199 //===----------------------------------------------------------------------===// 200 201 namespace { 202 class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 203 public: 204 ExplodedGraphViewer() {} 205 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 206 Eng.ViewGraph(0); 207 } 208 }; 209 210 } 211 212 void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 213 mgr.registerChecker<ExplodedGraphViewer>(); 214 } 215 216 //===----------------------------------------------------------------------===// 217 // DumpBugHash 218 //===----------------------------------------------------------------------===// 219 220 namespace { 221 class BugHashDumper : public Checker<check::PostStmt<Stmt>> { 222 public: 223 mutable std::unique_ptr<BugType> BT; 224 225 void checkPostStmt(const Stmt *S, CheckerContext &C) const { 226 if (!BT) 227 BT.reset(new BugType(this, "Dump hash components", "debug")); 228 229 ExplodedNode *N = C.generateNonFatalErrorNode(); 230 if (!N) 231 return; 232 233 const LangOptions &Opts = C.getLangOpts(); 234 const SourceManager &SM = C.getSourceManager(); 235 FullSourceLoc FL(S->getLocStart(), SM); 236 std::string HashContent = 237 GetIssueString(SM, FL, getCheckName().getName(), BT->getCategory(), 238 C.getLocationContext()->getDecl(), Opts); 239 240 C.emitReport(llvm::make_unique<BugReport>(*BT, HashContent, N)); 241 } 242 }; 243 } 244 245 void ento::registerBugHashDumper(CheckerManager &mgr) { 246 mgr.registerChecker<BugHashDumper>(); 247 } 248