157d736fdSArgyrios Kyrtzidis //==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==// 257d736fdSArgyrios Kyrtzidis // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 657d736fdSArgyrios Kyrtzidis // 757d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 857d736fdSArgyrios Kyrtzidis // 973b75e01SJordan Rose // This file defines checkers that display debugging information. 1057d736fdSArgyrios Kyrtzidis // 1157d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 1257d736fdSArgyrios Kyrtzidis 1376a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 143a02247dSChandler Carruth #include "clang/Analysis/Analyses/Dominators.h" 153a02247dSChandler Carruth #include "clang/Analysis/Analyses/LiveVariables.h" 163a02247dSChandler Carruth #include "clang/Analysis/CallGraph.h" 176a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h" 18efec1630SGabor Horvath #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 1957d736fdSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 20efec1630SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 217925e3dbSAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 227925e3dbSAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 2372be32afSTed Kremenek #include "llvm/Support/Process.h" 2457d736fdSArgyrios Kyrtzidis 2557d736fdSArgyrios Kyrtzidis using namespace clang; 2657d736fdSArgyrios Kyrtzidis using namespace ento; 2757d736fdSArgyrios Kyrtzidis 2857d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 290062e749STed Kremenek // DominatorsTreeDumper 300062e749STed Kremenek //===----------------------------------------------------------------------===// 310062e749STed Kremenek 320062e749STed Kremenek namespace { 330062e749STed Kremenek class DominatorsTreeDumper : public Checker<check::ASTCodeBody> { 340062e749STed Kremenek public: 350062e749STed Kremenek void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 360062e749STed Kremenek BugReporter &BR) const { 370062e749STed Kremenek if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 38*5e17ee1eSKristof Umann CFGDomTree Dom; 39*5e17ee1eSKristof Umann Dom.buildDominatorTree(AC->getCFG()); 40*5e17ee1eSKristof Umann Dom.dump(); 410062e749STed Kremenek } 420062e749STed Kremenek } 430062e749STed Kremenek }; 44ab9db510SAlexander Kornienko } 450062e749STed Kremenek 460062e749STed Kremenek void ento::registerDominatorsTreeDumper(CheckerManager &mgr) { 470062e749STed Kremenek mgr.registerChecker<DominatorsTreeDumper>(); 480062e749STed Kremenek } 490062e749STed Kremenek 50058a7a45SKristof Umann bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) { 51058a7a45SKristof Umann return true; 52058a7a45SKristof Umann } 53058a7a45SKristof Umann 540062e749STed Kremenek //===----------------------------------------------------------------------===// 5571a9dc39SKristof Umann // PostDominatorsTreeDumper 5671a9dc39SKristof Umann //===----------------------------------------------------------------------===// 5771a9dc39SKristof Umann 5871a9dc39SKristof Umann namespace { 5971a9dc39SKristof Umann class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> { 6071a9dc39SKristof Umann public: 6171a9dc39SKristof Umann void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 6271a9dc39SKristof Umann BugReporter &BR) const { 6371a9dc39SKristof Umann if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 64*5e17ee1eSKristof Umann CFGPostDomTree Dom; 65*5e17ee1eSKristof Umann Dom.buildDominatorTree(AC->getCFG()); 66*5e17ee1eSKristof Umann Dom.dump(); 6771a9dc39SKristof Umann } 6871a9dc39SKristof Umann } 6971a9dc39SKristof Umann }; 7071a9dc39SKristof Umann } 7171a9dc39SKristof Umann 7271a9dc39SKristof Umann void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { 7371a9dc39SKristof Umann mgr.registerChecker<PostDominatorsTreeDumper>(); 7471a9dc39SKristof Umann } 7571a9dc39SKristof Umann 7671a9dc39SKristof Umann bool ento::shouldRegisterPostDominatorsTreeDumper(const LangOptions &LO) { 7771a9dc39SKristof Umann return true; 7871a9dc39SKristof Umann } 7971a9dc39SKristof Umann 8071a9dc39SKristof Umann //===----------------------------------------------------------------------===// 81*5e17ee1eSKristof Umann // ControlDependencyTreeDumper 82*5e17ee1eSKristof Umann //===----------------------------------------------------------------------===// 83*5e17ee1eSKristof Umann 84*5e17ee1eSKristof Umann namespace { 85*5e17ee1eSKristof Umann class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> { 86*5e17ee1eSKristof Umann public: 87*5e17ee1eSKristof Umann void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 88*5e17ee1eSKristof Umann BugReporter &BR) const { 89*5e17ee1eSKristof Umann if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 90*5e17ee1eSKristof Umann ControlDependencyCalculator Dom(AC->getCFG()); 91*5e17ee1eSKristof Umann Dom.dump(); 92*5e17ee1eSKristof Umann } 93*5e17ee1eSKristof Umann } 94*5e17ee1eSKristof Umann }; 95*5e17ee1eSKristof Umann } 96*5e17ee1eSKristof Umann 97*5e17ee1eSKristof Umann void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) { 98*5e17ee1eSKristof Umann mgr.registerChecker<ControlDependencyTreeDumper>(); 99*5e17ee1eSKristof Umann } 100*5e17ee1eSKristof Umann 101*5e17ee1eSKristof Umann bool ento::shouldRegisterControlDependencyTreeDumper(const LangOptions &LO) { 102*5e17ee1eSKristof Umann return true; 103*5e17ee1eSKristof Umann } 104*5e17ee1eSKristof Umann 105*5e17ee1eSKristof Umann //===----------------------------------------------------------------------===// 10657d736fdSArgyrios Kyrtzidis // LiveVariablesDumper 10757d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 10857d736fdSArgyrios Kyrtzidis 10957d736fdSArgyrios Kyrtzidis namespace { 1106a5674ffSArgyrios Kyrtzidis class LiveVariablesDumper : public Checker<check::ASTCodeBody> { 11157d736fdSArgyrios Kyrtzidis public: 11257d736fdSArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 11357d736fdSArgyrios Kyrtzidis BugReporter &BR) const { 114dccc2b22STed Kremenek if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { 11557d736fdSArgyrios Kyrtzidis L->dumpBlockLiveness(mgr.getSourceManager()); 11657d736fdSArgyrios Kyrtzidis } 11757d736fdSArgyrios Kyrtzidis } 11857d736fdSArgyrios Kyrtzidis }; 119ab9db510SAlexander Kornienko } 12057d736fdSArgyrios Kyrtzidis 12157d736fdSArgyrios Kyrtzidis void ento::registerLiveVariablesDumper(CheckerManager &mgr) { 12257d736fdSArgyrios Kyrtzidis mgr.registerChecker<LiveVariablesDumper>(); 12357d736fdSArgyrios Kyrtzidis } 12457d736fdSArgyrios Kyrtzidis 125058a7a45SKristof Umann bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { 126058a7a45SKristof Umann return true; 127058a7a45SKristof Umann } 128058a7a45SKristof Umann 12957d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 130dda42164SArtem Dergachev // LiveStatementsDumper 131dda42164SArtem Dergachev //===----------------------------------------------------------------------===// 132dda42164SArtem Dergachev 133dda42164SArtem Dergachev namespace { 134dda42164SArtem Dergachev class LiveStatementsDumper : public Checker<check::ASTCodeBody> { 135dda42164SArtem Dergachev public: 136dda42164SArtem Dergachev void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, 137dda42164SArtem Dergachev BugReporter &BR) const { 138dda42164SArtem Dergachev if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) 139dda42164SArtem Dergachev L->dumpStmtLiveness(Mgr.getSourceManager()); 140dda42164SArtem Dergachev } 141dda42164SArtem Dergachev }; 142dda42164SArtem Dergachev } 143dda42164SArtem Dergachev 144dda42164SArtem Dergachev void ento::registerLiveStatementsDumper(CheckerManager &mgr) { 145dda42164SArtem Dergachev mgr.registerChecker<LiveStatementsDumper>(); 146dda42164SArtem Dergachev } 147dda42164SArtem Dergachev 148058a7a45SKristof Umann bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { 149058a7a45SKristof Umann return true; 150058a7a45SKristof Umann } 151058a7a45SKristof Umann 152dda42164SArtem Dergachev //===----------------------------------------------------------------------===// 15357d736fdSArgyrios Kyrtzidis // CFGViewer 15457d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 15557d736fdSArgyrios Kyrtzidis 15657d736fdSArgyrios Kyrtzidis namespace { 1576a5674ffSArgyrios Kyrtzidis class CFGViewer : public Checker<check::ASTCodeBody> { 15857d736fdSArgyrios Kyrtzidis public: 15957d736fdSArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 16057d736fdSArgyrios Kyrtzidis BugReporter &BR) const { 16157d736fdSArgyrios Kyrtzidis if (CFG *cfg = mgr.getCFG(D)) { 162bbafb8a7SDavid Blaikie cfg->viewCFG(mgr.getLangOpts()); 16357d736fdSArgyrios Kyrtzidis } 16457d736fdSArgyrios Kyrtzidis } 16557d736fdSArgyrios Kyrtzidis }; 166ab9db510SAlexander Kornienko } 16757d736fdSArgyrios Kyrtzidis 16857d736fdSArgyrios Kyrtzidis void ento::registerCFGViewer(CheckerManager &mgr) { 16957d736fdSArgyrios Kyrtzidis mgr.registerChecker<CFGViewer>(); 17057d736fdSArgyrios Kyrtzidis } 17157d736fdSArgyrios Kyrtzidis 172058a7a45SKristof Umann bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { 173058a7a45SKristof Umann return true; 174058a7a45SKristof Umann } 175058a7a45SKristof Umann 17657d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 17757d736fdSArgyrios Kyrtzidis // CFGDumper 17857d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 17957d736fdSArgyrios Kyrtzidis 18057d736fdSArgyrios Kyrtzidis namespace { 1816a5674ffSArgyrios Kyrtzidis class CFGDumper : public Checker<check::ASTCodeBody> { 18257d736fdSArgyrios Kyrtzidis public: 18357d736fdSArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 18457d736fdSArgyrios Kyrtzidis BugReporter &BR) const { 185e02e96a6SJordan Rose PrintingPolicy Policy(mgr.getLangOpts()); 186e02e96a6SJordan Rose Policy.TerseOutput = true; 187e02e96a6SJordan Rose Policy.PolishForDeclaration = true; 188e02e96a6SJordan Rose D->print(llvm::errs(), Policy); 189e02e96a6SJordan Rose 19057d736fdSArgyrios Kyrtzidis if (CFG *cfg = mgr.getCFG(D)) { 191bbafb8a7SDavid Blaikie cfg->dump(mgr.getLangOpts(), 19272be32afSTed Kremenek llvm::sys::Process::StandardErrHasColors()); 19357d736fdSArgyrios Kyrtzidis } 19457d736fdSArgyrios Kyrtzidis } 19557d736fdSArgyrios Kyrtzidis }; 196ab9db510SAlexander Kornienko } 19757d736fdSArgyrios Kyrtzidis 19857d736fdSArgyrios Kyrtzidis void ento::registerCFGDumper(CheckerManager &mgr) { 19957d736fdSArgyrios Kyrtzidis mgr.registerChecker<CFGDumper>(); 20057d736fdSArgyrios Kyrtzidis } 201c000e7edSAnna Zaks 202058a7a45SKristof Umann bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { 203058a7a45SKristof Umann return true; 204058a7a45SKristof Umann } 205058a7a45SKristof Umann 206c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 207c000e7edSAnna Zaks // CallGraphViewer 208c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 209c000e7edSAnna Zaks 210c000e7edSAnna Zaks namespace { 211c000e7edSAnna Zaks class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { 212c000e7edSAnna Zaks public: 213c000e7edSAnna Zaks void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 214c000e7edSAnna Zaks BugReporter &BR) const { 215c000e7edSAnna Zaks CallGraph CG; 216c000e7edSAnna Zaks CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 217c000e7edSAnna Zaks CG.viewGraph(); 218c000e7edSAnna Zaks } 219c000e7edSAnna Zaks }; 220ab9db510SAlexander Kornienko } 221c000e7edSAnna Zaks 222c000e7edSAnna Zaks void ento::registerCallGraphViewer(CheckerManager &mgr) { 223c000e7edSAnna Zaks mgr.registerChecker<CallGraphViewer>(); 224c000e7edSAnna Zaks } 225c000e7edSAnna Zaks 226058a7a45SKristof Umann bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { 227058a7a45SKristof Umann return true; 228058a7a45SKristof Umann } 229058a7a45SKristof Umann 230c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 231c000e7edSAnna Zaks // CallGraphDumper 232c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 233c000e7edSAnna Zaks 234c000e7edSAnna Zaks namespace { 235c000e7edSAnna Zaks class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { 236c000e7edSAnna Zaks public: 237c000e7edSAnna Zaks void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 238c000e7edSAnna Zaks BugReporter &BR) const { 239c000e7edSAnna Zaks CallGraph CG; 240c000e7edSAnna Zaks CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 241c000e7edSAnna Zaks CG.dump(); 242c000e7edSAnna Zaks } 243c000e7edSAnna Zaks }; 244ab9db510SAlexander Kornienko } 245c000e7edSAnna Zaks 246c000e7edSAnna Zaks void ento::registerCallGraphDumper(CheckerManager &mgr) { 247c000e7edSAnna Zaks mgr.registerChecker<CallGraphDumper>(); 248c000e7edSAnna Zaks } 24986917fdbSTed Kremenek 250058a7a45SKristof Umann bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { 251058a7a45SKristof Umann return true; 252058a7a45SKristof Umann } 25386917fdbSTed Kremenek 25486917fdbSTed Kremenek //===----------------------------------------------------------------------===// 25586917fdbSTed Kremenek // ConfigDumper 25686917fdbSTed Kremenek //===----------------------------------------------------------------------===// 25786917fdbSTed Kremenek 25886917fdbSTed Kremenek namespace { 25986917fdbSTed Kremenek class ConfigDumper : public Checker< check::EndOfTranslationUnit > { 260a92b80f8SBenjamin Kramer typedef AnalyzerOptions::ConfigTable Table; 261a92b80f8SBenjamin Kramer 2624cadf292SBenjamin Kramer static int compareEntry(const Table::MapEntryTy *const *LHS, 2634cadf292SBenjamin Kramer const Table::MapEntryTy *const *RHS) { 2644cadf292SBenjamin Kramer return (*LHS)->getKey().compare((*RHS)->getKey()); 2654cadf292SBenjamin Kramer } 2664cadf292SBenjamin Kramer 26786917fdbSTed Kremenek public: 26886917fdbSTed Kremenek void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, 26986917fdbSTed Kremenek AnalysisManager& mgr, 27086917fdbSTed Kremenek BugReporter &BR) const { 271a92b80f8SBenjamin Kramer const Table &Config = mgr.options.Config; 27286917fdbSTed Kremenek 273a92b80f8SBenjamin Kramer SmallVector<const Table::MapEntryTy *, 32> Keys; 274a92b80f8SBenjamin Kramer for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; 275a92b80f8SBenjamin Kramer ++I) 276a92b80f8SBenjamin Kramer Keys.push_back(&*I); 2774cadf292SBenjamin Kramer llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); 27886917fdbSTed Kremenek 27986917fdbSTed Kremenek llvm::errs() << "[config]\n"; 280a92b80f8SBenjamin Kramer for (unsigned I = 0, E = Keys.size(); I != E; ++I) 281549f9cd4SKristof Umann llvm::errs() << Keys[I]->getKey() << " = " 282549f9cd4SKristof Umann << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second) 283549f9cd4SKristof Umann << '\n'; 284a92b80f8SBenjamin Kramer 28586917fdbSTed Kremenek llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; 28686917fdbSTed Kremenek } 28786917fdbSTed Kremenek }; 288ab9db510SAlexander Kornienko } 28986917fdbSTed Kremenek 29086917fdbSTed Kremenek void ento::registerConfigDumper(CheckerManager &mgr) { 29186917fdbSTed Kremenek mgr.registerChecker<ConfigDumper>(); 29286917fdbSTed Kremenek } 2937925e3dbSAnna Zaks 294058a7a45SKristof Umann bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { 295058a7a45SKristof Umann return true; 296058a7a45SKristof Umann } 297058a7a45SKristof Umann 2987925e3dbSAnna Zaks //===----------------------------------------------------------------------===// 2997925e3dbSAnna Zaks // ExplodedGraph Viewer 3007925e3dbSAnna Zaks //===----------------------------------------------------------------------===// 3017925e3dbSAnna Zaks 3027925e3dbSAnna Zaks namespace { 3037925e3dbSAnna Zaks class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 3047925e3dbSAnna Zaks public: 3057925e3dbSAnna Zaks ExplodedGraphViewer() {} 3067925e3dbSAnna Zaks void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 3077925e3dbSAnna Zaks Eng.ViewGraph(0); 3087925e3dbSAnna Zaks } 3097925e3dbSAnna Zaks }; 3107925e3dbSAnna Zaks 3117925e3dbSAnna Zaks } 3127925e3dbSAnna Zaks 3137925e3dbSAnna Zaks void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 3147925e3dbSAnna Zaks mgr.registerChecker<ExplodedGraphViewer>(); 3157925e3dbSAnna Zaks } 316efec1630SGabor Horvath 317058a7a45SKristof Umann bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { 318058a7a45SKristof Umann return true; 319058a7a45SKristof Umann } 3204962816eSKristof Umann 3214962816eSKristof Umann //===----------------------------------------------------------------------===// 3224962816eSKristof Umann // Emits a report for every Stmt that the analyzer visits. 3234962816eSKristof Umann //===----------------------------------------------------------------------===// 3244962816eSKristof Umann 3254962816eSKristof Umann namespace { 3264962816eSKristof Umann 3274962816eSKristof Umann class ReportStmts : public Checker<check::PreStmt<Stmt>> { 3284962816eSKristof Umann BuiltinBug BT_stmtLoc{this, "Statement"}; 3294962816eSKristof Umann 3304962816eSKristof Umann public: 3314962816eSKristof Umann void checkPreStmt(const Stmt *S, CheckerContext &C) const { 3324962816eSKristof Umann ExplodedNode *Node = C.generateNonFatalErrorNode(); 3334962816eSKristof Umann if (!Node) 3344962816eSKristof Umann return; 3354962816eSKristof Umann 3364962816eSKristof Umann auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node); 3374962816eSKristof Umann 3384962816eSKristof Umann C.emitReport(std::move(Report)); 3394962816eSKristof Umann } 3404962816eSKristof Umann }; 3414962816eSKristof Umann 3424962816eSKristof Umann } // end of anonymous namespace 3434962816eSKristof Umann 3444962816eSKristof Umann void ento::registerReportStmts(CheckerManager &mgr) { 3454962816eSKristof Umann mgr.registerChecker<ReportStmts>(); 3464962816eSKristof Umann } 3474962816eSKristof Umann 3484962816eSKristof Umann bool ento::shouldRegisterReportStmts(const LangOptions &LO) { 3494962816eSKristof Umann return true; 3504962816eSKristof Umann } 351