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:
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");
}