summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdtrace.in6
-rw-r--r--runtime/runtime.h1
-rw-r--r--tapsets.cxx82
3 files changed, 52 insertions, 37 deletions
diff --git a/dtrace.in b/dtrace.in
index 98783604..c18f4efd 100755
--- a/dtrace.in
+++ b/dtrace.in
@@ -37,7 +37,8 @@ class provider:
typedefs += (type_name + type_name + "_v;\n")
return typedefs
def semaphore_def_append(self, this_probe):
- self.semaphores_def += "__extension__ long %s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % (this_probe)
+ # NB: unsigned short is fixed in ABI
+ self.semaphores_def += "__extension__ unsigned short %s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % (this_probe)
def semaphore_def_write(self, file):
file.write(self.semaphores_def)
def generate(self, provider, header, add_typedefs):
@@ -106,7 +107,8 @@ class provider:
i += 1
self.h.write ('/* %s (%s) */\n' % (this_probe_canon,args_string))
self.h.write ('#define %s_ENABLED() %s_semaphore\n' % (this_probe_canon,this_probe))
- self.h.write ("__extension__ extern long %s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % (this_probe))
+ # NB: unsigned short is fixed in ABI
+ self.h.write ("__extension__ extern unsigned short %s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % (this_probe))
self.h.write (define_str + ") \\\n")
self.h.write (stap_str + ")\n\n")
elif (line.find("}") != -1 and have_provider):
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 7087d435..a95627ae 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -28,6 +28,7 @@
#include <linux/kallsyms.h>
#include <linux/version.h>
#include <linux/compat.h>
+#include <linux/sched.h>
#include <linux/mm.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
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) << "}";