Per-task and per-cpu breakpoints have to be unambiguously identified for proper restoration of hw-breakpoints. The notion of pure user- and kernel- space breakpoints is antiquated. Store 'pid' of the process against which the perf-counter was requested to help proper distinction. This helps seamless handling of kernel-space breakpoints within the context of a user-space process and breakpoints for kernel-threads. Signed-off-by: K.Prasad --- arch/powerpc/kernel/hw_breakpoint.c | 24 +++++++++++++++++------- include/linux/perf_event.h | 1 + kernel/perf_event.c | 9 ++++++--- 3 files changed, 24 insertions(+), 10 deletions(-) Index: linux-2.6.ppc64_test/include/linux/perf_event.h =================================================================== --- linux-2.6.ppc64_test.orig/include/linux/perf_event.h +++ linux-2.6.ppc64_test/include/linux/perf_event.h @@ -698,6 +698,7 @@ struct perf_event { int oncpu; int cpu; + pid_t pid; struct list_head owner_entry; struct task_struct *owner; Index: linux-2.6.ppc64_test/kernel/perf_event.c =================================================================== --- linux-2.6.ppc64_test.orig/kernel/perf_event.c +++ linux-2.6.ppc64_test/kernel/perf_event.c @@ -4684,6 +4684,7 @@ static const struct pmu *sw_perf_event_i static struct perf_event * perf_event_alloc(struct perf_event_attr *attr, int cpu, + pid_t pid, struct perf_event_context *ctx, struct perf_event *group_leader, struct perf_event *parent_event, @@ -4717,6 +4718,7 @@ perf_event_alloc(struct perf_event_attr mutex_init(&event->mmap_mutex); event->cpu = cpu; + event->pid = pid; event->attr = *attr; event->group_leader = group_leader; event->pmu = NULL; @@ -5015,7 +5017,7 @@ SYSCALL_DEFINE5(perf_event_open, goto err_put_context; } - event = perf_event_alloc(&attr, cpu, ctx, group_leader, + event = perf_event_alloc(&attr, cpu, pid, ctx, group_leader, NULL, NULL, GFP_KERNEL); err = PTR_ERR(event); if (IS_ERR(event)) @@ -5090,7 +5092,7 @@ perf_event_create_kernel_counter(struct goto err_exit; } - event = perf_event_alloc(attr, cpu, ctx, NULL, + event = perf_event_alloc(attr, cpu, pid, ctx, NULL, NULL, overflow_handler, GFP_KERNEL); if (IS_ERR(event)) { err = PTR_ERR(event); @@ -5142,7 +5144,8 @@ inherit_event(struct perf_event *parent_ parent_event = parent_event->parent; child_event = perf_event_alloc(&parent_event->attr, - parent_event->cpu, child_ctx, + parent_event->cpu, child->pid, + child_ctx, group_leader, parent_event, NULL, GFP_KERNEL); if (IS_ERR(child_event)) 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 @@ -221,7 +221,7 @@ void thread_change_pc(struct task_struct */ int __kprobes hw_breakpoint_handler(struct die_args *args) { - bool is_kernel, is_ptrace_bp = false; + bool is_kernel, is_taskbound_bp, is_ptrace_bp = false; int rc = NOTIFY_STOP; struct perf_event *bp; struct pt_regs *regs = args->regs; @@ -246,6 +246,7 @@ int __kprobes hw_breakpoint_handler(stru is_kernel = is_kernel_addr(bp->attr.bp_addr); is_ptrace_bp = (bp->overflow_handler == ptrace_triggered) ? true : false; + is_taskbound_bp = (bp->pid > 0) ? true : false; /* * Verify if dar lies within the address range occupied by the symbol @@ -288,7 +289,14 @@ int __kprobes hw_breakpoint_handler(stru /* emulate_step() could not execute it, single-step them */ if (stepped == 0) { regs->msr |= MSR_SE; - __get_cpu_var(last_hit_bp) = bp; + /* + * Kernel-space addresses can also be bound to a task. If so, + * store the breakpoint in its 'thread_struct' + */ + if (is_taskbound_bp) + bp->ctx->task->thread.last_hit_ubp = bp; + else + __get_cpu_var(last_hit_bp) = bp; goto out; } /* @@ -310,17 +318,17 @@ out: int __kprobes single_step_dabr_instruction(struct die_args *args) { struct pt_regs *regs = args->regs; - struct perf_event *bp = NULL, *kernel_bp, *user_bp; + struct perf_event *bp = NULL, *kernel_bp, *per_task_bp; struct arch_hw_breakpoint *bp_info; /* * Identify the cause of single-stepping and find the corresponding * breakpoint structure */ - user_bp = current->thread.last_hit_ubp; + per_task_bp = current->thread.last_hit_ubp; kernel_bp = __get_cpu_var(last_hit_bp); - if (user_bp) { - bp = user_bp; + if (per_task_bp) { + bp = per_task_bp; current->thread.last_hit_ubp = NULL; } else if (kernel_bp) { bp = kernel_bp; @@ -348,7 +356,9 @@ int __kprobes single_step_dabr_instructi * for kernel-space breakpoints, so this cannot work along with other * debuggers (like KGDB, xmon) which may be single-stepping kernel code. */ - if (!(user_bp && test_thread_flag(TIF_SINGLESTEP))) + if (!(per_task_bp && + (!is_kernel_addr(bp->attr.bp_addr)) && + test_thread_flag(TIF_SINGLESTEP))) regs->msr &= ~MSR_SE; set_dabr(bp_info->address | bp_info->type | DABR_TRANSLATION); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/