Commit 3d2a71a5 authored by Alexander van Heukelum's avatar Alexander van Heukelum Committed by Ingo Molnar

x86, traps: converge do_debug handlers

Make the x86_64-version and the i386-version of do_debug
more similar.

 - introduce preempt_conditional_sti/cli to i386. The preempt-count
	is now elevated during the trap handler, like on x86_64. It
	does not run on a separate stack, however.
 - replace an open-coded "send_sigtrap"
 - copy some comments
Signed-off-by: default avatarAlexander van Heukelum <heukelum@fastmail.fm>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent e407d620
...@@ -88,6 +88,20 @@ static inline void conditional_sti(struct pt_regs *regs) ...@@ -88,6 +88,20 @@ static inline void conditional_sti(struct pt_regs *regs)
local_irq_enable(); local_irq_enable();
} }
static inline void preempt_conditional_sti(struct pt_regs *regs)
{
inc_preempt_count();
if (regs->flags & X86_EFLAGS_IF)
local_irq_enable();
}
static inline void preempt_conditional_cli(struct pt_regs *regs)
{
if (regs->flags & X86_EFLAGS_IF)
local_irq_disable();
dec_preempt_count();
}
static inline void static inline void
die_if_kernel(const char *str, struct pt_regs *regs, long err) die_if_kernel(const char *str, struct pt_regs *regs, long err)
{ {
...@@ -498,7 +512,7 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) ...@@ -498,7 +512,7 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
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 int condition; unsigned long condition;
int si_code; int si_code;
get_debugreg(condition, 6); get_debugreg(condition, 6);
...@@ -512,9 +526,9 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -512,9 +526,9 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, if (notify_die(DIE_DEBUG, "debug", regs, condition, 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 */
if (regs->flags & X86_EFLAGS_IF) preempt_conditional_sti(regs);
local_irq_enable();
/* Mask out spurious debug traps due to lazy DR7 setting */ /* Mask out spurious debug traps due to lazy DR7 setting */
if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
...@@ -533,16 +547,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -533,16 +547,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
* kernel space (but re-enable TF when returning to user mode). * kernel space (but re-enable TF when returning to user mode).
*/ */
if (condition & DR_STEP) { if (condition & DR_STEP) {
/*
* We already checked v86 mode above, so we can
* check for kernel mode by just checking the CPL
* of CS.
*/
if (!user_mode(regs)) if (!user_mode(regs))
goto clear_TF_reenable; goto clear_TF_reenable;
} }
si_code = get_si_code((unsigned long)condition); si_code = get_si_code(condition);
/* Ok, finally something we can handle */ /* Ok, finally something we can handle */
send_sigtrap(tsk, regs, error_code, si_code); send_sigtrap(tsk, regs, error_code, si_code);
...@@ -552,15 +561,18 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -552,15 +561,18 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
*/ */
clear_dr7: clear_dr7:
set_debugreg(0, 7); set_debugreg(0, 7);
preempt_conditional_cli(regs);
return; return;
debug_vm86: debug_vm86:
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
preempt_conditional_cli(regs);
return; return;
clear_TF_reenable: clear_TF_reenable:
set_tsk_thread_flag(tsk, TIF_SINGLESTEP); set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
regs->flags &= ~X86_EFLAGS_TF; regs->flags &= ~X86_EFLAGS_TF;
preempt_conditional_cli(regs);
return; return;
} }
......
...@@ -380,7 +380,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -380,7 +380,7 @@ 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 condition;
siginfo_t info; int si_code;
get_debugreg(condition, 6); get_debugreg(condition, 6);
...@@ -394,6 +394,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -394,6 +394,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
SIGTRAP) == NOTIFY_STOP) SIGTRAP) == NOTIFY_STOP)
return; return;
/* 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 */ /* Mask out spurious debug traps due to lazy DR7 setting */
...@@ -402,6 +403,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -402,6 +403,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
goto clear_dr7; goto clear_dr7;
} }
/* Save debug status register where ptrace can see it */
tsk->thread.debugreg6 = condition; tsk->thread.debugreg6 = condition;
/* /*
...@@ -413,15 +415,14 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) ...@@ -413,15 +415,14 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
goto clear_TF_reenable; goto clear_TF_reenable;
} }
si_code = get_si_code(condition);
/* Ok, finally something we can handle */ /* Ok, finally something we can handle */
tsk->thread.trap_no = 1; send_sigtrap(tsk, regs, error_code, si_code);
tsk->thread.error_code = error_code;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = get_si_code(condition);
info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
force_sig_info(SIGTRAP, &info, tsk);
/*
* Disable additional traps. They'll be re-enabled when
* the signal is delivered.
*/
clear_dr7: clear_dr7:
set_debugreg(0, 7); set_debugreg(0, 7);
preempt_conditional_cli(regs); preempt_conditional_cli(regs);
......
...@@ -174,12 +174,8 @@ extern unsigned long profile_pc(struct pt_regs *regs); ...@@ -174,12 +174,8 @@ extern unsigned long profile_pc(struct pt_regs *regs);
extern unsigned long extern unsigned long
convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs); convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
#ifdef CONFIG_X86_32
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
int error_code, int si_code); int error_code, int si_code);
#endif
void signal_fault(struct pt_regs *regs, void __user *frame, char *where); void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
extern long syscall_trace_enter(struct pt_regs *); extern long syscall_trace_enter(struct pt_regs *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment