Skip to content

Commit

Permalink
[MIPS] Fix handling of trap and breakpoint instructions
Browse files Browse the repository at this point in the history
With fixes and cleanups from Atsushi Nemoto ([email protected]).

Signed-off-by: Ralf Baechle <[email protected]>
  • Loading branch information
ralfbaechle committed Apr 28, 2008
1 parent cf85c10 commit df27005
Showing 1 changed file with 37 additions and 52 deletions.
89 changes: 37 additions & 52 deletions arch/mips/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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;
Expand All @@ -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:
Expand Down

0 comments on commit df27005

Please sign in to comment.