hw-breakpoints: modifying generic debug exception to use thread-specific debug registers
This patch modifies the breakpoint exception handler code to use the new abstract debug register names. [ fweisbec@gmail.com: fix conflict against kmemcheck ] [ Impact: refactor and cleanup x86 debug exception handler ] Original-patch-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
This commit is contained in:
Родитель
0067f12972
Коммит
08d68323d1
|
@ -529,73 +529,52 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
|
||||||
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
||||||
{
|
{
|
||||||
struct task_struct *tsk = current;
|
struct task_struct *tsk = current;
|
||||||
unsigned long condition;
|
unsigned long dr6;
|
||||||
int si_code;
|
int si_code;
|
||||||
|
|
||||||
get_debugreg(condition, 6);
|
get_debugreg(dr6, 6);
|
||||||
|
|
||||||
|
/* DR6 may or may not be cleared by the CPU */
|
||||||
|
set_debugreg(0, 6);
|
||||||
/*
|
/*
|
||||||
* The processor cleared BTF, so don't mark that we need it set.
|
* The processor cleared BTF, so don't mark that we need it set.
|
||||||
*/
|
*/
|
||||||
clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
|
clear_tsk_thread_flag(tsk, TIF_DEBUGCTLMSR);
|
||||||
tsk->thread.debugctlmsr = 0;
|
tsk->thread.debugctlmsr = 0;
|
||||||
|
|
||||||
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
|
/* Store the virtualized DR6 value */
|
||||||
|
tsk->thread.debugreg6 = dr6;
|
||||||
|
|
||||||
|
if (notify_die(DIE_DEBUG, "debug", regs, 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 */
|
||||||
preempt_conditional_sti(regs);
|
preempt_conditional_sti(regs);
|
||||||
|
|
||||||
/* Mask out spurious debug traps due to lazy DR7 setting */
|
if (regs->flags & X86_VM_MASK) {
|
||||||
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
|
handle_vm86_trap((struct kernel_vm86_regs *) regs,
|
||||||
if (!tsk->thread.debugreg7)
|
error_code, 1);
|
||||||
goto clear_dr7;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
if (regs->flags & X86_VM_MASK)
|
|
||||||
goto debug_vm86;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Save debug status register where ptrace can see it */
|
|
||||||
tsk->thread.debugreg6 = condition;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Single-stepping through TF: make sure we ignore any events in
|
* Single-stepping through system calls: ignore any exceptions in
|
||||||
* kernel space (but re-enable TF when returning to user mode).
|
* kernel space, but re-enable TF when returning to user mode.
|
||||||
|
*
|
||||||
|
* We already checked v86 mode above, so we can check for kernel mode
|
||||||
|
* by just checking the CPL of CS.
|
||||||
*/
|
*/
|
||||||
if (condition & DR_STEP) {
|
if ((dr6 & DR_STEP) && !user_mode(regs)) {
|
||||||
if (!user_mode(regs))
|
tsk->thread.debugreg6 &= ~DR_STEP;
|
||||||
goto clear_TF_reenable;
|
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
|
||||||
|
regs->flags &= ~X86_EFLAGS_TF;
|
||||||
}
|
}
|
||||||
|
si_code = get_si_code(tsk->thread.debugreg6);
|
||||||
si_code = get_si_code(condition);
|
if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS))
|
||||||
/* Ok, finally something we can handle */
|
send_sigtrap(tsk, regs, error_code, si_code);
|
||||||
send_sigtrap(tsk, regs, error_code, si_code);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Disable additional traps. They'll be re-enabled when
|
|
||||||
* the signal is delivered.
|
|
||||||
*/
|
|
||||||
clear_dr7:
|
|
||||||
set_debugreg(0, 7);
|
|
||||||
preempt_conditional_cli(regs);
|
preempt_conditional_cli(regs);
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
debug_vm86:
|
|
||||||
/* reenable preemption: handle_vm86_trap() might sleep */
|
|
||||||
dec_preempt_count();
|
|
||||||
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
|
|
||||||
conditional_cli(regs);
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
clear_TF_reenable:
|
|
||||||
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
|
|
||||||
regs->flags &= ~X86_EFLAGS_TF;
|
|
||||||
preempt_conditional_cli(regs);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче