summaryrefslogtreecommitdiffstats
path: root/buildrun.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'buildrun.cxx')
-rw-r--r--buildrun.cxx202
1 files changed, 176 insertions, 26 deletions
diff --git a/buildrun.cxx b/buildrun.cxx
index b9d648ef..54aa5d4f 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -10,6 +10,9 @@
#include "buildrun.h"
#include "session.h"
#include "util.h"
+#if HAVE_NSS
+#include "modsign.h"
+#endif
#include <cstdlib>
#include <fstream>
@@ -48,6 +51,12 @@ run_make_cmd(systemtap_session& s, string& make_cmd)
cerr << "unsetenv failed: " << e << endl;
}
+ // Disable ccache to avoid saving files that will never be reused.
+ // (ccache is useless to us, because our compiler commands always
+ // include the randomized tmpdir path.)
+ // It's not critical if this fails, so the return is ignored.
+ (void) setenv("CCACHE_DISABLE", "1", 0);
+
if (s.verbose > 2)
make_cmd += " V=1";
else if (s.verbose > 1)
@@ -56,8 +65,9 @@ run_make_cmd(systemtap_session& s, string& make_cmd)
make_cmd += " -s >/dev/null 2>&1";
if (s.verbose > 1) clog << "Running " << make_cmd << endl;
- rc = system (make_cmd.c_str());
-
+ rc = stap_system (make_cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return rc;
}
@@ -148,6 +158,8 @@ compile_pass (systemtap_session& s)
output_autoconf(s, o, "autoconf-vm-area.c", "STAPCONF_VM_AREA", NULL);
output_autoconf(s, o, "autoconf-procfs-owner.c", "STAPCONF_PROCFS_OWNER", NULL);
output_autoconf(s, o, "autoconf-alloc-percpu-align.c", "STAPCONF_ALLOC_PERCPU_ALIGN", NULL);
+ output_autoconf(s, o, "autoconf-find-task-pid.c", "STAPCONF_FIND_TASK_PID", NULL);
+ output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL);
#if 0
/* NB: For now, the performance hit of probe_kernel_read/write (vs. our
@@ -157,6 +169,8 @@ compile_pass (systemtap_session& s)
#endif
output_autoconf(s, o, "autoconf-save-stack-trace.c",
"STAPCONF_KERNEL_STACKTRACE", NULL);
+ output_autoconf(s, o, "autoconf-asm-syscall.c",
+ "STAPCONF_ASM_SYSCALL_H", NULL);
o << module_cflags << " += -include $(STAPCONF_HEADER)" << endl;
@@ -208,6 +222,15 @@ compile_pass (systemtap_session& s)
rc = run_make_cmd(s, make_cmd);
+#if HAVE_NSS
+ // If a certificate database was specified, then try to sign the module.
+ // Failure to do so is not a fatal error. If the signature is actually needed,
+ // staprun will complain at that time.
+ assert (! s.cert_db_path.empty());
+ if (!rc)
+ sign_module (s);
+#endif
+
return rc;
}
@@ -221,7 +244,9 @@ kernel_built_uprobes (systemtap_session& s)
{
string grep_cmd = string ("/bin/grep -q unregister_uprobe ") +
s.kernel_build_tree + string ("/Module.symvers");
- int rc = system (grep_cmd.c_str());
+ int rc = stap_system (grep_cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return (rc == 0);
}
@@ -272,7 +297,9 @@ copy_uprobes_symbols (systemtap_session& s)
string uprobes_home = s.runtime_path + "/uprobes";
string cp_cmd = string("/bin/cp ") + uprobes_home +
string("/Module.symvers ") + s.tmpdir;
- int rc = system (cp_cmd.c_str());
+ int rc = stap_system (cp_cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return rc;
}
@@ -328,20 +355,25 @@ run_pass (systemtap_session& s)
staprun_cmd += "-u ";
if (s.load_only)
- staprun_cmd += "-L ";
+ staprun_cmd += (s.output_file.empty() ? "-L " : "-D ");
+
+ if (!s.size_option.empty())
+ staprun_cmd += "-S " + s.size_option + " ";
staprun_cmd += s.tmpdir + "/" + s.module_name + ".ko";
if (s.verbose>1) clog << "Running " << staprun_cmd << endl;
- rc = system (staprun_cmd.c_str ());
+ rc = stap_system (staprun_cmd.c_str ());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
return rc;
}
// Build a tiny kernel module to query tracepoints
int
-make_tracequery(systemtap_session& s, string& name)
+make_tracequery(systemtap_session& s, string& name, const vector<string>& extra_headers)
{
// create a subdirectory for the module
string dir(s.tmpdir + "/tracequery");
@@ -357,14 +389,14 @@ make_tracequery(systemtap_session& s, string& name)
// create a simple Makefile
string makefile(dir + "/Makefile");
ofstream omf(makefile.c_str());
- omf << "EXTRA_CFLAGS := -g" << endl; // force debuginfo generation
+ // force debuginfo generation, and relax implicit functions
+ omf << "EXTRA_CFLAGS := -g -Wno-implicit-function-declaration" << endl;
omf << "obj-m := tracequery.o" << endl;
omf.close();
// create our source file
string source(dir + "/tracequery.c");
ofstream osrc(source.c_str());
- osrc << "#include <linux/module.h>" << endl;
osrc << "#ifdef CONFIG_TRACEPOINTS" << endl;
osrc << "#include <linux/tracepoint.h>" << endl;
@@ -378,30 +410,45 @@ make_tracequery(systemtap_session& s, string& name)
osrc << "#define DEFINE_TRACE(name, proto, args) \\" << endl;
osrc << " DECLARE_TRACE(name, TPPROTO(proto), TPARGS(args))" << endl;
+ // PR9993: Add extra headers to work around undeclared types in individual
+ // include/trace/foo.h files
+ for (unsigned z=0; z<extra_headers.size(); z++)
+ osrc << "#include <" << extra_headers[z] << ">\n";
+
// dynamically pull in all tracepoint headers from include/trace/
glob_t trace_glob;
- string glob_str(s.kernel_build_tree + "/include/trace/*.h");
- glob(glob_str.c_str(), 0, NULL, &trace_glob);
- for (unsigned i = 0; i < trace_glob.gl_pathc; ++i)
+ string globs[] = {
+ "/include/trace/*.h",
+ "/include/trace/events/*.h",
+ "/source/include/trace/*.h",
+ "/source/include/trace/events/*.h",
+ };
+ for (unsigned z = 0; z < sizeof(globs) / sizeof(globs[0]); z++)
{
- string header(basename(trace_glob.gl_pathv[i]));
-
- // filter out a few known "internal-only" headers
- if (header == "trace_events.h")
- continue;
- if (header.find("_event_types.h") != string::npos)
- continue;
-
- osrc << "#include <trace/" << header << ">" << endl;
+ string glob_str(s.kernel_build_tree + globs[z]);
+ glob(glob_str.c_str(), 0, NULL, &trace_glob);
+ for (unsigned i = 0; i < trace_glob.gl_pathc; ++i)
+ {
+ string header(trace_glob.gl_pathv[i]);
+ size_t root_pos = header.rfind("/include/");
+ assert(root_pos != string::npos);
+ header.erase(0, root_pos + 9);
+
+ // filter out a few known "internal-only" headers
+ if (header.find("/ftrace.h") != string::npos)
+ continue;
+ if (header.find("/trace_events.h") != string::npos)
+ continue;
+ if (header.find("_event_types.h") != string::npos)
+ continue;
+
+ osrc << "#include <" << header << ">" << endl;
+ }
+ globfree(&trace_glob);
}
- globfree(&trace_glob);
// finish up the module source
osrc << "#endif /* CONFIG_TRACEPOINTS */" << endl;
- osrc << "int init_module(void) { return 0; }" << endl;
- osrc << "void cleanup_module(void) {}" << endl;
- osrc << "MODULE_DESCRIPTION(\"tracepoint query\");" << endl;
- osrc << "MODULE_LICENSE(\"GPL\");" << endl;
osrc.close();
// make the module
@@ -412,4 +459,107 @@ make_tracequery(systemtap_session& s, string& name)
return run_make_cmd(s, make_cmd);
}
+
+// Build a tiny kernel module to query type information
+static int
+make_typequery_kmod(systemtap_session& s, const string& header, string& name)
+{
+ static unsigned tick = 0;
+ string basename("typequery_kmod_" + lex_cast<string>(++tick));
+
+ // create a subdirectory for the module
+ string dir(s.tmpdir + "/" + basename);
+ if (create_dir(dir.c_str()) != 0)
+ {
+ if (! s.suppress_warnings)
+ cerr << "Warning: failed to create directory for querying types." << endl;
+ return 1;
+ }
+
+ name = dir + "/" + basename + ".ko";
+
+ // create a simple Makefile
+ string makefile(dir + "/Makefile");
+ ofstream omf(makefile.c_str());
+ omf << "EXTRA_CFLAGS := -g -fno-eliminate-unused-debug-types" << endl;
+
+ // NB: We use -include instead of #include because that gives us more power.
+ // Using #include searches relative to the source's path, which in this case
+ // is /tmp/..., so that's not helpful. Using -include will search relative
+ // to the cwd, which will be the kernel build root. This means if you have a
+ // full kernel build tree, it's possible to get at types that aren't in the
+ // normal include path, e.g.:
+ // @cast(foo, "bsd_acct_struct", "kernel<kernel/acct.c>")->...
+ omf << "CFLAGS_" << basename << ".o := -include " << header << endl;
+
+ omf << "obj-m := " + basename + ".o" << endl;
+ omf.close();
+
+ // create our empty source file
+ string source(dir + "/" + basename + ".c");
+ ofstream osrc(source.c_str());
+ osrc.close();
+
+ // make the module
+ string make_cmd = "make -C '" + s.kernel_build_tree + "'"
+ + " M='" + dir + "' modules";
+ if (s.verbose < 4)
+ make_cmd += " >/dev/null 2>&1";
+ return run_make_cmd(s, make_cmd);
+}
+
+
+// Build a tiny user module to query type information
+static int
+make_typequery_umod(systemtap_session& s, const string& header, string& name)
+{
+ static unsigned tick = 0;
+
+ name = s.tmpdir + "/typequery_umod_" + lex_cast<string>(++tick) + ".so";
+
+ // make the module
+ //
+ // NB: As with kmod, using -include makes relative paths more useful. The
+ // cwd in this case will be the cwd of stap itself though, which may be
+ // trickier to deal with. It might be better to "cd `dirname $script`"
+ // first...
+ string cmd = "gcc -shared -g -fno-eliminate-unused-debug-types -o "
+ + name + " -xc /dev/null -include " + header;
+ if (s.verbose < 4)
+ cmd += " >/dev/null 2>&1";
+ int rc = stap_system (cmd.c_str());
+ if (rc && s.verbose > 1)
+ clog << "Error " << rc << " " << strerror(rc) << endl;
+ return rc;
+}
+
+
+int
+make_typequery(systemtap_session& s, string& module)
+{
+ int rc;
+ string new_module;
+
+ if (module[module.size() - 1] != '>')
+ return -1;
+
+ if (module[0] == '<')
+ {
+ string header = module.substr(1, module.size() - 2);
+ rc = make_typequery_umod(s, header, new_module);
+ }
+ else if (module.compare(0, 7, "kernel<") == 0)
+ {
+ string header = module.substr(7, module.size() - 8);
+ rc = make_typequery_kmod(s, header, new_module);
+ }
+ else
+ return -1;
+
+ if (!rc)
+ module = new_module;
+
+ return rc;
+}
+
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */