Many a times, the requested breakpoint length can be less than the fixed breakpoint length i.e. 8 bytes supported by PowerPC BookIII S. This could lead to extraneous interrupts resulting in false breakpoint notifications. The patch below detects and discards such interrupts for non-ptrace requests (we don't want to change ptrace behaviour for fear of breaking compatability).
Signed-off-by: K.Prasad <pra...@linux.vnet.ibm.com> --- arch/powerpc/kernel/hw_breakpoint.c | 39 ++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) Index: linux-2.6.ppc64_test/arch/powerpc/kernel/hw_breakpoint.c =================================================================== --- linux-2.6.ppc64_test.orig/arch/powerpc/kernel/hw_breakpoint.c +++ linux-2.6.ppc64_test/arch/powerpc/kernel/hw_breakpoint.c @@ -198,12 +198,13 @@ void thread_change_pc(struct task_struct */ int __kprobes hw_breakpoint_handler(struct die_args *args) { - bool is_ptrace_bp = false; + bool is_extraneous_interrupt = false, is_ptrace_bp = false; int rc = NOTIFY_STOP; struct perf_event *bp; struct pt_regs *regs = args->regs; int stepped = 1; struct arch_hw_breakpoint *info; + unsigned long dar = regs->dar; /* Disable breakpoints during exception handling */ set_dabr(0); @@ -234,9 +235,33 @@ int __kprobes hw_breakpoint_handler(stru 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; + } + /* Do not emulate user-space instructions, instead single-step them */ if (user_mode(regs)) { - bp->ctx->task->thread.last_hit_ubp = bp; + /* + * 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. + */ + if (is_extraneous_interrupt) + bp->ctx->task->thread.ptrace_bps[0] = bp; + else + bp->ctx->task->thread.last_hit_ubp = bp; regs->msr |= MSR_SE; goto out; } @@ -274,7 +299,12 @@ int __kprobes single_step_dabr_instructi struct perf_event *bp = NULL; struct arch_hw_breakpoint *bp_info; - bp = current->thread.last_hit_ubp; + if (current->thread.last_hit_ubp) + bp = current->thread.last_hit_ubp; + else { + bp = current->thread.ptrace_bps[0]; + current->thread.ptrace_bps[0] = NULL; + } /* * Check if we are single-stepping as a result of a * previous HW Breakpoint exception @@ -288,7 +318,8 @@ int __kprobes single_step_dabr_instructi * We shall invoke the user-defined callback function in the single * stepping handler to confirm to 'trigger-after-execute' semantics */ - perf_bp_event(bp, regs); + if (bp == current->thread.last_hit_ubp) + perf_bp_event(bp, regs); /* * Do not disable MSR_SE if the process was already in _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev