Skip to content

Commit

Permalink
hw-breakpoints: reset bits in dr6 after the corresponding exception i…
Browse files Browse the repository at this point in the history
…s 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>
  • Loading branch information
K.Prasad authored and Frederic Weisbecker committed Jun 2, 2009
1 parent 0722db0 commit 62edab9
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 6 deletions.
13 changes: 11 additions & 2 deletions arch/x86/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/kernel/kgdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <linux/smp.h>
#include <linux/nmi.h>

#include <asm/debugreg.h>
#include <asm/apicdef.h>
#include <asm/system.h>

Expand Down Expand Up @@ -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;
}
Expand Down
9 changes: 8 additions & 1 deletion arch/x86/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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:
/*
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
8 changes: 7 additions & 1 deletion arch/x86/mm/kmmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 62edab9

Please sign in to comment.