static void stapkp_add_missed(struct stap_dwarf_probe *sdp) { if (sdp->return_p) { struct kretprobe *krp = &sdp->kprobe->u.krp; atomic_add(krp->nmissed, skipped_count()); #ifdef STP_TIMING if (krp->nmissed) _stp_warn ("Skipped due to missed kretprobe/1 on '%s': %d\n", sdp->probe->pp, krp->nmissed); #endif atomic_add(krp->kp.nmissed, skipped_count()); #ifdef STP_TIMING if (krp->kp.nmissed) _stp_warn ("Skipped due to missed kretprobe/2 on '%s': %lu\n", sdp->probe->pp, krp->kp.nmissed); #endif } else { struct kprobe *kp = &sdp->kprobe->u.kp; atomic_add (kp->nmissed, skipped_count()); #ifdef STP_TIMING if (kp->nmissed) _stp_warn ("Skipped due to missed kprobe on '%s': %lu\n", sdp->probe->pp, kp->nmissed); #endif } }
static int stapkp_init(struct stap_kprobe_probe *probes, size_t nprobes) { size_t i; #ifdef STAPCONF_KALLSYMS_ON_EACH_SYMBOL // If we have any symbol_name+offset probes, we need to try to // convert those into address-based probes. size_t probe_max = 0; for (i = 0; i < nprobes; i++) { struct stap_kprobe_probe *skp = &probes[i]; if (! skp->symbol_name) continue; ++probe_max; } if (probe_max > 0) { // Here we're going to try to convert any symbol_name+offset // probes into address probes. struct stapkp_symbol_data sd; dbug_stapkp("looking up %lu probes\n", probe_max); sd.probes = probes; sd.nprobes = nprobes; sd.probe_max = probe_max; sd.modname = NULL; preempt_disable(); kallsyms_on_each_symbol(stapkp_symbol_callback, &sd); preempt_enable(); dbug_stapkp("found %lu probes\n", sd.probe_max); } #endif for (i = 0; i < nprobes; i++) { struct stap_kprobe_probe *skp = &probes[i]; int rc = 0; rc = stapkp_register_probe(skp); if (rc == 1) // failed to relocate addr? continue; // don't fuss about it, module probably not loaded // NB: We keep going even if a probe failed to register (PR6749). We only // warn about it if it wasn't optional and isn't in a module. if (rc && !skp->optional_p && ((skp->module == NULL) || skp->module[0] == '\0' || strcmp(skp->module, "kernel") == 0)) { if (skp->symbol_name) _stp_warn("probe %s (%s+%u) registration error (rc %d)", skp->probe->pp, skp->symbol_name, skp->offset, rc); else _stp_warn("probe %s (address 0x%lx) registration error (rc %d)", skp->probe->pp, stapkp_relocate_addr(skp), rc); } } return 0; }
/* Validate user module based on build-id (if present) */ static int _stp_usermodule_check(struct task_struct *tsk, const char *path_name, unsigned long addr) { struct _stp_module *m = NULL; unsigned long notes_addr; unsigned i, j; unsigned char practice_id_bits[MAXSTRINGLEN]; unsigned long vm_end = 0; #ifdef STP_NO_BUILDID_CHECK return 0; #endif for (i = 0; i < _stp_num_modules; i++) { m = _stp_modules[i]; if (strcmp(path_name, _stp_modules[i]->path) != 0) continue; if (m->build_id_len > 0) { int ret, build_id_len; notes_addr = addr + m->build_id_offset /* + m->module_base */; dbug_sym(1, "build-id validation [%d %s] address=%#lx build_id_offset=%#lx\n", tsk->pid, m->path, addr, m->build_id_offset); if (notes_addr <= addr) { _stp_warn ("build-id address %lx < base %lx\n", notes_addr, addr); continue; } return _stp_build_id_check (m, notes_addr, tsk); } } return 0; }
/* Iterate over _stp_modules, looking for a kernel module of given name. Run build-id checking for it. Return 0 on ok. */ static int _stp_kmodule_check (const char *name) { struct _stp_module *m = NULL; unsigned long notes_addr, base_addr; unsigned i,j; #ifdef STP_NO_BUILDID_CHECK return 0; #endif for (i = 0; i < _stp_num_modules; i++) { m = _stp_modules[i]; if (strcmp (name, m->name)) continue; if (m->build_id_len > 0 && m->notes_sect != 0) { dbug_sym(1, "build-id validation [%s]\n", m->name); /* notes end address */ notes_addr = m->notes_sect + m->build_id_offset; base_addr = m->notes_sect; if (notes_addr <= base_addr) { /* shouldn't happen */ _stp_warn ("build-id address %lx < base %lx\n", notes_addr, base_addr); continue; } return _stp_build_id_check (m, notes_addr, NULL); } /* end checking */ } /* end loop */ return 0; /* name not found */ }
static void _stp_handle_start(struct _stp_msg_start *st) { int handle_startup; mutex_lock(&_stp_transport_mutex); handle_startup = (! _stp_start_called && ! _stp_exit_called); _stp_start_called = 1; mutex_unlock(&_stp_transport_mutex); if (handle_startup) { dbug_trans(1, "stp_handle_start\n"); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) // linux commit #5f4352fb #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) // linux commit #9be260a6 #ifdef STAPCONF_VM_AREA { /* PR9740: workaround for kernel valloc bug. */ /* PR14611: not required except within above kernel range. */ void *dummy; #ifdef STAPCONF_VM_AREA_PTE dummy = alloc_vm_area (PAGE_SIZE, NULL); #else dummy = alloc_vm_area (PAGE_SIZE); #endif free_vm_area (dummy); } #endif #endif #endif _stp_target = st->target; st->res = systemtap_module_init(); if (st->res == 0) _stp_probes_started = 1; /* Register the module notifier. */ if (!_stp_module_notifier_active) { int rc = register_module_notifier(& _stp_module_notifier_nb); if (rc == 0) _stp_module_notifier_active = 1; else _stp_warn ("Cannot register module notifier (%d)\n", rc); } /* Called from the user context in response to a proc file write (in _stp_ctl_write_cmd), so may notify the reader directly. */ _stp_ctl_send_notify(STP_START, st, sizeof(*st)); /* Register the panic notifier. */ #if STP_TRANSPORT_VERSION == 2 atomic_notifier_chain_register(&panic_notifier_list, &_stp_module_panic_notifier_nb); #endif } }
static int _stp_stat_calc_buckets(int stop, int start, int interval) { int buckets; if (interval == 0) { _stp_warn("histogram: interval cannot be zero.\n"); return 0; } /* don't forget buckets for underflow and overflow */ buckets = (stop - start) / interval + 3; if (buckets > STP_MAX_BUCKETS || buckets < 3) { _stp_warn("histogram: Number of buckets must be between 1 and %d\n" "Number_of_buckets = (stop - start) / interval.\n" "Please adjust your start, stop, and interval values.\n", STP_MAX_BUCKETS-2); return 0; } return buckets; }
/* Validate all-modules + kernel based on build-id (if present). * The completed case is the following combination: * Debuginfo Module Kernel * X X * has build-id/not unloaded has build-id/not * loaded && (has build-id/not) * * NB: build-id exists only if ld>=2.18 and kernel>= 2.6.23 */ static int _stp_module_check(void) { struct _stp_module *m = NULL; unsigned long notes_addr, base_addr; unsigned i,j; int rc = 0; #ifdef STP_NO_BUILDID_CHECK return 0; #endif for (i = 0; i < _stp_num_modules; i++) { m = _stp_modules[i]; if (m->build_id_len > 0 && m->notes_sect != 0) { dbug_sym(1, "build-id validation [%s]\n", m->name); /* kernel only */ /* skip userspace program */ if (m->name[0] != '/') continue; /* notes end address */ if (!strcmp(m->name, "kernel")) { notes_addr = _stp_kmodule_relocate("kernel", "_stext", m->build_id_offset); base_addr = _stp_kmodule_relocate("kernel", "_stext", 0); } else { notes_addr = m->notes_sect + m->build_id_offset; base_addr = m->notes_sect; } if (notes_addr <= base_addr) { /* shouldn't happen */ _stp_warn ("build-id address %lx <= base %lx\n", notes_addr, base_addr); continue; } rc |= _stp_build_id_check (m, notes_addr, NULL); } /* end checking */ } /* end loop */ return rc; }
/* Validate user module based on build-id (if present) */ static int _stp_usermodule_check(struct task_struct *tsk, const char *path_name, unsigned long addr) { struct _stp_module *m = NULL; unsigned long notes_addr; unsigned i, j; unsigned char practice_id_bits[MAXSTRINGLEN]; unsigned long vm_end = 0; #ifdef STP_NO_BUILDID_CHECK return 0; #endif WARN_ON(!path_name || path_name[0]!='/'); // user-space only for (i = 0; i < _stp_num_modules; i++) { m = _stp_modules[i]; /* PR16406 must be unique userspace name (/-prefixed path); it's also in m->name */ if (strcmp(path_name, m->path) != 0) continue; if (m->build_id_len > 0) { int ret, build_id_len; notes_addr = addr + m->build_id_offset /* + m->module_base */; dbug_sym(1, "build-id validation [%d %s] address=%#lx build_id_offset=%#lx\n", tsk->pid, m->path, addr, m->build_id_offset); if (notes_addr <= addr) { _stp_warn ("build-id address %lx < base %lx\n", notes_addr, addr); continue; } return _stp_build_id_check (m, notes_addr, tsk); } } return 0; /* not found */ }
/* Iterate over _stp_modules, looking for a kernel module of given name. Run build-id checking for it. Return 0 on ok. */ static int _stp_kmodule_check (const char *name) { struct _stp_module *m = NULL; unsigned long notes_addr, base_addr; unsigned i,j; #ifdef STP_NO_BUILDID_CHECK return 0; #endif WARN_ON(!name || name[0]=='/'); // non-userspace only for (i = 0; i < _stp_num_modules; i++) { m = _stp_modules[i]; /* PR16406 must be unique kernel module name (non-/-prefixed path) */ if (strcmp (name, m->name)) continue; if (m->build_id_len > 0 && m->notes_sect != 0) { dbug_sym(1, "build-id validation [%s]\n", m->name); /* notes end address */ notes_addr = m->notes_sect + m->build_id_offset; base_addr = m->notes_sect; if (notes_addr <= base_addr) { /* shouldn't happen */ _stp_warn ("build-id address %lx < base %lx\n", notes_addr, base_addr); continue; } return _stp_build_id_check (m, notes_addr, NULL); } /* end checking */ } /* end loop */ return 0; /* not found */ }
static int stapkp_init(struct stap_dwarf_probe *probes, size_t nprobes) { size_t i; for (i = 0; i < nprobes; i++) { struct stap_dwarf_probe *sdp = &probes[i]; int rc = 0; rc = stapkp_register_probe(sdp); if (rc == 1) // failed to relocate addr? continue; // don't fuss about it, module probably not loaded // NB: We keep going even if a probe failed to register (PR6749). We only // warn about it if it wasn't optional. if (rc && !sdp->optional_p) { _stp_warn("probe %s (address 0x%lx) registration error (rc %d)", sdp->probe->pp, stapkp_relocate_addr(sdp), rc); } } return 0; }
static int _stp_build_id_check (struct _stp_module *m, unsigned long notes_addr, struct task_struct *tsk) { int j; for (j = 0; j < m->build_id_len; j++) { /* Use set_fs / get_user to access conceivably invalid addresses. * If loc2c-runtime.h were more easily usable, a deref() loop * could do it too. */ mm_segment_t oldfs = get_fs(); int rc; unsigned char theory, practice = 0; #ifdef STAPCONF_PROBE_KERNEL if (!tsk) { theory = m->build_id_bits[j]; set_fs(KERNEL_DS); rc = probe_kernel_read(&practice, (void*)(notes_addr + j), 1); } else #endif { theory = m->build_id_bits[j]; set_fs (tsk ? USER_DS : KERNEL_DS); /* * Why check CONFIG_UTRACE here? If we're using real in-kernel * utrace, we can always just call get_user() (since we're * either reading kernel memory or tsk == current). * * Since we're only reading here, we can call * __access_process_vm_noflush(), which only calls things that * are exported. */ #ifdef CONFIG_UTRACE rc = get_user(practice, ((unsigned char*)(void*)(notes_addr + j))); #else if (!tsk || tsk == current) { rc = get_user(practice, ((unsigned char*)(void*)(notes_addr + j))); } else { rc = (__access_process_vm_noflush(tsk, (notes_addr + j), &practice, 1, 0) != 1); } #endif } set_fs(oldfs); if (rc || (theory != practice)) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) _stp_error ("Build-id mismatch [man error::buildid]: \"%s\" byte %d (0x%02x vs 0x%02x) address %#lx rc %d\n", m->path, j, theory, practice, notes_addr, rc); return 1; #else /* This branch is a surrogate for kernels affected by Fedora bug * #465873. */ _stp_warn (KERN_WARNING "Build-id mismatch [man error::buildid]: \"%s\" byte %d (0x%02x vs 0x%02x) rc %d\n", m->path, j, theory, practice, rc); #endif break; } /* end mismatch */ } /* end per-byte check loop */ return 0; }
static int stap_uprobe_change_plus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf, unsigned long offset, unsigned long vm_flags) { int tfi = (stf - stap_uprobe_finders); int spec_index; /* iterate over stap_uprobe_spec[] that use this same stap_uprobe_tf */ for (spec_index=0; spec_index<sizeof(stap_uprobe_specs)/sizeof(stap_uprobe_specs[0]); spec_index++) { int handled_p = 0; int slotted_p = 0; const struct stap_uprobe_spec *sups = &stap_uprobe_specs [spec_index]; struct stap_uprobe *sup; pid_t sdt_sem_pid; int rc = 0; int i; int pci; 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 */ if (likely((vm_flags & VM_EXEC) && sups->address >= 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 unlock and do the register_*probe subsequently. */ mutex_lock (& stap_uprobes_lock); for (i=0; i<MAXUPROBES; i++) { /* XXX: slow linear search */ sup = & stap_uprobes[i]; /* register new uprobe We make two passes for semaphores; see stap_uprobe_change_semaphore_plus */ if (sup->spec_index < 0 || (sups->sdt_sem_offset && vm_flags & VM_WRITE && sup->spec_index == spec_index)) { #if (UPROBES_API_VERSION < 2) /* See PR6829 comment. */ if (sup->spec_index == -1 && sup->up.kdata != NULL) continue; else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue; #endif sup->spec_index = spec_index; slotted_p = 1; break; } } mutex_unlock (& stap_uprobes_lock); #ifdef DEBUG_UPROBES _stp_dbug(__FUNCTION__,__LINE__, "+uprobe spec %d idx %d process %s[%d] addr %p pp %s\n", spec_index, (slotted_p ? i : -1), tsk->comm, tsk->tgid, (void*)(relocation+sups->address), sups->probe->pp); #endif /* NB: check for user-module build-id only if we have a pathname at all; for a process(PID#).* probe, we may not. If at some point we map process(PID#) to process("/proc/PID#/exe"), we'll get a pathname. */ if (stf->pathname) if ((rc = _stp_usermodule_check(tsk, stf->pathname, relocation))) return rc; /* Here, slotted_p implies that `i' points to the single stap_uprobes[] element that has been slotted in for registration or unregistration processing. !slotted_p implies that the table was full (registration; MAXUPROBES) or that no matching entry was found (unregistration; should not happen). */ sdt_sem_pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid); if (sups->sdt_sem_offset && (sdt_sem_pid != tsk->tgid || sup->sdt_sem_address == 0)) { /* If the probe is in an ET_EXEC binary, then the sdt_sem_offset already * is a real address. But stap_uprobe_process_found calls us in this * case with relocation=offset=0, so we don't have to worry about it. */ sup->sdt_sem_address = (relocation - offset) + sups->sdt_sem_offset; } /* sdt_sem_offset */ for (pci=0; pci < sups->perf_counters_dim; pci++) { if ((sups->perf_counters)[pci] > -1) _stp_perf_read_init ((sups->perf_counters)[pci], tsk); } if (slotted_p) { struct stap_uprobe *sup = & stap_uprobes[i]; if (sups->return_p) { sup->urp.u.pid = tsk->tgid; sup->urp.u.vaddr = relocation + sups->address; sup->urp.handler = &enter_uretprobe_probe; rc = register_uretprobe (& sup->urp); } else { sup->up.pid = tsk->tgid; sup->up.vaddr = relocation + sups->address; sup->up.handler = &enter_uprobe_probe; rc = register_uprobe (& sup->up); } /* The u*probe failed to register. However, if we got EEXIST, * that means that the u*probe is already there, so just ignore * the error. This could happen if CLONE_THREAD or CLONE_VM was * used. */ if (rc != 0 && rc != -EEXIST) { _stp_warn ("u*probe failed %s[%d] '%s' addr %p rc %d\n", tsk->comm, tsk->tgid, sups->probe->pp, (void*)(relocation + sups->address), rc); /* NB: we need to release this slot, so we need to borrow the mutex temporarily. */ mutex_lock (& stap_uprobes_lock); sup->spec_index = -1; sup->sdt_sem_address = 0; mutex_unlock (& stap_uprobes_lock); } else { handled_p = 1; } } /* NB: handled_p implies slotted_p */ if (unlikely (! handled_p)) { #ifdef STP_TIMING atomic_inc (skipped_count_uprobe_reg()); #endif /* NB: duplicates common_entryfn_epilogue, but then this is not a probe entry fn epilogue. */ #ifndef STAP_SUPPRESS_HANDLER_ERRORS if (unlikely (atomic_inc_return (skipped_count()) > MAXSKIPPED)) { if (unlikely (pseudo_atomic_cmpxchg(session_state(), STAP_SESSION_RUNNING, STAP_SESSION_ERROR) == STAP_SESSION_RUNNING)) _stp_error ("Skipped too many probes, check MAXSKIPPED or try again with stap -t for more details."); } #endif } } /* close iteration over stap_uprobe_spec[] */ return 0; /* XXX: or rc? */ }
static int stap_uprobe_change_plus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf, unsigned long offset, unsigned long vm_flags) { int tfi = (stf - stap_uprobe_finders); int spec_index; /* iterate over stap_uprobe_spec[] that use this same stap_uprobe_tf */ for (spec_index=0; spec_index<sizeof(stap_uprobe_specs)/sizeof(stap_uprobe_specs[0]); spec_index++) { int handled_p = 0; int slotted_p = 0; const struct stap_uprobe_spec *sups = &stap_uprobe_specs [spec_index]; struct stap_uprobe *sup; pid_t sdt_sem_pid; int rc = 0; int i; 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 */ if (likely((vm_flags & VM_EXEC) && sups->address >= 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 unlock and do the register_*probe subsequently. */ mutex_lock (& stap_uprobes_lock); for (i=0; i<MAXUPROBES; i++) { /* XXX: slow linear search */ sup = & stap_uprobes[i]; /* register new uprobe We make two passes for semaphores; see _stap_uprobe_change_semaphore_plus */ if (sup->spec_index < 0 || (sups->sdt_sem_offset && vm_flags & VM_WRITE && sup->spec_index == spec_index)) { #if (UPROBES_API_VERSION < 2) /* See PR6829 comment. */ if (sup->spec_index == -1 && sup->up.kdata != NULL) continue; else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue; #endif sup->spec_index = spec_index; slotted_p = 1; break; } } mutex_unlock (& stap_uprobes_lock); #ifdef DEBUG_UPROBES _stp_dbug(__FUNCTION__,__LINE__, "+uprobe spec %d idx %d process %s[%d] addr %p pp %s\n", spec_index, (slotted_p ? i : -1), tsk->comm, tsk->tgid, (void*)(relocation+sups->address), sups->probe.pp); #endif /* Here, slotted_p implies that `i' points to the single stap_uprobes[] element that has been slotted in for registration or unregistration processing. !slotted_p implies that the table was full (registration; MAXUPROBES) or that no matching entry was found (unregistration; should not happen). */ sdt_sem_pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid); if (sups->sdt_sem_offset && (sdt_sem_pid != tsk->tgid || sup->sdt_sem_address == 0)) { /* If the probe is in the executable itself, the offset *is* the address. */ if (vm_flags & VM_EXECUTABLE) { sup->sdt_sem_address = relocation + sups->sdt_sem_offset; } else { sup->sdt_sem_address = (relocation - offset) + sups->sdt_sem_offset; } } /* sdt_sem_offset */ if (slotted_p) { struct stap_uprobe *sup = & stap_uprobes[i]; if (sups->return_p) { sup->urp.u.pid = tsk->tgid; sup->urp.u.vaddr = relocation + sups->address; sup->urp.handler = &enter_uretprobe_probe; rc = register_uretprobe (& sup->urp); } else { sup->up.pid = tsk->tgid; sup->up.vaddr = relocation + sups->address; sup->up.handler = &enter_uprobe_probe; rc = register_uprobe (& sup->up); } if (rc) { /* failed to register */ _stp_warn ("u*probe failed %s[%d] '%s' addr %p rc %d\n", tsk->comm, tsk->tgid, sups->probe.pp, (void*)(relocation + sups->address), rc); /* NB: we need to release this slot, so we need to borrow the mutex temporarily. */ mutex_lock (& stap_uprobes_lock); sup->spec_index = -1; mutex_unlock (& stap_uprobes_lock); } else { handled_p = 1; } } /* NB: handled_p implies slotted_p */ if (unlikely (! handled_p)) { #ifdef STP_TIMING atomic_inc (& skipped_count_uprobe_reg); #endif /* NB: duplicates common_entryfn_epilogue, but then this is not a probe entry fn epilogue. */ if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) { if (unlikely (pseudo_atomic_cmpxchg(& session_state, STAP_SESSION_RUNNING, STAP_SESSION_ERROR) == STAP_SESSION_RUNNING)) _stp_error ("Skipped too many probes, check MAXSKIPPED or try again with stap -t for more details."); } } } /* close iteration over stap_uprobe_spec[] */ return 0; /* XXX: or rc? */ }
/* when someone does /sbin/rmmod on a loaded systemtap module. */ static void _stp_cleanup_and_exit(int send_exit) { int handle_exit; int start_finished; mutex_lock(&_stp_transport_mutex); handle_exit = (_stp_start_called && ! _stp_exit_called); _stp_exit_called = 1; mutex_unlock(&_stp_transport_mutex); /* Note, we can be sure that the startup sequence has finished if handle_exit is true because it depends on _stp_start_called being set to true. _stp_start_called can only be set to true in _stp_handle_start() in response to a _STP_START message on the control channel. Only one writer can have the control channel open at a time, so the whole startup sequence in _stp_handle_start() has to be completed before another message can be send. _stp_cleanup_and_exit() can only be called through either a _STP_EXIT message, which cannot arrive while _STP_START is still being handled, or when the module is unloaded. The module can only be unloaded when there are no more users that keep the control channel open. */ if (handle_exit) { int failures; /* Unregister the module notifier. */ if (_stp_module_notifier_active) { _stp_module_notifier_active = 0; (void) unregister_module_notifier(& _stp_module_notifier_nb); /* -ENOENT is possible, if we were not already registered */ } dbug_trans(1, "cleanup_and_exit (%d)\n", send_exit); _stp_exit_flag = 1; if (_stp_probes_started) { dbug_trans(1, "calling systemtap_module_exit\n"); /* tell the stap-generated code to unload its probes, etc */ systemtap_module_exit(); dbug_trans(1, "done with systemtap_module_exit\n"); } failures = atomic_read(&_stp_transport_failures); if (failures) _stp_warn("There were %d transport failures.\n", failures); dbug_trans(1, "*** calling _stp_transport_data_fs_stop ***\n"); _stp_transport_data_fs_stop(); dbug_trans(1, "ctl_send STP_EXIT\n"); if (send_exit) { /* send_exit is only set to one if called from _stp_ctl_write_cmd() in response to a write to the proc cmd file, so in user context. It is safe to immediately notify the reader. */ _stp_ctl_send_notify(STP_EXIT, NULL, 0); } dbug_trans(1, "done with ctl_send STP_EXIT\n"); /* Unregister the panic notifier. */ #if STP_TRANSPORT_VERSION == 2 atomic_notifier_chain_unregister(&panic_notifier_list, &_stp_module_panic_notifier_nb); #endif } }
/* mmap callback, will match new vma with _stp_module or register vma name. */ static int _stp_vma_mmap_cb(struct stap_task_finder_target *tgt, struct task_struct *tsk, char *path, struct dentry *dentry, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags) { int i, res; struct _stp_module *module = NULL; const char *name = (dentry != NULL) ? dentry->d_name.name : NULL; #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "mmap_cb: tsk %d:%d path %s, addr 0x%08lx, length 0x%08lx, offset 0x%lx, flags 0x%lx\n", tsk->pid, tsk->tgid, path, addr, length, offset, vm_flags); #endif // We are only interested in the first load of the whole module that // is executable. We register whether or not we know the module, // so we can later lookup the name given an address for this task. if (path != NULL && offset == 0 && (vm_flags & VM_EXEC)) { for (i = 0; i < _stp_num_modules; i++) { if (strcmp(path, _stp_modules[i]->path) == 0) { #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "vm_cb: matched path %s to module (sec: %s)\n", path, _stp_modules[i]->sections[0].name); #endif module = _stp_modules[i]; /* XXX We really only need to register .dynamic sections, but .absolute exes are also necessary atm. */ res = stap_add_vma_map_info(tsk->group_leader, addr, addr + length, name, module); /* Warn, but don't error out. */ if (res != 0) _stp_warn ("Couldn't register module '%s' for pid %d\n", _stp_modules[i]->path, tsk->group_leader->pid); return 0; } } /* None of the tracked modules matched, register without, * to make sure we can lookup the name later. Ignore errors, * we will just report unknown when asked and tables were * full. Restrict to target process when given to preserve * vma_map entry slots. */ if (_stp_target == 0 || _stp_target == tsk->group_leader->pid) { res = stap_add_vma_map_info(tsk->group_leader, addr, addr + length, name, NULL); #ifdef DEBUG_TASK_FINDER_VMA _stp_dbug(__FUNCTION__, __LINE__, "registered '%s' for %d (res:%d)\n", name, tsk->group_leader->pid, res); #endif } } return 0; }