aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2014-03-30 12:56:22 -0400
committerOleg Nesterov <oleg@redhat.com>2014-04-17 15:58:16 -0400
commit8a6b173287bb94b3ef8360119020e856afb1c934 (patch)
tree98acc1790807a4505abf9f9cc20950ca8e5cb1ce
parentb3d5fc3c297fd379956689dc4d7d6af077ac35c2 (diff)
uprobes: Kill UPROBE_SKIP_SSTEP and can_skip_sstep()
UPROBE_COPY_INSN, UPROBE_SKIP_SSTEP, and uprobe->flags must die. This patch kills UPROBE_SKIP_SSTEP. I never understood why it was added; not only it doesn't help, it harms. It can only help to avoid arch_uprobe_skip_sstep() if it was already called before and failed. But this is ugly, if we want to know whether we can emulate this instruction or not we should do this analysis in arch_uprobe_analyze_insn(), not when we hit this probe for the first time. And in fact this logic is simply wrong. arch_uprobe_skip_sstep() can fail or not depending on the task/register state, if this insn can be emulated but, say, put_user() fails we need to xol it this time, but this doesn't mean we shouldn't try to emulate it when this or another thread hits this bp next time. And this is the actual reason for this change. We need to emulate the "call" insn, but push(return-address) can obviously fail. Per-arch notes: x86: __skip_sstep() can only emulate "rep;nop". With this change it will be called every time and most probably for no reason. This will be fixed by the next changes. We need to change this suboptimal code anyway. arm: Should not be affected. It has its own "bool simulate" flag checked in arch_uprobe_skip_sstep(). ppc: Looks like, it can emulate almost everything. Does it actually need to record the fact that emulate_step() failed? Hopefully not. But if yes, it can add the ppc- specific flag into arch_uprobe. TODO: rename arch_uprobe_skip_sstep() to arch_uprobe_emulate_insn(), Signed-off-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Reviewed-by: David A. Long <dave.long@linaro.org> Reviewed-by: Jim Keniston <jkenisto@us.ibm.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
-rw-r--r--kernel/events/uprobes.c23
1 files changed, 2 insertions, 21 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 04709b66369d..ea2a7c0728bb 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -60,8 +60,6 @@ static struct percpu_rw_semaphore dup_mmap_sem;
60 60
61/* Have a copy of original instruction */ 61/* Have a copy of original instruction */
62#define UPROBE_COPY_INSN 0 62#define UPROBE_COPY_INSN 0
63/* Can skip singlestep */
64#define UPROBE_SKIP_SSTEP 1
65 63
66struct uprobe { 64struct uprobe {
67 struct rb_node rb_node; /* node in the rb tree */ 65 struct rb_node rb_node; /* node in the rb tree */
@@ -491,12 +489,9 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
491 uprobe->offset = offset; 489 uprobe->offset = offset;
492 init_rwsem(&uprobe->register_rwsem); 490 init_rwsem(&uprobe->register_rwsem);
493 init_rwsem(&uprobe->consumer_rwsem); 491 init_rwsem(&uprobe->consumer_rwsem);
494 /* For now assume that the instruction need not be single-stepped */
495 __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
496 492
497 /* add to uprobes_tree, sorted on inode:offset */ 493 /* add to uprobes_tree, sorted on inode:offset */
498 cur_uprobe = insert_uprobe(uprobe); 494 cur_uprobe = insert_uprobe(uprobe);
499
500 /* a uprobe exists for this inode:offset combination */ 495 /* a uprobe exists for this inode:offset combination */
501 if (cur_uprobe) { 496 if (cur_uprobe) {
502 kfree(uprobe); 497 kfree(uprobe);
@@ -1628,20 +1623,6 @@ bool uprobe_deny_signal(void)
1628 return true; 1623 return true;
1629} 1624}
1630 1625
1631/*
1632 * Avoid singlestepping the original instruction if the original instruction
1633 * is a NOP or can be emulated.
1634 */
1635static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
1636{
1637 if (test_bit(UPROBE_SKIP_SSTEP, &uprobe->flags)) {
1638 if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
1639 return true;
1640 clear_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
1641 }
1642 return false;
1643}
1644
1645static void mmf_recalc_uprobes(struct mm_struct *mm) 1626static void mmf_recalc_uprobes(struct mm_struct *mm)
1646{ 1627{
1647 struct vm_area_struct *vma; 1628 struct vm_area_struct *vma;
@@ -1868,13 +1849,13 @@ static void handle_swbp(struct pt_regs *regs)
1868 1849
1869 handler_chain(uprobe, regs); 1850 handler_chain(uprobe, regs);
1870 1851
1871 if (can_skip_sstep(uprobe, regs)) 1852 if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
1872 goto out; 1853 goto out;
1873 1854
1874 if (!pre_ssout(uprobe, regs, bp_vaddr)) 1855 if (!pre_ssout(uprobe, regs, bp_vaddr))
1875 return; 1856 return;
1876 1857
1877 /* can_skip_sstep() succeeded, or restart if can't singlestep */ 1858 /* arch_uprobe_skip_sstep() succeeded, or restart if can't singlestep */
1878out: 1859out:
1879 put_uprobe(uprobe); 1860 put_uprobe(uprobe);
1880} 1861}