diff mbox

[3/9] uprobes: allow ignoring of probe hits

Message ID 1350242593-17761-3-git-send-email-rabin@rab.in (mailing list archive)
State New, archived
Headers show

Commit Message

Rabin Vincent Oct. 14, 2012, 7:23 p.m. UTC
Allow arches to decided to ignore a probe hit.  ARM will use this to
only call handlers if the conditions to execute a conditionally executed
instruction are satisfied.

Signed-off-by: Rabin Vincent <rabin@rab.in>
---
 include/linux/uprobes.h |    1 +
 kernel/events/uprobes.c |   14 +++++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

Comments

Oleg Nesterov Oct. 15, 2012, 4:52 p.m. UTC | #1
On 10/14, Rabin Vincent wrote:
>
> Allow arches to decided to ignore a probe hit.  ARM will use this to
> only call handlers if the conditions to execute a conditionally executed
> instruction are satisfied.

Not sure I understand why we shouldn't call handlers in this case,
but OK, I know nothing about arm.

>  static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
>  {
>  	struct mm_struct *mm = current->mm;
> @@ -1469,6 +1474,7 @@ static void handle_swbp(struct pt_regs *regs)
>  	struct uprobe *uprobe;
>  	unsigned long bp_vaddr;
>  	int uninitialized_var(is_swbp);
> +	bool ignored = false;
>  
>  	bp_vaddr = uprobe_get_swbp_addr(regs);
>  	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
> @@ -1499,6 +1505,12 @@ static void handle_swbp(struct pt_regs *regs)
>  			goto cleanup_ret;
>  	}
>  	utask->active_uprobe = uprobe;
> +
> +	if (arch_uprobe_ignore(&uprobe->arch, regs)) {
> +		ignored = true;
> +		goto cleanup_ret;
> +	}
> +
>  	handler_chain(uprobe, regs);
>  	if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs))
>  		goto cleanup_ret;
> @@ -1514,7 +1526,7 @@ cleanup_ret:
>  		utask->active_uprobe = NULL;
>  		utask->state = UTASK_RUNNING;
>  	}
> -	if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
> +	if (!ignored && !(uprobe->flags & UPROBE_SKIP_SSTEP))
>  
>  		/*
>  		 * cannot singlestep; cannot skip instruction;

This conflicts with other changes in

	git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc uprobes/core

Could you re-diff?

I'll try to read 1-7 tomorrow.

Oleg.
Rabin Vincent Oct. 16, 2012, 8:11 p.m. UTC | #2
2012/10/15 Oleg Nesterov <oleg@redhat.com>:
> On 10/14, Rabin Vincent wrote:
>> Allow arches to decided to ignore a probe hit.  ARM will use this to
>> only call handlers if the conditions to execute a conditionally executed
>> instruction are satisfied.
>
> Not sure I understand why we shouldn't call handlers in this case,
> but OK, I know nothing about arm.

This old discussion about kprobes should be useful:

http://lists.infradead.org/pipermail/linux-arm-kernel/2011-March/045755.html
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-March/046544.html

> This conflicts with other changes in
>
>         git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc uprobes/core
>
> Could you re-diff?

OK, I will rebase them.
Srikar Dronamraju Oct. 17, 2012, 4:52 p.m. UTC | #3
>  static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
>  {
>  	struct mm_struct *mm = current->mm;
> @@ -1469,6 +1474,7 @@ static void handle_swbp(struct pt_regs *regs)
>  	struct uprobe *uprobe;
>  	unsigned long bp_vaddr;
>  	int uninitialized_var(is_swbp);
> +	bool ignored = false;
> 
>  	bp_vaddr = uprobe_get_swbp_addr(regs);
>  	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
> @@ -1499,6 +1505,12 @@ static void handle_swbp(struct pt_regs *regs)
>  			goto cleanup_ret;
>  	}
>  	utask->active_uprobe = uprobe;
> +
> +	if (arch_uprobe_ignore(&uprobe->arch, regs)) {
> +		ignored = true;
> +		goto cleanup_ret;
> +	}
> +

With Oleg's changes, this should become simple. Something like:

	if (arch_uprobe_ignore(&uprobe->arch, regs))
		goto out;

>  	handler_chain(uprobe, regs);
>  	if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs))
>  		goto cleanup_ret;
> @@ -1514,7 +1526,7 @@ cleanup_ret:
>  		utask->active_uprobe = NULL;
>  		utask->state = UTASK_RUNNING;
>  	}
> -	if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
> +	if (!ignored && !(uprobe->flags & UPROBE_SKIP_SSTEP))
> 
>  		/*
>  		 * cannot singlestep; cannot skip instruction;
> -- 
> 1.7.9.5
>
Oleg Nesterov Oct. 17, 2012, 5:35 p.m. UTC | #4
On 10/16, Rabin Vincent wrote:
>
> 2012/10/15 Oleg Nesterov <oleg@redhat.com>:
> >
> > Not sure I understand why we shouldn't call handlers in this case,
> > but OK, I know nothing about arm.
>
> This old discussion about kprobes should be useful:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2011-March/045755.html

Thanks... Not sure I understand this discussion...

And, to clarify, I am not arguing. Just curious.

So, is this like cmov on x86? And this patch allows to not report if
the condition is not true? Or there are other issues on arm?

Oleg.
Rabin Vincent Oct. 21, 2012, 6:15 p.m. UTC | #5
On Wed, Oct 17, 2012 at 07:35:10PM +0200, Oleg Nesterov wrote:
> On 10/16, Rabin Vincent wrote:
> > 2012/10/15 Oleg Nesterov <oleg@redhat.com>:
> > > Not sure I understand why we shouldn't call handlers in this case,
> > > but OK, I know nothing about arm.
> >
> > This old discussion about kprobes should be useful:
> >
> > http://lists.infradead.org/pipermail/linux-arm-kernel/2011-March/045755.html
> 
> Thanks... Not sure I understand this discussion...
> 
> And, to clarify, I am not arguing. Just curious.
> 
> So, is this like cmov on x86? And this patch allows to not report if
> the condition is not true? Or there are other issues on arm?

Yes, I guess this is like CMOV on x86.  In the ARM instruction set most
instructions can be conditionally executed.

In order to set the probe on a conditional instruction, we use an
undefined instruction with the same condition as the instruction we
replace.  However, it is implementation defined whether an undefined
instruction with a failing condition code will trigger an undefined
instruction exception or just be executed as a NOP.  So for those
processor implementations where we do get the undefined instruction
exception even for a failing condition code, we have to ignore it in
order to provide consistent behaviour.
Oleg Nesterov Oct. 21, 2012, 7:40 p.m. UTC | #6
On 10/21, Rabin Vincent wrote:
>
> On Wed, Oct 17, 2012 at 07:35:10PM +0200, Oleg Nesterov wrote:
> >
> > And, to clarify, I am not arguing. Just curious.
> >
> > So, is this like cmov on x86? And this patch allows to not report if
> > the condition is not true? Or there are other issues on arm?
>
> Yes, I guess this is like CMOV on x86.  In the ARM instruction set most
> instructions can be conditionally executed.
>
> In order to set the probe on a conditional instruction, we use an
> undefined instruction with the same condition as the instruction we
> replace.  However, it is implementation defined whether an undefined
> instruction with a failing condition code will trigger an undefined
> instruction exception or just be executed as a NOP.  So for those
> processor implementations where we do get the undefined instruction
> exception even for a failing condition code, we have to ignore it in
> order to provide consistent behaviour.

OK, I see, thanks for your explanation.

Oleg.
diff mbox

Patch

diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index ac90704..da21b66 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -128,6 +128,7 @@  extern int  arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
 extern int  arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
 extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs);
 #else /* !CONFIG_UPROBES */
 struct uprobes_state {
 };
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index db4e3ab..a0e1a38 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1419,6 +1419,11 @@  static void mmf_recalc_uprobes(struct mm_struct *mm)
 	clear_bit(MMF_HAS_UPROBES, &mm->flags);
 }
 
+bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs)
+{
+	return false;
+}
+
 static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
 {
 	struct mm_struct *mm = current->mm;
@@ -1469,6 +1474,7 @@  static void handle_swbp(struct pt_regs *regs)
 	struct uprobe *uprobe;
 	unsigned long bp_vaddr;
 	int uninitialized_var(is_swbp);
+	bool ignored = false;
 
 	bp_vaddr = uprobe_get_swbp_addr(regs);
 	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
@@ -1499,6 +1505,12 @@  static void handle_swbp(struct pt_regs *regs)
 			goto cleanup_ret;
 	}
 	utask->active_uprobe = uprobe;
+
+	if (arch_uprobe_ignore(&uprobe->arch, regs)) {
+		ignored = true;
+		goto cleanup_ret;
+	}
+
 	handler_chain(uprobe, regs);
 	if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs))
 		goto cleanup_ret;
@@ -1514,7 +1526,7 @@  cleanup_ret:
 		utask->active_uprobe = NULL;
 		utask->state = UTASK_RUNNING;
 	}
-	if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
+	if (!ignored && !(uprobe->flags & UPROBE_SKIP_SSTEP))
 
 		/*
 		 * cannot singlestep; cannot skip instruction;