|
@@ -675,35 +675,24 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
|
|
|
force_sig_info(SIGFPE, &info, current);
|
|
|
}
|
|
|
|
|
|
-asmlinkage void do_bp(struct pt_regs *regs)
|
|
|
+static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
|
|
|
+ const char *str)
|
|
|
{
|
|
|
- unsigned int opcode, bcode;
|
|
|
siginfo_t info;
|
|
|
-
|
|
|
- if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
|
|
|
- goto out_sigsegv;
|
|
|
-
|
|
|
- /*
|
|
|
- * There is the ancient bug in the MIPS assemblers that the break
|
|
|
- * code starts left to bit 16 instead to bit 6 in the opcode.
|
|
|
- * Gas is bug-compatible, but not always, grrr...
|
|
|
- * We handle both cases with a simple heuristics. --macro
|
|
|
- */
|
|
|
- bcode = ((opcode >> 6) & ((1 << 20) - 1));
|
|
|
- if (bcode < (1 << 10))
|
|
|
- bcode <<= 10;
|
|
|
+ char b[40];
|
|
|
|
|
|
/*
|
|
|
- * (A short test says that IRIX 5.3 sends SIGTRAP for all break
|
|
|
- * insns, even for break codes that indicate arithmetic failures.
|
|
|
- * Weird ...)
|
|
|
+ * A short test says that IRIX 5.3 sends SIGTRAP for all trap
|
|
|
+ * insns, even for trap and break codes that indicate arithmetic
|
|
|
+ * failures. Weird ...
|
|
|
* But should we continue the brokenness??? --macro
|
|
|
*/
|
|
|
- switch (bcode) {
|
|
|
- case BRK_OVERFLOW << 10:
|
|
|
- case BRK_DIVZERO << 10:
|
|
|
- die_if_kernel("Break instruction in kernel code", regs);
|
|
|
- if (bcode == (BRK_DIVZERO << 10))
|
|
|
+ switch (code) {
|
|
|
+ case BRK_OVERFLOW:
|
|
|
+ case BRK_DIVZERO:
|
|
|
+ scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
|
|
|
+ die_if_kernel(b, regs);
|
|
|
+ if (code == BRK_DIVZERO)
|
|
|
info.si_code = FPE_INTDIV;
|
|
|
else
|
|
|
info.si_code = FPE_INTOVF;
|
|
@@ -713,12 +702,34 @@ asmlinkage void do_bp(struct pt_regs *regs)
|
|
|
force_sig_info(SIGFPE, &info, current);
|
|
|
break;
|
|
|
case BRK_BUG:
|
|
|
- die("Kernel bug detected", regs);
|
|
|
+ die_if_kernel("Kernel bug detected", regs);
|
|
|
+ force_sig(SIGTRAP, current);
|
|
|
break;
|
|
|
default:
|
|
|
- die_if_kernel("Break instruction in kernel code", regs);
|
|
|
+ scnprintf(b, sizeof(b), "%s instruction in kernel code", str);
|
|
|
+ die_if_kernel(b, regs);
|
|
|
force_sig(SIGTRAP, current);
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage void do_bp(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ unsigned int opcode, bcode;
|
|
|
+
|
|
|
+ if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
|
|
|
+ goto out_sigsegv;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There is the ancient bug in the MIPS assemblers that the break
|
|
|
+ * code starts left to bit 16 instead to bit 6 in the opcode.
|
|
|
+ * Gas is bug-compatible, but not always, grrr...
|
|
|
+ * We handle both cases with a simple heuristics. --macro
|
|
|
+ */
|
|
|
+ bcode = ((opcode >> 6) & ((1 << 20) - 1));
|
|
|
+ if (bcode >= (1 << 10))
|
|
|
+ bcode >>= 10;
|
|
|
+
|
|
|
+ do_trap_or_bp(regs, bcode, "Break");
|
|
|
return;
|
|
|
|
|
|
out_sigsegv:
|
|
@@ -728,7 +739,6 @@ out_sigsegv:
|
|
|
asmlinkage void do_tr(struct pt_regs *regs)
|
|
|
{
|
|
|
unsigned int opcode, tcode = 0;
|
|
|
- siginfo_t info;
|
|
|
|
|
|
if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
|
|
|
goto out_sigsegv;
|
|
@@ -737,32 +747,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
|
|
|
if (!(opcode & OPCODE))
|
|
|
tcode = ((opcode >> 6) & ((1 << 10) - 1));
|
|
|
|
|
|
- /*
|
|
|
- * (A short test says that IRIX 5.3 sends SIGTRAP for all trap
|
|
|
- * insns, even for trap codes that indicate arithmetic failures.
|
|
|
- * Weird ...)
|
|
|
- * But should we continue the brokenness??? --macro
|
|
|
- */
|
|
|
- switch (tcode) {
|
|
|
- case BRK_OVERFLOW:
|
|
|
- case BRK_DIVZERO:
|
|
|
- die_if_kernel("Trap instruction in kernel code", regs);
|
|
|
- if (tcode == BRK_DIVZERO)
|
|
|
- info.si_code = FPE_INTDIV;
|
|
|
- else
|
|
|
- info.si_code = FPE_INTOVF;
|
|
|
- info.si_signo = SIGFPE;
|
|
|
- info.si_errno = 0;
|
|
|
- info.si_addr = (void __user *) regs->cp0_epc;
|
|
|
- force_sig_info(SIGFPE, &info, current);
|
|
|
- break;
|
|
|
- case BRK_BUG:
|
|
|
- die("Kernel bug detected", regs);
|
|
|
- break;
|
|
|
- default:
|
|
|
- die_if_kernel("Trap instruction in kernel code", regs);
|
|
|
- force_sig(SIGTRAP, current);
|
|
|
- }
|
|
|
+ do_trap_or_bp(regs, tcode, "Trap");
|
|
|
return;
|
|
|
|
|
|
out_sigsegv:
|