diff options
Diffstat (limited to 'buildrun.cxx')
-rw-r--r-- | buildrun.cxx | 202 |
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 : */ |