[RFC Patch 2/5] PERF-HW_BKPT: Enable/disable the breakpoints whenstill registered

From: K.Prasad
Date: Thu Oct 29 2009 - 18:21:47 EST


Allow breakpoints to be enabled/disabled without yielding the
breakpoint request through new APIs -
<enable><disable>_hw_breakpoint()

Signed-off-by: K.Prasad <prasad@xxxxxxxxxxxxxxxxxx>
---
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 {
+ /*
+ * The 'enabled' flag denotes if a breakpoint hit would in-turn invoke
+ * the 'triggered' function. Not to be set directly by the end-user.
+ * Must be operated through <enable><disable>_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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/