AnalysisConsumer.cpp revision 218893
1218887Sdim//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// "Meta" ASTConsumer for running different source analyses. 11218887Sdim// 12218887Sdim//===----------------------------------------------------------------------===// 13218887Sdim 14234353Sdim#include "AnalysisConsumer.h" 15234353Sdim#include "clang/AST/ASTConsumer.h" 16218887Sdim#include "clang/AST/Decl.h" 17218887Sdim#include "clang/AST/DeclCXX.h" 18218887Sdim#include "clang/AST/DeclObjC.h" 19218887Sdim#include "clang/AST/ParentMap.h" 20218887Sdim#include "clang/Analysis/Analyses/LiveVariables.h" 21218887Sdim#include "clang/Analysis/Analyses/UninitializedValues.h" 22234353Sdim#include "clang/Analysis/CFG.h" 23218887Sdim#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" 24234353Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 25239462Sdim#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" 26218887Sdim#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 27218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 28218887Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 29218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 30218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" 31218887Sdim#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" 32218887Sdim 33226633Sdim// FIXME: Restructure checker registration. 34218887Sdim#include "../Checkers/ClangSACheckers.h" 35218887Sdim#include "../Checkers/ExperimentalChecks.h" 36218887Sdim#include "../Checkers/InternalChecks.h" 37218887Sdim#include "../Checkers/BasicObjCFoundationChecks.h" 38218887Sdim 39218887Sdim#include "clang/Basic/FileManager.h" 40218887Sdim#include "clang/Basic/SourceManager.h" 41218887Sdim#include "clang/Frontend/AnalyzerOptions.h" 42234353Sdim#include "clang/Lex/Preprocessor.h" 43234353Sdim#include "llvm/Support/raw_ostream.h" 44218887Sdim#include "llvm/Support/Path.h" 45234353Sdim#include "llvm/Support/Program.h" 46234353Sdim#include "llvm/ADT/OwningPtr.h" 47218887Sdim 48234353Sdimusing namespace clang; 49234353Sdimusing namespace ento; 50218887Sdim 51218887Sdimstatic ExplodedNode::Auditor* CreateUbiViz(); 52234353Sdim 53218887Sdim//===----------------------------------------------------------------------===// 54218887Sdim// Special PathDiagnosticClients. 55218887Sdim//===----------------------------------------------------------------------===// 56234353Sdim 57234353Sdimstatic PathDiagnosticClient* 58234353SdimcreatePlistHTMLDiagnosticClient(const std::string& prefix, 59234353Sdim const Preprocessor &PP) { 60234353Sdim PathDiagnosticClient *PD = 61239462Sdim createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP); 62234353Sdim return createPlistDiagnosticClient(prefix, PP, PD); 63218887Sdim} 64226633Sdim 65218887Sdim//===----------------------------------------------------------------------===// 66218887Sdim// AnalysisConsumer declaration. 67239462Sdim//===----------------------------------------------------------------------===// 68239462Sdim 69239462Sdimnamespace { 70239462Sdim 71239462Sdimclass AnalysisConsumer : public ASTConsumer { 72218887Sdimpublic: 73218887Sdim typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); 74239462Sdim typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, 75239462Sdim TranslationUnitDecl &TU); 76239462Sdim 77239462Sdimprivate: 78239462Sdim typedef std::vector<CodeAction> Actions; 79239462Sdim typedef std::vector<TUAction> TUActions; 80239462Sdim 81239462Sdim Actions FunctionActions; 82239462Sdim Actions ObjCMethodActions; 83239462Sdim Actions ObjCImplementationActions; 84239462Sdim Actions CXXMethodActions; 85239462Sdim 86239462Sdimpublic: 87239462Sdim ASTContext* Ctx; 88239462Sdim const Preprocessor &PP; 89239462Sdim const std::string OutDir; 90239462Sdim AnalyzerOptions Opts; 91239462Sdim 92239462Sdim // PD is owned by AnalysisManager. 93239462Sdim PathDiagnosticClient *PD; 94239462Sdim 95239462Sdim StoreManagerCreator CreateStoreMgr; 96239462Sdim ConstraintManagerCreator CreateConstraintMgr; 97239462Sdim 98239462Sdim llvm::OwningPtr<CheckerManager> checkerMgr; 99239462Sdim llvm::OwningPtr<AnalysisManager> Mgr; 100239462Sdim 101239462Sdim AnalysisConsumer(const Preprocessor& pp, 102239462Sdim const std::string& outdir, 103239462Sdim const AnalyzerOptions& opts) 104239462Sdim : Ctx(0), PP(pp), OutDir(outdir), 105239462Sdim Opts(opts), PD(0) { 106239462Sdim DigestAnalyzerOptions(); 107239462Sdim } 108239462Sdim 109239462Sdim void DigestAnalyzerOptions() { 110239462Sdim // Create the PathDiagnosticClient. 111239462Sdim if (!OutDir.empty()) { 112239462Sdim switch (Opts.AnalysisDiagOpt) { 113239462Sdim default: 114239462Sdim#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ 115239462Sdim case PD_##NAME: PD = CREATEFN(OutDir, PP); break; 116218887Sdim#include "clang/Frontend/Analyses.def" 117218887Sdim } 118218887Sdim } else if (Opts.AnalysisDiagOpt == PD_TEXT) { 119218887Sdim // Create the text client even without a specified output file since 120218887Sdim // it just uses diagnostic notes. 121218887Sdim PD = createTextPathDiagnosticClient("", PP); 122234353Sdim } 123234353Sdim 124234353Sdim // Create the analyzer component creators. 125234353Sdim switch (Opts.AnalysisStoreOpt) { 126234353Sdim default: 127234353Sdim assert(0 && "Unknown store manager."); 128234353Sdim#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 129234353Sdim case NAME##Model: CreateStoreMgr = CREATEFN; break; 130234353Sdim#include "clang/Frontend/Analyses.def" 131234353Sdim } 132234353Sdim 133234353Sdim switch (Opts.AnalysisConstraintsOpt) { 134234353Sdim default: 135218887Sdim assert(0 && "Unknown store manager."); 136226633Sdim#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 137218887Sdim case NAME##Model: CreateConstraintMgr = CREATEFN; break; 138218887Sdim#include "clang/Frontend/Analyses.def" 139218887Sdim } 140226633Sdim } 141218887Sdim 142234353Sdim void DisplayFunction(const Decl *D) { 143234353Sdim if (!Opts.AnalyzerDisplayProgress) 144234353Sdim return; 145234353Sdim 146234353Sdim SourceManager &SM = Mgr->getASTContext().getSourceManager(); 147234353Sdim PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); 148239462Sdim if (Loc.isValid()) { 149239462Sdim llvm::errs() << "ANALYZE: " << Loc.getFilename(); 150239462Sdim 151234353Sdim if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 152218887Sdim const NamedDecl *ND = cast<NamedDecl>(D); 153218887Sdim llvm::errs() << ' ' << ND << '\n'; 154218887Sdim } 155234353Sdim else if (isa<BlockDecl>(D)) { 156234353Sdim llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" 157218887Sdim << Loc.getColumn() << '\n'; 158234353Sdim } 159234353Sdim else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 160234353Sdim Selector S = MD->getSelector(); 161234353Sdim llvm::errs() << ' ' << S.getAsString(); 162234353Sdim } 163234353Sdim } 164234353Sdim } 165218887Sdim 166218887Sdim void addCodeAction(CodeAction action) { 167226633Sdim FunctionActions.push_back(action); 168226633Sdim ObjCMethodActions.push_back(action); 169234353Sdim CXXMethodActions.push_back(action); 170239462Sdim } 171218887Sdim 172234353Sdim void addObjCImplementationAction(CodeAction action) { 173234353Sdim ObjCImplementationActions.push_back(action); 174234353Sdim } 175234353Sdim 176218887Sdim virtual void Initialize(ASTContext &Context) { 177218887Sdim Ctx = &Context; 178234353Sdim checkerMgr.reset(registerCheckers(Opts, PP.getDiagnostics())); 179234353Sdim Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), 180234353Sdim PP.getLangOptions(), PD, 181234353Sdim CreateStoreMgr, CreateConstraintMgr, 182234353Sdim checkerMgr.get(), 183218887Sdim /* Indexer */ 0, 184226633Sdim Opts.MaxNodes, Opts.MaxLoop, 185239462Sdim Opts.VisualizeEGDot, Opts.VisualizeEGUbi, 186239462Sdim Opts.PurgeDead, Opts.EagerlyAssume, 187218887Sdim Opts.TrimGraph, Opts.InlineCall, 188218887Sdim Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, 189218887Sdim Opts.CFGAddInitializers, 190218887Sdim Opts.EagerlyTrimEGraph)); 191239462Sdim } 192218887Sdim 193218887Sdim virtual void HandleTranslationUnit(ASTContext &C); 194218887Sdim void HandleDeclContext(ASTContext &C, DeclContext *dc); 195218887Sdim 196218887Sdim void HandleCode(Decl *D, Actions& actions); 197239462Sdim}; 198218887Sdim} // end anonymous namespace 199218887Sdim 200218887Sdim//===----------------------------------------------------------------------===// 201218887Sdim// AnalysisConsumer implementation. 202218887Sdim//===----------------------------------------------------------------------===// 203226633Sdim 204218887Sdimvoid AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { 205218887Sdim BugReporter BR(*Mgr); 206218887Sdim for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end(); 207218887Sdim I != E; ++I) { 208218887Sdim Decl *D = *I; 209218887Sdim checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR); 210218887Sdim 211226633Sdim switch (D->getKind()) { 212218887Sdim case Decl::Namespace: { 213218887Sdim HandleDeclContext(C, cast<NamespaceDecl>(D)); 214218887Sdim break; 215218887Sdim } 216218887Sdim case Decl::CXXConstructor: 217218887Sdim case Decl::CXXDestructor: 218234353Sdim case Decl::CXXConversion: 219218887Sdim case Decl::CXXMethod: 220218887Sdim case Decl::Function: { 221218887Sdim FunctionDecl* FD = cast<FunctionDecl>(D); 222218887Sdim // We skip function template definitions, as their semantics is 223218887Sdim // only determined when they are instantiated. 224218887Sdim if (FD->isThisDeclarationADefinition() && 225234353Sdim !FD->isDependentContext()) { 226234353Sdim if (!Opts.AnalyzeSpecificFunction.empty() && 227234353Sdim FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) 228234353Sdim break; 229234353Sdim DisplayFunction(FD); 230234353Sdim HandleCode(FD, FunctionActions); 231234353Sdim } 232218887Sdim break; 233218887Sdim } 234226633Sdim 235218887Sdim case Decl::ObjCImplementation: { 236218887Sdim ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); 237218887Sdim HandleCode(ID, ObjCImplementationActions); 238218887Sdim 239218887Sdim for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), 240218887Sdim ME = ID->meth_end(); MI != ME; ++MI) { 241218887Sdim if ((*MI)->isThisDeclarationADefinition()) { 242218887Sdim if (!Opts.AnalyzeSpecificFunction.empty() && 243218887Sdim Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) 244218887Sdim break; 245218887Sdim DisplayFunction(*MI); 246218887Sdim HandleCode(*MI, ObjCMethodActions); 247218887Sdim } 248218887Sdim } 249234353Sdim break; 250226633Sdim } 251239462Sdim 252239462Sdim default: 253239462Sdim break; 254239462Sdim } 255239462Sdim } 256239462Sdim} 257218887Sdim 258218887Sdimvoid AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { 259218887Sdim BugReporter BR(*Mgr); 260226633Sdim TranslationUnitDecl *TU = C.getTranslationUnitDecl(); 261234353Sdim checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); 262218887Sdim HandleDeclContext(C, TU); 263234353Sdim 264234353Sdim // Explicitly destroy the PathDiagnosticClient. This will flush its output. 265234353Sdim // FIXME: This should be replaced with something that doesn't rely on 266234353Sdim // side-effects in PathDiagnosticClient's destructor. This is required when 267234353Sdim // used with option -disable-free. 268234353Sdim Mgr.reset(NULL); 269218887Sdim} 270218887Sdim 271234353Sdimstatic void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { 272234353Sdim if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) 273234353Sdim WL.push_back(BD); 274234353Sdim 275234353Sdim for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); 276218887Sdim I!=E; ++I) 277218887Sdim if (DeclContext *DC = dyn_cast<DeclContext>(*I)) 278234353Sdim FindBlocks(DC, WL); 279234353Sdim} 280239462Sdim 281234353Sdimvoid AnalysisConsumer::HandleCode(Decl *D, Actions& actions) { 282234353Sdim 283234353Sdim // Don't run the actions if an error has occured with parsing the file. 284234353Sdim Diagnostic &Diags = PP.getDiagnostics(); 285234353Sdim if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) 286234353Sdim return; 287234353Sdim 288234353Sdim // Don't run the actions on declarations in header files unless 289234353Sdim // otherwise specified. 290234353Sdim SourceManager &SM = Ctx->getSourceManager(); 291234353Sdim SourceLocation SL = SM.getInstantiationLoc(D->getLocation()); 292234353Sdim if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL)) 293234353Sdim return; 294234353Sdim 295234353Sdim // Clear the AnalysisManager of old AnalysisContexts. 296239462Sdim Mgr->ClearContexts(); 297234353Sdim 298234353Sdim // Dispatch on the actions. 299234353Sdim llvm::SmallVector<Decl*, 10> WL; 300234353Sdim WL.push_back(D); 301234353Sdim 302234353Sdim if (D->hasBody() && Opts.AnalyzeNestedBlocks) 303234353Sdim FindBlocks(cast<DeclContext>(D), WL); 304234353Sdim 305234353Sdim BugReporter BR(*Mgr); 306234353Sdim for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); 307234353Sdim WI != WE; ++WI) 308234353Sdim if ((*WI)->hasBody()) 309234353Sdim checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); 310234353Sdim 311234353Sdim for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) 312234353Sdim for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); 313234353Sdim WI != WE; ++WI) 314234353Sdim (*I)(*this, *Mgr, *WI); 315234353Sdim} 316234353Sdim 317234353Sdim//===----------------------------------------------------------------------===// 318234353Sdim// Analyses 319234353Sdim//===----------------------------------------------------------------------===// 320234353Sdim 321234353Sdimstatic void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, 322234353Sdim Decl *D) { 323234353Sdim if (CFG* c = mgr.getCFG(D)) { 324234353Sdim CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); 325234353Sdim } 326234353Sdim} 327234353Sdim 328234353Sdim 329234353Sdimstatic void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, 330234353Sdim Decl *D, 331218887Sdim TransferFuncs* tf) { 332218887Sdim 333218887Sdim llvm::OwningPtr<TransferFuncs> TF(tf); 334234353Sdim 335218887Sdim // Construct the analysis engine. We first query for the LiveVariables 336218887Sdim // information to see if the CFG is valid. 337218887Sdim // FIXME: Inter-procedural analysis will need to handle invalid CFGs. 338234353Sdim if (!mgr.getLiveVariables(D)) 339218887Sdim return; 340234353Sdim ExprEngine Eng(mgr, TF.take()); 341234353Sdim 342234353Sdim if (C.Opts.EnableExperimentalInternalChecks) 343234353Sdim RegisterExperimentalInternalChecks(Eng); 344234353Sdim 345234353Sdim RegisterNSErrorChecks(Eng.getBugReporter(), Eng, *D); 346234353Sdim 347234353Sdim if (C.Opts.EnableExperimentalChecks) 348234353Sdim RegisterExperimentalChecks(Eng); 349234353Sdim 350234353Sdim if (C.Opts.BufferOverflows) 351234353Sdim RegisterArrayBoundCheckerV2(Eng); 352234353Sdim 353234353Sdim // Enable AnalyzerStatsChecker if it was given as an argument 354234353Sdim if (C.Opts.AnalyzerStats) 355234353Sdim RegisterAnalyzerStatsChecker(Eng); 356234353Sdim 357239462Sdim // Set the graph auditor. 358226633Sdim llvm::OwningPtr<ExplodedNode::Auditor> Auditor; 359226633Sdim if (mgr.shouldVisualizeUbigraph()) { 360226633Sdim Auditor.reset(CreateUbiViz()); 361239462Sdim ExplodedNode::SetAuditor(Auditor.get()); 362234353Sdim } 363234353Sdim 364234353Sdim // Execute the worklist algorithm. 365239462Sdim Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes()); 366234353Sdim 367239462Sdim // Release the auditor (if any) so that it doesn't monitor the graph 368239462Sdim // created BugReporter. 369239462Sdim ExplodedNode::SetAuditor(0); 370239462Sdim 371239462Sdim // Visualize the exploded graph. 372239462Sdim if (mgr.shouldVisualizeGraphviz()) 373234353Sdim Eng.ViewGraph(mgr.shouldTrimGraph()); 374234353Sdim 375234353Sdim // Display warnings. 376234353Sdim Eng.getBugReporter().FlushReports(); 377234353Sdim} 378234353Sdim 379234353Sdimstatic void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, 380234353Sdim Decl *D, bool GCEnabled) { 381226633Sdim 382234353Sdim TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), 383234353Sdim GCEnabled, 384234353Sdim mgr.getLangOptions()); 385234353Sdim 386234353Sdim ActionExprEngine(C, mgr, D, TF); 387234353Sdim} 388218887Sdim 389234353Sdimstatic void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, 390234353Sdim Decl *D) { 391234353Sdim 392234353Sdim switch (mgr.getLangOptions().getGCMode()) { 393239462Sdim default: 394234353Sdim assert (false && "Invalid GC mode."); 395234353Sdim case LangOptions::NonGC: 396234353Sdim ActionObjCMemCheckerAux(C, mgr, D, false); 397239462Sdim break; 398234353Sdim 399234353Sdim case LangOptions::GCOnly: 400234353Sdim ActionObjCMemCheckerAux(C, mgr, D, true); 401234353Sdim break; 402234353Sdim 403234353Sdim case LangOptions::HybridGC: 404234353Sdim ActionObjCMemCheckerAux(C, mgr, D, false); 405239462Sdim ActionObjCMemCheckerAux(C, mgr, D, true); 406234353Sdim break; 407239462Sdim } 408239462Sdim} 409239462Sdim 410239462Sdim//===----------------------------------------------------------------------===// 411239462Sdim// AnalysisConsumer creation. 412239462Sdim//===----------------------------------------------------------------------===// 413239462Sdim 414234353SdimASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, 415234353Sdim const std::string& OutDir, 416234353Sdim const AnalyzerOptions& Opts) { 417234353Sdim llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); 418234353Sdim 419234353Sdim for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) 420234353Sdim switch (Opts.AnalysisList[i]) { 421234353Sdim#define ANALYSIS(NAME, CMD, DESC, SCOPE)\ 422234353Sdim case NAME:\ 423234353Sdim C->add ## SCOPE ## Action(&Action ## NAME);\ 424234353Sdim break; 425234353Sdim#include "clang/Frontend/Analyses.def" 426234353Sdim default: break; 427239462Sdim } 428239462Sdim 429234353Sdim // Last, disable the effects of '-Werror' when using the AnalysisConsumer. 430234353Sdim pp.getDiagnostics().setWarningsAsErrors(false); 431234353Sdim 432226633Sdim return C.take(); 433234353Sdim} 434226633Sdim 435218887Sdim//===----------------------------------------------------------------------===// 436218887Sdim// Ubigraph Visualization. FIXME: Move to separate file. 437218887Sdim//===----------------------------------------------------------------------===// 438234353Sdim 439234353Sdimnamespace { 440234353Sdim 441234353Sdimclass UbigraphViz : public ExplodedNode::Auditor { 442218887Sdim llvm::OwningPtr<llvm::raw_ostream> Out; 443234353Sdim llvm::sys::Path Dir, Filename; 444234353Sdim unsigned Cntr; 445223017Sdim 446234353Sdim typedef llvm::DenseMap<void*,unsigned> VMap; 447234353Sdim VMap M; 448234353Sdim 449234353Sdimpublic: 450234353Sdim UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, 451234353Sdim llvm::sys::Path& filename); 452234353Sdim 453234353Sdim ~UbigraphViz(); 454234353Sdim 455234353Sdim virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst); 456234353Sdim}; 457234353Sdim 458239462Sdim} // end anonymous namespace 459239462Sdim 460239462Sdimstatic ExplodedNode::Auditor* CreateUbiViz() { 461239462Sdim std::string ErrMsg; 462239462Sdim 463239462Sdim llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); 464239462Sdim if (!ErrMsg.empty()) 465239462Sdim return 0; 466239462Sdim 467234353Sdim llvm::sys::Path Filename = Dir; 468234353Sdim Filename.appendComponent("llvm_ubi"); 469239462Sdim Filename.makeUnique(true,&ErrMsg); 470234353Sdim 471234353Sdim if (!ErrMsg.empty()) 472234353Sdim return 0; 473234353Sdim 474234353Sdim llvm::errs() << "Writing '" << Filename.str() << "'.\n"; 475234353Sdim 476234353Sdim llvm::OwningPtr<llvm::raw_fd_ostream> Stream; 477226633Sdim Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg)); 478218887Sdim 479226633Sdim if (!ErrMsg.empty()) 480218887Sdim return 0; 481218887Sdim 482234353Sdim return new UbigraphViz(Stream.take(), Dir, Filename); 483234353Sdim} 484234353Sdim 485234353Sdimvoid UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) { 486234353Sdim 487234353Sdim assert (Src != Dst && "Self-edges are not allowed."); 488234353Sdim 489234353Sdim // Lookup the Src. If it is a new node, it's a root. 490234353Sdim VMap::iterator SrcI= M.find(Src); 491234353Sdim unsigned SrcID; 492218887Sdim 493218887Sdim if (SrcI == M.end()) { 494226633Sdim M[Src] = SrcID = Cntr++; 495218887Sdim *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n"; 496218887Sdim } 497218887Sdim else 498218887Sdim SrcID = SrcI->second; 499218887Sdim 500218887Sdim // Lookup the Dst. 501218887Sdim VMap::iterator DstI= M.find(Dst); 502218887Sdim unsigned DstID; 503218887Sdim 504234353Sdim if (DstI == M.end()) { 505234353Sdim M[Dst] = DstID = Cntr++; 506234353Sdim *Out << "('vertex', " << DstID << ")\n"; 507234353Sdim } 508234353Sdim else { 509234353Sdim // We have hit DstID before. Change its style to reflect a cache hit. 510234353Sdim DstID = DstI->second; 511234353Sdim *Out << "('change_vertex_style', " << DstID << ", 1)\n"; 512234353Sdim } 513234353Sdim 514234353Sdim // Add the edge. 515218887Sdim *Out << "('edge', " << SrcID << ", " << DstID 516234353Sdim << ", ('arrow','true'), ('oriented', 'true'))\n"; 517234353Sdim} 518234353Sdim 519234353SdimUbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, 520221345Sdim llvm::sys::Path& filename) 521218887Sdim : Out(out), Dir(dir), Filename(filename), Cntr(0) { 522218887Sdim 523218887Sdim *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; 524226633Sdim *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," 525218887Sdim " ('size', '1.5'))\n"; 526234353Sdim} 527234353Sdim 528234353SdimUbigraphViz::~UbigraphViz() { 529234353Sdim Out.reset(0); 530234353Sdim llvm::errs() << "Running 'ubiviz' program... "; 531234353Sdim std::string ErrMsg; 532234353Sdim llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz"); 533234353Sdim std::vector<const char*> args; 534218887Sdim args.push_back(Ubiviz.c_str()); 535218887Sdim args.push_back(Filename.c_str()); 536234353Sdim args.push_back(0); 537239462Sdim 538239462Sdim if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) { 539239462Sdim llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; 540239462Sdim } 541239462Sdim 542234353Sdim // Delete the directory. 543239462Sdim Dir.eraseFromDisk(true); 544234353Sdim} 545218887Sdim