diff options
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 138 |
1 files changed, 85 insertions, 53 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index a5717d16..4b6305b2 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -4593,6 +4593,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static struct stap_uprobe {"; s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };"; s.op->newline() << "int spec_index;"; // index into stap_uprobe_specs; <0 == free && unregistered + s.op->newline() << "unsigned long sdt_sem_address;"; 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 @@ -4651,14 +4652,6 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->assert_0_indent(); - s.op->newline() << "unsigned long sdt_sem_address [] = {"; - for (unsigned i =0; i<probes.size(); i++) - s.op->line() << "0,"; - s.op->line() << "0};"; - s.op->newline() << "unsigned long sdt_sem_tid [] = {"; - for (unsigned i =0; i<probes.size(); i++) - s.op->line() << "0,"; - s.op->line() << "0};"; 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 return_p:1;"; @@ -4761,13 +4754,15 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(1) << "int handled_p = 0;"; s.op->newline() << "int slotted_p = 0;"; s.op->newline() << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [spec_index];"; + s.op->newline() << "struct stap_uprobe *sup;"; + s.op->newline() << "pid_t sdt_sem_pid;"; s.op->newline() << "int rc = 0;"; s.op->newline() << "int i;"; s.op->newline() << "if (likely(sups->tfi != tfi)) continue;"; // skip probes with an address beyond this map event; should not // happen unless a shlib/exec got mmapped in weirdly piecemeal - s.op->newline() << "if (likely(sups->address >= length)) continue;"; + s.op->newline() << "if (likely((vm_flags & VM_EXEC) && ((sups->address >= length) || (sups->sdt_sem_offset >= length)))) continue;"; // Found a uprobe_spec for this stap_uprobe_tf. Need to lock the // stap_uprobes[] array to allocate a free spot, but then we can @@ -4775,10 +4770,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; s.op->newline() << "for (i=0; i<MAXUPROBES; i++) {"; // XXX: slow linear search - s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; + s.op->newline(1) << "sup = & stap_uprobes[i];"; // register new uprobe - s.op->newline() << "if (sup->spec_index < 0) {"; + // We make two passes for semaphores; see _stap_uprobe_change_semaphore_plus + s.op->newline() << "if (sup->spec_index < 0 || (sups->sdt_sem_offset && vm_flags & VM_WRITE && sup->spec_index == spec_index)) {"; s.op->newline(1) << "#if (UPROBES_API_VERSION < 2)"; // See PR6829 comment. s.op->newline() << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;"; @@ -4803,28 +4799,18 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // was full (registration; MAXUPROBES) or that no matching entry was // found (unregistration; should not happen). - s.op->newline() << "if (sups->sdt_sem_offset && (sdt_sem_tid[spec_index] != tsk->tgid || sdt_sem_address[spec_index] == 0)) {"; + s.op->newline() << "sdt_sem_pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid);"; + s.op->newline() << "if (sups->sdt_sem_offset && (sdt_sem_pid != tsk->tgid || sup->sdt_sem_address == 0)) {"; s.op->indent(1); // 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() << "sdt_sem_address[spec_index] = relocation + sups->sdt_sem_offset;"; - s.op->newline() << "sdt_sem_tid[spec_index] = tsk->tgid;"; + s.op->newline() << "sup->sdt_sem_address = relocation + sups->sdt_sem_offset;"; s.op->newline(-1) << "}"; - // If the probe is in a .so, we have to calculate the address - // when the initial mmap maps the entire solib, e.g. - // 7f089885a000-7f089885b000 rw-p- libtcl.so - // A subsequent mmap maps in the writeable segment where the - // semaphore control variable lives, which is when the variable is set. - // 7f089850d000-7f0898647000 r-xp- libtcl.so - // 7f0898647000-7f0898846000 ---p libtcl.so - // 7f0898846000-7f089885b000 rw-p- libtcl.so - // If the task changes, then recalculate the address. s.op->newline() << "else {"; s.op->indent(1); - s.op->newline() << "sdt_sem_address[spec_index] = (relocation - offset) + sups->sdt_sem_offset;"; - s.op->newline() << "sdt_sem_tid[spec_index] = tsk->tgid;"; + s.op->newline() << "sup->sdt_sem_address = (relocation - offset) + sups->sdt_sem_offset;"; s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; // sdt_sem_offset @@ -4841,23 +4827,9 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; s.op->newline() << "rc = register_uprobe (& sup->up);"; - s.op->newline() << "if (sdt_sem_address[spec_index]) {"; - s.op->newline(1) << "unsigned short sdt_semaphore = 0;"; // NB: fixed size - s.op->newline() << "if (get_user (sdt_semaphore, (unsigned short __user*) sdt_sem_address[spec_index]) == 0) {"; - // We have an executable or a writeable segment of a .so - s.op->newline(1) << "if (vm_flags == 0 || vm_flags & VM_WRITE) {"; - s.op->newline(1) << "sdt_semaphore ++;"; - s.op->newline() << "put_user (sdt_semaphore, (unsigned short __user*) sdt_sem_address[spec_index]);"; - s.op->newline(-1) << "}"; - s.op->newline(-1) << "}"; // sdt_sem_address - // 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 && !(vm_flags & VM_WRITE)) {"; // failed to register + 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);"; // NB: we need to release this slot, so we need to borrow the mutex temporarily. s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; @@ -4890,6 +4862,59 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->assert_0_indent(); + s.op->newline(); + s.op->newline() << "static int stap_uprobe_change_semaphore_plus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf) {"; + s.op->newline(1) << "int tfi = (stf - stap_uprobe_finders);"; + s.op->newline() << "int spec_index;"; + s.op->newline() << "int rc = 0;"; + s.op->newline() << "struct stap_uprobe *sup;"; + s.op->newline() << "int i;"; + + // We make two passes for semaphores. + // The first pass, stap_uprobe_change_plus, calculates the address of the + // semaphore. If the probe is in a .so, we calculate the + // address when the initial mmap maps the entire solib, e.g. + // 7f089885a000-7f089885b000 rw-p- libtcl.so + // A subsequent mmap maps in the writeable segment where the + // semaphore control variable lives, e.g. + // 7f089850d000-7f0898647000 r-xp- libtcl.so + // 7f0898647000-7f0898846000 ---p libtcl.so + // 7f0898846000-7f089885b000 rw-p- libtcl.so + // The second pass, stap_uprobe_change_semaphore_plus, sets the semaphore. + // If the probe is in a .so this will be when the writeable segment of the .so + // is mapped in. If the task changes, then recalculate the address. + + s.op->newline() << "for (i=0; i<MAXUPROBES; i++) {"; // XXX: slow linear search + s.op->newline(1) << "sup = & stap_uprobes[i];"; + s.op->newline() << "if (sup->spec_index == -1) continue;"; + s.op->newline() << "if (sup->sdt_sem_address != 0 && !(sup->up.pid == tsk->tgid " + << "&& sup->sdt_sem_address >= relocation && sup->sdt_sem_address < relocation+length)) continue;"; + + s.op->newline() << "if (sup->sdt_sem_address) {"; + s.op->newline(1) << "unsigned short sdt_semaphore = 0;"; // NB: fixed size + s.op->newline() << "if ((rc = get_user (sdt_semaphore, (unsigned short __user*) sup->sdt_sem_address)) == 0) {"; + s.op->newline(1) << "sdt_semaphore ++;"; + + s.op->newline() << "#ifdef DEBUG_UPROBES"; + s.op->newline() << "{"; + s.op->newline(1) << "const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];"; + s.op->newline() << "_stp_dbug(__FUNCTION__,__LINE__, \"+semaphore %#x @ %#lx spec %d idx %d task %d\\n\", " + << "sdt_semaphore, sup->sdt_sem_address, sup->spec_index, i, tsk->tgid);"; + s.op->newline(-1) << "}"; + s.op->newline() << "#endif"; + + s.op->newline() << "rc = put_user (sdt_semaphore, (unsigned short __user*) sup->sdt_sem_address);"; + s.op->newline(-1) << "}"; + // XXX: need to analyze possibility of race condition + + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + s.op->newline() << "return rc;"; + s.op->newline(-1) << "}"; + + s.op->assert_0_indent(); + + // Removing/unmapping a uprobe is simpler than adding one (in the _plus function above). // We need not care about stap_uprobe_finders or anything, we just scan through stap_uprobes[] // for a live probe within the given address range, and kill it. @@ -4989,9 +5014,12 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#endif"; // ET_EXEC events are modeled as if shlib events, but with 0 relocation bases - s.op->newline() << "if (register_p)"; - s.op->newline(1) << "return stap_uprobe_change_plus (tsk, 0, TASK_SIZE, stf, 0, 0);"; - s.op->newline(-1) << "else"; + s.op->newline() << "if (register_p) {"; + // s.op->newline(1) << "return stap_uprobe_change_plus (tsk, 0, TASK_SIZE, stf, 0, 0);"; + s.op->newline(1) << "int rc = stap_uprobe_change_plus (tsk, 0, TASK_SIZE, stf, 0, 0);"; + s.op->newline() << "stap_uprobe_change_semaphore_plus (tsk, 0, TASK_SIZE, stf);"; + s.op->newline() << "return rc;"; + s.op->newline(-1) << "} else"; s.op->newline(1) << "return stap_uprobe_change_minus (tsk, 0, TASK_SIZE, stf);"; s.op->indent(-1); s.op->newline(-1) << "}"; @@ -5008,14 +5036,19 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // 2 - the shared library we're interested in s.op->newline() << "if (path == NULL || strcmp (path, stf->pathname)) return 0;"; // 3 - mapping should be executable or writeable (for semaphore in .so) - s.op->newline() << "if (!((vm_flags & VM_EXEC) || (vm_flags & VM_WRITE))) return 0;"; - - s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA"; - s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+mmap pid %d path %s addr %p length %u offset %p stf %p %p path %s\\n\", " + s.op->newline() << "if (vm_flags & VM_EXEC) {"; + s.op->newline(1) << "#ifdef DEBUG_TASK_FINDER_VMA"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+mmap R-X pid %d path %s addr %p length %u offset %p stf %p %p path %s\\n\", " << "tsk->tgid, path, (void *) addr, (unsigned)length, (void*) offset, tgt, stf, stf->pathname);"; s.op->newline() << "#endif"; - s.op->newline() << "return stap_uprobe_change_plus (tsk, addr, length, stf, offset, vm_flags);"; + s.op->newline(-1) << "} else if (vm_flags & VM_WRITE) {"; + s.op->newline(1) << "#ifdef DEBUG_TASK_FINDER_VMA"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+mmap RW- pid %d path %s addr %p length %u offset %p stf %p %p path %s\\n\", " + << "tsk->tgid, path, (void *) addr, (unsigned)length, (void*) offset, tgt, stf, stf->pathname);"; + s.op->newline() << "#endif"; + s.op->newline() << "return stap_uprobe_change_semaphore_plus (tsk, addr, length, stf);"; + s.op->newline(-1) << "} else return 0;"; s.op->newline(-1) << "}"; s.op->assert_0_indent(); @@ -5093,7 +5126,7 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot // PR10655: decrement that ENABLED semaphore - s.op->newline() << "if (sdt_sem_address[sup->spec_index]) {"; + s.op->newline() << "if (sup->sdt_sem_address) {"; 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;"; @@ -5113,14 +5146,13 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) 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) << "if (get_user (sdt_semaphore, (unsigned short __user*) sdt_sem_address[sup->spec_index]) == 0) {"; + s.op->newline(1) << "if (get_user (sdt_semaphore, (unsigned short __user*) sup->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, sdt_sem_address[sup->spec_index]);"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-semaphore %#x @ %#lx\\n\", sdt_semaphore, sup->sdt_sem_address);"; s.op->newline() << "#endif"; - s.op->newline() << "put_user (sdt_semaphore, (unsigned short __user*) sdt_sem_address[sup->spec_index]);"; + s.op->newline() << "put_user (sdt_semaphore, (unsigned short __user*) sup->sdt_sem_address);"; s.op->newline(-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();"; |