commit a90c7f9894aec5bf8d0910726a139589339fdb96
parent 9f7ac79b0925b9476da3853423a38596ed14efe8
Author: Kyle Milz <kyle@0x30.net>
Date: Fri, 12 Aug 2016 19:17:37 -0600
src: add a logging class for instrument
Diffstat:
A | src/inst_log.h | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/inst_main.cc | | | 187 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
M | src/inst_main.h | | | 20 | ++++++++------------ |
3 files changed, 167 insertions(+), 105 deletions(-)
diff --git a/src/inst_log.h b/src/inst_log.h
@@ -0,0 +1,65 @@
+#include <llvm/Support/raw_ostream.h>
+
+class InstrumentLogger {
+public:
+ InstrumentLogger() :
+ m_pid(getpid()),
+ m_needs_prefix(true)
+ {};
+ ~InstrumentLogger()
+ { std::cerr << "~InstrumentLogger()" << std::endl; };
+
+ void set_output(const bool &is_citruninst) {
+
+ if (is_citruninst) {
+ m_output = &llvm::outs();
+ return;
+ } else {
+ std::error_code ec;
+ llvm::raw_fd_ostream *log_file =
+ new llvm::raw_fd_ostream("citrun.log", ec, llvm::sys::fs::F_Append);
+
+ if (ec.value()) {
+ warnx("citrun.log: %s", ec.message().c_str());
+ m_output = &llvm::nulls();
+ return;
+ }
+ m_output = log_file;
+ }
+
+ //m_output = &output;
+ };
+
+ template <typename T>
+ friend InstrumentLogger& operator<<(InstrumentLogger& out, const T &rhs)
+ {
+ out.print_prefix();
+ *out.m_output << rhs;
+ return out;
+ }
+ friend InstrumentLogger& operator<<(InstrumentLogger& out, const char *rhs)
+ {
+ out.print_prefix();
+ *out.m_output << rhs;
+ out.check_newline(rhs);
+ return out;
+ }
+
+ pid_t m_pid;
+ llvm::raw_ostream *m_output;
+
+private:
+ void print_prefix() {
+ if (m_needs_prefix) {
+ *m_output << m_pid << ": ";
+ m_needs_prefix = false;
+ }
+ };
+
+ void check_newline(const std::string &rhs) {
+ if (std::find(rhs.begin(), rhs.end(), '\n') != rhs.end())
+ m_needs_prefix = true;
+ };
+
+ bool m_needs_prefix;
+};
diff --git a/src/inst_main.cc b/src/inst_main.cc
@@ -39,73 +39,18 @@
static llvm::cl::OptionCategory ToolingCategory("citrun-inst options");
-int
-main(int argc, char *argv[])
-{
- CitrunInst main(argc, argv);
-
- main.clean_PATH();
-
- main.process_cmdline();
-
- if (main.instrument())
- return 1;
-
- return main.compile_modified();
-}
-
-CitrunInst::CitrunInst(int argc, char *argv[]) :
- m_args(argv, argv + argc),
- m_ec(),
- m_log("citrun.log", m_ec, llvm::sys::fs::F_Append),
- m_pid(getpid()),
- m_pfx(std::to_string(m_pid) + ": "),
- m_is_citruninst(false)
-{
- if (m_ec.value())
- warnx("citrun.log: %s", m_ec.message().c_str());
-
- struct utsname utsname;
- if (uname(&utsname) == -1)
- err(1, "uname");
-
- m_log << "\n" << m_pfx << "citrun-inst v"
- << unsigned(citrun_major) << "." << unsigned(citrun_minor)
- << " (" << utsname.sysname << "-" << utsname.release
- << " " << utsname.machine
- << ") called as '" << m_args[0] << "'.\n";
- m_log << m_pfx << "Resource directory is '" << STR(CITRUN_SHARE) << "'\n";
-
- char *base_name;
- if ((base_name = basename(m_args[0])) == NULL)
- err(1, "basename");
-
- if (std::strcmp(base_name, m_args[0]) != 0) {
- m_log << m_pfx << "Changing '" << m_args[0] << "' to '"
- << base_name << "'.\n";
- m_args[0] = base_name;
- }
-
- if (std::strcmp(m_args[0], "citrun-inst") == 0)
- m_is_citruninst = true;
-
- setprogname("citrun-inst");
-}
+InstrumentLogger llog;
void
-CitrunInst::clean_PATH()
+clean_PATH()
{
- if (m_is_citruninst)
- // Running citrun-inst directly is guarded against exec() loops
- return;
-
char *path;
if ((path = std::getenv("PATH")) == NULL) {
- m_log << m_pfx << "PATH is not set.\n";
+ llog << "PATH is not set.\n";
errx(1, "PATH must be set");
}
- m_log << m_pfx << "PATH='" << path << "'\n";
+ llog << "PATH='" << path << "'\n";
// Filter CITRUN_SHARE out of PATH
std::stringstream path_ss(path);
@@ -129,7 +74,7 @@ CitrunInst::clean_PATH()
}
if (!found_citrun_path) {
- m_log << m_pfx << "'" << STR(CITRUN_SHARE) << "' not in PATH.\n";
+ llog << "'" << STR(CITRUN_SHARE) << "' not in PATH.\n";
errx(1, "'%s' not in PATH", STR(CITRUN_SHARE));
}
@@ -138,6 +83,65 @@ CitrunInst::clean_PATH()
err(1, "setenv");
}
+void
+print_toolinfo(const char *argv0)
+{
+ llog << "citrun-inst "
+ << unsigned(citrun_major) << "."
+ << unsigned(citrun_minor) << " ";
+
+ struct utsname utsname;
+ if (uname(&utsname) == -1) {
+ warn("uname");
+ llog << "(?) ";
+ } else {
+ llog << "("
+ << utsname.sysname << "-"
+ << utsname.release << " "
+ << utsname.machine << ") ";
+ }
+ llog << "called as '" << argv0 << "'.\n";
+ llog << "Resource directory is '" << STR(CITRUN_SHARE) << "'\n";
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *base_name;
+ if ((base_name = basename(argv[0])) == NULL)
+ err(1, "basename");
+
+ bool is_citruninst = false;
+ if (std::strcmp(base_name, "citrun-inst") == 0)
+ is_citruninst = true;
+
+ llog.set_output(is_citruninst);
+
+ print_toolinfo(argv[0]);
+
+ if (std::strcmp(base_name, argv[0]) != 0) {
+ llog << "Changing '" << argv[0] << "' to '" << base_name << "'.\n";
+ argv[0] = base_name;
+ }
+
+ setprogname("citrun-inst");
+
+ if (is_citruninst == false)
+ clean_PATH();
+
+ CitrunInst main(argc, argv, &llog, is_citruninst);
+ main.process_cmdline();
+ if (main.instrument())
+ return 1;
+ return main.compile_modified();
+}
+
+CitrunInst::CitrunInst(int argc, char *argv[], InstrumentLogger *l, bool is_citruninst) :
+ m_args(argv, argv + argc),
+ m_log(l),
+ m_is_citruninst(is_citruninst)
+{
+}
// Returns true if value ends with suffix, false otherwise.
static bool
@@ -185,7 +189,7 @@ CitrunInst::save_if_srcfile(char *arg)
ends_with(arg, ".cpp") || ends_with(arg, ".cxx")) {
m_source_files.push_back(arg);
- m_log << m_pfx << "Found source file '" << arg << "'.\n";
+ *m_log << "Found source file '" << arg << "'.\n";
if (m_is_citruninst)
// In this mode the modified source file is written to a
@@ -207,15 +211,15 @@ CitrunInst::process_cmdline()
bool object_arg = false;
bool compile_arg = false;
- m_log << m_pfx << "Command line is '";
+ *m_log << "Command line is '";
for (auto &arg : m_args)
- m_log << arg << " ";
- m_log << "'.\n";
+ *m_log << arg << " ";
+ *m_log << "'.\n";
for (auto &arg : m_args) {
if (std::strcmp(arg, "-E") == 0) {
- m_log << m_pfx << "Preprocessor argument found\n";
+ *m_log << "Preprocessor argument found\n";
exec_compiler();
}
else if (std::strcmp(arg, "-o") == 0)
@@ -226,7 +230,7 @@ CitrunInst::process_cmdline()
save_if_srcfile(arg);
}
- m_log << m_pfx << "Object arg = " << object_arg << ", "
+ *m_log << "Object arg = " << object_arg << ", "
<< "compile arg = " << compile_arg << "\n";
bool linking = false;
@@ -240,24 +244,24 @@ CitrunInst::process_cmdline()
linking = true;
if (linking) {
- m_log << m_pfx << "Link detected, adding '";
+ *m_log << "Link detected, adding '";
#ifndef __APPLE__
// OSX always links this.
m_args.push_back(const_cast<char *>("-pthread"));
- m_log << m_args.back() << " ";
+ *m_log << m_args.back() << " ";
#endif
#ifdef CITRUN_COVERAGE
// Needed because libcitrun.a will be instrumented with gcov.
m_args.push_back(const_cast<char *>("-coverage"));
#endif
m_args.push_back(const_cast<char *>(STR(CITRUN_SHARE) "/libcitrun.a"));
- m_log << m_args.back() << "' to command line.\n";
+ *m_log << m_args.back() << "' to command line.\n";
}
if (m_source_files.size() != 0)
return;
- m_log << m_pfx << "No source files found. Executing command line.\n";
+ *m_log << "No source files found. Executing command line.\n";
exec_compiler();
}
@@ -276,10 +280,10 @@ CitrunInst::instrument()
clang_argv.insert(clang_argv.end(), m_args.begin(), m_args.end());
#if defined(__OpenBSD__)
clang_argv.push_back("-I/usr/local/lib/clang/3.8.1/include");
- m_log << m_pfx << "Added clangtool argument '" << clang_argv.back() << "'.\n";
+ *m_log << "Added clangtool argument '" << clang_argv.back() << "'.\n";
#elif defined(__APPLE__)
clang_argv.push_back("-I/opt/local/libexec/llvm-3.8/lib/clang/3.8.1/include");
- m_log << m_pfx << "Added clangtool argument '" << clang_argv.back() << "'.\n";
+ *m_log << "Added clangtool argument '" << clang_argv.back() << "'.\n";
#endif
int clang_argc = clang_argv.size();
@@ -288,26 +292,22 @@ CitrunInst::instrument()
clang::tooling::ClangTool
Tool(op.getCompilations(), op.getSourcePathList());
- if (!m_is_citruninst) {
- clang::DiagnosticOptions diags;
- clang::TextDiagnosticPrinter *log;
+ clang::DiagnosticOptions diags;
+ clang::TextDiagnosticPrinter *log;
- log = new clang::TextDiagnosticPrinter(m_log, &diags, false);
- log->setPrefix(std::to_string(m_pid));
- Tool.setDiagnosticConsumer(log);
- }
+ log = new clang::TextDiagnosticPrinter(*m_log->m_output, &diags, false);
+ log->setPrefix(std::to_string(m_log->m_pid));
+ Tool.setDiagnosticConsumer(log);
std::unique_ptr<InstrumentActionFactory> f =
- llvm::make_unique<InstrumentActionFactory>(&m_log, m_pfx, m_is_citruninst, m_source_files);
+ llvm::make_unique<InstrumentActionFactory>(m_log, m_is_citruninst, m_source_files);
int ret = Tool.run(f.get());
- m_log << m_pfx << "Instrumentation " << (ret ? "failed.\n" : "successful.\n");
+ *m_log << "Instrumentation " << (ret ? "failed.\n" : "successful.\n");
- if (m_is_citruninst) {
+ if (m_is_citruninst)
// Nothing left to do if we're in this mode.
- m_log.close();
exit(ret);
- }
if (ret)
return try_unmodified_compile();
@@ -321,11 +321,11 @@ CitrunInst::try_unmodified_compile()
int ret = fork_compiler();
if (ret == 0) {
- m_log << m_pfx << "But the native compile succeeded!\n";
+ *m_log << "But the native compile succeeded!\n";
return 1;
}
- m_log << m_pfx << "And the native compile failed.\n";
+ *m_log << "And the native compile failed.\n";
return ret;
}
@@ -333,7 +333,7 @@ void
CitrunInst::restore_original_src()
{
for (auto &tmp_file : m_temp_file_map) {
- m_log << m_pfx << "Restored '" << tmp_file.first << "'.\n";
+ *m_log << "Restored '" << tmp_file.first << "'.\n";
copy_file(tmp_file.first, tmp_file.second);
unlink(tmp_file.second.c_str());
@@ -343,10 +343,11 @@ CitrunInst::restore_original_src()
void
CitrunInst::exec_compiler()
{
- m_log.close();
+ // XXX: Need to destroy log here.
+ m_log->m_output->flush();
if (m_is_citruninst) {
- m_log << m_pfx << "Running as citrun-inst, not re-exec()'ing\n";
+ *m_log << "Running as citrun-inst, not re-exec()'ing\n";
exit(0);
}
@@ -359,7 +360,7 @@ int
CitrunInst::fork_compiler()
{
// Otherwise we'll get two copies of buffers after fork().
- m_log.flush();
+ m_log->m_output->flush();
pid_t child_pid;
if ((child_pid = fork()) < 0)
@@ -369,7 +370,7 @@ CitrunInst::fork_compiler()
// In child.
exec_compiler();
- m_log << m_pfx << "Forked '" << m_args[0] << "' "
+ *m_log << "Forked '" << m_args[0] << "' "
<< "pid is '" << child_pid << "'.\n";
int status;
@@ -381,14 +382,14 @@ CitrunInst::fork_compiler()
if (WIFEXITED(status))
exit = WEXITSTATUS(status);
- m_log << m_pfx << "'" << child_pid << "' exited " << exit << ".\n";
+ *m_log << "'" << child_pid << "' exited " << exit << ".\n";
return exit;
}
int
CitrunInst::compile_modified()
{
- m_log << m_pfx << "Running native compiler on modified source code.\n";
+ *m_log << "Running native compiler on modified source code.\n";
int ret = fork_compiler();
restore_original_src();
diff --git a/src/inst_main.h b/src/inst_main.h
@@ -1,10 +1,11 @@
#include <string>
#include "inst_action.h" // InstrumentAction
+#include "inst_log.h"
class CitrunInst {
public:
- CitrunInst(int, char *argv[]);
+ CitrunInst(int, char *argv[], InstrumentLogger *, bool);
void clean_PATH();
void process_cmdline();
@@ -19,13 +20,10 @@ private:
int try_unmodified_compile();
std::vector<char *> m_args;
+ InstrumentLogger *m_log;
+ bool m_is_citruninst;
std::vector<std::string> m_source_files;
std::map<std::string, std::string> m_temp_file_map;
- std::error_code m_ec;
- llvm::raw_fd_ostream m_log;
- pid_t m_pid;
- std::string m_pfx;
- bool m_is_citruninst;
};
//
@@ -33,22 +31,20 @@ private:
//
class InstrumentActionFactory : public clang::tooling::FrontendActionFactory {
public:
- InstrumentActionFactory(llvm::raw_fd_ostream *log, std::string const &pfx,
- bool citruninst, std::vector<std::string> const &src_files) :
+ InstrumentActionFactory(InstrumentLogger *log, bool citruninst,
+ std::vector<std::string> const &src_files) :
m_log(log),
- m_pfx(pfx),
m_is_citruninst(citruninst),
m_source_files(src_files),
m_i(0)
{};
clang::ASTFrontendAction *create() {
- return new InstrumentAction(m_log, m_pfx, m_is_citruninst, m_source_files[m_i++]);
+ return new InstrumentAction((llvm::raw_fd_ostream*)m_log->m_output, "", m_is_citruninst, m_source_files[m_i++]);
}
private:
- llvm::raw_fd_ostream *m_log;
- std::string m_pfx;
+ InstrumentLogger *m_log;
bool m_is_citruninst;
std::vector<std::string> m_source_files;
int m_i;