From: Prerna Saxena <prerna@linux.vnet.ibm.com>
To: systemtap@sourceware.org
Subject: [RFC] Hardware Breakpoint support for systemtap translator
Date: Fri, 24 Jul 2009 11:25:00 -0000 [thread overview]
Message-ID: <4A699A1C.6080205@linux.vnet.ibm.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 952 bytes --]
Hi,
The attached set patches enable systemtap translator to probe kernel
hardware breakpoints on x86.
It introduces the following language constructs :
1. probe kernel.data(ADDRESS).write {....} : To probe writes at
the given address
2. probe kernel.data(ADDRESS).rw {....} : To probe read &
write access to the given address.
3. probe kernel.data("SYMBOL").write {....}
4. probe kernel.data("SYMBOL").rw {....} : Similar to 1,2, but
using a symbol name as argument.
These are agnostic to dwarf/debuginfo and depend on the hardware
breakpoint infrastructure for resolving symbols.
Things that remain to be done :
1. Translator support for probing hardware breakpoints on other
architectures (ppc/s390 etc)
2. Implementation of userspace hardware breakpoints.
I'm still testing it...Looking for comments and feedback :-)
--
Prerna Saxena
Linux Technology Centre,
IBM Systems and Technology Lab,
Bangalore, India
[-- Attachment #2: hwbkpt-1.patch --]
[-- Type: text/x-diff, Size: 13523 bytes --]
Index: git-3-july/tapsets.cxx
===================================================================
--- git-3-july.orig/tapsets.cxx
+++ git-3-july/tapsets.cxx
@@ -4929,8 +4929,323 @@ kprobe_builder::build(systemtap_session
}
}
+// ------------------------------------------------------------------------
+// Hardware breakpoint based probes.
+// ------------------------------------------------------------------------
+
+static const string TOK_HWBKPT("data");
+static const string TOK_HWBKPT_WRITE("write");
+static const string TOK_HWBKPT_RW("rw");
+
+#define HWBKPT_READ 0
+#define HWBKPT_WRITE 1
+#define HWBKPT_RW 2
+struct hwbkpt_derived_probe: public derived_probe
+{
+ hwbkpt_derived_probe (probe *base,
+ probe_point *location,
+ int64_t addr,
+ string symname,
+ bool has_only_read_access,
+ bool has_only_write_access,
+ bool has_rw_access
+ );
+ Dwarf_Addr hwbkpt_addr;
+ string symbol_name;
+ unsigned int hwbkpt_access;
+
+ void printsig (std::ostream &o) const;
+ void join_group (systemtap_session& s);
+};
+
+struct hwbkpt_derived_probe_group: public derived_probe_group
+{
+private:
+
+ multimap<string, hwbkpt_derived_probe*> probes_by_module;
+ typedef map<string, hwbkpt_derived_probe*>::iterator p_b_m_iterator;
+public:
+ void enroll (hwbkpt_derived_probe* probe);
+ void emit_module_decls (systemtap_session& s);
+ void emit_module_init (systemtap_session& s);
+ void emit_module_exit (systemtap_session& s);
+};
+
+hwbkpt_derived_probe::hwbkpt_derived_probe (probe *base,
+ probe_point *location,
+ int64_t addr,
+ string symname,
+ bool has_only_read_access,
+ bool has_only_write_access,
+ bool has_rw_access
+ ):
+ derived_probe (base, location),
+ hwbkpt_addr (addr),
+ symbol_name (symname)
+{
+ this->tok = base->tok;
+
+ // Expansion of $target variables in the probe body produces an error
+ // during translate phase
+ vector<probe_point::component*> comps;
+ comps.push_back (new probe_point::component(TOK_KERNEL));
+
+ if (hwbkpt_addr)
+ comps.push_back (new probe_point::component (TOK_HWBKPT, new literal_number(hwbkpt_addr)));
+ else
+ if (symbol_name.size())
+ comps.push_back (new probe_point::component (TOK_HWBKPT, new literal_string(symbol_name)));
+
+ if (has_only_read_access)
+ this->hwbkpt_access = HWBKPT_READ ;
+//TODO add code for comps.push_back for read, since this flag is not for x86
+
+ else
+ {
+ if (has_only_write_access)
+ {
+ this->hwbkpt_access = HWBKPT_WRITE ;
+ comps.push_back (new probe_point::component(TOK_HWBKPT_WRITE));
+ }
+ else
+ {
+ this->hwbkpt_access = HWBKPT_RW ;
+ comps.push_back (new probe_point::component(TOK_HWBKPT_RW));
+ }
+ }
+
+ this->sole_location()->components = comps;
+}
+
+void hwbkpt_derived_probe::printsig (ostream& o) const
+{
+ sole_location()->print (o);
+ o << " /* " << " Address = " << hwbkpt_addr << "*/";
+ o << " /* " << " Symbol = " << symbol_name << "*/";
+ switch (hwbkpt_access)
+ {
+ case HWBKPT_READ:
+ o << " /* " << " Access = READ " << "*/";
+ case HWBKPT_WRITE:
+ o << " /* " << " Access = WRITE " << "*/";
+ case HWBKPT_RW:
+ o << " /* " << " Access = RW " << "*/";
+ }
+ printsig_nested (o);
+}
+
+void hwbkpt_derived_probe::join_group (systemtap_session& s)
+{
+ if (! s.hwbkpt_derived_probes)
+ s.hwbkpt_derived_probes = new hwbkpt_derived_probe_group ();
+ s.hwbkpt_derived_probes->enroll (this);
+}
+
+void hwbkpt_derived_probe_group::enroll (hwbkpt_derived_probe* p)
+{
+ string hwbkpt_key;
+ if (p->hwbkpt_addr)
+ {
+ char hwbkpt_addr_str[64];
+ sprintf(hwbkpt_addr_str, "%u",int(p->hwbkpt_addr));
+ hwbkpt_key=hwbkpt_addr_str;
+ }
+ else
+ hwbkpt_key=p->symbol_name;
+ switch (p->hwbkpt_access)
+ {
+ case HWBKPT_READ:
+ hwbkpt_key = string("R_") + hwbkpt_key;
+ case HWBKPT_WRITE:
+ hwbkpt_key = string("W_") + hwbkpt_key;
+ case HWBKPT_RW:
+ hwbkpt_key = string("RW") + hwbkpt_key;
+ }
+
+ probes_by_module.insert (make_pair (hwbkpt_key, p));
+}
+
+void
+hwbkpt_derived_probe_group::emit_module_decls (systemtap_session& s)
+{
+ if (probes_by_module.empty()) return;
+
+ s.op->newline() << "/* ---- hwbkpt-based probes ---- */";
+ s.op->newline() << "#include <asm/hw_breakpoint.h>";
+ s.op->newline();
+
+// Define macros for access type
+ s.op->newline() << "#define HWBKPT_READ 0";
+ s.op->newline() << "#define HWBKPT_WRITE 1";
+ s.op->newline() << "#define HWBKPT_RW 2";
+
+ // Forward declare the master entry functions
+ s.op->newline() << "static int enter_hwbkpt_probe (struct hw_breakpoint *inst,";
+ s.op->line() << " struct pt_regs *regs);";
+
+ // Emit the actual probe list.
+
+ s.op->newline() << "static struct hw_breakpoint ";
+ s.op->newline() << "stap_hwbkpt_probe_array[" << probes_by_module.size() << "];";
+
+ s.op->newline() << "static struct stap_hwbkpt_probe {";
+ s.op->newline() << "unsigned registered_p:1;";
+
+ // Probe point & Symbol Names are mostly small and uniform enough
+ // to justify putting char[MAX]'s into the array instead of
+ // relocated char*'s.
+
+ size_t pp_name_max = 0 , symbol_name_max = 0;
+ size_t pp_name_tot = 0 , symbol_name_tot = 0;
+ for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
+ {
+ hwbkpt_derived_probe* p = it->second;
+#define DOIT(var,expr) do { \
+ size_t var##_size = (expr) + 1; \
+ var##_max = max (var##_max, var##_size); \
+ var##_tot += var##_size; } while (0)
+ DOIT(pp_name, lex_cast_qstring(*p->sole_location()).size());
+ DOIT(symbol_name, p->symbol_name.size());
+#undef DOIT
+ }
+
+#define CALCIT(var) \
+ s.op->newline() << "const char " << #var << "[" << var##_name_max << "] ;";
+ CALCIT(pp);
+ CALCIT(symbol);
+#undef CALCIT
+
+ s.op->newline() << "const unsigned long address;";
+ s.op->newline() << "unsigned int atype;";
+ s.op->newline() << "void (* const ph) (struct context*);";
+ s.op->newline() << "} stap_hwbkpt_probes[] = {";
+ s.op->indent(1);
+
+ for (p_b_m_iterator it = probes_by_module.begin(); it != probes_by_module.end(); it++)
+ {
+ hwbkpt_derived_probe* p = it->second;
+ s.op->newline() << "{";
+ if (p->symbol_name.size())
+ s.op->line() << " .address=(unsigned long)0x0" << "ULL,";
+ else
+ s.op->line() << " .address=(unsigned long)0x" << hex << p->hwbkpt_addr << dec << "ULL,";
+ s.op->line() << " .atype=" << p->hwbkpt_access << ",";
+ s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ",";
+ s.op->line() << " .symbol=\"" << p->symbol_name << "\",";
+ s.op->line() << " .ph=&" << p->name << "";
+ s.op->line() << " },";
+ }
+ s.op->newline(-1) << "};";
+
+ // Emit the hwbkpt callback function
+ s.op->newline();
+ s.op->newline() << "static int enter_hwbkpt_probe (struct hw_breakpoint *inst,";
+ s.op->line() << " struct pt_regs *regs) {";
+ s.op->newline(1) << "int hwbkpt_probe_idx = ((uintptr_t)inst-(uintptr_t)stap_hwbkpt_probe_array)/sizeof(struct hw_breakpoint);";
+
+ // Check that the index is plausible
+ s.op->newline() << "struct stap_hwbkpt_probe *sdp = &stap_hwbkpt_probes[";
+ s.op->line() << "((hwbkpt_probe_idx >= 0 && hwbkpt_probe_idx < " << probes_by_module.size() << ")?";
+ s.op->line() << "hwbkpt_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", "sdp->pp");
+ s.op->newline() << "c->regs = regs;";
+ s.op->newline() << "(*sdp->ph) (c);";
+ common_probe_entryfn_epilogue (s.op);
+ s.op->newline() << "return 0;";
+ s.op->newline(-1) << "}";
+}
+
+
+void
+hwbkpt_derived_probe_group::emit_module_init (systemtap_session& s)
+{
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_hwbkpt_probe *sdp = & stap_hwbkpt_probes[i];";
+ s.op->newline() << "struct hw_breakpoint *hp = & stap_hwbkpt_probe_array[i];";
+ s.op->newline() << "void *addr = (void *) sdp->address;";
+ s.op->newline() << "const char *hwbkpt_symbol_name = addr ? NULL : sdp->symbol;";
+ s.op->newline() << "#ifdef CONFIG_X86";
+ s.op->newline() << " hp->info.name = (char *) hwbkpt_symbol_name;";
+ s.op->newline() << " hp->info.address = (unsigned long) addr;";
+ s.op->newline() << " hp->info.len = HW_BREAKPOINT_LEN_1;";
+ s.op->newline() << " switch(sdp->atype)";
+ s.op->newline() << " {";
+ s.op->newline() << " case HWBKPT_WRITE:";
+ s.op->newline() << " hp->info.type = HW_BREAKPOINT_WRITE;";
+ s.op->newline() << " case HWBKPT_RW:";
+ s.op->newline() << " hp->info.type = HW_BREAKPOINT_RW;";
+ s.op->newline() << " }";
+ s.op->newline() << "#endif /*CONFIG_X86*/";
+ s.op->newline() << "hp->triggered = (void *)&enter_hwbkpt_probe;";
+ s.op->newline() << "probe_point = sdp->pp;"; // for error messages
+ s.op->newline() << "rc = register_kernel_hw_breakpoint(hp);";
+ s.op->newline() << "if (rc < 0) {";
+ s.op->newline() << " sdp->registered_p = 0;";
+ s.op->newline(1) << " _stp_warn(\" Hwbkpt Probe %s : Registration error (rc = %d), Addr = %u, name = %s\",probe_point,rc,hp->info.address,hp->info.name);";
+ s.op->newline(-1) << "}";
+ s.op->newline() << "else sdp->registered_p = 1;";
+ s.op->newline(-1) << "}"; // for loop
+}
+
+void
+hwbkpt_derived_probe_group::emit_module_exit (systemtap_session& s)
+{
+ //Unregister hwbkpt probes by batch interfaces.
+ s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
+ s.op->newline(1) << "struct stap_hwbkpt_probe *sdp = & stap_hwbkpt_probes[i];";
+ s.op->newline() << "struct hw_breakpoint *hp = & stap_hwbkpt_probe_array[i];";
+ s.op->newline() << "if (! sdp->registered_p) continue;";
+ s.op->newline() << " unregister_kernel_hw_breakpoint(hp);";
+ s.op->newline() << "sdp->registered_p = 0;";
+ s.op->newline(-1) << "}";
+}
+
+struct hwbkpt_builder: public derived_probe_builder
+{
+ hwbkpt_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results);
+};
+
+void
+hwbkpt_builder::build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+{
+ string symbol_str_val;
+ int64_t hwbkpt_address;
+ bool has_addr, has_symbol_str, has_write, has_rw;
+
+ has_addr = get_param (parameters, TOK_HWBKPT, hwbkpt_address);
+ has_symbol_str = get_param (parameters, TOK_HWBKPT, symbol_str_val);
+ has_write = (parameters.find(TOK_HWBKPT_WRITE) != parameters.end());
+ has_rw = (parameters.find(TOK_HWBKPT_RW) != parameters.end());
+
+ if (has_addr)
+ finished_results.push_back (new hwbkpt_derived_probe (base,
+ location,
+ hwbkpt_address,
+ "",0,
+ has_write,
+ has_rw));
+ else // has symbol_str
+ finished_results.push_back (new hwbkpt_derived_probe (base,
+ location,
+ 0,
+ symbol_str_val,0,
+ has_write,
+ has_rw));
+}
+
// ------------------------------------------------------------------------
// statically inserted kernel-tracepoint derived probes
// ------------------------------------------------------------------------
@@ -5487,7 +5802,7 @@ tracepoint_derived_probe_group::emit_mod
}
s.op->line() << ") {";
s.op->indent(1);
- common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING",
+ common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING",
lex_cast_qstring (*p->sole_location()));
s.op->newline() << "c->marker_name = "
<< lex_cast_qstring (p->tracepoint_name)
@@ -5732,7 +6047,6 @@ tracepoint_builder::init_dw(systemtap_se
return true;
}
-
void
tracepoint_builder::build(systemtap_session& s,
probe *base, probe_point *location,
@@ -5750,7 +6064,6 @@ tracepoint_builder::build(systemtap_sess
}
-
// ------------------------------------------------------------------------
// Standard tapset registry.
// ------------------------------------------------------------------------
@@ -5798,6 +6111,16 @@ register_standard_tapsets(systemtap_sess
->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());
+
+ //Hwbkpt based probe
+ s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_HWBKPT)
+ ->bind(TOK_HWBKPT_WRITE)->bind(new hwbkpt_builder());
+ s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_HWBKPT)
+ ->bind(TOK_HWBKPT_WRITE)->bind(new hwbkpt_builder());
+ s.pattern_root->bind(TOK_KERNEL)->bind_num(TOK_HWBKPT)
+ ->bind(TOK_HWBKPT_RW)->bind(new hwbkpt_builder());
+ s.pattern_root->bind(TOK_KERNEL)->bind_str(TOK_HWBKPT)
+ ->bind(TOK_HWBKPT_RW)->bind(new hwbkpt_builder());
}
@@ -5824,6 +6147,7 @@ all_session_groups(systemtap_session& s)
DOONE(mark);
DOONE(tracepoint);
DOONE(kprobe);
+ DOONE(hwbkpt);
DOONE(hrtimer);
DOONE(perfmon);
DOONE(procfs);
[-- Attachment #3: hwbkpt-2.patch --]
[-- Type: text/x-diff, Size: 851 bytes --]
Index: git-3-july/session.h
===================================================================
--- git-3-july.orig/session.h
+++ git-3-july/session.h
@@ -31,6 +31,7 @@ struct derived_probe;
struct be_derived_probe_group;
struct dwarf_derived_probe_group;
struct kprobe_derived_probe_group;
+struct hwbkpt_derived_probe_group;
struct uprobe_derived_probe_group;
struct utrace_derived_probe_group;
struct itrace_derived_probe_group;
@@ -173,6 +174,7 @@ struct systemtap_session
be_derived_probe_group* be_derived_probes;
dwarf_derived_probe_group* dwarf_derived_probes;
kprobe_derived_probe_group* kprobe_derived_probes;
+ hwbkpt_derived_probe_group* hwbkpt_derived_probes;
uprobe_derived_probe_group* uprobe_derived_probes;
utrace_derived_probe_group* utrace_derived_probes;
itrace_derived_probe_group* itrace_derived_probes;
[-- Attachment #4: hwbkpt-3.patch --]
[-- Type: text/x-diff, Size: 424 bytes --]
Index: git-3-july/elaborate.cxx
===================================================================
--- git-3-july.orig/elaborate.cxx
+++ git-3-july/elaborate.cxx
@@ -1457,6 +1457,7 @@ systemtap_session::systemtap_session ():
be_derived_probes(0),
dwarf_derived_probes(0),
kprobe_derived_probes(0),
+ hwbkpt_derived_probes(0),
uprobe_derived_probes(0),
utrace_derived_probes(0),
itrace_derived_probes(0),
next reply other threads:[~2009-07-24 11:25 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-07-24 11:25 Prerna Saxena [this message]
2009-07-24 12:22 ` Prerna Saxena
2009-07-24 15:08 ` Frank Ch. Eigler
2009-07-30 11:38 ` Prerna Saxena
2009-07-24 21:12 ` Roland McGrath
2009-07-31 12:43 ` Prerna Saxena
2009-08-02 21:19 ` Roland McGrath
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A699A1C.6080205@linux.vnet.ibm.com \
--to=prerna@linux.vnet.ibm.com \
--cc=systemtap@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).