linux/arch/m68knommu/kernel/traps.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/m68knommu/kernel/traps.c
   3 *
   4 *  Copyright (C) 1993, 1994 by Hamish Macdonald
   5 *
   6 *  68040 fixes by Michael Rausch
   7 *  68040 fixes by Martin Apel
   8 *  68060 fixes by Roman Hodek
   9 *  68060 fixes by Jesper Skov
  10 *
  11 * This file is subject to the terms and conditions of the GNU General Public
  12 * License.  See the file COPYING in the main directory of this archive
  13 * for more details.
  14 */
  15
  16/*
  17 * Sets up all exception vectors
  18 */
  19#include <linux/sched.h>
  20#include <linux/signal.h>
  21#include <linux/kernel.h>
  22#include <linux/mm.h>
  23#include <linux/module.h>
  24#include <linux/types.h>
  25#include <linux/user.h>
  26#include <linux/string.h>
  27#include <linux/linkage.h>
  28#include <linux/init.h>
  29#include <linux/ptrace.h>
  30#include <linux/kallsyms.h>
  31
  32#include <asm/setup.h>
  33#include <asm/fpu.h>
  34#include <asm/system.h>
  35#include <asm/uaccess.h>
  36#include <asm/traps.h>
  37#include <asm/pgtable.h>
  38#include <asm/machdep.h>
  39#include <asm/siginfo.h>
  40
  41static char const * const vec_names[] = {
  42        "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
  43        "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
  44        "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
  45        "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
  46        "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
  47        "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
  48        "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
  49        "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
  50        "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
  51        "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
  52        "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
  53        "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
  54        "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
  55        "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
  56        "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
  57        "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
  58        "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
  59        "FPCP UNSUPPORTED OPERATION",
  60        "MMU CONFIGURATION ERROR"
  61};
  62
  63void __init trap_init(void)
  64{
  65}
  66
  67void die_if_kernel(char *str, struct pt_regs *fp, int nr)
  68{
  69        if (!(fp->sr & PS_S))
  70                return;
  71
  72        console_verbose();
  73        printk(KERN_EMERG "%s: %08x\n",str,nr);
  74        printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
  75               fp->pc, fp->sr, fp, fp->a2);
  76        printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
  77               fp->d0, fp->d1, fp->d2, fp->d3);
  78        printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
  79               fp->d4, fp->d5, fp->a0, fp->a1);
  80
  81        printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
  82                current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
  83        show_stack(NULL, (unsigned long *)(fp + 1));
  84        add_taint(TAINT_DIE);
  85        do_exit(SIGSEGV);
  86}
  87
  88asmlinkage void buserr_c(struct frame *fp)
  89{
  90        /* Only set esp0 if coming from user mode */
  91        if (user_mode(&fp->ptregs))
  92                current->thread.esp0 = (unsigned long) fp;
  93
  94#if defined(DEBUG)
  95        printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
  96#endif
  97
  98        die_if_kernel("bad frame format",&fp->ptregs,0);
  99#if defined(DEBUG)
 100        printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
 101#endif
 102        force_sig(SIGSEGV, current);
 103}
 104
 105static void print_this_address(unsigned long addr, int i)
 106{
 107#ifdef CONFIG_KALLSYMS
 108        printk(KERN_EMERG " [%08lx] ", addr);
 109        print_symbol(KERN_CONT "%s\n", addr);
 110#else
 111        if (i % 5)
 112                printk(KERN_CONT " [%08lx] ", addr);
 113        else
 114                printk(KERN_EMERG " [%08lx] ", addr);
 115        i++;
 116#endif
 117}
 118
 119int kstack_depth_to_print = 48;
 120
 121static void __show_stack(struct task_struct *task, unsigned long *stack)
 122{
 123        unsigned long *endstack, addr;
 124#ifdef CONFIG_FRAME_POINTER
 125        unsigned long *last_stack;
 126#endif
 127        int i;
 128
 129        if (!stack)
 130                stack = (unsigned long *)task->thread.ksp;
 131
 132        addr = (unsigned long) stack;
 133        endstack = (unsigned long *) PAGE_ALIGN(addr);
 134
 135        printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
 136        for (i = 0; i < kstack_depth_to_print; i++) {
 137                if (stack + 1 + i > endstack)
 138                        break;
 139                if (i % 8 == 0)
 140                        printk(KERN_EMERG "       ");
 141                printk(KERN_CONT " %08lx", *(stack + i));
 142        }
 143        printk("\n");
 144        i = 0;
 145
 146#ifdef CONFIG_FRAME_POINTER
 147        printk(KERN_EMERG "Call Trace:\n");
 148
 149        last_stack = stack - 1;
 150        while (stack <= endstack && stack > last_stack) {
 151
 152                addr = *(stack + 1);
 153                print_this_address(addr, i);
 154                i++;
 155
 156                last_stack = stack;
 157                stack = (unsigned long *)*stack;
 158        }
 159        printk("\n");
 160#else
 161        printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
 162        while (stack <= endstack) {
 163                addr = *stack++;
 164                /*
 165                 * If the address is either in the text segment of the kernel,
 166                 * or in a region which is occupied by a module then it *may*
 167                 * be the address of a calling routine; if so, print it so that
 168                 * someone tracing down the cause of the crash will be able to
 169                 * figure out the call path that was taken.
 170                 */
 171                if (__kernel_text_address(addr)) {
 172                        print_this_address(addr, i);
 173                        i++;
 174                }
 175        }
 176        printk(KERN_CONT "\n");
 177#endif
 178}
 179
 180void bad_super_trap(struct frame *fp)
 181{
 182        int vector = (fp->ptregs.vector >> 2) & 0xff;
 183
 184        console_verbose();
 185        if (vector < ARRAY_SIZE(vec_names))
 186                printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
 187                        vec_names[vector],
 188                        fp->ptregs.format);
 189        else
 190                printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
 191                        vector,
 192                        fp->ptregs.format);
 193        printk (KERN_WARNING "Current process id is %d\n", current->pid);
 194        die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
 195}
 196
 197asmlinkage void trap_c(struct frame *fp)
 198{
 199        int sig;
 200        int vector = (fp->ptregs.vector >> 2) & 0xff;
 201        siginfo_t info;
 202
 203        if (fp->ptregs.sr & PS_S) {
 204                if (vector == VEC_TRACE) {
 205                        /* traced a trapping instruction */
 206                } else
 207                        bad_super_trap(fp);
 208                return;
 209        }
 210
 211        /* send the appropriate signal to the user program */
 212        switch (vector) {
 213            case VEC_ADDRERR:
 214                info.si_code = BUS_ADRALN;
 215                sig = SIGBUS;
 216                break;
 217            case VEC_ILLEGAL:
 218            case VEC_LINE10:
 219            case VEC_LINE11:
 220                info.si_code = ILL_ILLOPC;
 221                sig = SIGILL;
 222                break;
 223            case VEC_PRIV:
 224                info.si_code = ILL_PRVOPC;
 225                sig = SIGILL;
 226                break;
 227            case VEC_COPROC:
 228                info.si_code = ILL_COPROC;
 229                sig = SIGILL;
 230                break;
 231            case VEC_TRAP1: /* gdbserver breakpoint */
 232                fp->ptregs.pc -= 2;
 233                info.si_code = TRAP_TRACE;
 234                sig = SIGTRAP;
 235                break;
 236            case VEC_TRAP2:
 237            case VEC_TRAP3:
 238            case VEC_TRAP4:
 239            case VEC_TRAP5:
 240            case VEC_TRAP6:
 241            case VEC_TRAP7:
 242            case VEC_TRAP8:
 243            case VEC_TRAP9:
 244            case VEC_TRAP10:
 245            case VEC_TRAP11:
 246            case VEC_TRAP12:
 247            case VEC_TRAP13:
 248            case VEC_TRAP14:
 249                info.si_code = ILL_ILLTRP;
 250                sig = SIGILL;
 251                break;
 252            case VEC_FPBRUC:
 253            case VEC_FPOE:
 254            case VEC_FPNAN:
 255                info.si_code = FPE_FLTINV;
 256                sig = SIGFPE;
 257                break;
 258            case VEC_FPIR:
 259                info.si_code = FPE_FLTRES;
 260                sig = SIGFPE;
 261                break;
 262            case VEC_FPDIVZ:
 263                info.si_code = FPE_FLTDIV;
 264                sig = SIGFPE;
 265                break;
 266            case VEC_FPUNDER:
 267                info.si_code = FPE_FLTUND;
 268                sig = SIGFPE;
 269                break;
 270            case VEC_FPOVER:
 271                info.si_code = FPE_FLTOVF;
 272                sig = SIGFPE;
 273                break;
 274            case VEC_ZERODIV:
 275                info.si_code = FPE_INTDIV;
 276                sig = SIGFPE;
 277                break;
 278            case VEC_CHK:
 279            case VEC_TRAP:
 280                info.si_code = FPE_INTOVF;
 281                sig = SIGFPE;
 282                break;
 283            case VEC_TRACE:             /* ptrace single step */
 284                info.si_code = TRAP_TRACE;
 285                sig = SIGTRAP;
 286                break;
 287            case VEC_TRAP15:            /* breakpoint */
 288                info.si_code = TRAP_BRKPT;
 289                sig = SIGTRAP;
 290                break;
 291            default:
 292                info.si_code = ILL_ILLOPC;
 293                sig = SIGILL;
 294                break;
 295        }
 296        info.si_signo = sig;
 297        info.si_errno = 0;
 298        switch (fp->ptregs.format) {
 299            default:
 300                info.si_addr = (void *) fp->ptregs.pc;
 301                break;
 302            case 2:
 303                info.si_addr = (void *) fp->un.fmt2.iaddr;
 304                break;
 305            case 7:
 306                info.si_addr = (void *) fp->un.fmt7.effaddr;
 307                break;
 308            case 9:
 309                info.si_addr = (void *) fp->un.fmt9.iaddr;
 310                break;
 311            case 10:
 312                info.si_addr = (void *) fp->un.fmta.daddr;
 313                break;
 314            case 11:
 315                info.si_addr = (void *) fp->un.fmtb.daddr;
 316                break;
 317        }
 318        force_sig_info (sig, &info, current);
 319}
 320
 321asmlinkage void set_esp0(unsigned long ssp)
 322{
 323        current->thread.esp0 = ssp;
 324}
 325
 326/*
 327 * The architecture-independent backtrace generator
 328 */
 329void dump_stack(void)
 330{
 331        /*
 332         * We need frame pointers for this little trick, which works as follows:
 333         *
 334         * +------------+ 0x00
 335         * | Next SP    |       -> 0x0c
 336         * +------------+ 0x04
 337         * | Caller     |
 338         * +------------+ 0x08
 339         * | Local vars |       -> our stack var
 340         * +------------+ 0x0c
 341         * | Next SP    |       -> 0x18, that is what we pass to show_stack()
 342         * +------------+ 0x10
 343         * | Caller     |
 344         * +------------+ 0x14
 345         * | Local vars |
 346         * +------------+ 0x18
 347         * | ...        |
 348         * +------------+
 349         */
 350
 351        unsigned long *stack;
 352
 353        stack = (unsigned long *)&stack;
 354        stack++;
 355        __show_stack(current, stack);
 356}
 357EXPORT_SYMBOL(dump_stack);
 358
 359void show_stack(struct task_struct *task, unsigned long *stack)
 360{
 361        if (!stack && !task)
 362                dump_stack();
 363        else
 364                __show_stack(task, stack);
 365}
 366