runtime/linux/uprobes-common.c - systemtap
Functions defined
Macros defined
Source code
#ifndef _UPROBE_COMMON_C_
#define _UPROBE_COMMON_C_
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;
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;
if (likely((vm_flags & VM_EXEC) && sups->address >= length)) continue;
mutex_lock (& stap_uprobes_lock);
for (i=0; i<MAXUPROBES; i++) { XXX sup = & stap_uprobes[i];
if (sup->spec_index < 0 || (sups->sdt_sem_offset && vm_flags & VM_WRITE && sup->spec_index == spec_index)) {
#if (UPROBES_API_VERSION < 2)
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
if (stf->pathname)
if ((rc = _stp_usermodule_check(tsk, stf->pathname, relocation)))
return rc;
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)) {
sup->sdt_sem_address = (relocation - offset) + sups->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);
}
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);
mutex_lock (& stap_uprobes_lock);
sup->spec_index = -1;
sup->sdt_sem_address = 0;
mutex_unlock (& stap_uprobes_lock);
} else {
handled_p = 1;
}
}
if (unlikely (! handled_p)) {
#ifdef STP_TIMING
atomic_inc (skipped_count_uprobe_reg());
#endif
#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
}
} return 0; XXX}
static int stap_uprobe_change_semaphore_plus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf) {
int tfi = (stf - stap_uprobe_finders);
int spec_index;
int rc = 0;
struct stap_uprobe *sup;
int i;
for (i=0; i<MAXUPROBES; i++) { XXX sup = & stap_uprobes[i];
if (sup->spec_index == -1) continue;
if (sup->sdt_sem_address != 0 && !(sup->up.pid == tsk->tgid && sup->sdt_sem_address >= relocation && sup->sdt_sem_address < relocation+length)) continue;
if (sup->sdt_sem_address) {
unsigned short sdt_semaphore = 0; if ((rc = get_user (sdt_semaphore, (unsigned short __user*) sup->sdt_sem_address)) == 0) {
sdt_semaphore ++;
#ifdef DEBUG_UPROBES
{
const struct stap_uprobe_spec *sups = &stap_uprobe_specs [sup->spec_index];
_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);
}
#endif
rc = put_user (sdt_semaphore, (unsigned short __user*) sup->sdt_sem_address);
XXX }
}
}
return rc;
}
static int stap_uprobe_change_minus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf) {
int i;
for (i=0; i<MAXUPROBES; i++) { XXX struct stap_uprobe *sup = & stap_uprobes[i];
struct stap_uprobe_spec *sups;
if (sup->spec_index < 0) continue; sups = (struct stap_uprobe_spec*) & stap_uprobe_specs[sup->spec_index];
mutex_lock (& stap_uprobes_lock);
if (sups->return_p && sup->urp.u.pid == tsk->tgid && sup->urp.u.vaddr >= relocation && sup->urp.u.vaddr < relocation+length) {
#ifdef DEBUG_UPROBES
_stp_dbug (__FUNCTION__,__LINE__, "-uretprobe spec %d idx %d process %s[%d] addr %p pp %s\n", sup->spec_index, i, tsk->comm, tsk->tgid, (void*) sup->urp.u.vaddr, sups->probe->pp);
#endif
#if (UPROBES_API_VERSION >= 2)
unmap_uretprobe (& sup->urp);
sup->spec_index = -1;
sup->sdt_sem_address = 0;
#else
sup->spec_index = -2;
#endif
} else if (!sups->return_p && sup->up.pid == tsk->tgid && sup->up.vaddr >= relocation && sup->up.vaddr < relocation+length) {
#ifdef DEBUG_UPROBES
_stp_dbug (__FUNCTION__,__LINE__, "-uprobe spec %d idx %d process %s[%d] reloc %p pp %s\n", sup->spec_index, i, tsk->comm, tsk->tgid, (void*) sup->up.vaddr, sups->probe->pp);
#endif
#if (UPROBES_API_VERSION >= 2)
unmap_uprobe (& sup->up);
sup->spec_index = -1;
sup->sdt_sem_address = 0;
#else
sup->spec_index = -1;
sup->sdt_sem_address = 0;
#endif
}
mutex_unlock (& stap_uprobes_lock);
} return 0; XXX}
static int stap_uprobe_process_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {
const struct stap_uprobe_tf *stf = container_of(tgt, struct stap_uprobe_tf, finder);
if (! process_p) return 0; dbug_task_vma(1, "%cproc pid %d stf %p %p path %s\n", register_p?'+':'-', tsk->tgid, tgt, stf, stf->pathname);
if (register_p) {
int rc = stap_uprobe_change_plus (tsk, 0, TASK_SIZE, stf, 0, 0);
stap_uprobe_change_semaphore_plus (tsk, 0, TASK_SIZE, stf);
return rc;
} else
return stap_uprobe_change_minus (tsk, 0, TASK_SIZE, stf);
}
static int
stap_uprobe_mmap_found (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 rc = 0;
const struct stap_uprobe_tf *stf = container_of(tgt, struct stap_uprobe_tf, finder);
if (path == NULL || strcmp (path, stf->pathname))
return 0;
if ((vm_flags & VM_EXEC) && !(vm_flags & VM_WRITE)) {
dbug_task_vma (1,
"+mmap 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);
rc = stap_uprobe_change_plus (tsk, addr, length, stf, offset, vm_flags);
}
if ((rc == 0) && (vm_flags & VM_WRITE)) {
dbug_task_vma (1,
"+mmap W 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);
rc = stap_uprobe_change_semaphore_plus (tsk, addr, length, stf);
}
return rc;
}
static int stap_uprobe_munmap_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, unsigned long addr, unsigned long length) {
const struct stap_uprobe_tf *stf = container_of(tgt, struct stap_uprobe_tf, finder);
dbug_task_vma (1, "-mmap pid %d addr %p length %lu stf %p %p path %s\n", tsk->tgid, (void *) addr, length, tgt, stf, stf->pathname);
return stap_uprobe_change_minus (tsk, addr, length, stf);
}
static int stap_uprobe_process_munmap (struct stap_task_finder_target *tgt, struct task_struct *tsk, int register_p, int process_p) {
const struct stap_uprobe_tf *stf = container_of(tgt, struct stap_uprobe_tf, finder);
if (! process_p) return 0; dbug_task_vma (1, "%cproc pid %d stf %p %p path %s\n", register_p?'+':'-', tsk->tgid, tgt, stf, stf->pathname);
if (!register_p)
return stap_uprobe_change_minus (tsk, 0, TASK_SIZE, stf);
return 0;
}
#endif