diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-02 02:36:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-02 02:36:47 +0000 |
commit | 8624512aa908741ba2795200133eae0d7f4557ea (patch) | |
tree | d5d3036fccf2604f4c98dedc11e8adb929d6b52e /arch/ia64/kernel/traps.c | |
parent | 7b8f5d6f1d45d9f9de1d26e7d3c32aa5af11b488 (diff) |
Merge with 2.3.48.
Diffstat (limited to 'arch/ia64/kernel/traps.c')
-rw-r--r-- | arch/ia64/kernel/traps.c | 116 |
1 files changed, 97 insertions, 19 deletions
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index c242622ec..1f5106036 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -110,15 +110,75 @@ void ia64_bad_break (unsigned long break_num, struct pt_regs *regs) { siginfo_t siginfo; + int sig, code; - /* gdb uses a break number of 0xccccc for debug breakpoints: */ - if (break_num != 0xccccc) - die_if_kernel("Bad break", regs, break_num); + /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + siginfo.si_imm = break_num; - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = break_num; /* XXX is it legal to abuse si_errno like this? */ - siginfo.si_code = TRAP_BRKPT; - send_sig_info(SIGTRAP, &siginfo, current); + switch (break_num) { + case 0: /* unknown error */ + sig = SIGILL; code = ILL_ILLOPC; + break; + + case 1: /* integer divide by zero */ + sig = SIGFPE; code = FPE_INTDIV; + break; + + case 2: /* integer overflow */ + sig = SIGFPE; code = FPE_INTOVF; + break; + + case 3: /* range check/bounds check */ + sig = SIGFPE; code = FPE_FLTSUB; + break; + + case 4: /* null pointer dereference */ + sig = SIGSEGV; code = SEGV_MAPERR; + break; + + case 5: /* misaligned data */ + sig = SIGSEGV; code = BUS_ADRALN; + break; + + case 6: /* decimal overflow */ + sig = SIGFPE; code = __FPE_DECOVF; + break; + + case 7: /* decimal divide by zero */ + sig = SIGFPE; code = __FPE_DECDIV; + break; + + case 8: /* packed decimal error */ + sig = SIGFPE; code = __FPE_DECERR; + break; + + case 9: /* invalid ASCII digit */ + sig = SIGFPE; code = __FPE_INVASC; + break; + + case 10: /* invalid decimal digit */ + sig = SIGFPE; code = __FPE_INVDEC; + break; + + case 11: /* paragraph stack overflow */ + sig = SIGSEGV; code = __SEGV_PSTKOVF; + break; + + default: + if (break_num < 0x40000 || break_num > 0x100000) + die_if_kernel("Bad break", regs, break_num); + + if (break_num < 0x80000) { + sig = SIGILL; code = __ILL_BREAK; + } else { + sig = SIGTRAP; code = TRAP_BRKPT; + } + } + siginfo.si_signo = sig; + siginfo.si_errno = 0; + siginfo.si_code = code; + send_sig_info(sig, &siginfo, current); } /* @@ -240,6 +300,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) { long exception, bundle[2]; unsigned long fault_ip; + struct siginfo siginfo; static int fpu_swa_count = 0; static unsigned long last_time; @@ -265,21 +326,41 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ia64_increment_ip(regs); } else if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); - return -2; + return -1; } else { /* is next instruction a trap? */ if (exception & 2) { ia64_increment_ip(regs); } - return -1; + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + if (isr & 0x11) { + siginfo.si_code = FPE_FLTINV; + } else if (isr & 0x44) { + siginfo.si_code = FPE_FLTDIV; + } + send_sig_info(SIGFPE, &siginfo, current); } } else { if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); - return -2; + return -1; } else if (exception != 0) { /* raise exception */ - return -1; + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + if (isr & 0x880) { + siginfo.si_code = FPE_FLTOVF; + } else if (isr & 0x1100) { + siginfo.si_code = FPE_FLTUND; + } else if (isr & 0x2200) { + siginfo.si_code = FPE_FLTRES; + } + send_sig_info(SIGFPE, &siginfo, current); } } return 0; @@ -369,22 +450,19 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, return; case 30: /* Unaligned fault */ - sprintf(buf, "Unaligned access in kernel mode---don't do this!"); + sprintf(buf, "Kernel unaligned trap accessing %016lx (ip=%016lx)!", + ifa, regs->cr_iip + ia64_psr(regs)->ri); break; case 32: /* fp fault */ case 33: /* fp trap */ - result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); + result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, &isr); if (result < 0) { siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; - siginfo.si_code = 0; /* XXX fix me */ + siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - send_sig_info(SIGFPE, &siginfo, current); - if (result == -1) - send_sig_info(SIGFPE, &siginfo, current); - else - force_sig(SIGFPE, current); + force_sig(SIGFPE, current); } return; |