]> git.karo-electronics.de Git - linux-beck.git/commitdiff
hw-breakpoints: reset bits in dr6 after the corresponding exception is handled
authorK.Prasad <prasad@linux.vnet.ibm.com>
Mon, 1 Jun 2009 18:17:06 +0000 (23:47 +0530)
committerFrederic Weisbecker <fweisbec@gmail.com>
Tue, 2 Jun 2009 20:47:00 +0000 (22:47 +0200)
This patch resets the bit in dr6 after the corresponding exception is
handled in code, so that we keep a clean track of the current virtual debug
status register.

[ Impact: keep track of breakpoints triggering completion ]

Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
arch/x86/kernel/hw_breakpoint.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/kprobes.c
arch/x86/kernel/traps.c
arch/x86/mm/kmmio.c

index 4867c9f3b5fb4a45f0b2ef29db5ff6d1f4f979a9..69451473dbd2a2abbc95a9833644b4a02043fabc 100644 (file)
@@ -314,8 +314,12 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
 {
        int i, cpu, rc = NOTIFY_STOP;
        struct hw_breakpoint *bp;
-       /* The DR6 value is stored in args->err */
-       unsigned long dr7, dr6 = args->err;
+       unsigned long dr7, dr6;
+       unsigned long *dr6_p;
+
+       /* The DR6 value is pointed by args->err */
+       dr6_p = (unsigned long *)ERR_PTR(args->err);
+       dr6 = *dr6_p;
 
        /* Do an early return if no trap bits are set in DR6 */
        if ((dr6 & DR_TRAP_BITS) == 0)
@@ -351,6 +355,11 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
                        if (bp)
                                rc = NOTIFY_DONE;
                }
+               /*
+                * Reset the 'i'th TRAP bit in dr6 to denote completion of
+                * exception handling
+                */
+               (*dr6_p) &= ~(DR_TRAP0 << i);
                /*
                 * bp can be NULL due to lazy debug register switching
                 * or due to the delay between updates of hbp_kernel_pos
index b1f4dffb919e8c708421cb8c29af80ad50d6a7c9..f820b73c7f28461f9f979228adc26a281d955ed4 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/smp.h>
 #include <linux/nmi.h>
 
+#include <asm/debugreg.h>
 #include <asm/apicdef.h>
 #include <asm/system.h>
 
@@ -434,6 +435,11 @@ single_step_cont(struct pt_regs *regs, struct die_args *args)
                        "resuming...\n");
        kgdb_arch_handle_exception(args->trapnr, args->signr,
                                   args->err, "c", "", regs);
+       /*
+        * Reset the BS bit in dr6 (pointed by args->err) to
+        * denote completion of processing
+        */
+       (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP;
 
        return NOTIFY_STOP;
 }
index 7b5169d2b00026272ed26874913c42ff315befb3..b5b1848c5336e505a5a147f0497865056f34b307 100644 (file)
@@ -54,6 +54,7 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/alternative.h>
+#include <asm/debugreg.h>
 
 void jprobe_return_end(void);
 
@@ -967,8 +968,14 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
                        ret = NOTIFY_STOP;
                break;
        case DIE_DEBUG:
-               if (post_kprobe_handler(args->regs))
+               if (post_kprobe_handler(args->regs)) {
+                       /*
+                        * Reset the BS bit in dr6 (pointed by args->err) to
+                        * denote completion of processing
+                        */
+                       (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP;
                        ret = NOTIFY_STOP;
+               }
                break;
        case DIE_GPF:
                /*
index de9913247dd07c7728367722892753ef6eb83a88..124a4d5a95b29ca44a71767a1f8dc6c92ba21635 100644 (file)
@@ -545,8 +545,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
        /* Store the virtualized DR6 value */
        tsk->thread.debugreg6 = dr6;
 
-       if (notify_die(DIE_DEBUG, "debug", regs, dr6, error_code,
-                                               SIGTRAP) == NOTIFY_STOP)
+       if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
+                                                       SIGTRAP) == NOTIFY_STOP)
                return;
 
        /* It's safe to allow irq's after DR6 has been saved */
index 16ccbd77917f22c1693b9b41fcb8dc7485acee39..11a4ad4d62530ff58b7bfa56d086ad69e3fc0bd1 100644 (file)
@@ -540,8 +540,14 @@ kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args)
        struct die_args *arg = args;
 
        if (val == DIE_DEBUG && (arg->err & DR_STEP))
-               if (post_kmmio_handler(arg->err, arg->regs) == 1)
+               if (post_kmmio_handler(arg->err, arg->regs) == 1) {
+                       /*
+                        * Reset the BS bit in dr6 (pointed by args->err) to
+                        * denote completion of processing
+                        */
+                       (*(unsigned long *)ERR_PTR(arg->err)) &= ~DR_STEP;
                        return NOTIFY_STOP;
+               }
 
        return NOTIFY_DONE;
 }