[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>
This commit is contained in:
parent
cf85c10983
commit
df2700519c
1 changed files with 41 additions and 56 deletions
|
@ -675,10 +675,46 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
|
|||
force_sig_info(SIGFPE, &info, current);
|
||||
}
|
||||
|
||||
static void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
|
||||
const char *str)
|
||||
{
|
||||
siginfo_t info;
|
||||
char b[40];
|
||||
|
||||
/*
|
||||
* 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 (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;
|
||||
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_if_kernel("Kernel bug detected", regs);
|
||||
force_sig(SIGTRAP, current);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
siginfo_t info;
|
||||
|
||||
if (__get_user(opcode, (unsigned int __user *) exception_epc(regs)))
|
||||
goto out_sigsegv;
|
||||
|
@ -690,35 +726,10 @@ asmlinkage void do_bp(struct pt_regs *regs)
|
|||
* We handle both cases with a simple heuristics. --macro
|
||||
*/
|
||||
bcode = ((opcode >> 6) & ((1 << 20) - 1));
|
||||
if (bcode < (1 << 10))
|
||||
bcode <<= 10;
|
||||
if (bcode >= (1 << 10))
|
||||
bcode >>= 10;
|
||||
|
||||
/*
|
||||
* (A short test says that IRIX 5.3 sends SIGTRAP for all break
|
||||
* insns, even for 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))
|
||||
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("Break instruction in kernel code", regs);
|
||||
force_sig(SIGTRAP, current);
|
||||
}
|
||||
do_trap_or_bp(regs, bcode, "Break");
|
||||
return;
|
||||
|
||||
out_sigsegv:
|
||||
|
@ -728,7 +739,6 @@ asmlinkage void do_bp(struct pt_regs *regs)
|
|||
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:
|
||||
|
|
Loading…
Reference in a new issue