citrun

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

commit 2db720d7babdf7233c369d817dec26ca303f8cff
parent c84e8963e659f905c961c9fb07b79f589f8f63e2
Author: Kyle Milz <kyle@getaddrinfo.net>
Date:   Thu, 24 Mar 2016 22:08:22 -0600

instrument: let it pass a configure run

- fix some bugs to allow instrument to be used during autoconf ./configure run
- mkdir() for the inst dir was wrong, fix that
- keep track of -c and -o flags, as this tells us when a link is attempted
  - links are important because it means we should reset our source counter
- also convert more stuff to c++ style idioms

Diffstat:
Minstrument/instrumenter.cc | 72+++++++++++++++++++++++++++++++++++++++++++++---------------------------
Minstrument/main.cc | 94++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
2 files changed, 107 insertions(+), 59 deletions(-)

diff --git a/instrument/instrumenter.cc b/instrument/instrumenter.cc @@ -115,37 +115,46 @@ MyFrontendAction::CreateASTConsumer(CompilerInstance &CI, StringRef file) } unsigned int -get_src_number() +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"); - std::fstream src_number_file; if (access(src_number_filename.c_str(), F_OK) == -1) { - // SRC_NUMBER does not exist, create it - src_number_file.open(src_number_filename, std::fstream::out); - src_number_file << 0; - src_number_file.close(); - - // First source file is zero + // SRC_NUMBER does not exist, source number is 0 return 0; } - // SRC_NUMBER existed, read its contents and write incremented value - src_number_file.open(src_number_filename, std::fstream::in | std::fstream::out); - + // 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_num; + src_number_file.close(); - // Write the new source number - src_number_file.seekg(0); - src_number_file << src_num; + // 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"); - return src_num; + 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 @@ -163,7 +172,7 @@ MyFrontendAction::EndSourceFileAction() unsigned int num_lines = sm.getPresumedLineNumber(end); std::string file_name = getCurrentFile(); - unsigned int tu_number = get_src_number(); + unsigned int tu_number = read_src_number(); std::stringstream ss; // Embed the header directly in the primary source file. @@ -180,25 +189,34 @@ MyFrontendAction::EndSourceFileAction() 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; - ss << " .next = &_scv_node" << tu_number + 1 << "," << std::endl; - ss << "};" << std::endl; + << " .file_name = \"" << file_name << "\"," << std::endl + << " .next = &_scv_node" << tu_number + 1 << "," << std::endl + << "};" << std::endl; TheRewriter.InsertTextAfter(start, ss.str()); - // write the instrumented source file to another directory - if (mkdir("inst", S_IWUSR | S_IRUSR | S_IXUSR)) - // already existing directory is ok + 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"); - size_t last_slash = file_name.find_last_of('/'); file_name.insert(last_slash + 1, "inst/"); - int fd = open(file_name.c_str(), O_WRONLY | O_CREAT, - S_IRUSR | S_IWUSR); + + // 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); - // TheRewriter.getEditBuffer(main_fid).write(llvm::outs()); + + // If we got this far write the new translation unit number + write_src_number(tu_number); } diff --git a/instrument/main.cc b/instrument/main.cc @@ -54,20 +54,23 @@ clean_path() setenv("PATH", new_path.str().c_str(), 1); } -void -instrument(int argc, char *argv[], std::vector<std::string> &source_files) +int +instrument(int argc, char *argv[], std::vector<std::string> const &source_files) { std::vector<const char *> clang_argv; - clang_argv.push_back(argv[0]); + if (source_files.size() == 0) + // Nothing to do + return 1; + + clang_argv.push_back(argv[0]); for (auto s : source_files) clang_argv.push_back(s.c_str()); clang_argv.push_back("--"); - // append original command line verbatim after -- - for (int i = 0; i < argc; i++) - clang_argv.push_back(argv[i]); + // Append original command line verbatim + clang_argv.insert(clang_argv.end(), argv, argv + argc); // give clang it's <source files> -- <native command line> arg style int clang_argc = clang_argv.size(); @@ -82,7 +85,8 @@ instrument(int argc, char *argv[], std::vector<std::string> &source_files) // int ret = Tool.run(new MFAF(inst_files)); int ret = Tool.run(newFrontendActionFactory<MyFrontendAction>()); if (ret) - errx(1, "Instrumentation failed"); + warnx("Instrumentation failed"); + return ret; } bool @@ -97,16 +101,26 @@ ends_with(std::string const &value, std::string const &suffix) int main(int argc, char *argv[]) { + std::vector<std::string> args(argv, argv + argc); + std::vector<char *> modified_args; std::vector<std::string> source_files; - std::vector<char *> real_compiler_argv; - - for (int i = 0; i < argc; i++) { - std::string arg(argv[i]); - - // copy argument verbatim for now, we'll replace later if needed - real_compiler_argv.push_back(argv[i]); - - // Dirty hack to find source files + bool preprocess_arg = false; + bool object_arg = false; + bool compile_arg = false; + + // Set a better name than the symlink that was used to find this program + setprogname("scv_instrument"); + + for (auto &arg : args) { + // Special case some hopefully universal arguments + if (arg.compare("-E") == 0) + preprocess_arg = true; + else if (arg.compare("-o") == 0) + object_arg = true; + else if (arg.compare("-c") == 0) + compile_arg = true; + + // Find source files if (ends_with(arg, ".cpp") || ends_with(arg, ".c") || ends_with(arg, ".cxx")) { @@ -129,33 +143,49 @@ main(int argc, char *argv[]) if (src_name == NULL) err(1, "basename"); - std::string inst_src_path; - inst_src_path.append(src_dir); - inst_src_path.append("/inst/"); - inst_src_path.append(src_name); + // modified_args will hang onto the contents of this + std::string *inst_src_path = new std::string(); + inst_src_path->append(src_dir); + inst_src_path->append("/inst/"); + inst_src_path->append(src_name); - // Compilation file will be instrumented source - real_compiler_argv.at(i) = strdup(inst_src_path.c_str()); + // Switch the original file name with the instrumented + // one. + modified_args.push_back(&(*inst_src_path)[0]); + continue; } + + // Non source file argument, copy verbatim + modified_args.push_back((char *)arg.c_str()); } - // NULL terminate arguments we will be passing to exec*() - real_compiler_argv.push_back(NULL); + // NULL terminate the arg vectors we pass to exec() + modified_args.push_back(NULL); argv[argc] = NULL; - if (source_files.size() == 0) { - // We didn't detect any source code on the command line + // -o with -c means output object file + // -o without -c means output binary + if (object_arg && !compile_arg) { + char *cwd = getcwd(NULL, PATH_MAX); + if (cwd == NULL) + errx(1, "getcwd"); + + std::string src_number_filename(cwd); + src_number_filename.append("/SRC_NUMBER"); + unlink(src_number_filename.c_str()); + } + + if (preprocess_arg || instrument(argc, argv, source_files)) { + // The preprocessor arg was found or instrumentation failed. + // In Either case, run the native command unmodified. clean_path(); if (execvp(argv[0], argv)) err(1, "execvp"); } - // Instument the detected source files, storing them in inst/ - instrument(argc, argv, source_files); - - // Run the native compiler on the *instrumented* source files. - // Source file name substitution has already been done. + // Instrumentation succeeded. Run the native compiler with a modified + // command line. clean_path(); - if (execvp(real_compiler_argv[0], &real_compiler_argv[0])) + if (execvp(modified_args[0], &modified_args[0])) err(1, "execvp"); }