diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2009-09-18 21:31:06 -0400 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2009-09-18 21:40:30 -0400 |
commit | 8faa1fc5f98ccb87beb2e71c0ce087278a950dde (patch) | |
tree | 5510a35d85c996aa3d01594970af07536252175a /tapsets.cxx | |
parent | ba01c24c38c098ae93cf62b239f03e824b5f5600 (diff) | |
download | systemtap-steved-8faa1fc5f98ccb87beb2e71c0ce087278a950dde.tar.gz systemtap-steved-8faa1fc5f98ccb87beb2e71c0ce087278a950dde.tar.xz systemtap-steved-8faa1fc5f98ccb87beb2e71c0ce087278a950dde.zip |
PR10655 part 1: uprobes: track sdt semaphores properly
commit 6846cfc8 introduced an unintended side-effect where semaphore tracking
was identified with stap_uprobe_specs[] elements, which are normally static/const.
This kernel patch <http://article.gmane.org/gmane.linux.kernel/854187> catches
and panics on this. The cure is to move the variable over to the stap_uprobes[]
array.
* tapsets.cxx (uprobe emit_module_decls): Add sdt_sem_address to stap_uprobe{} struct,
to contain per-process relocated semaphore address.
(emit_module_decls,_init): Remove tsk field, restore constness of appropriate
locals. Activate uprobe semaphore right around uprobe activation time. Remove
semaphore clearing upon process exit, since by then it's gone.
(emit_module_exit): Use remembered relocated semaphore address to clean up.
Fix "-uprobe" DEBUG_UPROBES message.
* runtime.h: #include <linux/sched.h>.
* dtrace.in (*_semaphore): Make it an unsigned short - intended 16 bits on all
common architectures/multilibs.
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 82 |
1 files changed, 47 insertions, 35 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index 03239ad6..79e3b6d9 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4381,6 +4381,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // too big to embed in the initialized .data stap_uprobe_spec array. s.op->newline() << "static struct stap_uprobe {"; s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };"; + s.op->newline() << "unsigned long sdt_sem_address;"; // relocated to this process s.op->newline() << "int spec_index;"; // index into stap_uprobe_specs; <0 == free && unregistered s.op->newline(-1) << "} stap_uprobes [MAXUPROBES];"; // XXX: consider a slab cache or somesuch s.op->newline() << "DEFINE_MUTEX(stap_uprobes_lock);"; // protects against concurrent registration/unregistration @@ -4438,15 +4439,14 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->assert_0_indent(); - s.op->newline() << "static const struct stap_uprobe_spec {"; + s.op->newline() << "static const struct stap_uprobe_spec {"; // NB: read-only structure s.op->newline(1) << "unsigned tfi;"; // index into stap_uprobe_finders[] s.op->newline() << "unsigned long address;"; s.op->newline() << "const char *pp;"; s.op->newline() << "void (*ph) (struct context*);"; s.op->newline() << "unsigned long sdt_sem_address;"; - s.op->newline() << "struct task_struct *tsk;"; s.op->newline() << "unsigned return_p:1;"; - s.op->newline(-1) << "} stap_uprobe_specs [] = {"; + s.op->newline(-1) << "} stap_uprobe_specs [] = {"; // NB: read-only structure s.op->indent(1); for (unsigned i =0; i<probes.size(); i++) { @@ -4540,7 +4540,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "for (spec_index=0; spec_index<sizeof(stap_uprobe_specs)/sizeof(stap_uprobe_specs[0]); spec_index++) {"; s.op->newline(1) << "int handled_p = 0;"; s.op->newline() << "int slotted_p = 0;"; - s.op->newline() << "struct stap_uprobe_spec *sups = (struct stap_uprobe_spec*) &stap_uprobe_specs [spec_index];"; + s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [spec_index];"; s.op->newline() << "int rc = 0;"; s.op->newline() << "int i;"; @@ -4595,6 +4595,18 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "sup->up.vaddr = relocation + sups->address;"; s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; s.op->newline() << "rc = register_uprobe (& sup->up);"; + + // PR10655: also handle ENABLED semaphore manipulations here + s.op->newline() << "if (!rc && sups->sdt_sem_address) {"; + s.op->newline(1) << "unsigned short sdt_semaphore;"; // NB: fixed size + s.op->newline() << "sup->sdt_sem_address = relocation + sups->sdt_sem_address;"; + s.op->newline() << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; + s.op->newline() << "sdt_semaphore ++;"; + s.op->newline() << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + // XXX: error handling in __access_process_vm! + // XXX: need to analyze possibility of race condition + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; s.op->newline() << "if (rc) {"; // failed to register s.op->newline(1) << "_stp_warn (\"u*probe failed %s[%d] '%s' addr %p rc %d\\n\", tsk->comm, tsk->tgid, sups->pp, (void*)(relocation + sups->address), rc);"; @@ -4620,17 +4632,6 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; - //---------- - s.op->newline() << "if (sups->sdt_sem_address != 0) {"; - s.op->newline(1) << "size_t sdt_semaphore;"; - // XXX sups could get registered to more than one task! - s.op->newline() << "sups->tsk = tsk;"; - s.op->newline() << "__access_process_vm (tsk, relocation + sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore += 1;"; - s.op->newline() << "__access_process_vm (tsk, relocation + sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; - s.op->newline(-1) << "}"; - //---------- - // close iteration over stap_uprobe_spec[] s.op->newline(-1) << "}"; @@ -4711,21 +4712,13 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "sup->spec_index = -1;"; s.op->newline() << "#endif"; + // PR10655: we don't need to fidget with the ENABLED semaphore either, + // as the process is gone, buh-bye, toodaloo, au revoir, see ya later! + s.op->newline(-1) << "}"; s.op->newline() << "mutex_unlock (& stap_uprobes_lock);"; - //---------- - s.op->newline() << "if (sups->sdt_sem_address != 0) {"; - s.op->newline(1) << "size_t sdt_semaphore;"; - // XXX sups could get registered to more than one task! - s.op->newline() << "sups->tsk = tsk;"; - s.op->newline() << "__access_process_vm (tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore += 1;"; - s.op->newline() << "__access_process_vm (tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; - s.op->newline(-1) << "}"; - //---------- - // close iteration over stap_uprobes[] s.op->newline(-1) << "}"; @@ -4849,16 +4842,35 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot - //---------- + // PR10655: decrement that ENABLED semaphore s.op->newline() << "if (sups->sdt_sem_address != 0) {"; - s.op->newline(1) << "size_t sdt_semaphore;"; - // XXX sups could get registered to more than one task! - s.op->newline() << "__access_process_vm (sups->tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore -= 1;"; - s.op->newline() << "__access_process_vm (sups->tsk, sups->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; - s.op->newline(-1) << "}"; - //---------- + s.op->newline(1) << "unsigned short sdt_semaphore;"; // NB: fixed size + s.op->newline() << "pid_t pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid);"; + s.op->newline() << "struct task_struct *tsk;"; + s.op->newline() << "rcu_read_lock();"; + // XXX: what a gross cut & paste job from tapset/task.stp, just for a lousy pid->task_struct* lookup + s.op->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)"; + s.op->newline() << " { struct pid *p_pid = find_get_pid(pid);"; + s.op->newline() << " tsk = pid_task(p_pid, PIDTYPE_PID);"; + s.op->newline() << " put_pid(p_pid); }"; + s.op->newline() << "#else"; + s.op->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)"; + s.op->newline() << " tsk = find_task_by_vpid (pid);"; + s.op->newline() << "#else"; + s.op->newline() << " tsk = find_task_by_pid (pid);"; + s.op->newline() << "#endif /* 2.6.24 */"; + s.op->newline() << "#endif /* 2.6.31 */"; + + s.op->newline() << "if (tsk) {"; // just in case the thing exited while we weren't watching + s.op->newline(1) << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; + s.op->newline() << "sdt_semaphore --;"; + s.op->newline() << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + // XXX: error handling in __access_process_vm! + // XXX: need to analyze possibility of race condition + s.op->newline(-1) << "}"; + s.op->newline() << "rcu_read_unlock();"; + s.op->newline(-1) << "}"; s.op->newline() << "if (sups->return_p) {"; s.op->newline(1) << "#ifdef DEBUG_UPROBES"; @@ -4869,7 +4881,7 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "unregister_uretprobe (& sup->urp);"; s.op->newline(-1) << "} else {"; s.op->newline(1) << "#ifdef DEBUG_UPROBES"; - s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-uprobe spec %d index %d pid %d addr %p\\n\", sup->spec_index, j, sup->urp.u.pid, (void*) sup->urp.u.vaddr);"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-uprobe spec %d index %d pid %d addr %p\\n\", sup->spec_index, j, sup->up.pid, (void*) sup->up.vaddr);"; s.op->newline() << "#endif"; s.op->newline() << "unregister_uprobe (& sup->up);"; s.op->newline(-1) << "}"; |