Patchwork powerpc/uprobes: teach uprobes to ignore gdb breakpoints

login
register
mail settings
Submitter Ananth N Mavinakayanahalli
Date March 20, 2013, 10:40 a.m.
Message ID <20130320104033.GA19844@in.ibm.com>
Download mbox | patch
Permalink /patch/229316/
State Superseded, archived
Headers show

Comments

Ananth N Mavinakayanahalli - March 20, 2013, 10:40 a.m.
From: Ananth N Mavinakayanahalli <ananth@in.ibm.com>

GDB uses a variant of the trap instruction that is different from the
one used by uprobes. Currently, running gdb on a program being traced
by uprobes causes an endless loop since uprobes doesn't understand
that the trap is inserted by some other entity and hence a SIGTRAP needs
to be delivered.

Teach uprobes to ignore breakpoints that doesn't belong to it.

Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: stable@vger.kernel.org
---
 arch/powerpc/kernel/uprobes.c |   10 ++++++++++
 1 file changed, 10 insertions(+)
Oleg Nesterov - March 20, 2013, 12:26 p.m.
Hi Ananth,

First of all, let me remind that I know nothing about powerpc ;)

But iirc we already discussed this a bit, I forgot the details but
still I have some concerns...

On 03/20, Ananth N Mavinakayanahalli wrote:
>
> GDB uses a variant of the trap instruction that is different from the
> one used by uprobes. Currently, running gdb on a program being traced
> by uprobes causes an endless loop since uprobes doesn't understand
> that the trap is inserted by some other entity and hence a SIGTRAP needs
> to be delivered.

Yes, and thus is_swbp_at_addr()->is_swbp_insn() called by handle_swbp()
should be updated,

> +bool is_swbp_insn(uprobe_opcode_t *insn)
> +{
> +	return (is_trap(*insn));
> +}

And this patch should fix the problem. (and probably this is fine
for prepare_uprobe()).


But, at the same time, is the new definition fine for verify_opcode()?

IOW, powerpc has another is_trap() insn(s) used by gdb, lets denote it X.
X != UPROBE_SWBP_INSN.

Suppose that gdb installs the trap X at some addr, and then uprobe_register()
tries to install uprobe at the same address. Then set_swbp() will do nothing,
assuming the uprobe was already installed.

But we did not install UPROBE_SWBP_INSN. Is it fine? I hope yes, just to
verify. If not, we need 2 definitions. is_uprobe_insn() should still check
insns == UPROBE_SWBP_INSN, and is_swbp_insn() should check is_trap().

And I am just curious, could you explain how X and UPROBE_SWBP_INSN
differ?

Oleg.
Ananth N Mavinakayanahalli - March 20, 2013, 3:41 p.m.
On Wed, Mar 20, 2013 at 01:26:39PM +0100, Oleg Nesterov wrote:
> Hi Ananth,
> 
> First of all, let me remind that I know nothing about powerpc ;)
> 
> But iirc we already discussed this a bit, I forgot the details but
> still I have some concerns...
> 
> On 03/20, Ananth N Mavinakayanahalli wrote:
> >
> > GDB uses a variant of the trap instruction that is different from the
> > one used by uprobes. Currently, running gdb on a program being traced
> > by uprobes causes an endless loop since uprobes doesn't understand
> > that the trap is inserted by some other entity and hence a SIGTRAP needs
> > to be delivered.
> 
> Yes, and thus is_swbp_at_addr()->is_swbp_insn() called by handle_swbp()
> should be updated,
>
> > +bool is_swbp_insn(uprobe_opcode_t *insn)
> > +{
> > +	return (is_trap(*insn));
> > +}
> 
> And this patch should fix the problem. (and probably this is fine
> for prepare_uprobe()).

Correct

> But, at the same time, is the new definition fine for verify_opcode()?
> 
> IOW, powerpc has another is_trap() insn(s) used by gdb, lets denote it X.
> X != UPROBE_SWBP_INSN.
> 
> Suppose that gdb installs the trap X at some addr, and then uprobe_register()
> tries to install uprobe at the same address. Then set_swbp() will do nothing,
> assuming the uprobe was already installed.
> 
> But we did not install UPROBE_SWBP_INSN. Is it fine? I hope yes, just to
> verify. If not, we need 2 definitions. is_uprobe_insn() should still check
> insns == UPROBE_SWBP_INSN, and is_swbp_insn() should check is_trap().

is_trap() checks for all trap variants on powerpc, including the one
uprobe uses. It returns true if the instruction is *any* trap variant.
So, install_breakpoint()->prepare_uprobe()->is_swbp_insn() will return
ENOTSUPP. In fact, arch_uprobe_analyze_insn() will also do the same.

This itself should take care of all the cases.

> And I am just curious, could you explain how X and UPROBE_SWBP_INSN
> differ?

Powerpc has numerous variants of the trap instruction based on
comparison of two registers or a regsiter and immediate value and a condition
(less than, greater than, [signed forms thereof], or equal to).

Uprobes uses 0x7fe0008 which is 'tw 31,0,0'  which essentially is an
unconditional trap.

Gdb uses many traps, one of which is 0x7d821008 which is twge r2,r2,
which is basically trap if r2 greater than or equal to r2.

Ananth

Patch

Index: linux-3.9-rc3/arch/powerpc/kernel/uprobes.c
===================================================================
--- linux-3.9-rc3.orig/arch/powerpc/kernel/uprobes.c
+++ linux-3.9-rc3/arch/powerpc/kernel/uprobes.c
@@ -80,6 +80,16 @@  unsigned long uprobe_get_swbp_addr(struc
 	return instruction_pointer(regs);
 }
 
+/**
+ * is_swbp_insn - check if the instruction is a breakpoint instruction.
+ * @insn: instruction to be checked.
+ * Returns true if @insn is a breakpoint instruction.
+ */
+bool is_swbp_insn(uprobe_opcode_t *insn)
+{
+	return (is_trap(*insn));
+}
+
 /*
  * If xol insn itself traps and generates a signal (SIGILL/SIGSEGV/etc),
  * then detect the case where a singlestepped instruction jumps back to its