From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19784 invoked by alias); 24 Jul 2009 11:25:36 -0000 Received: (qmail 19567 invoked by uid 22791); 24 Jul 2009 11:25:33 -0000 X-SWARE-Spam-Status: No, hits=1.5 required=5.0 tests=AWL,BAYES_50,J_CHICKENPOX_36,J_CHICKENPOX_43,URIBL_BLACK X-Spam-Check-By: sourceware.org Received: from e28smtp06.in.ibm.com (HELO e28smtp06.in.ibm.com) (59.145.155.6) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 24 Jul 2009 11:25:24 +0000 Received: from d28relay04.in.ibm.com (d28relay04.in.ibm.com [9.184.220.61]) by e28smtp06.in.ibm.com (8.14.3/8.13.1) with ESMTP id n6OBPJuu018371 for ; Fri, 24 Jul 2009 16:55:19 +0530 Received: from d28av03.in.ibm.com (d28av03.in.ibm.com [9.184.220.65]) by d28relay04.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id n6OBPIhC2453608 for ; Fri, 24 Jul 2009 16:55:18 +0530 Received: from d28av03.in.ibm.com (loopback [127.0.0.1]) by d28av03.in.ibm.com (8.13.1/8.13.3) with ESMTP id n6OBPISs023232 for ; Fri, 24 Jul 2009 21:25:18 +1000 Received: from localhost.localdomain ([9.77.205.124]) by d28av03.in.ibm.com (8.13.1/8.12.11) with ESMTP id n6OBPI9h023222 for ; Fri, 24 Jul 2009 21:25:18 +1000 Message-ID: <4A699A1C.6080205@linux.vnet.ibm.com> Date: Fri, 24 Jul 2009 11:25:00 -0000 From: Prerna Saxena User-Agent: Thunderbird 2.0.0.19 (X11/20090105) MIME-Version: 1.0 To: systemtap@sourceware.org Subject: [RFC] Hardware Breakpoint support for systemtap translator Content-Type: multipart/mixed; boundary="------------090507070906030202000500" X-IsSubscribed: yes Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org X-SW-Source: 2009-q3/txt/msg00196.txt.bz2 This is a multi-part message in MIME format. --------------090507070906030202000500 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 952 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 --------------090507070906030202000500 Content-Type: text/x-diff; name="hwbkpt-1.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="hwbkpt-1.patch" Content-length: 13523 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 probes_by_module; + typedef map::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 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 "; + 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 & finished_results); +}; + +void +hwbkpt_builder::build(systemtap_session & sess, + probe * base, + probe_point * location, + literal_map_t const & parameters, + vector & 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); --------------090507070906030202000500 Content-Type: text/x-diff; name="hwbkpt-2.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="hwbkpt-2.patch" Content-length: 851 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; --------------090507070906030202000500 Content-Type: text/x-diff; name="hwbkpt-3.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="hwbkpt-3.patch" Content-length: 424 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), --------------090507070906030202000500--