]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
x86, traps: converge do_debug handlers
authorAlexander van Heukelum <heukelum@fastmail.fm>
Tue, 30 Sep 2008 16:41:37 +0000 (18:41 +0200)
committerIngo Molnar <mingo@elte.hu>
Mon, 13 Oct 2008 08:33:21 +0000 (10:33 +0200)
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>
arch/x86/kernel/traps_32.c
arch/x86/kernel/traps_64.c
include/asm-x86/ptrace.h

index 7eb1203c909d74fdeb28f36a56ab153d7ab52083..953172af6e511919730963fdd6496f879d898095 100644 (file)
@@ -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;
 }
 
index be73323ca9520d9726f8110b64be8ca8991f55dc..a851eca6d04cdd625a3b60cb4dffe55cc6e93e99 100644 (file)
@@ -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);
index ac578f11c1c563e03cb31bf3e1a61fdfe2288c34..a2025525a15ab20dca199a9e3acf95b2d1d7fcff 100644 (file)
@@ -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 *);