summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-03-04 19:32:25 -0800
committerJosh Stone <jistone@redhat.com>2009-03-06 18:47:01 -0800
commit0a6f5a3f0c2ecfb8b4a416dd07d5b976daf79551 (patch)
treecfd5e16f08c214df9a5b1f47e4c86205bec63c89
parent2da9cedbf2a1916107fe829692af5113646a894d (diff)
downloadsystemtap-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.cxx70
-rw-r--r--buildrun.h1
-rw-r--r--session.h2
-rw-r--r--tapsets.cxx82
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 : */
diff --git a/buildrun.h b/buildrun.h
index 98c81251..88127449 100644
--- a/buildrun.h
+++ b/buildrun.h
@@ -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
diff --git a/session.h b/session.h
index e6d8eb82..8fa491fd 100644
--- a/session.h
+++ b/session.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);