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);
+};