aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorAnton Arapov <anton@redhat.com>2013-04-03 12:00:36 -0400
committerOleg Nesterov <oleg@redhat.com>2013-04-13 09:31:57 -0400
commitfec8898d86ad0fb4d2161fc89885fa52da1e8b72 (patch)
tree93232f5c2b1eb2d4e4d0d8ef11dd502b18d530a5 /kernel/events
parent0dfd0eb8e4d72ded8b21f4fee74ba5547408cbe9 (diff)
uretprobes: Return probe exit, invoke handlers
Uretprobe handlers are invoked when the trampoline is hit, on completion the trampoline is replaced with the saved return address and the uretprobe instance deleted. TODO: handle_trampoline() assumes that ->return_instances is always valid. We should teach it to handle longjmp() which can invalidate the pending return_instance's. This is nontrivial, we will try to do this in a separate series. Signed-off-by: Anton Arapov <anton@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/uprobes.c65
1 files changed, 64 insertions, 1 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 3798947b3b58..65429ad2ce51 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1633,6 +1633,62 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
1633 up_read(&uprobe->register_rwsem); 1633 up_read(&uprobe->register_rwsem);
1634} 1634}
1635 1635
1636static void
1637handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
1638{
1639 struct uprobe *uprobe = ri->uprobe;
1640 struct uprobe_consumer *uc;
1641
1642 down_read(&uprobe->register_rwsem);
1643 for (uc = uprobe->consumers; uc; uc = uc->next) {
1644 if (uc->ret_handler)
1645 uc->ret_handler(uc, ri->func, regs);
1646 }
1647 up_read(&uprobe->register_rwsem);
1648}
1649
1650static bool handle_trampoline(struct pt_regs *regs)
1651{
1652 struct uprobe_task *utask;
1653 struct return_instance *ri, *tmp;
1654 bool chained;
1655
1656 utask = current->utask;
1657 if (!utask)
1658 return false;
1659
1660 ri = utask->return_instances;
1661 if (!ri)
1662 return false;
1663
1664 /*
1665 * TODO: we should throw out return_instance's invalidated by
1666 * longjmp(), currently we assume that the probed function always
1667 * returns.
1668 */
1669 instruction_pointer_set(regs, ri->orig_ret_vaddr);
1670
1671 for (;;) {
1672 handle_uretprobe_chain(ri, regs);
1673
1674 chained = ri->chained;
1675 put_uprobe(ri->uprobe);
1676
1677 tmp = ri;
1678 ri = ri->next;
1679 kfree(tmp);
1680
1681 if (!chained)
1682 break;
1683
1684 BUG_ON(!ri);
1685 }
1686
1687 utask->return_instances = ri;
1688
1689 return true;
1690}
1691
1636/* 1692/*
1637 * Run handler and ask thread to singlestep. 1693 * Run handler and ask thread to singlestep.
1638 * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. 1694 * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1644,8 +1700,15 @@ static void handle_swbp(struct pt_regs *regs)
1644 int uninitialized_var(is_swbp); 1700 int uninitialized_var(is_swbp);
1645 1701
1646 bp_vaddr = uprobe_get_swbp_addr(regs); 1702 bp_vaddr = uprobe_get_swbp_addr(regs);
1647 uprobe = find_active_uprobe(bp_vaddr, &is_swbp); 1703 if (bp_vaddr == get_trampoline_vaddr()) {
1704 if (handle_trampoline(regs))
1705 return;
1648 1706
1707 pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n",
1708 current->pid, current->tgid);
1709 }
1710
1711 uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
1649 if (!uprobe) { 1712 if (!uprobe) {
1650 if (is_swbp > 0) { 1713 if (is_swbp > 0) {
1651 /* No matching uprobe; signal SIGTRAP. */ 1714 /* No matching uprobe; signal SIGTRAP. */