|
@@ -1633,6 +1633,62 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
|
|
|
up_read(&uprobe->register_rwsem);
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
|
|
|
+{
|
|
|
+ struct uprobe *uprobe = ri->uprobe;
|
|
|
+ struct uprobe_consumer *uc;
|
|
|
+
|
|
|
+ down_read(&uprobe->register_rwsem);
|
|
|
+ for (uc = uprobe->consumers; uc; uc = uc->next) {
|
|
|
+ if (uc->ret_handler)
|
|
|
+ uc->ret_handler(uc, ri->func, regs);
|
|
|
+ }
|
|
|
+ up_read(&uprobe->register_rwsem);
|
|
|
+}
|
|
|
+
|
|
|
+static bool handle_trampoline(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ struct uprobe_task *utask;
|
|
|
+ struct return_instance *ri, *tmp;
|
|
|
+ bool chained;
|
|
|
+
|
|
|
+ utask = current->utask;
|
|
|
+ if (!utask)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ ri = utask->return_instances;
|
|
|
+ if (!ri)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * TODO: we should throw out return_instance's invalidated by
|
|
|
+ * longjmp(), currently we assume that the probed function always
|
|
|
+ * returns.
|
|
|
+ */
|
|
|
+ instruction_pointer_set(regs, ri->orig_ret_vaddr);
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ handle_uretprobe_chain(ri, regs);
|
|
|
+
|
|
|
+ chained = ri->chained;
|
|
|
+ put_uprobe(ri->uprobe);
|
|
|
+
|
|
|
+ tmp = ri;
|
|
|
+ ri = ri->next;
|
|
|
+ kfree(tmp);
|
|
|
+
|
|
|
+ if (!chained)
|
|
|
+ break;
|
|
|
+
|
|
|
+ BUG_ON(!ri);
|
|
|
+ }
|
|
|
+
|
|
|
+ utask->return_instances = ri;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Run handler and ask thread to singlestep.
|
|
|
* Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
|
|
@@ -1644,8 +1700,15 @@ static void handle_swbp(struct pt_regs *regs)
|
|
|
int uninitialized_var(is_swbp);
|
|
|
|
|
|
bp_vaddr = uprobe_get_swbp_addr(regs);
|
|
|
- uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
|
|
|
+ if (bp_vaddr == get_trampoline_vaddr()) {
|
|
|
+ if (handle_trampoline(regs))
|
|
|
+ return;
|
|
|
|
|
|
+ pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n",
|
|
|
+ current->pid, current->tgid);
|
|
|
+ }
|
|
|
+
|
|
|
+ uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
|
|
|
if (!uprobe) {
|
|
|
if (is_swbp > 0) {
|
|
|
/* No matching uprobe; signal SIGTRAP. */
|