diff options
author | Jim Keniston <jkenisto@us.ibm.com> | 2009-04-15 16:11:17 -0700 |
---|---|---|
committer | Jim Keniston <jkenisto@us.ibm.com> | 2009-04-15 16:11:17 -0700 |
commit | 9d4518784bedd11e8563c999658f307c5c01b3a3 (patch) | |
tree | 46cb6f8cd7ec3c9ae836cc8277249469e9ae80dc | |
parent | 900686f5e209099d493a15f4e36a5030dc0aa8be (diff) | |
download | systemtap-steved-9d4518784bedd11e8563c999658f307c5c01b3a3.tar.gz systemtap-steved-9d4518784bedd11e8563c999658f307c5c01b3a3.tar.xz systemtap-steved-9d4518784bedd11e8563c999658f307c5c01b3a3.zip |
PR9940: add/use unmap_u[ret]probe
For uprobes 1 and 2, add unmap_u[ret]probe() and define UPROBES_API_VERSION=2.
Adapt tapsets.cxx accordingly.
-rw-r--r-- | runtime/uprobes/uprobes.c | 34 | ||||
-rw-r--r-- | runtime/uprobes/uprobes.h | 6 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.c | 43 | ||||
-rw-r--r-- | runtime/uprobes2/uprobes.h | 6 | ||||
-rw-r--r-- | tapsets.cxx | 41 |
5 files changed, 107 insertions, 23 deletions
diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c index 9dfb82b9..27e923b8 100644 --- a/runtime/uprobes/uprobes.c +++ b/runtime/uprobes/uprobes.c @@ -1049,8 +1049,7 @@ fail_tsk: } EXPORT_SYMBOL_GPL(register_uprobe); -/* See Documentation/uprobes.txt. */ -void unregister_uprobe(struct uprobe *u) +void __unregister_uprobe(struct uprobe *u, bool remove_bkpt) { struct task_struct *p; struct uprobe_process *uproc; @@ -1104,10 +1103,13 @@ void unregister_uprobe(struct uprobe *u) if (!list_empty(&ppt->uprobe_list)) goto done; - /* - * The last uprobe at ppt's probepoint is being unregistered. - * Queue the breakpoint for removal. - */ + /* The last uprobe at ppt's probepoint is being unregistered. */ + if (!remove_bkpt) { + uprobe_free_probept(ppt); + goto done; + } + + /* Queue the breakpoint for removal. */ ppt->state = UPROBE_REMOVING; list_add_tail(&ppt->pd_node, &uproc->pending_uprobes); @@ -1132,8 +1134,20 @@ done: up_write(&uproc->rwsem); uprobe_put_process(uproc); } + +/* See Documentation/uprobes.txt. */ +void unregister_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, true); +} EXPORT_SYMBOL_GPL(unregister_uprobe); +void unmap_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, false); +} +EXPORT_SYMBOL_GPL(unmap_uprobe); + /* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */ static struct task_struct *find_surviving_thread(struct uprobe_process *uproc) { @@ -2540,6 +2554,14 @@ void unregister_uretprobe(struct uretprobe *rp) } EXPORT_SYMBOL_GPL(unregister_uretprobe); +void unmap_uretprobe(struct uretprobe *rp) +{ + if (!rp) + return; + unmap_uprobe(&rp->u); +} +EXPORT_SYMBOL_GPL(unmap_uretprobe); + /* * uproc->ssol_area has been successfully set up. Establish the * uretprobe trampoline in slot 0. diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h index 0266cb7d..d542420d 100644 --- a/runtime/uprobes/uprobes.h +++ b/runtime/uprobes/uprobes.h @@ -35,6 +35,9 @@ #include <linux/types.h> #include <linux/list.h> +/* Version 2 includes unmap_u[ret]probe(). */ +#define UPROBES_API_VERSION 2 + struct pt_regs; enum uprobe_type { @@ -89,6 +92,9 @@ extern void unregister_uprobe(struct uprobe *u); /* For runtime, assume uprobes support includes uretprobes. */ extern int register_uretprobe(struct uretprobe *rp); extern void unregister_uretprobe(struct uretprobe *rp); +/* For PRs 9940, 6852... */ +extern void unmap_uprobe(struct uprobe *u); +extern void unmap_uretprobe(struct uretprobe *rp); #ifdef UPROBES_IMPLEMENTATION diff --git a/runtime/uprobes2/uprobes.c b/runtime/uprobes2/uprobes.c index a0e9f2fe..9ea05349 100644 --- a/runtime/uprobes2/uprobes.c +++ b/runtime/uprobes2/uprobes.c @@ -955,10 +955,15 @@ static int defer_registration(struct uprobe *u, int regflag, */ static struct pid *uprobe_get_tg_leader(pid_t p) { - struct pid *pid; + struct pid *pid = NULL; rcu_read_lock(); - pid = find_vpid(p); + /* + * We need this check because unmap_u[ret]probe() can be called + * from a report_death callback, where current->proxy is NULL. + */ + if (current->nsproxy) + pid = find_vpid(p); if (pid) { struct task_struct *t = pid_task(pid, PIDTYPE_PID); if (t) @@ -1138,8 +1143,7 @@ fail_tsk: } EXPORT_SYMBOL_GPL(register_uprobe); -/* See Documentation/uprobes.txt. */ -void unregister_uprobe(struct uprobe *u) +void __unregister_uprobe(struct uprobe *u, bool remove_bkpt) { struct pid *p; struct uprobe_process *uproc; @@ -1193,10 +1197,13 @@ void unregister_uprobe(struct uprobe *u) if (!list_empty(&ppt->uprobe_list)) goto done; - /* - * The last uprobe at ppt's probepoint is being unregistered. - * Queue the breakpoint for removal. - */ + /* The last uprobe at ppt's probepoint is being unregistered. */ + if (!remove_bkpt) { + uprobe_free_probept(ppt); + goto done; + } + + /* Queue the breakpoint for removal. */ ppt->state = UPROBE_REMOVING; list_add_tail(&ppt->pd_node, &uproc->pending_uprobes); @@ -1221,8 +1228,20 @@ done: up_write(&uproc->rwsem); uprobe_put_process(uproc, false); } + +/* See Documentation/uprobes.txt. */ +void unregister_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, true); +} EXPORT_SYMBOL_GPL(unregister_uprobe); +void unmap_uprobe(struct uprobe *u) +{ + __unregister_uprobe(u, false); +} +EXPORT_SYMBOL_GPL(unmap_uprobe); + /* Find a surviving thread in uproc. Runs with uproc->rwsem locked. */ static struct task_struct *find_surviving_thread(struct uprobe_process *uproc) { @@ -2718,6 +2737,14 @@ void unregister_uretprobe(struct uretprobe *rp) } EXPORT_SYMBOL_GPL(unregister_uretprobe); +void unmap_uretprobe(struct uretprobe *rp) +{ + if (!rp) + return; + unmap_uprobe(&rp->u); +} +EXPORT_SYMBOL_GPL(unmap_uretprobe); + /* * uproc->ssol_area has been successfully set up. Establish the * uretprobe trampoline in the next available slot following the diff --git a/runtime/uprobes2/uprobes.h b/runtime/uprobes2/uprobes.h index 112e29e2..ae0692f0 100644 --- a/runtime/uprobes2/uprobes.h +++ b/runtime/uprobes2/uprobes.h @@ -28,6 +28,9 @@ #define utrace_attached_engine utrace_engine #endif +/* Version 2 includes unmap_u[ret]probe(). */ +#define UPROBES_API_VERSION 2 + struct pt_regs; enum uprobe_type { @@ -82,6 +85,9 @@ extern void unregister_uprobe(struct uprobe *u); /* For runtime, assume uprobes support includes uretprobes. */ extern int register_uretprobe(struct uretprobe *rp); extern void unregister_uretprobe(struct uretprobe *rp); +/* For PRs 9940, 6852... */ +extern void unmap_uprobe(struct uprobe *u); +extern void unmap_uretprobe(struct uretprobe *rp); #ifdef UPROBES_IMPLEMENTATION diff --git a/tapsets.cxx b/tapsets.cxx index c63151e1..1f38023c 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -7590,6 +7590,9 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#else"; s.op->newline() << "#include \"uprobes/uprobes.h\""; s.op->newline() << "#endif"; + s.op->newline() << "#ifndef UPROBES_API_VERSION"; + s.op->newline() << "#define UPROBES_API_VERSION 1"; + s.op->newline() << "#endif"; s.op->newline() << "#ifndef MULTIPLE_UPROBES"; s.op->newline() << "#define MULTIPLE_UPROBES 256"; // maximum possible armed uprobes per process() probe point @@ -7701,10 +7704,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // register new uprobe s.op->newline() << "if (register_p && sup->spec_index < 0) {"; - // PR6829: we need to check that the sup we're about to reuse is really completely free. - // See PR6829 notes below. - s.op->newline(1) << "if (sup->spec_index == -1 && sup->up.kdata != NULL) continue;"; + 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;"; s.op->newline() << "else if (sup->spec_index == -2 && sup->urp.u.kdata != NULL) continue;"; + s.op->newline() << "#endif"; s.op->newline() << "sup->spec_index = spec_index;"; s.op->newline() << "slotted_p = 1;"; s.op->newline() << "break;"; @@ -7755,13 +7759,32 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline(-1) << "} else if (!register_p && slotted_p) {"; s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; - // NB: we need to release this slot, so we need to borrow the mutex temporarily. + s.op->newline() << "int unregistered_flag;"; + // PR6829, PR9940: + // Here we're unregistering for one of two reasons: + // 1. the process image is going away (or gone) due to exit or exec; or + // 2. the vma containing the probepoint has been unmapped. + // In case 1, it's sort of a nop, because uprobes will notice the event + // and dispose of the probes eventually, if it hasn't already. But by + // calling unmap_u[ret]probe() ourselves, we free up sup right away. + // + // In both cases, we must use unmap_u[ret]probe instead of + // unregister_u[ret]probe, so uprobes knows not to try to restore the + // original opcode. + s.op->newline() << "#if (UPROBES_API_VERSION >= 2)"; + s.op->newline() << "if (sups->return_p)"; + s.op->newline(1) << "unmap_uretprobe (& sup->urp);"; + s.op->newline(-1) << "else"; + s.op->newline(1) << "unmap_uprobe (& sup->up);"; + s.op->newline(-1) << "unregistered_flag = -1;"; + s.op->newline() << "#else"; + // Uprobes lacks unmap_u[ret]probe. Before reusing sup, we must wait + // until uprobes turns loose of the u[ret]probe on its own, as indicated + // by uprobe.kdata = NULL. + s.op->newline() << "unregistered_flag = (sups->return_p ? -2 : -1);"; + s.op->newline() << "#endif"; s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; - // NB: We must not actually uregister u[ret]probes when a target process execs or exits; - // uprobes does that by itself asynchronously. We can reuse the up/urp struct after - // uprobes clears the sup->{up,urp}->kdata pointer. PR6829. To tell the two - // cases apart, we use spec_index -2 vs -1. - s.op->newline() << "sup->spec_index = (sups->return_p ? -2 : -1);"; + s.op->newline() << "sup->spec_index = unregistered_flag;"; s.op->newline() << "mutex_unlock (& stap_uprobes_lock);"; s.op->newline() << "handled_p = 1;"; s.op->newline(-1) << "}"; // if slotted_p |