aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAlexander van Heukelum <heukelum@fastmail.fm>2008-09-30 12:41:37 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-13 04:33:21 -0400
commit3d2a71a596bd9c761c8487a2178e95f8a61da083 (patch)
treeeb02df788007f136e20ec557009242992396c845 /arch
parente407d62088b7f61f38e1086062650c75a4f2757a (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/traps_32.c30
-rw-r--r--arch/x86/kernel/traps_64.c17
2 files changed, 30 insertions, 17 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c
index 7eb1203c909d..953172af6e51 100644
--- a/arch/x86/kernel/traps_32.c
+++ b/arch/x86/kernel/traps_32.c
@@ -88,6 +88,20 @@ static inline void conditional_sti(struct pt_regs *regs)
88 local_irq_enable(); 88 local_irq_enable();
89} 89}
90 90
91static inline void preempt_conditional_sti(struct pt_regs *regs)
92{
93 inc_preempt_count();
94 if (regs->flags & X86_EFLAGS_IF)
95 local_irq_enable();
96}
97
98static inline void preempt_conditional_cli(struct pt_regs *regs)
99{
100 if (regs->flags & X86_EFLAGS_IF)
101 local_irq_disable();
102 dec_preempt_count();
103}
104
91static inline void 105static inline void
92die_if_kernel(const char *str, struct pt_regs *regs, long err) 106die_if_kernel(const char *str, struct pt_regs *regs, long err)
93{ 107{
@@ -498,7 +512,7 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
498dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) 512dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
499{ 513{
500 struct task_struct *tsk = current; 514 struct task_struct *tsk = current;
501 unsigned int condition; 515 unsigned long condition;
502 int si_code; 516 int si_code;
503 517
504 get_debugreg(condition, 6); 518 get_debugreg(condition, 6);
@@ -512,9 +526,9 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
512 if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, 526 if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
513 SIGTRAP) == NOTIFY_STOP) 527 SIGTRAP) == NOTIFY_STOP)
514 return; 528 return;
529
515 /* It's safe to allow irq's after DR6 has been saved */ 530 /* It's safe to allow irq's after DR6 has been saved */
516 if (regs->flags & X86_EFLAGS_IF) 531 preempt_conditional_sti(regs);
517 local_irq_enable();
518 532
519 /* Mask out spurious debug traps due to lazy DR7 setting */ 533 /* Mask out spurious debug traps due to lazy DR7 setting */
520 if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { 534 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 * kernel space (but re-enable TF when returning to user mode). 547 * kernel space (but re-enable TF when returning to user mode).
534 */ 548 */
535 if (condition & DR_STEP) { 549 if (condition & DR_STEP) {
536 /*
537 * We already checked v86 mode above, so we can
538 * check for kernel mode by just checking the CPL
539 * of CS.
540 */
541 if (!user_mode(regs)) 550 if (!user_mode(regs))
542 goto clear_TF_reenable; 551 goto clear_TF_reenable;
543 } 552 }
544 553
545 si_code = get_si_code((unsigned long)condition); 554 si_code = get_si_code(condition);
546 /* Ok, finally something we can handle */ 555 /* Ok, finally something we can handle */
547 send_sigtrap(tsk, regs, error_code, si_code); 556 send_sigtrap(tsk, regs, error_code, si_code);
548 557
@@ -552,15 +561,18 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
552 */ 561 */
553clear_dr7: 562clear_dr7:
554 set_debugreg(0, 7); 563 set_debugreg(0, 7);
564 preempt_conditional_cli(regs);
555 return; 565 return;
556 566
557debug_vm86: 567debug_vm86:
558 handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); 568 handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
569 preempt_conditional_cli(regs);
559 return; 570 return;
560 571
561clear_TF_reenable: 572clear_TF_reenable:
562 set_tsk_thread_flag(tsk, TIF_SINGLESTEP); 573 set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
563 regs->flags &= ~X86_EFLAGS_TF; 574 regs->flags &= ~X86_EFLAGS_TF;
575 preempt_conditional_cli(regs);
564 return; 576 return;
565} 577}
566 578
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c
index be73323ca952..a851eca6d04c 100644
--- a/arch/x86/kernel/traps_64.c
+++ b/arch/x86/kernel/traps_64.c
@@ -380,7 +380,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
380{ 380{
381 struct task_struct *tsk = current; 381 struct task_struct *tsk = current;
382 unsigned long condition; 382 unsigned long condition;
383 siginfo_t info; 383 int si_code;
384 384
385 get_debugreg(condition, 6); 385 get_debugreg(condition, 6);
386 386
@@ -394,6 +394,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
394 SIGTRAP) == NOTIFY_STOP) 394 SIGTRAP) == NOTIFY_STOP)
395 return; 395 return;
396 396
397 /* It's safe to allow irq's after DR6 has been saved */
397 preempt_conditional_sti(regs); 398 preempt_conditional_sti(regs);
398 399
399 /* Mask out spurious debug traps due to lazy DR7 setting */ 400 /* 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 goto clear_dr7; 403 goto clear_dr7;
403 } 404 }
404 405
406 /* Save debug status register where ptrace can see it */
405 tsk->thread.debugreg6 = condition; 407 tsk->thread.debugreg6 = condition;
406 408
407 /* 409 /*
@@ -413,15 +415,14 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
413 goto clear_TF_reenable; 415 goto clear_TF_reenable;
414 } 416 }
415 417
418 si_code = get_si_code(condition);
416 /* Ok, finally something we can handle */ 419 /* Ok, finally something we can handle */
417 tsk->thread.trap_no = 1; 420 send_sigtrap(tsk, regs, error_code, si_code);
418 tsk->thread.error_code = error_code;
419 info.si_signo = SIGTRAP;
420 info.si_errno = 0;
421 info.si_code = get_si_code(condition);
422 info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
423 force_sig_info(SIGTRAP, &info, tsk);
424 421
422 /*
423 * Disable additional traps. They'll be re-enabled when
424 * the signal is delivered.
425 */
425clear_dr7: 426clear_dr7:
426 set_debugreg(0, 7); 427 set_debugreg(0, 7);
427 preempt_conditional_cli(regs); 428 preempt_conditional_cli(regs);