AnalysisConsumer.cpp revision 219077
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 14218887Sdim#include "AnalysisConsumer.h" 15218887Sdim#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" 22218887Sdim#include "clang/Analysis/CFG.h" 23218887Sdim#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" 24218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 25218887Sdim#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 33218887Sdim// 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" 42218887Sdim#include "clang/Lex/Preprocessor.h" 43218887Sdim#include "llvm/Support/raw_ostream.h" 44218887Sdim#include "llvm/Support/Path.h" 45218887Sdim#include "llvm/Support/Program.h" 46218887Sdim#include "llvm/ADT/OwningPtr.h" 47218887Sdim 48218887Sdimusing namespace clang; 49218887Sdimusing namespace ento; 50218887Sdim 51218887Sdimstatic ExplodedNode::Auditor* CreateUbiViz(); 52218887Sdim 53218887Sdim//===----------------------------------------------------------------------===// 54218887Sdim// Special PathDiagnosticClients. 55218887Sdim//===----------------------------------------------------------------------===// 56218887Sdim 57218887Sdimstatic PathDiagnosticClient* 58218887SdimcreatePlistHTMLDiagnosticClient(const std::string& prefix, 59218887Sdim const Preprocessor &PP) { 60218887Sdim PathDiagnosticClient *PD = 61218887Sdim createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP); 62218887Sdim return createPlistDiagnosticClient(prefix, PP, PD); 63218887Sdim} 64218887Sdim 65218887Sdim//===----------------------------------------------------------------------===// 66218887Sdim// AnalysisConsumer declaration. 67218887Sdim//===----------------------------------------------------------------------===// 68218887Sdim 69218887Sdimnamespace { 70218887Sdim 71218887Sdimclass AnalysisConsumer : public ASTConsumer { 72218887Sdimpublic: 73218887Sdim typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); 74218887Sdim typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, 75218887Sdim TranslationUnitDecl &TU); 76218887Sdim 77218887Sdimprivate: 78218887Sdim typedef std::vector<CodeAction> Actions; 79218887Sdim typedef std::vector<TUAction> TUActions; 80218887Sdim 81218887Sdim Actions FunctionActions; 82218887Sdim Actions ObjCMethodActions; 83218887Sdim Actions ObjCImplementationActions; 84218887Sdim Actions CXXMethodActions; 85218887Sdim 86218887Sdimpublic: 87218887Sdim ASTContext* Ctx; 88218887Sdim const Preprocessor &PP; 89218887Sdim const std::string OutDir; 90218887Sdim AnalyzerOptions Opts; 91218887Sdim 92218887Sdim // PD is owned by AnalysisManager. 93218887Sdim PathDiagnosticClient *PD; 94218887Sdim 95218887Sdim StoreManagerCreator CreateStoreMgr; 96218887Sdim ConstraintManagerCreator CreateConstraintMgr; 97218887Sdim 98218887Sdim llvm::OwningPtr<CheckerManager> checkerMgr; 99218887Sdim llvm::OwningPtr<AnalysisManager> Mgr; 100218887Sdim 101218887Sdim AnalysisConsumer(const Preprocessor& pp, 102218887Sdim const std::string& outdir, 103218887Sdim const AnalyzerOptions& opts) 104218887Sdim : Ctx(0), PP(pp), OutDir(outdir), 105218887Sdim Opts(opts), PD(0) { 106218887Sdim DigestAnalyzerOptions(); 107218887Sdim } 108218887Sdim 109218887Sdim void DigestAnalyzerOptions() { 110218887Sdim // Create the PathDiagnosticClient. 111218887Sdim if (!OutDir.empty()) { 112218887Sdim switch (Opts.AnalysisDiagOpt) { 113218887Sdim default: 114218887Sdim#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ 115218887Sdim 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); 122218887Sdim } 123218887Sdim 124218887Sdim // Create the analyzer component creators. 125218887Sdim switch (Opts.AnalysisStoreOpt) { 126218887Sdim default: 127218887Sdim assert(0 && "Unknown store manager."); 128218887Sdim#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 129218887Sdim case NAME##Model: CreateStoreMgr = CREATEFN; break; 130218887Sdim#include "clang/Frontend/Analyses.def" 131218887Sdim } 132218887Sdim 133218887Sdim switch (Opts.AnalysisConstraintsOpt) { 134218887Sdim default: 135218887Sdim assert(0 && "Unknown store manager."); 136218887Sdim#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 137218887Sdim case NAME##Model: CreateConstraintMgr = CREATEFN; break; 138218887Sdim#include "clang/Frontend/Analyses.def" 139218887Sdim } 140218887Sdim } 141218887Sdim 142218887Sdim void DisplayFunction(const Decl *D) { 143218887Sdim if (!Opts.AnalyzerDisplayProgress) 144218887Sdim return; 145218887Sdim 146218887Sdim SourceManager &SM = Mgr->getASTContext().getSourceManager(); 147218887Sdim PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); 148218887Sdim if (Loc.isValid()) { 149218887Sdim llvm::errs() << "ANALYZE: " << Loc.getFilename(); 150218887Sdim 151218887Sdim if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 152218887Sdim const NamedDecl *ND = cast<NamedDecl>(D); 153218887Sdim llvm::errs() << ' ' << ND << '\n'; 154218887Sdim } 155218887Sdim else if (isa<BlockDecl>(D)) { 156218887Sdim llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" 157218887Sdim << Loc.getColumn() << '\n'; 158218887Sdim } 159218887Sdim else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 160218887Sdim Selector S = MD->getSelector(); 161218887Sdim llvm::errs() << ' ' << S.getAsString(); 162218887Sdim } 163218887Sdim } 164218887Sdim } 165218887Sdim 166218887Sdim void addCodeAction(CodeAction action) { 167218887Sdim FunctionActions.push_back(action); 168218887Sdim ObjCMethodActions.push_back(action); 169218887Sdim CXXMethodActions.push_back(action); 170218887Sdim } 171218887Sdim 172218887Sdim void addObjCImplementationAction(CodeAction action) { 173218887Sdim ObjCImplementationActions.push_back(action); 174218887Sdim } 175218887Sdim 176218887Sdim virtual void Initialize(ASTContext &Context) { 177218887Sdim Ctx = &Context; 178219077Sdim checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(), 179219077Sdim PP.getDiagnostics())); 180218887Sdim Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), 181218887Sdim PP.getLangOptions(), PD, 182218887Sdim CreateStoreMgr, CreateConstraintMgr, 183218887Sdim checkerMgr.get(), 184218887Sdim /* Indexer */ 0, 185218887Sdim Opts.MaxNodes, Opts.MaxLoop, 186218887Sdim Opts.VisualizeEGDot, Opts.VisualizeEGUbi, 187218887Sdim Opts.PurgeDead, Opts.EagerlyAssume, 188218887Sdim Opts.TrimGraph, Opts.InlineCall, 189218887Sdim Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, 190218887Sdim Opts.CFGAddInitializers, 191218887Sdim Opts.EagerlyTrimEGraph)); 192218887Sdim } 193218887Sdim 194218887Sdim virtual void HandleTranslationUnit(ASTContext &C); 195218887Sdim void HandleDeclContext(ASTContext &C, DeclContext *dc); 196218887Sdim 197218887Sdim void HandleCode(Decl *D, Actions& actions); 198218887Sdim}; 199218887Sdim} // end anonymous namespace 200218887Sdim 201218887Sdim//===----------------------------------------------------------------------===// 202218887Sdim// AnalysisConsumer implementation. 203218887Sdim//===----------------------------------------------------------------------===// 204218887Sdim 205218887Sdimvoid AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { 206218887Sdim BugReporter BR(*Mgr); 207218887Sdim for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end(); 208218887Sdim I != E; ++I) { 209218887Sdim Decl *D = *I; 210218887Sdim checkerMgr->runCheckersOnASTDecl(D, *Mgr, BR); 211218887Sdim 212218887Sdim switch (D->getKind()) { 213218887Sdim case Decl::Namespace: { 214218887Sdim HandleDeclContext(C, cast<NamespaceDecl>(D)); 215218887Sdim break; 216218887Sdim } 217218887Sdim case Decl::CXXConstructor: 218218887Sdim case Decl::CXXDestructor: 219218887Sdim case Decl::CXXConversion: 220218887Sdim case Decl::CXXMethod: 221218887Sdim case Decl::Function: { 222218887Sdim FunctionDecl* FD = cast<FunctionDecl>(D); 223218887Sdim // We skip function template definitions, as their semantics is 224218887Sdim // only determined when they are instantiated. 225218887Sdim if (FD->isThisDeclarationADefinition() && 226218887Sdim !FD->isDependentContext()) { 227218887Sdim if (!Opts.AnalyzeSpecificFunction.empty() && 228218887Sdim FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) 229218887Sdim break; 230218887Sdim DisplayFunction(FD); 231218887Sdim HandleCode(FD, FunctionActions); 232218887Sdim } 233218887Sdim break; 234218887Sdim } 235218887Sdim 236218887Sdim case Decl::ObjCImplementation: { 237218887Sdim ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); 238218887Sdim HandleCode(ID, ObjCImplementationActions); 239218887Sdim 240218887Sdim for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), 241218887Sdim ME = ID->meth_end(); MI != ME; ++MI) { 242218887Sdim if ((*MI)->isThisDeclarationADefinition()) { 243218887Sdim if (!Opts.AnalyzeSpecificFunction.empty() && 244218887Sdim Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) 245218887Sdim break; 246218887Sdim DisplayFunction(*MI); 247218887Sdim HandleCode(*MI, ObjCMethodActions); 248218887Sdim } 249218887Sdim } 250218887Sdim break; 251218887Sdim } 252218887Sdim 253218887Sdim default: 254218887Sdim break; 255218887Sdim } 256218887Sdim } 257218887Sdim} 258218887Sdim 259218887Sdimvoid AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { 260218887Sdim BugReporter BR(*Mgr); 261218887Sdim TranslationUnitDecl *TU = C.getTranslationUnitDecl(); 262218887Sdim checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); 263218887Sdim HandleDeclContext(C, TU); 264218887Sdim 265218887Sdim // Explicitly destroy the PathDiagnosticClient. This will flush its output. 266218887Sdim // FIXME: This should be replaced with something that doesn't rely on 267218887Sdim // side-effects in PathDiagnosticClient's destructor. This is required when 268218887Sdim // used with option -disable-free. 269218887Sdim Mgr.reset(NULL); 270218887Sdim} 271218887Sdim 272218887Sdimstatic void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { 273218887Sdim if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) 274218887Sdim WL.push_back(BD); 275218887Sdim 276218887Sdim for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); 277218887Sdim I!=E; ++I) 278218887Sdim if (DeclContext *DC = dyn_cast<DeclContext>(*I)) 279218887Sdim FindBlocks(DC, WL); 280218887Sdim} 281218887Sdim 282218887Sdimvoid AnalysisConsumer::HandleCode(Decl *D, Actions& actions) { 283218887Sdim 284218887Sdim // Don't run the actions if an error has occured with parsing the file. 285218887Sdim Diagnostic &Diags = PP.getDiagnostics(); 286218887Sdim if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) 287218887Sdim return; 288218887Sdim 289218887Sdim // Don't run the actions on declarations in header files unless 290218887Sdim // otherwise specified. 291218887Sdim SourceManager &SM = Ctx->getSourceManager(); 292218887Sdim SourceLocation SL = SM.getInstantiationLoc(D->getLocation()); 293218887Sdim if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL)) 294218887Sdim return; 295218887Sdim 296218887Sdim // Clear the AnalysisManager of old AnalysisContexts. 297218887Sdim Mgr->ClearContexts(); 298218887Sdim 299218887Sdim // Dispatch on the actions. 300218887Sdim llvm::SmallVector<Decl*, 10> WL; 301218887Sdim WL.push_back(D); 302218887Sdim 303218887Sdim if (D->hasBody() && Opts.AnalyzeNestedBlocks) 304218887Sdim FindBlocks(cast<DeclContext>(D), WL); 305218887Sdim 306218887Sdim BugReporter BR(*Mgr); 307218887Sdim for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); 308218887Sdim WI != WE; ++WI) 309218887Sdim if ((*WI)->hasBody()) 310218887Sdim checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); 311218887Sdim 312218887Sdim for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) 313218887Sdim for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); 314218887Sdim WI != WE; ++WI) 315218887Sdim (*I)(*this, *Mgr, *WI); 316218887Sdim} 317218887Sdim 318218887Sdim//===----------------------------------------------------------------------===// 319218887Sdim// Analyses 320218887Sdim//===----------------------------------------------------------------------===// 321218887Sdim 322218887Sdimstatic void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, 323218887Sdim Decl *D) { 324218887Sdim if (CFG* c = mgr.getCFG(D)) { 325218887Sdim CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); 326218887Sdim } 327218887Sdim} 328218887Sdim 329218887Sdim 330218887Sdimstatic void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, 331218887Sdim Decl *D, 332218887Sdim TransferFuncs* tf) { 333218887Sdim 334218887Sdim llvm::OwningPtr<TransferFuncs> TF(tf); 335218887Sdim 336218887Sdim // Construct the analysis engine. We first query for the LiveVariables 337218887Sdim // information to see if the CFG is valid. 338218887Sdim // FIXME: Inter-procedural analysis will need to handle invalid CFGs. 339218887Sdim if (!mgr.getLiveVariables(D)) 340218887Sdim return; 341218887Sdim ExprEngine Eng(mgr, TF.take()); 342218887Sdim 343218887Sdim RegisterNSErrorChecks(Eng.getBugReporter(), Eng, *D); 344218887Sdim 345218887Sdim if (C.Opts.EnableExperimentalChecks) 346218887Sdim RegisterExperimentalChecks(Eng); 347218887Sdim 348218887Sdim if (C.Opts.BufferOverflows) 349218887Sdim RegisterArrayBoundCheckerV2(Eng); 350218887Sdim 351218887Sdim // Enable AnalyzerStatsChecker if it was given as an argument 352218887Sdim if (C.Opts.AnalyzerStats) 353218887Sdim RegisterAnalyzerStatsChecker(Eng); 354218887Sdim 355218887Sdim // Set the graph auditor. 356218887Sdim llvm::OwningPtr<ExplodedNode::Auditor> Auditor; 357218887Sdim if (mgr.shouldVisualizeUbigraph()) { 358218887Sdim Auditor.reset(CreateUbiViz()); 359218887Sdim ExplodedNode::SetAuditor(Auditor.get()); 360218887Sdim } 361218887Sdim 362218887Sdim // Execute the worklist algorithm. 363218887Sdim Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes()); 364218887Sdim 365218887Sdim // Release the auditor (if any) so that it doesn't monitor the graph 366218887Sdim // created BugReporter. 367218887Sdim ExplodedNode::SetAuditor(0); 368218887Sdim 369218887Sdim // Visualize the exploded graph. 370218887Sdim if (mgr.shouldVisualizeGraphviz()) 371218887Sdim Eng.ViewGraph(mgr.shouldTrimGraph()); 372218887Sdim 373218887Sdim // Display warnings. 374218887Sdim Eng.getBugReporter().FlushReports(); 375218887Sdim} 376218887Sdim 377218887Sdimstatic void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, 378218887Sdim Decl *D, bool GCEnabled) { 379218887Sdim 380218887Sdim TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), 381218887Sdim GCEnabled, 382218887Sdim mgr.getLangOptions()); 383218887Sdim 384218887Sdim ActionExprEngine(C, mgr, D, TF); 385218887Sdim} 386218887Sdim 387218887Sdimstatic void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, 388218887Sdim Decl *D) { 389218887Sdim 390218887Sdim switch (mgr.getLangOptions().getGCMode()) { 391218887Sdim default: 392218887Sdim assert (false && "Invalid GC mode."); 393218887Sdim case LangOptions::NonGC: 394218887Sdim ActionObjCMemCheckerAux(C, mgr, D, false); 395218887Sdim break; 396218887Sdim 397218887Sdim case LangOptions::GCOnly: 398218887Sdim ActionObjCMemCheckerAux(C, mgr, D, true); 399218887Sdim break; 400218887Sdim 401218887Sdim case LangOptions::HybridGC: 402218887Sdim ActionObjCMemCheckerAux(C, mgr, D, false); 403218887Sdim ActionObjCMemCheckerAux(C, mgr, D, true); 404218887Sdim break; 405218887Sdim } 406218887Sdim} 407218887Sdim 408218887Sdim//===----------------------------------------------------------------------===// 409218887Sdim// AnalysisConsumer creation. 410218887Sdim//===----------------------------------------------------------------------===// 411218887Sdim 412218887SdimASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, 413218887Sdim const std::string& OutDir, 414218887Sdim const AnalyzerOptions& Opts) { 415218887Sdim llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); 416218887Sdim 417218887Sdim for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) 418218887Sdim switch (Opts.AnalysisList[i]) { 419218887Sdim#define ANALYSIS(NAME, CMD, DESC, SCOPE)\ 420218887Sdim case NAME:\ 421218887Sdim C->add ## SCOPE ## Action(&Action ## NAME);\ 422218887Sdim break; 423218887Sdim#include "clang/Frontend/Analyses.def" 424218887Sdim default: break; 425218887Sdim } 426218887Sdim 427218887Sdim // Last, disable the effects of '-Werror' when using the AnalysisConsumer. 428218887Sdim pp.getDiagnostics().setWarningsAsErrors(false); 429218887Sdim 430218887Sdim return C.take(); 431218887Sdim} 432218887Sdim 433218887Sdim//===----------------------------------------------------------------------===// 434218887Sdim// Ubigraph Visualization. FIXME: Move to separate file. 435218887Sdim//===----------------------------------------------------------------------===// 436218887Sdim 437218887Sdimnamespace { 438218887Sdim 439218887Sdimclass UbigraphViz : public ExplodedNode::Auditor { 440218887Sdim llvm::OwningPtr<llvm::raw_ostream> Out; 441218887Sdim llvm::sys::Path Dir, Filename; 442218887Sdim unsigned Cntr; 443218887Sdim 444218887Sdim typedef llvm::DenseMap<void*,unsigned> VMap; 445218887Sdim VMap M; 446218887Sdim 447218887Sdimpublic: 448218887Sdim UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, 449218887Sdim llvm::sys::Path& filename); 450218887Sdim 451218887Sdim ~UbigraphViz(); 452218887Sdim 453218887Sdim virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst); 454218887Sdim}; 455218887Sdim 456218887Sdim} // end anonymous namespace 457218887Sdim 458218887Sdimstatic ExplodedNode::Auditor* CreateUbiViz() { 459218887Sdim std::string ErrMsg; 460218887Sdim 461218887Sdim llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); 462218887Sdim if (!ErrMsg.empty()) 463218887Sdim return 0; 464218887Sdim 465218887Sdim llvm::sys::Path Filename = Dir; 466218887Sdim Filename.appendComponent("llvm_ubi"); 467218887Sdim Filename.makeUnique(true,&ErrMsg); 468218887Sdim 469218887Sdim if (!ErrMsg.empty()) 470218887Sdim return 0; 471218887Sdim 472218887Sdim llvm::errs() << "Writing '" << Filename.str() << "'.\n"; 473218887Sdim 474218887Sdim llvm::OwningPtr<llvm::raw_fd_ostream> Stream; 475218887Sdim Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg)); 476218887Sdim 477218887Sdim if (!ErrMsg.empty()) 478218887Sdim return 0; 479218887Sdim 480218887Sdim return new UbigraphViz(Stream.take(), Dir, Filename); 481218887Sdim} 482218887Sdim 483218887Sdimvoid UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) { 484218887Sdim 485218887Sdim assert (Src != Dst && "Self-edges are not allowed."); 486218887Sdim 487218887Sdim // Lookup the Src. If it is a new node, it's a root. 488218887Sdim VMap::iterator SrcI= M.find(Src); 489218887Sdim unsigned SrcID; 490218887Sdim 491218887Sdim if (SrcI == M.end()) { 492218887Sdim M[Src] = SrcID = Cntr++; 493218887Sdim *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n"; 494218887Sdim } 495218887Sdim else 496218887Sdim SrcID = SrcI->second; 497218887Sdim 498218887Sdim // Lookup the Dst. 499218887Sdim VMap::iterator DstI= M.find(Dst); 500218887Sdim unsigned DstID; 501218887Sdim 502218887Sdim if (DstI == M.end()) { 503218887Sdim M[Dst] = DstID = Cntr++; 504218887Sdim *Out << "('vertex', " << DstID << ")\n"; 505218887Sdim } 506218887Sdim else { 507218887Sdim // We have hit DstID before. Change its style to reflect a cache hit. 508218887Sdim DstID = DstI->second; 509218887Sdim *Out << "('change_vertex_style', " << DstID << ", 1)\n"; 510218887Sdim } 511218887Sdim 512218887Sdim // Add the edge. 513218887Sdim *Out << "('edge', " << SrcID << ", " << DstID 514218887Sdim << ", ('arrow','true'), ('oriented', 'true'))\n"; 515218887Sdim} 516218887Sdim 517218887SdimUbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, 518218887Sdim llvm::sys::Path& filename) 519218887Sdim : Out(out), Dir(dir), Filename(filename), Cntr(0) { 520218887Sdim 521218887Sdim *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; 522218887Sdim *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," 523218887Sdim " ('size', '1.5'))\n"; 524218887Sdim} 525218887Sdim 526218887SdimUbigraphViz::~UbigraphViz() { 527218887Sdim Out.reset(0); 528218887Sdim llvm::errs() << "Running 'ubiviz' program... "; 529218887Sdim std::string ErrMsg; 530218887Sdim llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz"); 531218887Sdim std::vector<const char*> args; 532218887Sdim args.push_back(Ubiviz.c_str()); 533218887Sdim args.push_back(Filename.c_str()); 534218887Sdim args.push_back(0); 535218887Sdim 536218887Sdim if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) { 537218887Sdim llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; 538218887Sdim } 539218887Sdim 540218887Sdim // Delete the directory. 541218887Sdim Dir.eraseFromDisk(true); 542218887Sdim} 543