diff options
author | K.Prasad <prasad@linux.vnet.ibm.com> | 2009-06-01 14:17:06 -0400 |
---|---|---|
committer | Frederic Weisbecker <fweisbec@gmail.com> | 2009-06-02 16:47:00 -0400 |
commit | 62edab9056a6cf0c9207339c8892c923a5217e45 (patch) | |
tree | 2becd775fdc2a25df3daacf69d80685b251fbed9 /arch/x86 | |
parent | 0722db015c246204044299eae3b02d18d3ca4faf (diff) |
hw-breakpoints: reset bits in dr6 after the corresponding exception is handled
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>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/hw_breakpoint.c | 13 | ||||
-rw-r--r-- | arch/x86/kernel/kgdb.c | 6 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes.c | 9 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 4 | ||||
-rw-r--r-- | arch/x86/mm/kmmio.c | 8 |
5 files changed, 34 insertions, 6 deletions
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c index 4867c9f3b5fb..69451473dbd2 100644 --- a/arch/x86/kernel/hw_breakpoint.c +++ b/arch/x86/kernel/hw_breakpoint.c | |||
@@ -314,8 +314,12 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
314 | { | 314 | { |
315 | int i, cpu, rc = NOTIFY_STOP; | 315 | int i, cpu, rc = NOTIFY_STOP; |
316 | struct hw_breakpoint *bp; | 316 | struct hw_breakpoint *bp; |
317 | /* The DR6 value is stored in args->err */ | 317 | unsigned long dr7, dr6; |
318 | unsigned long dr7, dr6 = args->err; | 318 | unsigned long *dr6_p; |
319 | |||
320 | /* The DR6 value is pointed by args->err */ | ||
321 | dr6_p = (unsigned long *)ERR_PTR(args->err); | ||
322 | dr6 = *dr6_p; | ||
319 | 323 | ||
320 | /* Do an early return if no trap bits are set in DR6 */ | 324 | /* Do an early return if no trap bits are set in DR6 */ |
321 | if ((dr6 & DR_TRAP_BITS) == 0) | 325 | if ((dr6 & DR_TRAP_BITS) == 0) |
@@ -352,6 +356,11 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
352 | rc = NOTIFY_DONE; | 356 | rc = NOTIFY_DONE; |
353 | } | 357 | } |
354 | /* | 358 | /* |
359 | * Reset the 'i'th TRAP bit in dr6 to denote completion of | ||
360 | * exception handling | ||
361 | */ | ||
362 | (*dr6_p) &= ~(DR_TRAP0 << i); | ||
363 | /* | ||
355 | * bp can be NULL due to lazy debug register switching | 364 | * bp can be NULL due to lazy debug register switching |
356 | * or due to the delay between updates of hbp_kernel_pos | 365 | * or due to the delay between updates of hbp_kernel_pos |
357 | * and this_hbp_kernel. | 366 | * and this_hbp_kernel. |
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index b1f4dffb919e..f820b73c7f28 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/smp.h> | 43 | #include <linux/smp.h> |
44 | #include <linux/nmi.h> | 44 | #include <linux/nmi.h> |
45 | 45 | ||
46 | #include <asm/debugreg.h> | ||
46 | #include <asm/apicdef.h> | 47 | #include <asm/apicdef.h> |
47 | #include <asm/system.h> | 48 | #include <asm/system.h> |
48 | 49 | ||
@@ -434,6 +435,11 @@ single_step_cont(struct pt_regs *regs, struct die_args *args) | |||
434 | "resuming...\n"); | 435 | "resuming...\n"); |
435 | kgdb_arch_handle_exception(args->trapnr, args->signr, | 436 | kgdb_arch_handle_exception(args->trapnr, args->signr, |
436 | args->err, "c", "", regs); | 437 | args->err, "c", "", regs); |
438 | /* | ||
439 | * Reset the BS bit in dr6 (pointed by args->err) to | ||
440 | * denote completion of processing | ||
441 | */ | ||
442 | (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP; | ||
437 | 443 | ||
438 | return NOTIFY_STOP; | 444 | return NOTIFY_STOP; |
439 | } | 445 | } |
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index 7b5169d2b000..b5b1848c5336 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <asm/pgtable.h> | 54 | #include <asm/pgtable.h> |
55 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
56 | #include <asm/alternative.h> | 56 | #include <asm/alternative.h> |
57 | #include <asm/debugreg.h> | ||
57 | 58 | ||
58 | void jprobe_return_end(void); | 59 | void jprobe_return_end(void); |
59 | 60 | ||
@@ -967,8 +968,14 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
967 | ret = NOTIFY_STOP; | 968 | ret = NOTIFY_STOP; |
968 | break; | 969 | break; |
969 | case DIE_DEBUG: | 970 | case DIE_DEBUG: |
970 | if (post_kprobe_handler(args->regs)) | 971 | if (post_kprobe_handler(args->regs)) { |
972 | /* | ||
973 | * Reset the BS bit in dr6 (pointed by args->err) to | ||
974 | * denote completion of processing | ||
975 | */ | ||
976 | (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP; | ||
971 | ret = NOTIFY_STOP; | 977 | ret = NOTIFY_STOP; |
978 | } | ||
972 | break; | 979 | break; |
973 | case DIE_GPF: | 980 | case DIE_GPF: |
974 | /* | 981 | /* |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index de9913247dd0..124a4d5a95b2 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -545,8 +545,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
545 | /* Store the virtualized DR6 value */ | 545 | /* Store the virtualized DR6 value */ |
546 | tsk->thread.debugreg6 = dr6; | 546 | tsk->thread.debugreg6 = dr6; |
547 | 547 | ||
548 | if (notify_die(DIE_DEBUG, "debug", regs, dr6, error_code, | 548 | if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code, |
549 | SIGTRAP) == NOTIFY_STOP) | 549 | SIGTRAP) == NOTIFY_STOP) |
550 | return; | 550 | return; |
551 | 551 | ||
552 | /* It's safe to allow irq's after DR6 has been saved */ | 552 | /* It's safe to allow irq's after DR6 has been saved */ |
diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index 16ccbd77917f..11a4ad4d6253 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c | |||
@@ -540,8 +540,14 @@ kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args) | |||
540 | struct die_args *arg = args; | 540 | struct die_args *arg = args; |
541 | 541 | ||
542 | if (val == DIE_DEBUG && (arg->err & DR_STEP)) | 542 | if (val == DIE_DEBUG && (arg->err & DR_STEP)) |
543 | if (post_kmmio_handler(arg->err, arg->regs) == 1) | 543 | if (post_kmmio_handler(arg->err, arg->regs) == 1) { |
544 | /* | ||
545 | * Reset the BS bit in dr6 (pointed by args->err) to | ||
546 | * denote completion of processing | ||
547 | */ | ||
548 | (*(unsigned long *)ERR_PTR(arg->err)) &= ~DR_STEP; | ||
544 | return NOTIFY_STOP; | 549 | return NOTIFY_STOP; |
550 | } | ||
545 | 551 | ||
546 | return NOTIFY_DONE; | 552 | return NOTIFY_DONE; |
547 | } | 553 | } |