diff options
author | Alexander van Heukelum <heukelum@fastmail.fm> | 2008-09-30 12:41:37 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-13 04:33:21 -0400 |
commit | 3d2a71a596bd9c761c8487a2178e95f8a61da083 (patch) | |
tree | eb02df788007f136e20ec557009242992396c845 /arch | |
parent | e407d62088b7f61f38e1086062650c75a4f2757a (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.c | 30 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 17 |
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 | ||
91 | static 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 | |||
98 | static 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 | |||
91 | static inline void | 105 | static inline void |
92 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | 106 | die_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) | |||
498 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | 512 | dotraplinkage 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 | */ |
553 | clear_dr7: | 562 | clear_dr7: |
554 | set_debugreg(0, 7); | 563 | set_debugreg(0, 7); |
564 | preempt_conditional_cli(regs); | ||
555 | return; | 565 | return; |
556 | 566 | ||
557 | debug_vm86: | 567 | debug_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 | ||
561 | clear_TF_reenable: | 572 | clear_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 | */ | ||
425 | clear_dr7: | 426 | clear_dr7: |
426 | set_debugreg(0, 7); | 427 | set_debugreg(0, 7); |
427 | preempt_conditional_cli(regs); | 428 | preempt_conditional_cli(regs); |