forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
0722db015c
commit
62edab9056
@ -314,8 +314,12 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
|
|||||||
{
|
{
|
||||||
int i, cpu, rc = NOTIFY_STOP;
|
int i, cpu, rc = NOTIFY_STOP;
|
||||||
struct hw_breakpoint *bp;
|
struct hw_breakpoint *bp;
|
||||||
/* The DR6 value is stored in args->err */
|
unsigned long dr7, dr6;
|
||||||
unsigned long dr7, dr6 = args->err;
|
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 */
|
/* Do an early return if no trap bits are set in DR6 */
|
||||||
if ((dr6 & DR_TRAP_BITS) == 0)
|
if ((dr6 & DR_TRAP_BITS) == 0)
|
||||||
@ -351,6 +355,11 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
|
|||||||
if (bp)
|
if (bp)
|
||||||
rc = NOTIFY_DONE;
|
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
|
* bp can be NULL due to lazy debug register switching
|
||||||
* or due to the delay between updates of hbp_kernel_pos
|
* or due to the delay between updates of hbp_kernel_pos
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/nmi.h>
|
#include <linux/nmi.h>
|
||||||
|
|
||||||
|
#include <asm/debugreg.h>
|
||||||
#include <asm/apicdef.h>
|
#include <asm/apicdef.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
|
||||||
@ -434,6 +435,11 @@ single_step_cont(struct pt_regs *regs, struct die_args *args)
|
|||||||
"resuming...\n");
|
"resuming...\n");
|
||||||
kgdb_arch_handle_exception(args->trapnr, args->signr,
|
kgdb_arch_handle_exception(args->trapnr, args->signr,
|
||||||
args->err, "c", "", regs);
|
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;
|
return NOTIFY_STOP;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/alternative.h>
|
#include <asm/alternative.h>
|
||||||
|
#include <asm/debugreg.h>
|
||||||
|
|
||||||
void jprobe_return_end(void);
|
void jprobe_return_end(void);
|
||||||
|
|
||||||
@ -967,8 +968,14 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
|
|||||||
ret = NOTIFY_STOP;
|
ret = NOTIFY_STOP;
|
||||||
break;
|
break;
|
||||||
case DIE_DEBUG:
|
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;
|
ret = NOTIFY_STOP;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DIE_GPF:
|
case DIE_GPF:
|
||||||
/*
|
/*
|
||||||
|
@ -545,8 +545,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
|||||||
/* Store the virtualized DR6 value */
|
/* Store the virtualized DR6 value */
|
||||||
tsk->thread.debugreg6 = dr6;
|
tsk->thread.debugreg6 = dr6;
|
||||||
|
|
||||||
if (notify_die(DIE_DEBUG, "debug", regs, dr6, error_code,
|
if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
|
||||||
SIGTRAP) == NOTIFY_STOP)
|
SIGTRAP) == NOTIFY_STOP)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* It's safe to allow irq's after DR6 has been saved */
|
/* It's safe to allow irq's after DR6 has been saved */
|
||||||
|
@ -540,8 +540,14 @@ kmmio_die_notifier(struct notifier_block *nb, unsigned long val, void *args)
|
|||||||
struct die_args *arg = args;
|
struct die_args *arg = args;
|
||||||
|
|
||||||
if (val == DIE_DEBUG && (arg->err & DR_STEP))
|
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_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user