commit a614fce0e51e0c64bbddfd7794fcd7f81d08870b
parent 9f24643c8b7425f5b9fb80dcc4b3e10c63401b68
Author: Kyle Milz <kyle@getaddrinfo.net>
Date: Fri, 25 Mar 2016 11:35:49 -0600
instrument: shuffle some code around
Diffstat:
8 files changed, 291 insertions(+), 302 deletions(-)
diff --git a/instrument/Makefile b/instrument/Makefile
@@ -1,7 +1,7 @@
PROG = scv_instrument
-SRCS = main.cc instrumenter.cc
-
-MKDEP = `llvm-config --cppflags`
+SRCS = main.cc \
+ instrument_action.cc \
+ rewrite_ast_visitor.cc
CXXFLAGS += -std=c++11
CXXFLAGS += `llvm-config --cxxflags`
diff --git a/instrument/instrument_action.cc b/instrument/instrument_action.cc
@@ -0,0 +1,132 @@
+#include <err.h>
+#include <fcntl.h> // open
+#include <limits.h>
+#include <sys/stat.h> // mode flags
+#include <unistd.h> // getcwd, access
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <clang/Frontend/CompilerInstance.h>
+
+#include "instrument_action.h"
+#include "runtime_h.h"
+
+
+std::unique_ptr<ASTConsumer>
+InstrumentAction::CreateASTConsumer(CompilerInstance &CI, StringRef file)
+{
+ // llvm::errs() << "** Creating AST consumer for: " << file << "\n";
+ SourceManager &sm = CI.getSourceManager();
+ TheRewriter.setSourceMgr(sm, CI.getLangOpts());
+
+ return std::unique_ptr<ASTConsumer>(new MyASTConsumer(TheRewriter));
+}
+
+unsigned int
+read_src_number()
+{
+ char *cwd = getcwd(NULL, PATH_MAX);
+ if (cwd == NULL)
+ errx(1, "getcwd");
+
+ std::string src_number_filename(cwd);
+ src_number_filename.append("/SRC_NUMBER");
+
+ if (access(src_number_filename.c_str(), F_OK) == -1) {
+ // SRC_NUMBER does not exist, source number is 0
+ return 0;
+ }
+
+ // SRC_NUMBER exists, read its content
+ std::ifstream src_number_file;
+ unsigned int src_num = 0;
+
+ src_number_file.open(src_number_filename, std::fstream::in);
+ src_number_file >> src_num;
+ src_number_file.close();
+
+ // Pre-increment. The current source number is the last one plus one
+ return ++src_num;
+}
+
+void
+write_src_number(int src_num)
+{
+ char *cwd = getcwd(NULL, PATH_MAX);
+ if (cwd == NULL)
+ errx(1, "getcwd");
+
+ std::string src_number_filename(cwd);
+ src_number_filename.append("/SRC_NUMBER");
+
+ std::ofstream src_number_file;
+ src_number_file.open(src_number_filename, std::fstream::out);
+ src_number_file << src_num;
+ src_number_file.close();
+}
+
+void
+InstrumentAction::EndSourceFileAction()
+{
+ SourceManager &sm = TheRewriter.getSourceMgr();
+ const FileID main_fid = sm.getMainFileID();
+ // llvm::errs() << "** EndSourceFileAction for: "
+ // << sm.getFileEntryForID(main_fid)->getName()
+ // << "\n";
+
+ SourceLocation start = sm.getLocForStartOfFile(main_fid);
+
+ SourceLocation end = sm.getLocForEndOfFile(main_fid);
+ unsigned int num_lines = sm.getPresumedLineNumber(end);
+
+ std::string file_name = getCurrentFile();
+ unsigned int tu_number = read_src_number();
+
+ std::stringstream ss;
+ // Embed the header directly in the primary source file.
+ ss << runtime_h << std::endl;
+
+ // Define storage for coverage data
+ ss << "static uint64_t _scv_lines[" << num_lines << "];" << std::endl;
+
+ // Always declare this. The next TU will overwrite this or there won't
+ // be a next TU.
+ ss << "struct _scv_node _scv_node" << tu_number + 1 << ";" << std::endl;
+
+ // Define this translation units main book keeping data structure
+ ss << "struct _scv_node _scv_node" << tu_number << " = {" << std::endl
+ << " .lines_ptr = _scv_lines," << std::endl
+ << " .size = " << num_lines << "," << std::endl
+ << " .file_name = \"" << file_name << "\"," << std::endl
+ << " .next = &_scv_node" << tu_number + 1 << "," << std::endl
+ << "};" << std::endl;
+
+ TheRewriter.InsertTextAfter(start, ss.str());
+
+ size_t last_slash = file_name.find_last_of('/');
+ std::string base_dir(file_name.substr(0, last_slash + 1));
+ base_dir.append("inst");
+
+ if (mkdir(base_dir.c_str(), S_IWUSR | S_IRUSR | S_IXUSR))
+ if (errno != EEXIST)
+ // An error other than the directory existing occurred
+ err(1, "mkdir");
+
+ file_name.insert(last_slash + 1, "inst/");
+
+ // Instrumented source file might already exist
+ unlink(file_name.c_str());
+
+ int fd = open(file_name.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ err(1, "open");
+ llvm::raw_fd_ostream output(fd, /* close */ 1);
+
+ // Write the instrumented source file
+ TheRewriter.getEditBuffer(main_fid).write(output);
+
+ write_src_number(tu_number);
+}
diff --git a/instrument/instrument_action.h b/instrument/instrument_action.h
@@ -0,0 +1,41 @@
+#include <clang/AST/ASTConsumer.h>
+#include <clang/Frontend/FrontendActions.h>
+#include <clang/Rewrite/Core/Rewriter.h>
+
+#include "rewrite_ast_visitor.h"
+
+using namespace clang;
+
+// For each source file provided to the tool, a new FrontendAction is created.
+class InstrumentAction : public ASTFrontendAction {
+public:
+ InstrumentAction() {};
+
+ void EndSourceFileAction() override;
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &, StringRef) override;
+
+private:
+ Rewriter TheRewriter;
+};
+
+
+// Implementation of the ASTConsumer interface for reading an AST produced
+// by the Clang parser.
+class MyASTConsumer : public ASTConsumer {
+public:
+ MyASTConsumer(Rewriter &R) : Visitor(R) {}
+
+ // Override the method that gets called for each parsed top-level
+ // declaration.
+ bool HandleTopLevelDecl(DeclGroupRef DR) override {
+ for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
+ // Traverse the declaration using our AST visitor.
+ Visitor.TraverseDecl(*b);
+ // (*b)->dump();
+ }
+ return true;
+ }
+
+private:
+ RewriteASTVisitor Visitor;
+};
diff --git a/instrument/instrumenter.cc b/instrument/instrumenter.cc
@@ -1,222 +0,0 @@
-#include <err.h>
-#include <fcntl.h> // open
-#include <limits.h>
-#include <sys/stat.h> // mode flags
-#include <unistd.h> // getcwd, access
-
-#include <fstream>
-#include <iostream>
-#include <sstream>
-#include <string>
-
-#include <clang/AST/AST.h>
-#include <clang/Lex/Lexer.h>
-#include <clang/Frontend/CompilerInstance.h>
-
-#include "instrumenter.h"
-#include "runtime_h.h"
-
-bool
-instrumenter::VisitVarDecl(VarDecl *d)
-{
- return true;
-}
-
-bool
-instrumenter::VisitStmt(Stmt *s)
-{
- std::stringstream ss;
- unsigned line = SM.getPresumedLineNumber(s->getLocStart());
- Stmt *stmt_to_inst = NULL;
-
- if (isa<IfStmt>(s)) {
- stmt_to_inst = cast<IfStmt>(s)->getCond();
- }
- else if (isa<ForStmt>(s)) {
- stmt_to_inst = cast<ForStmt>(s)->getCond();
- }
- else if (isa<WhileStmt>(s)) {
- stmt_to_inst = cast<WhileStmt>(s)->getCond();
- }
- else if (isa<SwitchStmt>(s)) {
- stmt_to_inst = cast<SwitchStmt>(s)->getCond();
- }
- else if (isa<ReturnStmt>(s)) {
- stmt_to_inst = cast<ReturnStmt>(s)->getRetValue();
- }
- /*
- else if (isa<BreakStmt>(s) || isa<ContinueStmt>(s) ||
- || isa<SwitchCase>(s)) {
- }
- */
- else if (isa<DeclStmt>(s)) {
- }
- else if (isa<CallExpr>(s)) {
- stmt_to_inst = s;
- }
-
- if (stmt_to_inst == NULL)
- return true;
-
- ss << "(++_scv_lines[" << line << "], ";
- if (TheRewriter.InsertTextBefore(stmt_to_inst->getLocStart(), ss.str()))
- // writing failed, don't attempt to add ")"
- return true;
-
- TheRewriter.InsertTextAfter(real_loc_end(stmt_to_inst), ")");
-
- return true;
-}
-
-bool
-instrumenter::VisitFunctionDecl(FunctionDecl *f)
-{
- // Only function definitions (with bodies), not declarations.
- if (f->hasBody() == 0)
- return true;
-
- Stmt *FuncBody = f->getBody();
-
- DeclarationName DeclName = f->getNameInfo().getName();
- std::string FuncName = DeclName.getAsString();
-
- if (FuncName.compare("main") != 0)
- // Function is not main
- return true;
-
- std::stringstream ss;
- // On some platforms we need to depend directly on a symbol provided by
- // the runtime. Normally this isn't needed because the runtime only
- // depends on symbols in the isntrumented application.
- ss << "libscv_init();";
- SourceLocation curly_brace(FuncBody->getLocStart().getLocWithOffset(1));
- TheRewriter.InsertTextBefore(curly_brace, ss.str());
-
- return true;
-}
-
-SourceLocation
-instrumenter::real_loc_end(Stmt *d)
-{
- SourceLocation _e(d->getLocEnd());
- return SourceLocation(Lexer::getLocForEndOfToken(_e, 0, SM, lopt));
-}
-
-// MyFrontendAction ---
-
-ASTConsumer *
-MyFrontendAction::CreateASTConsumer(CompilerInstance &CI, StringRef file)
-{
- // llvm::errs() << "** Creating AST consumer for: " << file << "\n";
- SourceManager &sm = CI.getSourceManager();
- TheRewriter.setSourceMgr(sm, CI.getLangOpts());
-
- return new MyASTConsumer(TheRewriter);
-}
-
-unsigned int
-read_src_number()
-{
- char *cwd = getcwd(NULL, PATH_MAX);
- if (cwd == NULL)
- errx(1, "getcwd");
-
- std::string src_number_filename(cwd);
- src_number_filename.append("/SRC_NUMBER");
-
- if (access(src_number_filename.c_str(), F_OK) == -1) {
- // SRC_NUMBER does not exist, source number is 0
- return 0;
- }
-
- // SRC_NUMBER exists, read its content
- std::ifstream src_number_file;
- unsigned int src_num = 0;
-
- src_number_file.open(src_number_filename, std::fstream::in);
- src_number_file >> src_num;
- src_number_file.close();
-
- // Pre-increment. The current source number is the last one plus one
- return ++src_num;
-}
-
-void
-write_src_number(int src_num)
-{
- char *cwd = getcwd(NULL, PATH_MAX);
- if (cwd == NULL)
- errx(1, "getcwd");
-
- std::string src_number_filename(cwd);
- src_number_filename.append("/SRC_NUMBER");
-
- std::ofstream src_number_file;
- src_number_file.open(src_number_filename, std::fstream::out);
- src_number_file << src_num;
- src_number_file.close();
-}
-
-void
-MyFrontendAction::EndSourceFileAction()
-{
- SourceManager &sm = TheRewriter.getSourceMgr();
- const FileID main_fid = sm.getMainFileID();
- // llvm::errs() << "** EndSourceFileAction for: "
- // << sm.getFileEntryForID(main_fid)->getName()
- // << "\n";
-
- SourceLocation start = sm.getLocForStartOfFile(main_fid);
-
- SourceLocation end = sm.getLocForEndOfFile(main_fid);
- unsigned int num_lines = sm.getPresumedLineNumber(end);
-
- std::string file_name = getCurrentFile();
- unsigned int tu_number = read_src_number();
-
- std::stringstream ss;
- // Embed the header directly in the primary source file.
- ss << runtime_h << std::endl;
-
- // Define storage for coverage data
- ss << "static uint64_t _scv_lines[" << num_lines << "];" << std::endl;
-
- // Always declare this. The next TU will overwrite this or there won't
- // be a next TU.
- ss << "struct _scv_node _scv_node" << tu_number + 1 << ";" << std::endl;
-
- // Define this translation units main book keeping data structure
- ss << "struct _scv_node _scv_node" << tu_number << " = {" << std::endl
- << " .lines_ptr = _scv_lines," << std::endl
- << " .size = " << num_lines << "," << std::endl
- << " .file_name = \"" << file_name << "\"," << std::endl
- << " .next = &_scv_node" << tu_number + 1 << "," << std::endl
- << "};" << std::endl;
-
- TheRewriter.InsertTextAfter(start, ss.str());
-
- size_t last_slash = file_name.find_last_of('/');
- std::string base_dir(file_name.substr(0, last_slash + 1));
- base_dir.append("inst");
-
- if (mkdir(base_dir.c_str(), S_IWUSR | S_IRUSR | S_IXUSR))
- if (errno != EEXIST)
- // An error other than the directory existing occurred
- err(1, "mkdir");
-
- file_name.insert(last_slash + 1, "inst/");
-
- // Instrumented source file might already exist
- unlink(file_name.c_str());
-
- int fd = open(file_name.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
- if (fd < 0)
- err(1, "open");
- llvm::raw_fd_ostream output(fd, /* close */ 1);
-
- // Write the instrumented source file
- TheRewriter.getEditBuffer(main_fid).write(output);
-
- // If we got this far write the new translation unit number
- write_src_number(tu_number);
-}
diff --git a/instrument/instrumenter.h b/instrument/instrumenter.h
@@ -1,74 +0,0 @@
-#include <clang/AST/ASTConsumer.h>
-#include <clang/AST/RecursiveASTVisitor.h>
-#include <clang/Frontend/FrontendActions.h>
-#include <clang/Rewrite/Core/Rewriter.h>
-
-using namespace clang;
-
-
-// By implementing RecursiveASTVisitor, we can specify which AST nodes
-// we're interested in by overriding relevant methods.
-class instrumenter : public RecursiveASTVisitor<instrumenter> {
-public:
- instrumenter(Rewriter &R) : TheRewriter(R), SM(R.getSourceMgr()) {}
-
-
- bool VisitVarDecl(VarDecl *d);
- bool VisitStmt(Stmt *s);
- bool VisitFunctionDecl(FunctionDecl *f);
-
-private:
- Rewriter &TheRewriter;
- SourceManager &SM;
- LangOptions lopt;
-
- SourceLocation real_loc_end(Stmt *s);
-};
-
-// Implementation of the ASTConsumer interface for reading an AST produced
-// by the Clang parser.
-class MyASTConsumer : public ASTConsumer {
-public:
- MyASTConsumer(Rewriter &R) : Visitor(R) {}
-
- // Override the method that gets called for each parsed top-level
- // declaration.
- bool HandleTopLevelDecl(DeclGroupRef DR) override {
- for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
- // Traverse the declaration using our AST visitor.
- Visitor.TraverseDecl(*b);
- // (*b)->dump();
- }
- return true;
- }
-
-private:
- instrumenter Visitor;
-};
-
-// For each source file provided to the tool, a new FrontendAction is created.
-class MyFrontendAction : public ASTFrontendAction {
-public:
- MyFrontendAction() {};
-
- void EndSourceFileAction() override;
- ASTConsumer *CreateASTConsumer(CompilerInstance &CI, StringRef file);
-
-private:
- Rewriter TheRewriter;
-};
-
-
-#if 0
-class MFAF : public FrontendActionFactory {
-public:
- MFAF(std::vector<const char *> &i) : inst_files(i) {}
-
- FrontendAction *create() {
- return new MyFrontendAction();
- }
-
-private:
- std::vector<const char *> inst_files;
-};
-#endif
diff --git a/instrument/main.cc b/instrument/main.cc
@@ -10,10 +10,8 @@
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
-#include <clang/Rewrite/Core/Rewriter.h>
-#include <llvm/Support/raw_ostream.h>
-#include "instrumenter.h"
+#include "instrument_action.h"
using namespace clang;
using namespace clang::tooling;
diff --git a/instrument/rewrite_ast_visitor.cc b/instrument/rewrite_ast_visitor.cc
@@ -0,0 +1,93 @@
+#include <sstream>
+#include <string>
+
+#include <clang/AST/AST.h>
+#include <clang/Lex/Lexer.h>
+
+#include "rewrite_ast_visitor.h"
+
+bool
+RewriteASTVisitor::VisitVarDecl(VarDecl *d)
+{
+ return true;
+}
+
+bool
+RewriteASTVisitor::VisitStmt(Stmt *s)
+{
+ std::stringstream ss;
+ unsigned line = SM.getPresumedLineNumber(s->getLocStart());
+ Stmt *stmt_to_inst = NULL;
+
+ if (isa<IfStmt>(s)) {
+ stmt_to_inst = cast<IfStmt>(s)->getCond();
+ }
+ else if (isa<ForStmt>(s)) {
+ stmt_to_inst = cast<ForStmt>(s)->getCond();
+ }
+ else if (isa<WhileStmt>(s)) {
+ stmt_to_inst = cast<WhileStmt>(s)->getCond();
+ }
+ else if (isa<SwitchStmt>(s)) {
+ stmt_to_inst = cast<SwitchStmt>(s)->getCond();
+ }
+ else if (isa<ReturnStmt>(s)) {
+ stmt_to_inst = cast<ReturnStmt>(s)->getRetValue();
+ }
+ /*
+ else if (isa<BreakStmt>(s) || isa<ContinueStmt>(s) ||
+ || isa<SwitchCase>(s)) {
+ }
+ */
+ else if (isa<DeclStmt>(s)) {
+ }
+ else if (isa<CallExpr>(s)) {
+ stmt_to_inst = s;
+ }
+
+ if (stmt_to_inst == NULL)
+ return true;
+
+ ss << "(++_scv_lines[" << line << "], ";
+ if (TheRewriter.InsertTextBefore(stmt_to_inst->getLocStart(), ss.str()))
+ // writing failed, don't attempt to add ")"
+ return true;
+
+ TheRewriter.InsertTextAfter(real_loc_end(stmt_to_inst), ")");
+
+ return true;
+}
+
+bool
+RewriteASTVisitor::VisitFunctionDecl(FunctionDecl *f)
+{
+ // Only function definitions (with bodies), not declarations.
+ if (f->hasBody() == 0)
+ return true;
+
+ Stmt *FuncBody = f->getBody();
+
+ DeclarationName DeclName = f->getNameInfo().getName();
+ std::string FuncName = DeclName.getAsString();
+
+ if (FuncName.compare("main") != 0)
+ // Function is not main
+ return true;
+
+ std::stringstream ss;
+ // On some platforms we need to depend directly on a symbol provided by
+ // the runtime. Normally this isn't needed because the runtime only
+ // depends on symbols in the isntrumented application.
+ ss << "libscv_init();";
+ SourceLocation curly_brace(FuncBody->getLocStart().getLocWithOffset(1));
+ TheRewriter.InsertTextBefore(curly_brace, ss.str());
+
+ return true;
+}
+
+SourceLocation
+RewriteASTVisitor::real_loc_end(Stmt *d)
+{
+ SourceLocation _e(d->getLocEnd());
+ return SourceLocation(Lexer::getLocForEndOfToken(_e, 0, SM, lopt));
+}
diff --git a/instrument/rewrite_ast_visitor.h b/instrument/rewrite_ast_visitor.h
@@ -0,0 +1,21 @@
+#include <clang/AST/RecursiveASTVisitor.h>
+#include <clang/Rewrite/Core/Rewriter.h>
+
+using namespace clang;
+
+
+class RewriteASTVisitor : public RecursiveASTVisitor<RewriteASTVisitor> {
+public:
+ RewriteASTVisitor(Rewriter &R) : TheRewriter(R), SM(R.getSourceMgr()) {}
+
+ bool VisitVarDecl(VarDecl *d);
+ bool VisitStmt(Stmt *s);
+ bool VisitFunctionDecl(FunctionDecl *f);
+
+private:
+ Rewriter &TheRewriter;
+ SourceManager &SM;
+ LangOptions lopt;
+
+ SourceLocation real_loc_end(Stmt *s);
+};