Commit df2700519c84ee8ee1e5ea165725c651f6d4d1a4

Authored by Ralf Baechle
1 parent cf85c10983

[MIPS] Fix handling of trap and breakpoint instructions

With fixes and cleanups from Atsushi Nemoto (anemo@mba.ocn.ne.jp).

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

Showing 1 changed file with 37 additions and 52 deletions Side-by-side Diff

arch/mips/kernel/traps.c
... ... @@ -675,35 +675,24 @@
675 675 force_sig_info(SIGFPE, &info, current);
676 676 }
677 677  
678   -asmlinkage void do_bp(struct pt_regs *regs)
  678 +static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
  679 + const char *str)
679 680 {
680   - unsigned int opcode, bcode;
681 681 siginfo_t info;
  682 + char b[40];
682 683  
683   - if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
684   - goto out_sigsegv;
685   -
686 684 /*
687   - * There is the ancient bug in the MIPS assemblers that the break
688   - * code starts left to bit 16 instead to bit 6 in the opcode.
689   - * Gas is bug-compatible, but not always, grrr...
690   - * We handle both cases with a simple heuristics. --macro
691   - */
692   - bcode = ((opcode >> 6) & ((1 << 20) - 1));
693   - if (bcode < (1 << 10))
694   - bcode <<= 10;
695   -
696   - /*
697   - * (A short test says that IRIX 5.3 sends SIGTRAP for all break
698   - * insns, even for break codes that indicate arithmetic failures.
699   - * Weird ...)
  685 + * A short test says that IRIX 5.3 sends SIGTRAP for all trap
  686 + * insns, even for trap and break codes that indicate arithmetic
  687 + * failures. Weird ...
700 688 * But should we continue the brokenness??? --macro
701 689 */
702   - switch (bcode) {
703   - case BRK_OVERFLOW << 10:
704   - case BRK_DIVZERO << 10:
705   - die_if_kernel("Break instruction in kernel code", regs);
706   - if (bcode == (BRK_DIVZERO << 10))
  690 + switch (code) {
  691 + case BRK_OVERFLOW:
  692 + case BRK_DIVZERO:
  693 + scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
  694 + die_if_kernel(b, regs);
  695 + if (code == BRK_DIVZERO)
707 696 info.si_code = FPE_INTDIV;
708 697 else
709 698 info.si_code = FPE_INTOVF;
710 699  
711 700  
... ... @@ -713,12 +702,34 @@
713 702 force_sig_info(SIGFPE, &info, current);
714 703 break;
715 704 case BRK_BUG:
716   - die("Kernel bug detected", regs);
  705 + die_if_kernel("Kernel bug detected", regs);
  706 + force_sig(SIGTRAP, current);
717 707 break;
718 708 default:
719   - die_if_kernel("Break instruction in kernel code", regs);
  709 + scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
  710 + die_if_kernel(b, regs);
720 711 force_sig(SIGTRAP, current);
721 712 }
  713 +}
  714 +
  715 +asmlinkage void do_bp(struct pt_regs *regs)
  716 +{
  717 + unsigned int opcode, bcode;
  718 +
  719 + if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
  720 + goto out_sigsegv;
  721 +
  722 + /*
  723 + * There is the ancient bug in the MIPS assemblers that the break
  724 + * code starts left to bit 16 instead to bit 6 in the opcode.
  725 + * Gas is bug-compatible, but not always, grrr...
  726 + * We handle both cases with a simple heuristics. --macro
  727 + */
  728 + bcode = ((opcode >> 6) & ((1 << 20) - 1));
  729 + if (bcode >= (1 << 10))
  730 + bcode >>= 10;
  731 +
  732 + do_trap_or_bp(regs, bcode, "Break");
722 733 return;
723 734  
724 735 out_sigsegv:
... ... @@ -728,7 +739,6 @@
728 739 asmlinkage void do_tr(struct pt_regs *regs)
729 740 {
730 741 unsigned int opcode, tcode = 0;
731   - siginfo_t info;
732 742  
733 743 if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
734 744 goto out_sigsegv;
... ... @@ -737,32 +747,7 @@
737 747 if (!(opcode & OPCODE))
738 748 tcode = ((opcode >> 6) & ((1 << 10) - 1));
739 749  
740   - /*
741   - * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
742   - * insns, even for trap codes that indicate arithmetic failures.
743   - * Weird ...)
744   - * But should we continue the brokenness??? --macro
745   - */
746   - switch (tcode) {
747   - case BRK_OVERFLOW:
748   - case BRK_DIVZERO:
749   - die_if_kernel("Trap instruction in kernel code", regs);
750   - if (tcode == BRK_DIVZERO)
751   - info.si_code = FPE_INTDIV;
752   - else
753   - info.si_code = FPE_INTOVF;
754   - info.si_signo = SIGFPE;
755   - info.si_errno = 0;
756   - info.si_addr = (void __user *) regs->cp0_epc;
757   - force_sig_info(SIGFPE, &info, current);
758   - break;
759   - case BRK_BUG:
760   - die("Kernel bug detected", regs);
761   - break;
762   - default:
763   - die_if_kernel("Trap instruction in kernel code", regs);
764   - force_sig(SIGTRAP, current);
765   - }
  750 + do_trap_or_bp(regs, tcode, "Trap");
766 751 return;
767 752  
768 753 out_sigsegv: