citrun

watch C/C++ source code execute
Log | Files | Refs | LICENSE

commit 6d37d7d4c0fb5e1d7fd68d513126a6abba065852
parent a87b2c48b669f89921b53219c2f30cf808c00765
Author: kyle <kyle@getaddrinfo.net>
Date:   Sat, 31 Oct 2015 15:25:23 -0600

instrument: write instrumented source to file

- make source rewriter send source to <orig_file>_inst.c
- then, if instrumentation succeeds compile this file

Diffstat:
Minstrument/instrument.cpp | 141+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 91 insertions(+), 50 deletions(-)

diff --git a/instrument/instrument.cpp b/instrument/instrument.cpp @@ -1,15 +1,8 @@ -//------------------------------------------------------------------------------ -// Tooling sample. Demonstrates: -// -// * How to write a simple source tool using libTooling. -// * How to use RecursiveASTVisitor to find interesting AST nodes. -// * How to use the Rewriter API to rewrite the source code. -// -// Eli Bendersky (eliben@gmail.com) -// This code is in the public domain -//------------------------------------------------------------------------------ -#include <err.h> +#include <err.h> // err, errx +#include <fcntl.h> // open +#include <stdlib.h> // mktemp #include <unistd.h> +#include <sys/stat.h> // mode flags #include <sstream> #include <string> @@ -169,7 +162,7 @@ private: // For each source file provided to the tool, a new FrontendAction is created. class MyFrontendAction : public ASTFrontendAction { public: - MyFrontendAction() {} + MyFrontendAction(std::vector<const char *> &); void EndSourceFileAction() override { SourceManager &sm = TheRewriter.getSourceMgr(); const FileID main_fid = sm.getMainFileID(); @@ -188,7 +181,13 @@ public: TheRewriter.InsertTextAfter(start, ss.str()); // Now emit the rewritten buffer. - TheRewriter.getEditBuffer(main_fid).write(llvm::outs()); + // std::ofstream output(inst_files[0]); + int fd = open(inst_files[0], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (fd < 0) + err(1, "open"); + llvm::raw_fd_ostream output(fd, /* close */ 1); + TheRewriter.getEditBuffer(main_fid).write(output); + // TheRewriter.getEditBuffer(main_fid).write(llvm::outs()); } ASTConsumer *CreateASTConsumer(CompilerInstance &CI, @@ -202,6 +201,25 @@ public: private: Rewriter TheRewriter; + + std::vector<const char *> inst_files; +}; + +MyFrontendAction::MyFrontendAction(std::vector<const char *> &i) : + inst_files(i) +{ +} + +class MFAF : public FrontendActionFactory { +public: + MFAF(std::vector<const char *> &i) : inst_files(i) {} + + FrontendAction *create() { + return new MyFrontendAction(inst_files); + } + +private: + std::vector<const char *> inst_files; }; void @@ -229,6 +247,7 @@ clean_path() bool wrote_first_token = false; while (tok != NULL) { if (strncmp(scv_path, tok, 1024) != 0) { + // didn't find SCV_PATH in PATH if (wrote_first_token == true) { strcat(new_path + new_path_pos, ":"); new_path_pos++; @@ -247,36 +266,10 @@ clean_path() #endif } -int -main(int argc, char *argv[]) +void +instrument(int argc, char *argv[], std::vector<const char *> &source_files, + std::vector<const char *> &inst_files) { - std::vector<const char *> source_files; - char *exec_argv[argc + 1]; - - for (int i = 0; i < argc; i++) { - exec_argv[i] = strdup(argv[i]); - - int arg_len = strlen(argv[i]); - if (arg_len < 4) - continue; - - // compare last four bytes of argument - if (strcmp(argv[i] + arg_len - 4, ".cpp") == 0 || - strcmp(argv[i] + arg_len - 2, ".c") == 0) - source_files.push_back(argv[i]); - } - // very important that argv passed to execvp is NULL terminated - exec_argv[argc] = NULL; - - // run native command if there's no source files to instrument - if (source_files.size() == 0) { - warnx("no source files found on command line"); - clean_path(); - - if (execvp(exec_argv[0], exec_argv)) - err(1, "execvp"); - } - const char *clang_argv[source_files.size() + 1 + argc]; int clang_argc = 0; @@ -286,12 +279,12 @@ main(int argc, char *argv[]) clang_argv[clang_argc++] = "--"; - // append original command line verbatim + // append original command line verbatim after -- for (int i = 0; i < argc; i++) clang_argv[clang_argc++] = argv[i]; - // print out #ifdef DEBUG + // print out for (int i = 0; i < clang_argc; i++) std::cout << clang_argv[i] << " "; std::cout << std::endl; @@ -306,18 +299,66 @@ main(int argc, char *argv[]) // use the helper newFrontendActionFactory to create a default factory // that will return a new MyFrontendAction object every time. To // further customize this, we could create our own factory class. - int ret = Tool.run(newFrontendActionFactory<MyFrontendAction>()); - if (ret) { - std::cout << "Instrumentation failed" << std::endl; - return ret; + int ret = Tool.run(new MFAF(inst_files)); + // int ret = Tool.run(newFrontendActionFactory<MyFrontendAction>()); + if (ret) + errx(1, "Instrumentation failed"); +} + +int +main(int argc, char *argv[]) +{ + std::vector<const char *> source_files; + std::vector<const char *> inst_files; + char *exec_argv[argc + 1]; + + for (int i = 0; i < argc; i++) { + exec_argv[i] = strdup(argv[i]); + + int arg_len = strlen(argv[i]); + if (arg_len < 4) + continue; + + // compare last four bytes of argument + if (strcmp(argv[i] + arg_len - 4, ".cpp") == 0 || + strcmp(argv[i] + arg_len - 2, ".c") == 0) { + // keep track of original source file names + source_files.push_back(argv[i]); + + char *inst_filename = (char *)calloc(PATH_MAX, 1); + if (inst_filename == NULL) + err(1, "calloc"); + + strncpy(inst_filename, argv[i], arg_len - 2); + strcat(inst_filename, "_inst.c"); + + // source code rewriter needs to know this file + inst_files.push_back(inst_filename); + // native compiler uses this source file instead + exec_argv[i] = inst_filename; + } } + // very important that argv passed to execvp is NULL terminated + exec_argv[argc] = NULL; + + // run native command if there's no source files to instrument + if (source_files.size() == 0) { + warnx("no source files found on command line"); + + clean_path(); + if (execvp(exec_argv[0], exec_argv)) + err(1, "execvp"); + } + + // run instrumentation on detected source files + instrument(argc, argv, source_files, inst_files); - clean_path(); #if DEBUG std::cout << "Calling real compiler " << exec_argv[0] << std::endl; #endif + // exec native compiler with instrumented source files + clean_path(); if (execvp(exec_argv[0], exec_argv)) err(1, "execvp"); - std::cout << "here" << std::endl; }