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*71a9dc39SKristof Umann CFGDomTree dom; 39*71a9dc39SKristof Umann dom.buildDominatorTree(AC->getCFG()); 400062e749STed Kremenek 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 //===----------------------------------------------------------------------===// 55*71a9dc39SKristof Umann // PostDominatorsTreeDumper 56*71a9dc39SKristof Umann //===----------------------------------------------------------------------===// 57*71a9dc39SKristof Umann 58*71a9dc39SKristof Umann namespace { 59*71a9dc39SKristof Umann class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> { 60*71a9dc39SKristof Umann public: 61*71a9dc39SKristof Umann void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 62*71a9dc39SKristof Umann BugReporter &BR) const { 63*71a9dc39SKristof Umann if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { 64*71a9dc39SKristof Umann CFGPostDomTree dom; 65*71a9dc39SKristof Umann dom.buildDominatorTree(AC->getCFG()); 66*71a9dc39SKristof Umann dom.dump(); 67*71a9dc39SKristof Umann } 68*71a9dc39SKristof Umann } 69*71a9dc39SKristof Umann }; 70*71a9dc39SKristof Umann } 71*71a9dc39SKristof Umann 72*71a9dc39SKristof Umann void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { 73*71a9dc39SKristof Umann mgr.registerChecker<PostDominatorsTreeDumper>(); 74*71a9dc39SKristof Umann } 75*71a9dc39SKristof Umann 76*71a9dc39SKristof Umann bool ento::shouldRegisterPostDominatorsTreeDumper(const LangOptions &LO) { 77*71a9dc39SKristof Umann return true; 78*71a9dc39SKristof Umann } 79*71a9dc39SKristof Umann 80*71a9dc39SKristof Umann //===----------------------------------------------------------------------===// 8157d736fdSArgyrios Kyrtzidis // LiveVariablesDumper 8257d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 8357d736fdSArgyrios Kyrtzidis 8457d736fdSArgyrios Kyrtzidis namespace { 856a5674ffSArgyrios Kyrtzidis class LiveVariablesDumper : public Checker<check::ASTCodeBody> { 8657d736fdSArgyrios Kyrtzidis public: 8757d736fdSArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 8857d736fdSArgyrios Kyrtzidis BugReporter &BR) const { 89dccc2b22STed Kremenek if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { 9057d736fdSArgyrios Kyrtzidis L->dumpBlockLiveness(mgr.getSourceManager()); 9157d736fdSArgyrios Kyrtzidis } 9257d736fdSArgyrios Kyrtzidis } 9357d736fdSArgyrios Kyrtzidis }; 94ab9db510SAlexander Kornienko } 9557d736fdSArgyrios Kyrtzidis 9657d736fdSArgyrios Kyrtzidis void ento::registerLiveVariablesDumper(CheckerManager &mgr) { 9757d736fdSArgyrios Kyrtzidis mgr.registerChecker<LiveVariablesDumper>(); 9857d736fdSArgyrios Kyrtzidis } 9957d736fdSArgyrios Kyrtzidis 100058a7a45SKristof Umann bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { 101058a7a45SKristof Umann return true; 102058a7a45SKristof Umann } 103058a7a45SKristof Umann 10457d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 105dda42164SArtem Dergachev // LiveStatementsDumper 106dda42164SArtem Dergachev //===----------------------------------------------------------------------===// 107dda42164SArtem Dergachev 108dda42164SArtem Dergachev namespace { 109dda42164SArtem Dergachev class LiveStatementsDumper : public Checker<check::ASTCodeBody> { 110dda42164SArtem Dergachev public: 111dda42164SArtem Dergachev void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, 112dda42164SArtem Dergachev BugReporter &BR) const { 113dda42164SArtem Dergachev if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) 114dda42164SArtem Dergachev L->dumpStmtLiveness(Mgr.getSourceManager()); 115dda42164SArtem Dergachev } 116dda42164SArtem Dergachev }; 117dda42164SArtem Dergachev } 118dda42164SArtem Dergachev 119dda42164SArtem Dergachev void ento::registerLiveStatementsDumper(CheckerManager &mgr) { 120dda42164SArtem Dergachev mgr.registerChecker<LiveStatementsDumper>(); 121dda42164SArtem Dergachev } 122dda42164SArtem Dergachev 123058a7a45SKristof Umann bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { 124058a7a45SKristof Umann return true; 125058a7a45SKristof Umann } 126058a7a45SKristof Umann 127dda42164SArtem Dergachev //===----------------------------------------------------------------------===// 12857d736fdSArgyrios Kyrtzidis // CFGViewer 12957d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 13057d736fdSArgyrios Kyrtzidis 13157d736fdSArgyrios Kyrtzidis namespace { 1326a5674ffSArgyrios Kyrtzidis class CFGViewer : public Checker<check::ASTCodeBody> { 13357d736fdSArgyrios Kyrtzidis public: 13457d736fdSArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 13557d736fdSArgyrios Kyrtzidis BugReporter &BR) const { 13657d736fdSArgyrios Kyrtzidis if (CFG *cfg = mgr.getCFG(D)) { 137bbafb8a7SDavid Blaikie cfg->viewCFG(mgr.getLangOpts()); 13857d736fdSArgyrios Kyrtzidis } 13957d736fdSArgyrios Kyrtzidis } 14057d736fdSArgyrios Kyrtzidis }; 141ab9db510SAlexander Kornienko } 14257d736fdSArgyrios Kyrtzidis 14357d736fdSArgyrios Kyrtzidis void ento::registerCFGViewer(CheckerManager &mgr) { 14457d736fdSArgyrios Kyrtzidis mgr.registerChecker<CFGViewer>(); 14557d736fdSArgyrios Kyrtzidis } 14657d736fdSArgyrios Kyrtzidis 147058a7a45SKristof Umann bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { 148058a7a45SKristof Umann return true; 149058a7a45SKristof Umann } 150058a7a45SKristof Umann 15157d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 15257d736fdSArgyrios Kyrtzidis // CFGDumper 15357d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===// 15457d736fdSArgyrios Kyrtzidis 15557d736fdSArgyrios Kyrtzidis namespace { 1566a5674ffSArgyrios Kyrtzidis class CFGDumper : public Checker<check::ASTCodeBody> { 15757d736fdSArgyrios Kyrtzidis public: 15857d736fdSArgyrios Kyrtzidis void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 15957d736fdSArgyrios Kyrtzidis BugReporter &BR) const { 160e02e96a6SJordan Rose PrintingPolicy Policy(mgr.getLangOpts()); 161e02e96a6SJordan Rose Policy.TerseOutput = true; 162e02e96a6SJordan Rose Policy.PolishForDeclaration = true; 163e02e96a6SJordan Rose D->print(llvm::errs(), Policy); 164e02e96a6SJordan Rose 16557d736fdSArgyrios Kyrtzidis if (CFG *cfg = mgr.getCFG(D)) { 166bbafb8a7SDavid Blaikie cfg->dump(mgr.getLangOpts(), 16772be32afSTed Kremenek llvm::sys::Process::StandardErrHasColors()); 16857d736fdSArgyrios Kyrtzidis } 16957d736fdSArgyrios Kyrtzidis } 17057d736fdSArgyrios Kyrtzidis }; 171ab9db510SAlexander Kornienko } 17257d736fdSArgyrios Kyrtzidis 17357d736fdSArgyrios Kyrtzidis void ento::registerCFGDumper(CheckerManager &mgr) { 17457d736fdSArgyrios Kyrtzidis mgr.registerChecker<CFGDumper>(); 17557d736fdSArgyrios Kyrtzidis } 176c000e7edSAnna Zaks 177058a7a45SKristof Umann bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { 178058a7a45SKristof Umann return true; 179058a7a45SKristof Umann } 180058a7a45SKristof Umann 181c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 182c000e7edSAnna Zaks // CallGraphViewer 183c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 184c000e7edSAnna Zaks 185c000e7edSAnna Zaks namespace { 186c000e7edSAnna Zaks class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { 187c000e7edSAnna Zaks public: 188c000e7edSAnna Zaks void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 189c000e7edSAnna Zaks BugReporter &BR) const { 190c000e7edSAnna Zaks CallGraph CG; 191c000e7edSAnna Zaks CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 192c000e7edSAnna Zaks CG.viewGraph(); 193c000e7edSAnna Zaks } 194c000e7edSAnna Zaks }; 195ab9db510SAlexander Kornienko } 196c000e7edSAnna Zaks 197c000e7edSAnna Zaks void ento::registerCallGraphViewer(CheckerManager &mgr) { 198c000e7edSAnna Zaks mgr.registerChecker<CallGraphViewer>(); 199c000e7edSAnna Zaks } 200c000e7edSAnna Zaks 201058a7a45SKristof Umann bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { 202058a7a45SKristof Umann return true; 203058a7a45SKristof Umann } 204058a7a45SKristof Umann 205c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 206c000e7edSAnna Zaks // CallGraphDumper 207c000e7edSAnna Zaks //===----------------------------------------------------------------------===// 208c000e7edSAnna Zaks 209c000e7edSAnna Zaks namespace { 210c000e7edSAnna Zaks class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { 211c000e7edSAnna Zaks public: 212c000e7edSAnna Zaks void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, 213c000e7edSAnna Zaks BugReporter &BR) const { 214c000e7edSAnna Zaks CallGraph CG; 215c000e7edSAnna Zaks CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); 216c000e7edSAnna Zaks CG.dump(); 217c000e7edSAnna Zaks } 218c000e7edSAnna Zaks }; 219ab9db510SAlexander Kornienko } 220c000e7edSAnna Zaks 221c000e7edSAnna Zaks void ento::registerCallGraphDumper(CheckerManager &mgr) { 222c000e7edSAnna Zaks mgr.registerChecker<CallGraphDumper>(); 223c000e7edSAnna Zaks } 22486917fdbSTed Kremenek 225058a7a45SKristof Umann bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { 226058a7a45SKristof Umann return true; 227058a7a45SKristof Umann } 22886917fdbSTed Kremenek 22986917fdbSTed Kremenek //===----------------------------------------------------------------------===// 23086917fdbSTed Kremenek // ConfigDumper 23186917fdbSTed Kremenek //===----------------------------------------------------------------------===// 23286917fdbSTed Kremenek 23386917fdbSTed Kremenek namespace { 23486917fdbSTed Kremenek class ConfigDumper : public Checker< check::EndOfTranslationUnit > { 235a92b80f8SBenjamin Kramer typedef AnalyzerOptions::ConfigTable Table; 236a92b80f8SBenjamin Kramer 2374cadf292SBenjamin Kramer static int compareEntry(const Table::MapEntryTy *const *LHS, 2384cadf292SBenjamin Kramer const Table::MapEntryTy *const *RHS) { 2394cadf292SBenjamin Kramer return (*LHS)->getKey().compare((*RHS)->getKey()); 2404cadf292SBenjamin Kramer } 2414cadf292SBenjamin Kramer 24286917fdbSTed Kremenek public: 24386917fdbSTed Kremenek void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, 24486917fdbSTed Kremenek AnalysisManager& mgr, 24586917fdbSTed Kremenek BugReporter &BR) const { 246a92b80f8SBenjamin Kramer const Table &Config = mgr.options.Config; 24786917fdbSTed Kremenek 248a92b80f8SBenjamin Kramer SmallVector<const Table::MapEntryTy *, 32> Keys; 249a92b80f8SBenjamin Kramer for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; 250a92b80f8SBenjamin Kramer ++I) 251a92b80f8SBenjamin Kramer Keys.push_back(&*I); 2524cadf292SBenjamin Kramer llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); 25386917fdbSTed Kremenek 25486917fdbSTed Kremenek llvm::errs() << "[config]\n"; 255a92b80f8SBenjamin Kramer for (unsigned I = 0, E = Keys.size(); I != E; ++I) 256549f9cd4SKristof Umann llvm::errs() << Keys[I]->getKey() << " = " 257549f9cd4SKristof Umann << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second) 258549f9cd4SKristof Umann << '\n'; 259a92b80f8SBenjamin Kramer 26086917fdbSTed Kremenek llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; 26186917fdbSTed Kremenek } 26286917fdbSTed Kremenek }; 263ab9db510SAlexander Kornienko } 26486917fdbSTed Kremenek 26586917fdbSTed Kremenek void ento::registerConfigDumper(CheckerManager &mgr) { 26686917fdbSTed Kremenek mgr.registerChecker<ConfigDumper>(); 26786917fdbSTed Kremenek } 2687925e3dbSAnna Zaks 269058a7a45SKristof Umann bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { 270058a7a45SKristof Umann return true; 271058a7a45SKristof Umann } 272058a7a45SKristof Umann 2737925e3dbSAnna Zaks //===----------------------------------------------------------------------===// 2747925e3dbSAnna Zaks // ExplodedGraph Viewer 2757925e3dbSAnna Zaks //===----------------------------------------------------------------------===// 2767925e3dbSAnna Zaks 2777925e3dbSAnna Zaks namespace { 2787925e3dbSAnna Zaks class ExplodedGraphViewer : public Checker< check::EndAnalysis > { 2797925e3dbSAnna Zaks public: 2807925e3dbSAnna Zaks ExplodedGraphViewer() {} 2817925e3dbSAnna Zaks void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { 2827925e3dbSAnna Zaks Eng.ViewGraph(0); 2837925e3dbSAnna Zaks } 2847925e3dbSAnna Zaks }; 2857925e3dbSAnna Zaks 2867925e3dbSAnna Zaks } 2877925e3dbSAnna Zaks 2887925e3dbSAnna Zaks void ento::registerExplodedGraphViewer(CheckerManager &mgr) { 2897925e3dbSAnna Zaks mgr.registerChecker<ExplodedGraphViewer>(); 2907925e3dbSAnna Zaks } 291efec1630SGabor Horvath 292058a7a45SKristof Umann bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { 293058a7a45SKristof Umann return true; 294058a7a45SKristof Umann } 2954962816eSKristof Umann 2964962816eSKristof Umann //===----------------------------------------------------------------------===// 2974962816eSKristof Umann // Emits a report for every Stmt that the analyzer visits. 2984962816eSKristof Umann //===----------------------------------------------------------------------===// 2994962816eSKristof Umann 3004962816eSKristof Umann namespace { 3014962816eSKristof Umann 3024962816eSKristof Umann class ReportStmts : public Checker<check::PreStmt<Stmt>> { 3034962816eSKristof Umann BuiltinBug BT_stmtLoc{this, "Statement"}; 3044962816eSKristof Umann 3054962816eSKristof Umann public: 3064962816eSKristof Umann void checkPreStmt(const Stmt *S, CheckerContext &C) const { 3074962816eSKristof Umann ExplodedNode *Node = C.generateNonFatalErrorNode(); 3084962816eSKristof Umann if (!Node) 3094962816eSKristof Umann return; 3104962816eSKristof Umann 3114962816eSKristof Umann auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node); 3124962816eSKristof Umann 3134962816eSKristof Umann C.emitReport(std::move(Report)); 3144962816eSKristof Umann } 3154962816eSKristof Umann }; 3164962816eSKristof Umann 3174962816eSKristof Umann } // end of anonymous namespace 3184962816eSKristof Umann 3194962816eSKristof Umann void ento::registerReportStmts(CheckerManager &mgr) { 3204962816eSKristof Umann mgr.registerChecker<ReportStmts>(); 3214962816eSKristof Umann } 3224962816eSKristof Umann 3234962816eSKristof Umann bool ento::shouldRegisterReportStmts(const LangOptions &LO) { 3244962816eSKristof Umann return true; 3254962816eSKristof Umann } 326