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: Alexander van Heukelum <heukelum@fastmail.fm> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
e407d62088
commit
3d2a71a596
|
@ -88,6 +88,20 @@ static inline void conditional_sti(struct pt_regs *regs)
|
|||
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
|
||||
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)
|
|||
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
unsigned int condition;
|
||||
unsigned long condition;
|
||||
int si_code;
|
||||
|
||||
get_debugreg(condition, 6);
|
||||
|
@ -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,
|
||||
SIGTRAP) == NOTIFY_STOP)
|
||||
return;
|
||||
|
||||
/* It's safe to allow irq's after DR6 has been saved */
|
||||
if (regs->flags & X86_EFLAGS_IF)
|
||||
local_irq_enable();
|
||||
preempt_conditional_sti(regs);
|
||||
|
||||
/* Mask out spurious debug traps due to lazy DR7 setting */
|
||||
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)
|
|||
* kernel space (but re-enable TF when returning to user mode).
|
||||
*/
|
||||
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))
|
||||
goto clear_TF_reenable;
|
||||
}
|
||||
|
||||
si_code = get_si_code((unsigned long)condition);
|
||||
si_code = get_si_code(condition);
|
||||
/* Ok, finally something we can handle */
|
||||
send_sigtrap(tsk, regs, error_code, si_code);
|
||||
|
||||
|
@ -552,15 +561,18 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
|||
*/
|
||||
clear_dr7:
|
||||
set_debugreg(0, 7);
|
||||
preempt_conditional_cli(regs);
|
||||
return;
|
||||
|
||||
debug_vm86:
|
||||
handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
|
||||
preempt_conditional_cli(regs);
|
||||
return;
|
||||
|
||||
clear_TF_reenable:
|
||||
set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
|
||||
regs->flags &= ~X86_EFLAGS_TF;
|
||||
preempt_conditional_cli(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -380,7 +380,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
|||
{
|
||||
struct task_struct *tsk = current;
|
||||
unsigned long condition;
|
||||
siginfo_t info;
|
||||
int si_code;
|
||||
|
||||
get_debugreg(condition, 6);
|
||||
|
||||
|
@ -394,6 +394,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
|||
SIGTRAP) == NOTIFY_STOP)
|
||||
return;
|
||||
|
||||
/* It's safe to allow irq's after DR6 has been saved */
|
||||
preempt_conditional_sti(regs);
|
||||
|
||||
/* 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)
|
|||
goto clear_dr7;
|
||||
}
|
||||
|
||||
/* Save debug status register where ptrace can see it */
|
||||
tsk->thread.debugreg6 = condition;
|
||||
|
||||
/*
|
||||
|
@ -413,15 +415,14 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
|
|||
goto clear_TF_reenable;
|
||||
}
|
||||
|
||||
si_code = get_si_code(condition);
|
||||
/* Ok, finally something we can handle */
|
||||
tsk->thread.trap_no = 1;
|
||||
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);
|
||||
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);
|
||||
|
|
|
@ -174,12 +174,8 @@ extern unsigned long profile_pc(struct pt_regs *regs);
|
|||
|
||||
extern unsigned long
|
||||
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,
|
||||
int error_code, int si_code);
|
||||
#endif
|
||||
|
||||
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
|
||||
|
||||
extern long syscall_trace_enter(struct pt_regs *);
|
||||
|
|
Loading…
Reference in New Issue