- Follow the perf "event " rename- The ptrace regression have been fixed (ptrace breakpoint perf events weren't released when a task ended)- Drop the struct hw_breakpoint and store generic fields in perf_event_attr.- Separate core and arch specific headers, drop asm-generic/hw_breakpoint.h and create linux/hw_breakpoint.h- Use new generic len/type for breakpoint- Handle off case: when breakpoints api is not supported by an arch

/*- * Install the debug register values for just the kernel, no thread.+ * Uninstall the breakpoint contained in the given counter.+ *+ * First we search the debug address register it uses and then we disable+ * it.+ *+ * Atomic: we hold the counter->ctx->lock and we only handle variables+ * and registers local to this cpu. */-void arch_uninstall_thread_hw_breakpoint(void)+void arch_uninstall_hw_breakpoint(struct perf_event *bp) {- /* Clear the user-space portion of debugreg7 by setting only kdr7 */- set_debugreg(kdr7, 7);+ struct arch_hw_breakpoint *info = counter_arch_bp(bp);+ unsigned long *dr7;+ int i;

percpu_write(current_task, next_p);- /*- * There's a problem with moving the arch_install_thread_hw_breakpoint()- * call before current is updated. Suppose a kernel breakpoint is- * triggered in between the two, the hw-breakpoint handler will see that- * the 'current' task does not have TIF_DEBUG flag set and will think it- * is leftover from an old task (lazy switching) and will erase it. Then- * until the next context switch, no user-breakpoints will be installed.- *- * The real problem is that it's impossible to update both current and- * physical debug registers at the same instant, so there will always be- * a window in which they disagree and a breakpoint might get triggered.- * Since we use lazy switching, we are forced to assume that a- * disagreement means that current is correct and the exception is due- * to lazy debug register switching.- */- if (unlikely(test_tsk_thread_flag(next_p, TIF_DEBUG)))- arch_install_thread_hw_breakpoint(next_p);

return err; }@@ -508,23 +501,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) */ if (preload_fpu) __math_state_restore();- /*- * There's a problem with moving the arch_install_thread_hw_breakpoint()- * call before current is updated. Suppose a kernel breakpoint is- * triggered in between the two, the hw-breakpoint handler will see that- * the 'current' task does not have TIF_DEBUG flag set and will think it- * is leftover from an old task (lazy switching) and will erase it. Then- * until the next context switch, no user-breakpoints will be installed.- *- * The real problem is that it's impossible to update both current and- * physical debug registers at the same instant, so there will always be- * a window in which they disagree and a breakpoint might get triggered.- * Since we use lazy switching, we are forced to assume that a- * disagreement means that current is correct and the exception is due- * to lazy debug register switching.- */- if (unlikely(test_tsk_thread_flag(next_p, TIF_DEBUG)))- arch_install_thread_hw_breakpoint(next_p);

/* * Store in the virtual DR6 register the fact that the breakpoint * was hit so the thread's debugger will see it. */- for (i = 0; i < hbp_kernel_pos; i++)- /*- * We will check bp->info.address against the address stored in- * thread's hbp structure and not debugreg[i]. This is to ensure- * that the corresponding bit for 'i' in DR7 register is enabled- */- if (bp->info.address == thread->hbp[i]->info.address)+ for (i = 0; i < HBP_NUM; i++) {+ if (thread->ptrace_bps[i] == bp) break;+ }

-/*- * Copy the hardware breakpoint info from a thread to its cloned child.- */-int copy_thread_hw_breakpoint(struct task_struct *tsk,- struct task_struct *child, unsigned long clone_flags)+void release_bp_slot(struct perf_event *bp) {- /*- * We will assume that breakpoint settings are not inherited- * and the child starts out with no debug registers set.- * But what about CLONE_PTRACE?- */- clear_tsk_thread_flag(child, TIF_DEBUG);-- /* We will call flush routine since the debugregs are not inherited */- arch_flush_thread_hw_breakpoint(child);-- return 0;+ atomic_dec(&bp_slot); }

- arch_update_user_hw_breakpoint(pos, tsk);- /*- * Does it need to be installed right now?- * Otherwise it will get installed the next time tsk runs- */- if (tsk == current)- arch_install_thread_hw_breakpoint(tsk);+int register_perf_hw_breakpoint(struct perf_event *bp)+{+ bp->callback = perf_bp_event;