Subject: Re: [Patch 0/5] PPC64-HWBKPT: Hardware Breakpoint interfaces - ver XXII

From: "K.Prasad" <[email-masked]>
Date: Mon, 7 Jun 2010 12:33:51 +0530

On Fri, Jun 04, 2010 at 07:06:48PM +1000, Paul Mackerras wrote:
> On Fri, Jun 04, 2010 at 12:21:45PM +0530, K.Prasad wrote:
> 
> > Meanwhile I tested the per-cpu breakpoints with the new emulate_step
> > patch (refer linuxppc-dev message-id:
> > [email-masked]) and they continue to fail
> > due to emulate_step() failure, in my case, on a "lwz r0,0(r28)"
> > instruction.
> 
> Strange, what was in r28?  The emulator should handle that instruction.
> 

It must be containing one of the offsets of "struct tracer" which is a
parameter to the function trace_selftest_startup_ksym(). Basically this
function does a selftest over hw-breakpoints by placing read-write
breakpoint on a dummy global-variable and performs read-write access
thereupon. The lwz instruction which fails here corresponds to the
instruction that does read-write. A complete disassemble of the function
upto the failing instruction (at address) is pasted at the end of this
mail.

> > About the latest patchset, given that we chose to ignore extraneous
> > interrupts for non-ptrace breakpoints, I thought that re-using
> > current->thread.ptrace_bps as a flag would be efficient than
> > introducing
> > a new member in 'struct thread_struct' to do the same. I'm not sure
> > if
> > you foresee any issues with that.
> 
> I just wonder what provides exclusion between its use as a flag and
> its use to hold a real ptrace breakpoint.  As far as I can see nothing
> does.  If there is something, it's off in some other source file,
> unless I'm missing something.  And in that case there should be a bit
> fat comment explaining why it's safe.
> 

The hw_breakpoint_handler() goes like this:

int __kprobes hw_breakpoint_handler(struct die_args *args)
{
...
....
	/*
	 * Return early after invoking user-callback function without restoring
	 * DABR if the breakpoint is from ptrace which always operates in
	 * one-shot mode. The ptrace-ed process will receive the SIGTRAP signal
	 * generated in do_dabr().
	 */
	if (is_ptrace_bp) {
		perf_bp_event(bp, regs);
		rc = NOTIFY_DONE;
		goto out;
	}

	/*
	 * Verify if dar lies within the address range occupied by the symbol
	 * being watched to filter extraneous exceptions.
	 */
	if (!((bp->attr.bp_addr <= dar) &&
	     (dar <= (bp->attr.bp_addr + bp->attr.bp_len)))) {
		/*
		 * This exception is triggered not because of a memory access
		 * on the monitored variable but in the double-word address
		 * range in which it is contained. We will consume this
		 * exception, considering it as 'noise'.
		 */
		is_extraneous_interrupt = true;
	}
....
...
}

Given that 'ptrace_bps' is used only for ptrace originated breakpoints
and that we return early i.e. before detecting extraneous interrupts
in hw_breakpoint_handler() (as shown above) they shouldn't overlap each
other. The following comment in hw_breakpoint_handler() explains the
same.
		/*
		 * To prevent invocation of perf_event_bp(), we shall overload
		 * thread.ptrace_bps[] pointer (unused for non-ptrace
		 * exceptions) to flag an extraneous interrupt which must be
		 * skipped.
		 */
Thanks,
K.Prasad

(gdb) disass trace_selftest_startup_ksym
Dump of assembler code for function trace_selftest_startup_ksym:
0xc000000000125580 <trace_selftest_startup_ksym+0>:	mflr    r0
0xc000000000125584 <trace_selftest_startup_ksym+4>:	std     r26,-48(r1)
0xc000000000125588 <trace_selftest_startup_ksym+8>:	std     r27,-40(r1)
0xc00000000012558c <trace_selftest_startup_ksym+12>:	std     r28,-32(r1)
0xc000000000125590 <trace_selftest_startup_ksym+16>:	std     r29,-24(r1)
0xc000000000125594 <trace_selftest_startup_ksym+20>:	std     r30,-16(r1)
0xc000000000125598 <trace_selftest_startup_ksym+24>:	std     r31,-8(r1)
0xc00000000012559c <trace_selftest_startup_ksym+28>:	std     r0,16(r1)
0xc0000000001255a0 <trace_selftest_startup_ksym+32>:	stdu    r1,-176(r1)
0xc0000000001255a4 <trace_selftest_startup_ksym+36>:	mr      r31,r1
0xc0000000001255a8 <trace_selftest_startup_ksym+40>:	ld      r30,-17784(r2)
0xc0000000001255ac <trace_selftest_startup_ksym+44>:	mr      r26,r4
0xc0000000001255b0 <trace_selftest_startup_ksym+48>:	mr      r27,r3
0xc0000000001255b4 <trace_selftest_startup_ksym+52>:	bl      0xc000000000125510 <tracer_init>
0xc0000000001255b8 <trace_selftest_startup_ksym+56>:	li      r4,3
0xc0000000001255bc <trace_selftest_startup_ksym+60>:	mr.     r29,r3
0xc0000000001255c0 <trace_selftest_startup_ksym+64>:	mr      r5,r29
0xc0000000001255c4 <trace_selftest_startup_ksym+68>:	beq     0xc0000000001255e0 <trace_selftest_startup_ksym+96>
0xc0000000001255c8 <trace_selftest_startup_ksym+72>:	ld      r3,-31520(r30)
0xc0000000001255cc <trace_selftest_startup_ksym+76>:	ld      r4,0(r27)
0xc0000000001255d0 <trace_selftest_startup_ksym+80>:	bl      0xc00000000009c560 <printk>
0xc0000000001255d4 <trace_selftest_startup_ksym+84>:	nop
0xc0000000001255d8 <trace_selftest_startup_ksym+88>:	b       0xc000000000125690 <trace_selftest_startup_ksym+272>
0xc0000000001255dc <trace_selftest_startup_ksym+92>:	nop
0xc0000000001255e0 <trace_selftest_startup_ksym+96>:	ld      r28,-31512(r30)
0xc0000000001255e4 <trace_selftest_startup_ksym+100>:	ld      r3,-31504(r30)
0xc0000000001255e8 <trace_selftest_startup_ksym+104>:	stw     r29,0(r28)
0xc0000000001255ec <trace_selftest_startup_ksym+108>:	mr      r5,r28
0xc0000000001255f0 <trace_selftest_startup_ksym+112>:	bl      0xc000000000140760 <process_new_ksym_entry>
0xc0000000001255f4 <trace_selftest_startup_ksym+116>:	nop
0xc0000000001255f8 <trace_selftest_startup_ksym+120>:	cmpwi   cr7,r3,0
0xc0000000001255fc <trace_selftest_startup_ksym+124>:	mr      r29,r3
0xc000000000125600 <trace_selftest_startup_ksym+128>:	blt     cr7,0xc00000000012567c <trace_selftest_startup_ksym+252>
0xc000000000125604 <trace_selftest_startup_ksym+132>:	lwz     r0,0(r28)
0xc000000000125608 <trace_selftest_startup_ksym+136>:	cmpwi   cr7,r0,0
0xc00000000012560c <trace_selftest_startup_ksym+140>:	bne     cr7,0xc000000000125618 <trace_selftest_startup_ksym+152>
0xc000000000125610 <trace_selftest_startup_ksym+144>:	li      r0,1