Allow breakpoints to be enabled/disabled without yielding the breakpoint request through new APIs - _hw_breakpoint() Signed-off-by: K.Prasad --- arch/x86/kernel/hw_breakpoint.c | 15 ++++++++++----- include/asm-generic/hw_breakpoint.h | 14 ++++++++++++++ kernel/hw_breakpoint.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 6 deletions(-) Index: linux-2.6-tip.perf_hbkpt/arch/x86/kernel/hw_breakpoint.c =================================================================== --- linux-2.6-tip.perf_hbkpt.orig/arch/x86/kernel/hw_breakpoint.c +++ linux-2.6-tip.perf_hbkpt/arch/x86/kernel/hw_breakpoint.c @@ -85,10 +85,11 @@ void arch_update_kernel_hw_breakpoint(vo for (i = hbp_kernel_pos; i < HBP_NUM; i++) { bp = per_cpu(this_hbp_kernel[i], cpu); - if (bp) { + if (!bp) + continue; + set_debugreg(bp->info.address, i); + if (atomic_read(&bp->enabled) == BP_ENABLED) temp_kdr7 |= encode_dr7(i, bp->info.len, bp->info.type); - set_debugreg(bp->info.address, i); - } } /* No need to set DR6. Update the debug registers with kernel-space @@ -288,8 +289,9 @@ void arch_update_user_hw_breakpoint(int thread->debugreg7 &= ~dr7_masks[pos]; if (bp) { thread->debugreg[pos] = bp->info.address; - thread->debugreg7 |= encode_dr7(pos, bp->info.len, - bp->info.type); + if (atomic_read(&bp->enabled) == BP_ENABLED) + thread->debugreg7 |= encode_dr7(pos, bp->info.len, + bp->info.type); } else thread->debugreg[pos] = 0; } @@ -377,6 +379,9 @@ static int __kprobes hw_breakpoint_handl */ if (!bp) continue; + /* Ignore exceptions due to disabled breakpoints */ + if (atomic_read(&bp->enabled) == BP_DISABLED) + continue; (bp->triggered)(bp, args->regs); } Index: linux-2.6-tip.perf_hbkpt/include/asm-generic/hw_breakpoint.h =================================================================== --- linux-2.6-tip.perf_hbkpt.orig/include/asm-generic/hw_breakpoint.h +++ linux-2.6-tip.perf_hbkpt/include/asm-generic/hw_breakpoint.h @@ -101,7 +101,19 @@ * * ---------------------------------------------------------------------- */ + +enum bp_status { + BP_DISABLED = 0, + BP_ENABLED = 1 +}; + struct hw_breakpoint { + /* + * Denotes if a breakpoint is currently enabled in physical debug + * registers. Not to be set directly by the end-user. Must be + * operated through _hw_breakpoint() APIs only. + */ + atomic_t enabled; void (*triggered)(struct hw_breakpoint *, struct pt_regs *); const cpumask_t *cpumask; struct arch_hw_breakpoint info; @@ -135,6 +147,8 @@ extern void unregister_user_hw_breakpoin extern int register_kernel_hw_breakpoint(struct hw_breakpoint *bp); extern void unregister_kernel_hw_breakpoint(struct hw_breakpoint *bp); +extern void enable_hw_breakpoint(struct hw_breakpoint *bp); +extern void disable_hw_breakpoint(struct hw_breakpoint *bp); extern unsigned int hbp_kernel_pos; #endif /* __KERNEL__ */ Index: linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c =================================================================== --- linux-2.6-tip.perf_hbkpt.orig/kernel/hw_breakpoint.c +++ linux-2.6-tip.perf_hbkpt/kernel/hw_breakpoint.c @@ -229,8 +229,10 @@ int register_user_hw_breakpoint(struct t break; } } - if (!rc) + if (!rc) { set_tsk_thread_flag(tsk, TIF_DEBUG); + atomic_set(&bp->enabled, BP_ENABLED); + } spin_unlock_bh(&hw_breakpoint_lock); return rc; @@ -351,6 +353,7 @@ int register_kernel_hw_breakpoint(struct } } + atomic_set(&bp->enabled, BP_ENABLED); if (cpumask_test_cpu(smp_processor_id(), bp->cpumask)) update_each_cpu_kernel_hbp(bp); smp_call_function_many(bp->cpumask, update_each_cpu_kernel_hbp, bp, 1); @@ -420,6 +423,32 @@ ret_path: } EXPORT_SYMBOL_GPL(unregister_kernel_hw_breakpoint); +/** + * enable_hw_breakpoint - re-enable a breakpoint previously disabled + * @bp: pointer to the breakpoint structure to be enabled + * + * Re-enable or disable a breakpoint, previously disabled using + * disable_hw_breakpoint() + */ +void enable_hw_breakpoint(struct hw_breakpoint *bp) +{ + atomic_set(&bp->enabled, BP_ENABLED); +} +EXPORT_SYMBOL_GPL(enable_hw_breakpoint); + +/** + * disable_hw_breakpoint - disable a breakpoint from raising breakpoint exceptions + * @bp: pointer to the breakpoint structure to be disabled + * + * Disable a breakpoint without actually losing the registration. Re-enable it + * again using enable_hw_breakpoint() + */ +void disable_hw_breakpoint(struct hw_breakpoint *bp) +{ + atomic_set(&bp->enabled, BP_DISABLED); +} +EXPORT_SYMBOL_GPL(disable_hw_breakpoint); + static struct notifier_block hw_breakpoint_exceptions_nb = { .notifier_call = hw_breakpoint_exceptions_notify, /* we need to be notified first */ -- 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/