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)) { 385e17ee1eSKristof Umann CFGDomTree Dom; 395e17ee1eSKristof Umann Dom.buildDominatorTree(AC->getCFG()); 405e17ee1eSKristof 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 50bda3dd0dSKirstóf Umann bool ento::shouldRegisterDominatorsTreeDumper(const CheckerManager &mgr) { 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)) { 645e17ee1eSKristof Umann CFGPostDomTree Dom; 655e17ee1eSKristof Umann Dom.buildDominatorTree(AC->getCFG()); 665e17ee1eSKristof 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 76bda3dd0dSKirstóf Umann bool ento::shouldRegisterPostDominatorsTreeDumper(const CheckerManager &mgr) { 7771a9dc39SKristof Umann return true; 7871a9dc39SKristof Umann } 7971a9dc39SKristof Umann 8071a9dc39SKristof Umann //===----------------------------------------------------------------------===// 815e17ee1eSKristof Umann // ControlDependencyTreeDumper 825e17ee1eSKristof Umann //===----------------------------------------------------------------------===// 835e17ee1eSKristof Umann 845e17ee1eSKristof Umann namespace { 855e17ee1eSKristof Umann class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> { 865e17ee1eSKristof Umann public: 875e17ee1eSKristof Umann void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 885e17ee1eSKristof Umann BugReporter &BR) const { 895e17ee1eSKristof Umann if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 905e17ee1eSKristof Umann ControlDependencyCalculator Dom(AC->getCFG()); 915e17ee1eSKristof Umann Dom.dump(); 925e17ee1eSKristof Umann } 935e17ee1eSKristof Umann } 945e17ee1eSKristof Umann }; 955e17ee1eSKristof Umann } 965e17ee1eSKristof Umann 975e17ee1eSKristof Umann void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) { 985e17ee1eSKristof Umann mgr.registerChecker<ControlDependencyTreeDumper>(); 995e17ee1eSKristof Umann } 1005e17ee1eSKristof Umann 101bda3dd0dSKirstóf Umann bool ento::shouldRegisterControlDependencyTreeDumper(const CheckerManager &mgr) { 1025e17ee1eSKristof Umann return true; 1035e17ee1eSKristof Umann } 1045e17ee1eSKristof Umann 1055e17ee1eSKristof 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 125bda3dd0dSKirstóf Umann bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) { 126058a7a45SKristof Umann return true; 127058a7a45SKristof Umann } 128058a7a45SKristof Umann 12957d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 130dda42164SArtem Dergachev // LiveStatementsDumper 131dda42164SArtem Dergachev //===----------------------------------------------------------------------===// 132dda42164SArtem Dergachev 133dda42164SArtem Dergachev namespace { 134*dd1d5488SKristóf Umann class LiveExpressionsDumper : 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)) 139*dd1d5488SKristóf Umann L->dumpExprLiveness(Mgr.getSourceManager()); 140dda42164SArtem Dergachev } 141dda42164SArtem Dergachev }; 142dda42164SArtem Dergachev } 143dda42164SArtem Dergachev 144*dd1d5488SKristóf Umann void ento::registerLiveExpressionsDumper(CheckerManager &mgr) { 145*dd1d5488SKristóf Umann mgr.registerChecker<LiveExpressionsDumper>(); 146dda42164SArtem Dergachev } 147dda42164SArtem Dergachev 148*dd1d5488SKristóf Umann bool ento::shouldRegisterLiveExpressionsDumper(const CheckerManager &mgr) { 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 172bda3dd0dSKirstóf Umann bool ento::shouldRegisterCFGViewer(const CheckerManager &mgr) { 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 202bda3dd0dSKirstóf Umann bool ento::shouldRegisterCFGDumper(const CheckerManager &mgr) { 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 226bda3dd0dSKirstóf Umann bool ento::shouldRegisterCallGraphViewer(const CheckerManager &mgr) { 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 250bda3dd0dSKirstóf Umann bool ento::shouldRegisterCallGraphDumper(const CheckerManager &mgr) { 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'; 28486917fdbSTed Kremenek } 28586917fdbSTed Kremenek }; 286ab9db510SAlexander Kornienko } 28786917fdbSTed Kremenek 28886917fdbSTed Kremenek void ento::registerConfigDumper(CheckerManager &mgr) { 28986917fdbSTed Kremenek mgr.registerChecker<ConfigDumper>(); 29086917fdbSTed Kremenek } 2917925e3dbSAnna Zaks 292bda3dd0dSKirstóf Umann bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) { 293058a7a45SKristof Umann return true; 294058a7a45SKristof Umann } 295058a7a45SKristof Umann 2967925e3dbSAnna Zaks //===----------------------------------------------------------------------===// 2977925e3dbSAnna Zaks // ExplodedGraph Viewer 2987925e3dbSAnna Zaks //===----------------------------------------------------------------------===// 2997925e3dbSAnna Zaks 3007925e3dbSAnna Zaks namespace { 3017925e3dbSAnna Zaks class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 3027925e3dbSAnna Zaks public: 3037925e3dbSAnna Zaks ExplodedGraphViewer() {} 3047925e3dbSAnna Zaks void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 3057925e3dbSAnna Zaks Eng.ViewGraph(0); 3067925e3dbSAnna Zaks } 3077925e3dbSAnna Zaks }; 3087925e3dbSAnna Zaks 3097925e3dbSAnna Zaks } 3107925e3dbSAnna Zaks 3117925e3dbSAnna Zaks void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 3127925e3dbSAnna Zaks mgr.registerChecker<ExplodedGraphViewer>(); 3137925e3dbSAnna Zaks } 314efec1630SGabor Horvath 315bda3dd0dSKirstóf Umann bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) { 316058a7a45SKristof Umann return true; 317058a7a45SKristof Umann } 3184962816eSKristof Umann 3194962816eSKristof Umann //===----------------------------------------------------------------------===// 3204962816eSKristof Umann // Emits a report for every Stmt that the analyzer visits. 3214962816eSKristof Umann //===----------------------------------------------------------------------===// 3224962816eSKristof Umann 3234962816eSKristof Umann namespace { 3244962816eSKristof Umann 3254962816eSKristof Umann class ReportStmts : public Checker<check::PreStmt<Stmt>> { 3264962816eSKristof Umann BuiltinBug BT_stmtLoc{this, "Statement"}; 3274962816eSKristof Umann 3284962816eSKristof Umann public: 3294962816eSKristof Umann void checkPreStmt(const Stmt *S, CheckerContext &C) const { 3304962816eSKristof Umann ExplodedNode *Node = C.generateNonFatalErrorNode(); 3314962816eSKristof Umann if (!Node) 3324962816eSKristof Umann return; 3334962816eSKristof Umann 3342f169e7cSArtem Dergachev auto Report = 3352f169e7cSArtem Dergachev std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node); 3364962816eSKristof Umann 3374962816eSKristof Umann C.emitReport(std::move(Report)); 3384962816eSKristof Umann } 3394962816eSKristof Umann }; 3404962816eSKristof Umann 3414962816eSKristof Umann } // end of anonymous namespace 3424962816eSKristof Umann 3434962816eSKristof Umann void ento::registerReportStmts(CheckerManager &mgr) { 3444962816eSKristof Umann mgr.registerChecker<ReportStmts>(); 3454962816eSKristof Umann } 3464962816eSKristof Umann 347bda3dd0dSKirstóf Umann bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) { 3484962816eSKristof Umann return true; 3494962816eSKristof Umann } 350