This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[RFC] PR6983 kmmio probes
- From: Elliott Baron <ebaron at redhat dot com>
- To: systemtap at sourceware dot org
- Date: Fri, 15 May 2009 12:13:48 -0400
- Subject: [RFC] PR6983 kmmio probes
I have come up with an initial implementation for kmmio probe support
(PR6983). I am having trouble getting the probe to trigger on a given
address, additionally it can also hang at the call to register_kmmio_probe.
There is an ftrace-like tracing tool that will intercept calls to
ioremap and register a kmmio probe using the returned __iomem address
from ioremap.
As it is currently implemented, creating a systemtap probe on a
particular address will pass that address directly to
register_kmmio_probe. To test I have been using physical addresses from
/proc/iomem. Perhaps someone familiar with memory-mapped I/O could shed
some light on what I'm doing wrong.
Thanks,
Elliott
diff --git a/elaborate.cxx b/elaborate.cxx
index 7c4a5fc..c98cbb0 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -1464,6 +1464,7 @@ systemtap_session::systemtap_session ():
hrtimer_derived_probes(0),
perfmon_derived_probes(0),
procfs_derived_probes(0),
+ kmmio_derived_probes(0),
op (0), up (0),
sym_kprobes_text_start (0),
sym_kprobes_text_end (0),
diff --git a/session.h b/session.h
index 151094b..d2a3396 100644
--- a/session.h
+++ b/session.h
@@ -42,6 +42,7 @@ struct tracepoint_derived_probe_group;
struct hrtimer_derived_probe_group;
struct perfmon_derived_probe_group;
struct procfs_derived_probe_group;
+struct kmmio_derived_probe_group;
struct embeddedcode;
struct translator_output;
struct unparser;
@@ -184,6 +185,7 @@ struct systemtap_session
hrtimer_derived_probe_group* hrtimer_derived_probes;
perfmon_derived_probe_group* perfmon_derived_probes;
procfs_derived_probe_group* procfs_derived_probes;
+ kmmio_derived_probe_group* kmmio_derived_probes;
// NB: It is very important for all of the above (and below) fields
// to be cleared in the systemtap_session ctor (elaborate.cxx)
diff --git a/tapsets.cxx b/tapsets.cxx
index d7e9ab4..6c248a1 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -7950,7 +7950,168 @@ tracepoint_builder::build(systemtap_session& s,
dw->query_modules(&q);
}
+//-------------------------------------------------------------------------
+// kernel MMIO derived probes
+//-------------------------------------------------------------------------
+static string TOK_MMIO("mmio");
+static string TOK_LENGTH("length");
+
+struct kmmio_derived_probe: public derived_probe
+{
+ kmmio_derived_probe (systemtap_session &s, probe *p, probe_point *l,
+ unsigned long addr, unsigned long length);
+ void join_group (systemtap_session &s);
+
+ unsigned long addr;
+ unsigned long length;
+};
+
+struct kmmio_derived_probe_group: public generic_dpg<kmmio_derived_probe>
+{
+public:
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+struct kmmio_builder: public derived_probe_builder
+{
+ virtual void build(systemtap_session& sess,
+ probe* base,
+ probe_point* location,
+ literal_map_t const & parameters,
+ std::vector<derived_probe*> & finished_results);
+};
+
+kmmio_derived_probe::kmmio_derived_probe (systemtap_session &s, probe *p, probe_point *l,
+ unsigned long addr, unsigned long length) : derived_probe(p, l),
+ addr(addr), length(length) {}
+
+void
+kmmio_derived_probe::join_group(systemtap_session &s)
+{
+ if (!s.kmmio_derived_probes)
+ {
+ s.kmmio_derived_probes = new kmmio_derived_probe_group();
+ }
+ s.kmmio_derived_probes->enroll(this);
+}
+
+void
+kmmio_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes.empty()) return;
+
+ s.op->newline() << "/* ---- kernel mmio probes ---- */";
+
+ s.op->newline() << "#if ! defined(CONFIG_MMIOTRACE)";
+ s.op->newline() << "#error \"Need CONFIG_MMIOTRACE!\"";
+ s.op->newline() << "#endif";
+ s.op->newline();
+
+ s.op->newline() << "#include <linux/mmiotrace.h>";
+ s.op->newline();
+
+ // Forward declare the master entry functions
+ s.op->newline() << "static void enter_kmmio_probe (struct kmmio_probe *inst,";
+ s.op->line() << " struct pt_regs *regs, unsigned long addr);";
+
+ // Emit the actual probe list.
+
+ s.op->newline() << "static struct kmmio_probe ";
+ s.op->line() << "kmmio_probes[" << probes.size() << "];";
+
+ s.op->newline() << "static struct stap_kmmio_probe {";
+ s.op->newline(1) << "unsigned registered_p:1;";
+ s.op->newline() << "const unsigned long address;";
+ s.op->newline() << "const unsigned long length;";
+ s.op->newline() << "const char * const pp;";
+ s.op->newline() << "void (* const ph) (struct context*);";
+ s.op->newline(-1) << "} stap_kmmio_probes[] = {";
+ s.op->indent(1);
+
+ for (unsigned int i = 0; i < probes.size(); i++)
+ {
+ kmmio_derived_probe *p = probes[i];
+ s.op->newline() << "{ ";
+ s.op->line() << ".address = (unsigned long) 0x" << hex << p->addr << dec << "ULL, ";
+ s.op->line() << ".length = (unsigned long) 0x" << hex << p->length << dec << "ULL, ";
+ s.op->line() << ".pp=" << lex_cast_qstring (*p->sole_location()) << ", ";
+ s.op->line() << ".ph = &" << p->name;
+ s.op->line() << " }";
+ }
+
+ s.op->newline(-1) << "};";
+
+ // Emit kmmio_probe callback.
+ s.op->newline();
+ s.op->newline() << "static void enter_kmmio_probe (struct kmmio_probe *inst,";
+ s.op->line() << " struct pt_regs *regs, unsigned long addr) {";
+ s.op->newline(1) << "int kmmio_probe_idx = ((uintptr_t)inst-(uintptr_t)kmmio_probes)/sizeof(struct kmmio_probe);";
+ // Check that the index is plausible
+ s.op->newline() << "struct stap_kmmio_probe *sp = &stap_kmmio_probes[";
+ s.op->line() << "((kmmio_probe_idx >= 0 && kmmio_probe_idx < " << probes.size() << ") ? ";
+ s.op->line() << "kmmio_probe_idx : 0)"; // NB: at least we avoid memory corruption
+ // XXX: it would be nice to give a more verbose error though; BUG_ON later?
+ s.op->line() << "];";
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "sp->pp");
+ s.op->newline() << "c->regs = regs;";
+ s.op->newline() << "(*sp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline(-1) << "}";
+}
+
+void
+kmmio_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ s.op->newline() << "for (i = 0; i < " << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_kmmio_probe *sp = &stap_kmmio_probes[i];";
+ s.op->newline() << "struct kmmio_probe *kp = &kmmio_probes[i];";
+ s.op->newline() << "probe_point = sp->pp;"; // for error messages
+ s.op->newline() << "kp->addr = sp->address;";
+ s.op->newline() << "kp->len = sp->length;";
+ s.op->newline() << "kp->pre_handler = &enter_kmmio_probe;";
+ s.op->newline() << "kp->post_handler = NULL;";
+ s.op->newline() << "rc = register_kmmio_probe(kp);";
+ s.op->newline() << "if (rc != 0) {";
+ s.op->newline(1) << "sp->registered_p = 0;";
+ s.op->newline() << "_stp_warn(\"probe %s registration error (rc %d)\", probe_point, rc);";
+ s.op->newline() << "atomic_inc(&skipped_count);"; // increment skipped count here
+ s.op->newline() << "rc = 0;"; // continue with other probes
+ s.op->newline(-1) << "}";
+ s.op->newline() << "else sp->registered_p = 1;";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+void
+kmmio_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ s.op->newline() << "for (i = 0; i < " << probes.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_kmmio_probe *sp = &stap_kmmio_probes[i];";
+ s.op->newline() << "struct kmmio_probe *kp = &kmmio_probes[i];";
+ s.op->newline() << "if (sp->registered_p) {";
+ s.op->newline(1) << "unregister_kmmio_probe(kp);";
+ s.op->newline() << "sp->registered_p = 0;";
+ s.op->newline(-1) << "}";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+void
+kmmio_builder::build(systemtap_session& sess,
+ probe* base,
+ probe_point* location,
+ literal_map_t const & parameters,
+ std::vector<derived_probe*> & finished_results)
+{
+ int64_t addr, length;
+
+ assert(get_param(parameters, TOK_MMIO, addr));
+ assert(get_param(parameters, TOK_LENGTH, length));
+
+ finished_results.push_back(new kmmio_derived_probe(sess, base, location,
+ addr, length));
+}
// ------------------------------------------------------------------------
// Standard tapset registry.
@@ -7999,6 +8160,10 @@ register_standard_tapsets(systemtap_session & s)
->bind_num(TOK_MAXACTIVE)->bind(new kprobe_builder());
s.pattern_root->bind(TOK_KPROBE)->bind_num(TOK_STATEMENT)
->bind(TOK_ABSOLUTE)->bind(new kprobe_builder());
+
+ // kernel mmio probes
+ s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_MMIO)->bind_num(TOK_LENGTH)
+ ->bind(new kmmio_builder());
}
@@ -8028,6 +8193,7 @@ all_session_groups(systemtap_session& s)
DOONE(hrtimer);
DOONE(perfmon);
DOONE(procfs);
+ DOONE(kmmio);
// Another "order is important" item. We want to make sure we
// "register" the dummy task_finder probe group after all probe