5

For the past 5 years I have been using Gnu Compiler Collection (gcc/g++),so I'm a newbie for clang and I would like to generate a control flow graph for C/Objective C/C++ source code. Thankfully I have read here and here and found out I can get basic blocks representation of source-level statements by using the CFG class functions: CFG::buildCFG() CFG::dump()

which is great :) , but it's still unclear for me how do I get the function's body in AST form and ASTContext before passing it to buildCFG??

Can someone please give here a short snippet which demonstrates how do I export with clang a CFG for a given source code ?

Thank you all

JammingThebBits
  • 732
  • 11
  • 31

2 Answers2

4

I was able to generate the CFGs using a different method than you mentioned above. It may do what you need. Comment out the following line (TEMPORARILY):

sys::fs::remove(Filename);

from the ExecGraphViewer() function in Support/GraphWriter.cpp and rebuild clang.

Then, run the clang static analysis tool:

clang -cc1 -analyze -analyze-checker=debug.ViewCFG src_code.cpp

Typically this command will open a graphical viewer to view your CFG in, then when you are done it will delete all of the .dot files it created for viewing. But if you comment this line out you can copy these files elsewhere even after you close the viewer.

Be sure to add it back in or else it will probably get really big...

Also want to add that I was helped by Adam

cmoses
  • 196
  • 1
  • 2
  • 16
1

This source code snippet is going to print the CFG for a given function (in this case, the main function) to the terminal.

#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"

using namespace clang;
using namespace clang::ast_matchers;
using namespace clang::tooling;

using namespace llvm;

DeclarationMatcher FunctionMatcher =
    functionDecl(isMain()).bind("mainFunction");

class CFGPrinter : public MatchFinder::MatchCallback {
public:
  virtual void run(const MatchFinder::MatchResult &Result) {
    if (const FunctionDecl *funcDecl =
            Result.Nodes.getNodeAs<clang::FunctionDecl>("mainFunction")) {
      ASTContext *context = Result.Context;
      Stmt *funcBody = funcDecl->getBody();
      static std::unique_ptr<CFG> sourceCFG = CFG::buildCFG(
          funcDecl, funcBody, context, clang::CFG::BuildOptions());
      auto langOpt = context->getLangOpts();
      sourceCFG->dump(langOpt, true);
    }
  }
};

// Apply a custom category to all command-line options so that they are the
// only ones displayed.
static llvm::cl::OptionCategory MyToolCategory("my-tool options");

// CommonOptionsParser declares HelpMessage with a description of the common
// command-line options related to the compilation database and input files.
// It's nice to have this help message in all tools.
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);

// A help message for this specific tool can be added afterwards.
static cl::extrahelp MoreHelp("\nMore help text...\n");

int main(int argc, const char **argv) {
  CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
  ClangTool Tool(OptionsParser.getCompilations(),
                 OptionsParser.getSourcePathList());

  CFGPrinter Printer;
  MatchFinder Finder;
  Finder.addMatcher(FunctionMatcher, &Printer);

  return Tool.run(newFrontendActionFactory(&Finder).get());
}
Gizmo
  • 871
  • 1
  • 15
  • 38