diff options
author | Josh Stone <jistone@redhat.com> | 2009-03-04 19:32:25 -0800 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2009-03-06 18:47:01 -0800 |
commit | 0a6f5a3f0c2ecfb8b4a416dd07d5b976daf79551 (patch) | |
tree | cfd5e16f08c214df9a5b1f47e4c86205bec63c89 | |
parent | 2da9cedbf2a1916107fe829692af5113646a894d (diff) | |
download | systemtap-steved-0a6f5a3f0c2ecfb8b4a416dd07d5b976daf79551.tar.gz systemtap-steved-0a6f5a3f0c2ecfb8b4a416dd07d5b976daf79551.tar.xz systemtap-steved-0a6f5a3f0c2ecfb8b4a416dd07d5b976daf79551.zip |
Build tracequery to scan for tracepoints
* session.h (systemtap_session): add tracepoint_derived_probes
* buildrun.cxx (make_tracequery): New - builds a kernel module that
hijacks the tracepoint declarations, so we can query debuginfo.
* buildrun.h: declare above
* tapsets.cxx (tracepoint_builder): New builder for tracepoint
probes. For now it just handles the initialization to build the
tracequery kernel module.
-rw-r--r-- | buildrun.cxx | 70 | ||||
-rw-r--r-- | buildrun.h | 1 | ||||
-rw-r--r-- | session.h | 2 | ||||
-rw-r--r-- | tapsets.cxx | 82 |
4 files changed, 155 insertions, 0 deletions
diff --git a/buildrun.cxx b/buildrun.cxx index 973343cd..b81cba23 100644 --- a/buildrun.cxx +++ b/buildrun.cxx @@ -24,6 +24,7 @@ extern "C" { #include <unistd.h> #include <string.h> #include <errno.h> +#include <glob.h> } @@ -336,4 +337,73 @@ run_pass (systemtap_session& s) return rc; } + +// Build a tiny kernel module to query tracepoints +int +make_tracequery(systemtap_session& s, string& name) +{ + // create a subdirectory for the module + string dir(s.tmpdir + "/tracequery"); + if (create_dir(dir.c_str()) != 0) + { + if (! s.suppress_warnings) + cerr << "Warning: failed to create directory for querying tracepoints." << endl; + return 1; + } + + name = dir + "/tracequery.ko"; + + // create a simple Makefile + string makefile(dir + "/Makefile"); + ofstream omf(makefile.c_str()); + omf << "EXTRA_CFLAGS := -g" << endl; // force debuginfo generation + 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; + + // override DECLARE_TRACE to synthesize probe functions for us + osrc << "#undef DECLARE_TRACE" << endl; + osrc << "#define DECLARE_TRACE(name, proto, args) \\" << endl; + osrc << " void stapprobe_##name(proto) {}" << endl; + + // 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 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; + } + 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 + 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); +} + /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ @@ -14,6 +14,7 @@ int compile_pass (systemtap_session& s); int run_pass (systemtap_session& s); +int make_tracequery(systemtap_session& s, std::string& name); #endif // BUILDRUN_H @@ -37,6 +37,7 @@ struct task_finder_derived_probe_group; struct timer_derived_probe_group; struct profile_derived_probe_group; struct mark_derived_probe_group; +struct tracepoint_derived_probe_group; struct hrtimer_derived_probe_group; struct perfmon_derived_probe_group; struct procfs_derived_probe_group; @@ -162,6 +163,7 @@ struct systemtap_session timer_derived_probe_group* timer_derived_probes; profile_derived_probe_group* profile_derived_probes; mark_derived_probe_group* mark_derived_probes; + tracepoint_derived_probe_group* tracepoint_derived_probes; hrtimer_derived_probe_group* hrtimer_derived_probes; perfmon_derived_probe_group* perfmon_derived_probes; procfs_derived_probe_group* procfs_derived_probes; diff --git a/tapsets.cxx b/tapsets.cxx index 834aa06a..6693e9c3 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -15,6 +15,7 @@ #include "translate.h" #include "session.h" #include "util.h" +#include "buildrun.h" #include "dwarf_wrappers.h" #include "auto_free.h" @@ -465,6 +466,7 @@ static string TOK_STATEMENT("statement"); static string TOK_ABSOLUTE("absolute"); static string TOK_PROCESS("process"); static string TOK_MARK("mark"); +static string TOK_TRACE("trace"); static string TOK_LABEL("label"); // Can we handle this query with just symbol-table info? @@ -9201,6 +9203,81 @@ mark_builder::build(systemtap_session & sess, // ------------------------------------------------------------------------ +// statically inserted kernel-tracepoint derived probes +// ------------------------------------------------------------------------ + + +struct tracepoint_derived_probe: public derived_probe +{ + // TODO +}; + + +struct tracepoint_derived_probe_group: public generic_dpg<tracepoint_derived_probe> +{ + // TODO +}; + + +struct tracepoint_builder: public derived_probe_builder +{ +private: + dwflpp *dw; + bool init_dw(systemtap_session& s); + +public: + tracepoint_builder(): dw(0) {} + ~tracepoint_builder() { delete dw; } + + void build_no_more (systemtap_session& s) + { + if (dw && s.verbose > 3) + clog << "tracepoint_builder releasing dwflpp" << endl; + delete dw; + dw = NULL; + } + + void build(systemtap_session& s, + probe *base, probe_point *location, + literal_map_t const& parameters, + vector<derived_probe*>& finished_results); +}; + + +bool +tracepoint_builder::init_dw(systemtap_session& s) +{ + if (dw != NULL) + return true; + + string tracequery_ko; + int rc = make_tracequery(s, tracequery_ko); + if (rc != 0) + return false; + + // TODO cache tracequery.ko + + dw = new dwflpp(s); + dw->setup_user(tracequery_ko); + return true; +} + + +void +tracepoint_builder::build(systemtap_session& s, + probe *base, probe_point *location, + literal_map_t const& parameters, + vector<derived_probe*>& finished_results) +{ + if (!init_dw(s)) + return; + + // TODO run a query to match tracepoint locations +} + + + +// ------------------------------------------------------------------------ // hrtimer derived probes // ------------------------------------------------------------------------ // This is a new timer interface that provides more flexibility in specifying @@ -10002,6 +10079,10 @@ register_standard_tapsets(systemtap_session & s) s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_MARK)->bind_str(TOK_FORMAT) ->bind(new mark_builder()); + // kernel tracepoint probes + s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_TRACE) + ->bind(new tracepoint_builder()); + // procfs parts s.pattern_root->bind(TOK_PROCFS)->bind(TOK_READ)->bind(new procfs_builder()); s.pattern_root->bind_str(TOK_PROCFS)->bind(TOK_READ) @@ -10030,6 +10111,7 @@ all_session_groups(systemtap_session& s) DOONE(timer); DOONE(profile); DOONE(mark); + DOONE(tracepoint); DOONE(hrtimer); DOONE(perfmon); DOONE(procfs); |