diff options
author | Stan Cox <scox@redhat.com> | 2010-03-26 17:14:32 -0400 |
---|---|---|
committer | Stan Cox <scox@redhat.com> | 2010-03-26 17:14:32 -0400 |
commit | b642c901a918a92fdd6b1167ed02dfe4c50cdd3e (patch) | |
tree | d84a778e61848003cd48ea6b42db5614d8a26bae | |
parent | 7ad76102c4cd18e083ea74abd413332da55426d1 (diff) | |
download | systemtap-steved-b642c901a918a92fdd6b1167ed02dfe4c50cdd3e.tar.gz systemtap-steved-b642c901a918a92fdd6b1167ed02dfe4c50cdd3e.tar.xz systemtap-steved-b642c901a918a92fdd6b1167ed02dfe4c50cdd3e.zip |
Add kprobe user probe semaphore handling.
Adds stap_kprobe_process_found and stap_kprobe_mmap_found handlers
and then the task_finder uses those to set the semaphore values.
The probe adds user_path and user_lib which are used by the
task_finder to decide what object to sniff.
* sdt.h (STAP_SEMAPHORE): Also define for kprobes.
* tapsets.cxx (dwarf_derived_probe): Add user_path and user_lib.
(dwarf_derived_probe::join_group): Enable task finder for kprobes.
(dwarf_derived_probe::dwarf_derived_probe): Set user_path and
user_lib.
(dwarf_derived_probe_group::emit_module_decls): Emit
stap_kprobe_mmap_found, sdt_sem_offset, sdt_sem_address, pathname,
and finder declarations. Emit stap_kprobe_process_found and
stap_kprobe_mmap_found.
(dwarf_derived_probe_group::emit_module_init): Setup task finder.
(sdt_query::convert_location): Remove TOK_LIBRARY token.
(dwarf_builder::build): Set user_path and user_lib.
(kprobe_derived_probe): Add path and library.
(kprobe_builder::build): Get process and library params
-rw-r--r-- | includes/sys/sdt.h | 10 | ||||
-rw-r--r-- | tapsets.cxx | 213 |
2 files changed, 198 insertions, 25 deletions
diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h index 39ebfb50..74906783 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -29,12 +29,12 @@ #define STAP_PROBE_DATA_(probe,guard,arg) \ __asm__ volatile (".section .probes," ALLOCSEC "\n" \ "\t.balign 8\n" \ - "1:\n\t.asciz " #probe "\n" \ - "\t.balign 4\n" \ + "1:\n\t.asciz " #probe "\n" \ + "\t.balign 4\n" \ "\t.int " #guard "\n" \ "\t.balign 8\n" \ - STAP_PROBE_ADDR("1b\n") \ - "\t.balign 8\n" \ + STAP_PROBE_ADDR("1b\n") \ + "\t.balign 8\n" \ STAP_PROBE_ADDR(#arg "\n") \ "\t.int 0\n" \ "\t.previous\n") @@ -42,7 +42,7 @@ #define STAP_PROBE_DATA(probe, guard, arg) \ STAP_PROBE_DATA_(#probe,guard,arg) -#if defined STAP_HAS_SEMAPHORES && ! defined EXPERIMENTAL_KPROBE_SDT +#if defined STAP_HAS_SEMAPHORES #define STAP_SEMAPHORE(probe) \ if (__builtin_expect ( probe ## _semaphore , 0)) #else diff --git a/tapsets.cxx b/tapsets.cxx index 2e2a3f0f..97c6fb76 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -357,6 +357,8 @@ struct dwarf_derived_probe: public derived_probe bool has_maxactive; bool has_library; long maxactive_val; + string user_path; + string user_lib; bool access_vars; unsigned saved_longs, saved_strings; @@ -564,11 +566,15 @@ struct dwarf_query : public base_query probe_point * base_loc, dwflpp & dw, literal_map_t const & params, - vector<derived_probe *> & results); + vector<derived_probe *> & results, + const string user_path, + const string user_lib); vector<derived_probe *> & results; probe * base_probe; probe_point * base_loc; + string user_path; + string user_lib; virtual void handle_query_module(); void query_module_dwarf(); @@ -642,6 +648,8 @@ struct dwarf_builder: public derived_probe_builder { map <string,dwflpp*> kern_dw; /* NB: key string could be a wildcard */ map <string,dwflpp*> user_dw; + string user_path; + string user_lib; dwarf_builder() {} dwflpp *get_kern_dw(systemtap_session& sess, const string& module) @@ -704,9 +712,12 @@ dwarf_query::dwarf_query(probe * base_probe, probe_point * base_loc, dwflpp & dw, literal_map_t const & params, - vector<derived_probe *> & results) + vector<derived_probe *> & results, + const string user_path, + const string user_lib) : base_query(dw, params), results(results), - base_probe(base_probe), base_loc(base_loc) + base_probe(base_probe), base_loc(base_loc), + user_path(user_path), user_lib(user_lib) { // Reduce the query to more reasonable semantic values (booleans, // extracted strings, numbers, etc). @@ -2958,6 +2969,8 @@ dwarf_derived_probe::join_group (systemtap_session& s) if (! s.dwarf_derived_probes) s.dwarf_derived_probes = new dwarf_derived_probe_group (); s.dwarf_derived_probes->enroll (this); + + enable_task_finder(s); } @@ -2985,10 +2998,15 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, has_maxactive (q.has_maxactive), has_library (q.has_library), maxactive_val (q.maxactive_val), + user_path (q.user_path), + user_lib (q.user_lib), access_vars(false), saved_longs(0), saved_strings(0), entry_handler(0) { + if (user_lib.size() != 0) + has_library = true; + if (q.has_process) { // We may receive probes on two types of ELF objects: ET_EXEC or ET_DYN. @@ -3390,6 +3408,9 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "} stap_dwarf_kprobes[" << probes_by_module.size() << "];"; // NB: bss! + s.op->newline() << "static int stap_kprobe_mmap_found (struct stap_task_finder_target *finder, struct task_struct *tsk, char *path, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags);"; + s.op->newline() << "static int stap_kprobe_process_found (struct stap_task_finder_target *finder, struct task_struct *tsk, int register_p, int process_p);"; + s.op->newline() << "static struct stap_dwarf_probe {"; s.op->newline(1) << "const unsigned return_p:1;"; s.op->newline() << "const unsigned maxactive_p:1;"; @@ -3444,6 +3465,11 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "const unsigned long address;"; s.op->newline() << "void (* const ph) (struct context*);"; s.op->newline() << "void (* const entry_ph) (struct context*);"; + s.op->newline() << "const unsigned long sdt_sem_offset;"; + s.op->newline() << "unsigned long sdt_sem_address;"; + s.op->newline() << "struct task_struct *tsk;"; + s.op->newline() << "const char *pathname;"; + s.op->newline() << "struct stap_task_finder_target finder;"; s.op->newline(-1) << "} stap_dwarf_probes[] = {"; s.op->indent(1); @@ -3474,7 +3500,34 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << " .module=\"" << p->module << "\","; s.op->line() << " .section=\"" << p->section << "\","; s.op->line() << " .pp=" << lex_cast_qstring (*p->sole_location()) << ","; + if (p->sdt_semaphore_addr != 0) + { + s.op->line() << " .sdt_sem_offset=(unsigned long)0x" << hex << p->sdt_semaphore_addr << dec << "ULL,"; + s.op->line() << " .sdt_sem_address=0,"; + if (p->has_library) + { + s.op->line() << " .finder={"; + s.op->line() << " .pid=0,"; + s.op->line() << " .procname=\"" << p->user_path << "\","; + s.op->line() << " .mmap_callback=&stap_kprobe_mmap_found,"; + s.op->line() << " },"; + s.op->line() << " .pathname=\"" << p->user_lib << "\","; + } + else + { + s.op->line() << " .finder={"; + s.op->line() << " .pid=0,"; + s.op->line() << " .procname=\"" << p->user_path << "\","; + s.op->line() << " .callback=&stap_kprobe_process_found,"; + s.op->line() << " },"; + s.op->line() << " .pathname=\"" << p->user_path << "\","; + } + + } + else + s.op->line() << " .sdt_sem_offset=0,"; s.op->line() << " .ph=&" << p->name; + s.op->line() << " },"; } @@ -3565,12 +3618,85 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->line() << " struct pt_regs *regs) {"; s.op->newline(1) << "return enter_kretprobe_common(inst, regs, 1);"; s.op->newline(-1) << "}"; + + s.op->newline() << "static int stap_kprobe_process_found (struct stap_task_finder_target *finder, struct task_struct *tsk, int register_p, int process_p) {"; + s.op->newline(1) << "struct stap_dwarf_probe *p = container_of(finder, struct stap_dwarf_probe, finder);"; + s.op->newline() << "unsigned short sdt_semaphore = 0;"; // NB: fixed size + s.op->newline() << "if (! process_p) return 0; /* ignore threads */"; + s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"%cproc pid %d stf %p %p path %s\\n\", register_p?'+':'-', tsk->tgid, finder, p, p->pathname);"; + s.op->newline() << "#endif"; + s.op->newline() << "p->tsk = tsk;"; + s.op->newline() << "p->sdt_sem_address = p->sdt_sem_offset;"; + s.op->newline() << "if (get_user (sdt_semaphore, (unsigned short __user *) p->sdt_sem_address) == 0) {"; + s.op->newline(1) << "sdt_semaphore ++;"; + s.op->newline() << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+semaphore %#x @ %#lx\\n\", sdt_semaphore, p->sdt_sem_address);"; + s.op->newline() << "#endif"; + s.op->newline() << "put_user (sdt_semaphore, (unsigned short __user *) p->sdt_sem_address);"; + s.op->newline(-1) << "}"; + s.op->newline() << "return 0;"; + s.op->newline(-1) << "}"; + + // The task_finder_mmap_callback + s.op->newline() << "static int stap_kprobe_mmap_found (struct stap_task_finder_target *finder, struct task_struct *tsk, char *path, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags) {"; + s.op->newline(1) << "struct stap_dwarf_probe *p = container_of(finder, struct stap_dwarf_probe, finder);"; + s.op->newline() << "int rc = 0;"; + // the shared library we're interested in + s.op->newline() << "if (path == NULL || strcmp (path, p->pathname)) return 0;"; + s.op->newline() << "if (p->sdt_sem_offset && p->sdt_sem_address == 0) {"; + s.op->indent(1); + s.op->newline() << "p->tsk = tsk;"; + // If the probe is in the executable itself, the offset *is* the + // address. + s.op->newline() << "if (vm_flags & VM_EXECUTABLE) {"; + s.op->indent(1); + s.op->newline() << "p->sdt_sem_address = addr + p->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + // If the probe is in a .so, we have to calculate the address. + s.op->newline() << "else {"; + s.op->indent(1); + s.op->newline() << "p->sdt_sem_address = (addr - offset) + p->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + s.op->newline() << "if (p->sdt_sem_address && (vm_flags & VM_WRITE)) {"; + s.op->newline(1) << "unsigned short sdt_semaphore = 0;"; // NB: fixed size + s.op->newline() << "if (get_user (sdt_semaphore, (unsigned short __user *) p->sdt_sem_address) == 0) {"; + s.op->newline(1) << "sdt_semaphore ++;"; + s.op->newline() << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+semaphore %#x @ %#lx\\n\", sdt_semaphore, p->sdt_sem_address);"; + s.op->newline() << "#endif"; + s.op->newline() << "put_user (sdt_semaphore, (unsigned short __user *) p->sdt_sem_address);"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + s.op->newline() << "return 0;"; + s.op->newline(-1) << "}"; } void dwarf_derived_probe_group::emit_module_init (systemtap_session& s) { + p_b_m_iterator it; + for (it = probes_by_module.begin(); it != probes_by_module.end(); it++) + { + dwarf_derived_probe* p = it->second; + if (p->sdt_semaphore_addr != 0) + break; + } + if (it != probes_by_module.end()) // Ignore if there are no semaphores + { + s.op->newline() << "for (i=0; i<ARRAY_SIZE(stap_dwarf_probes); i++) {"; + s.op->newline(1) << "int rc;"; + s.op->newline() << "struct stap_dwarf_probe *p = &stap_dwarf_probes[i];"; + s.op->newline() << "probe_point = p->pp;"; // for error messages + s.op->newline() << "if (p->sdt_sem_offset) {"; + s.op->newline(1) << "rc = stap_register_task_finder_target(&p->finder);"; + s.op->newline(-1) << "}"; + s.op->newline() << "if (rc) break;"; + s.op->newline(-1) << "}"; + } + s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];"; s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];"; @@ -3654,6 +3780,15 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s) void dwarf_derived_probe_group::emit_module_exit (systemtap_session& s) { + s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {"; + s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];"; + s.op->newline() << "unsigned short sdt_semaphore = 0;"; // NB: fixed size + s.op->newline() << "if (sdp->sdt_sem_address && __access_process_vm_noflush (sdp->tsk, sdp->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0)) {"; + s.op->newline(1) << "sdt_semaphore --;"; + s.op->newline() << "__access_process_vm_noflush (sdp->tsk, sdp->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + //Unregister kprobes by batch interfaces. s.op->newline() << "#if defined(STAPCONF_UNREGISTER_KPROBES)"; s.op->newline() << "j = 0;"; @@ -3959,7 +4094,7 @@ sdt_query::handle_query_module() params[c->functor] = c->arg; } - dwarf_query q(new_base, new_location, dw, params, results); + dwarf_query q(new_base, new_location, dw, params, results, "", ""); q.has_mark = true; // enables mid-statement probing dw.iterate_over_modules(&query_module, &q); } @@ -4209,13 +4344,15 @@ sdt_query::convert_location () new literal_number(probe_arg, true)); break; - case kprobe_type: - if (sess.verbose > 3) - clog << "probe_type == kprobe_type" << endl; - // kernel.function("*getegid*") - derived_loc->components[i] = - new probe_point::component(TOK_FUNCTION, new literal_string("*getegid*")); - break; + case kprobe_type: + if (sess.verbose > 3) + clog << "probe_type == kprobe_type" << endl; + // kernel.function("*getegid*") + derived_loc->components[i] = + new probe_point::component(TOK_FUNCTION, new literal_string("*getegid*")); + if (derived_loc->components[i - 1]->functor == TOK_LIBRARY) + derived_loc->components.erase (derived_loc->components.begin() + i - 1); + break; default: if (sess.verbose > 3) @@ -4265,10 +4402,14 @@ dwarf_builder::build(systemtap_session & sess, else if (get_param (parameters, TOK_PROCESS, module_name)) { string library_name; + user_path = find_executable (module_name); // canonicalize it if (get_param (parameters, TOK_LIBRARY, library_name)) - module_name = find_executable (library_name, "LD_LIBRARY_PATH"); + { + module_name = find_executable (library_name, "LD_LIBRARY_PATH"); + user_lib = module_name; + } else - module_name = find_executable (module_name); // canonicalize it + module_name = user_path; // canonicalize it if (sess.kernel_config["CONFIG_UTRACE"] != string("y")) throw semantic_error ("process probes not available without kernel CONFIG_UTRACE"); @@ -4289,7 +4430,7 @@ dwarf_builder::build(systemtap_session & sess, return; } - dwarf_query q(base, location, *dw, parameters, finished_results); + dwarf_query q(base, location, *dw, parameters, finished_results, user_path, user_lib); // XXX: kernel.statement.absolute is a special case that requires no // dwfl processing. This code should be in a separate builder. @@ -5026,14 +5167,22 @@ struct kprobe_derived_probe: public derived_probe bool has_return, bool has_statement, bool has_maxactive, - long maxactive_val + bool has_path, + bool has_library, + long maxactive_val, + const string& path, + const string& library ); string symbol_name; Dwarf_Addr addr; bool has_return; bool has_statement; bool has_maxactive; + bool has_path; + bool has_library; long maxactive_val; + string path; + string library; bool access_var; void printsig (std::ostream &o) const; void join_group (systemtap_session& s); @@ -5059,12 +5208,19 @@ kprobe_derived_probe::kprobe_derived_probe (probe *base, bool has_return, bool has_statement, bool has_maxactive, - long maxactive_val + bool has_path, + bool has_library, + long maxactive_val, + const string& path, + const string& library ): derived_probe (base, location), symbol_name (name), addr (stmt_addr), has_return (has_return), has_statement (has_statement), - has_maxactive (has_maxactive), maxactive_val (maxactive_val) + has_maxactive (has_maxactive), has_path (has_path), + has_library (has_library), + maxactive_val (maxactive_val), + path (path), library (library) { this->tok = base->tok; this->access_var = false; @@ -5450,9 +5606,11 @@ kprobe_builder::build(systemtap_session & sess, vector<derived_probe *> & finished_results) { string function_string_val, module_string_val; + string path, library; int64_t statement_num_val = 0, maxactive_val = 0; bool has_function_str, has_module_str, has_statement_num; bool has_absolute, has_return, has_maxactive; + bool has_path, has_library; has_function_str = get_param(parameters, TOK_FUNCTION, function_string_val); has_module_str = get_param(parameters, TOK_MODULE, module_string_val); @@ -5460,7 +5618,14 @@ kprobe_builder::build(systemtap_session & sess, has_maxactive = get_param(parameters, TOK_MAXACTIVE, maxactive_val); has_statement_num = get_param(parameters, TOK_STATEMENT, statement_num_val); has_absolute = has_null_param (parameters, TOK_ABSOLUTE); - + has_path = get_param (parameters, TOK_PROCESS, path); + has_library = get_param (parameters, TOK_LIBRARY, library); + + if (has_path) + path = find_executable (path); + if (has_library) + library = find_executable (library, "LD_LIBRARY_PATH"); + if (has_function_str) { if (has_module_str) @@ -5471,7 +5636,11 @@ kprobe_builder::build(systemtap_session & sess, 0, has_return, has_statement_num, has_maxactive, - maxactive_val)); + has_path, + has_library, + maxactive_val, + path, + library)); } else { @@ -5485,7 +5654,11 @@ kprobe_builder::build(systemtap_session & sess, has_return, has_statement_num, has_maxactive, - maxactive_val)); + has_path, + has_library, + maxactive_val, + path, + library)); } } |