root/arch/sh/kernel/traps.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. die
  2. die_if_kernel
  3. die_if_no_fixup
  4. handle_BUG
  5. is_valid_bugaddr
  6. BUILD_TRAP_HANDLER
  7. BUILD_TRAP_HANDLER
  8. BUILD_TRAP_HANDLER

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/bug.h>
   3 #include <linux/io.h>
   4 #include <linux/types.h>
   5 #include <linux/kdebug.h>
   6 #include <linux/signal.h>
   7 #include <linux/sched.h>
   8 #include <linux/sched/debug.h>
   9 #include <linux/sched/task_stack.h>
  10 #include <linux/uaccess.h>
  11 #include <linux/hardirq.h>
  12 #include <linux/kernel.h>
  13 #include <linux/kexec.h>
  14 #include <linux/sched/signal.h>
  15 
  16 #include <linux/extable.h>
  17 #include <linux/module.h>       /* print_modules */
  18 #include <asm/unwinder.h>
  19 #include <asm/traps.h>
  20 
  21 static DEFINE_SPINLOCK(die_lock);
  22 
  23 void die(const char *str, struct pt_regs *regs, long err)
  24 {
  25         static int die_counter;
  26 
  27         oops_enter();
  28 
  29         spin_lock_irq(&die_lock);
  30         console_verbose();
  31         bust_spinlocks(1);
  32 
  33         printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
  34         print_modules();
  35         show_regs(regs);
  36 
  37         printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
  38                         task_pid_nr(current), task_stack_page(current) + 1);
  39 
  40         if (!user_mode(regs) || in_interrupt())
  41                 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
  42                          (unsigned long)task_stack_page(current));
  43 
  44         notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
  45 
  46         bust_spinlocks(0);
  47         add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
  48         spin_unlock_irq(&die_lock);
  49         oops_exit();
  50 
  51         if (kexec_should_crash(current))
  52                 crash_kexec(regs);
  53 
  54         if (in_interrupt())
  55                 panic("Fatal exception in interrupt");
  56 
  57         if (panic_on_oops)
  58                 panic("Fatal exception");
  59 
  60         do_exit(SIGSEGV);
  61 }
  62 
  63 void die_if_kernel(const char *str, struct pt_regs *regs, long err)
  64 {
  65         if (!user_mode(regs))
  66                 die(str, regs, err);
  67 }
  68 
  69 /*
  70  * try and fix up kernelspace address errors
  71  * - userspace errors just cause EFAULT to be returned, resulting in SEGV
  72  * - kernel/userspace interfaces cause a jump to an appropriate handler
  73  * - other kernel errors are bad
  74  */
  75 void die_if_no_fixup(const char *str, struct pt_regs *regs, long err)
  76 {
  77         if (!user_mode(regs)) {
  78                 const struct exception_table_entry *fixup;
  79                 fixup = search_exception_tables(regs->pc);
  80                 if (fixup) {
  81                         regs->pc = fixup->fixup;
  82                         return;
  83                 }
  84 
  85                 die(str, regs, err);
  86         }
  87 }
  88 
  89 #ifdef CONFIG_GENERIC_BUG
  90 static void handle_BUG(struct pt_regs *regs)
  91 {
  92         const struct bug_entry *bug;
  93         unsigned long bugaddr = regs->pc;
  94         enum bug_trap_type tt;
  95 
  96         if (!is_valid_bugaddr(bugaddr))
  97                 goto invalid;
  98 
  99         bug = find_bug(bugaddr);
 100 
 101         /* Switch unwinders when unwind_stack() is called */
 102         if (bug->flags & BUGFLAG_UNWINDER)
 103                 unwinder_faulted = 1;
 104 
 105         tt = report_bug(bugaddr, regs);
 106         if (tt == BUG_TRAP_TYPE_WARN) {
 107                 regs->pc += instruction_size(bugaddr);
 108                 return;
 109         }
 110 
 111 invalid:
 112         die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
 113 }
 114 
 115 int is_valid_bugaddr(unsigned long addr)
 116 {
 117         insn_size_t opcode;
 118 
 119         if (addr < PAGE_OFFSET)
 120                 return 0;
 121         if (probe_kernel_address((insn_size_t *)addr, opcode))
 122                 return 0;
 123         if (opcode == TRAPA_BUG_OPCODE)
 124                 return 1;
 125 
 126         return 0;
 127 }
 128 #endif
 129 
 130 /*
 131  * Generic trap handler.
 132  */
 133 BUILD_TRAP_HANDLER(debug)
 134 {
 135         TRAP_HANDLER_DECL;
 136 
 137         /* Rewind */
 138         regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
 139 
 140         if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
 141                        SIGTRAP) == NOTIFY_STOP)
 142                 return;
 143 
 144         force_sig(SIGTRAP);
 145 }
 146 
 147 /*
 148  * Special handler for BUG() traps.
 149  */
 150 BUILD_TRAP_HANDLER(bug)
 151 {
 152         TRAP_HANDLER_DECL;
 153 
 154         /* Rewind */
 155         regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
 156 
 157         if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
 158                        SIGTRAP) == NOTIFY_STOP)
 159                 return;
 160 
 161 #ifdef CONFIG_GENERIC_BUG
 162         if (__kernel_text_address(instruction_pointer(regs))) {
 163                 insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
 164                 if (insn == TRAPA_BUG_OPCODE)
 165                         handle_BUG(regs);
 166                 return;
 167         }
 168 #endif
 169 
 170         force_sig(SIGTRAP);
 171 }
 172 
 173 BUILD_TRAP_HANDLER(nmi)
 174 {
 175         unsigned int cpu = smp_processor_id();
 176         TRAP_HANDLER_DECL;
 177 
 178         nmi_enter();
 179         nmi_count(cpu)++;
 180 
 181         switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
 182         case NOTIFY_OK:
 183         case NOTIFY_STOP:
 184                 break;
 185         case NOTIFY_BAD:
 186                 die("Fatal Non-Maskable Interrupt", regs, SIGINT);
 187         default:
 188                 printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n");
 189                 break;
 190         }
 191 
 192         nmi_exit();
 193 }

/* [<][>][^][v][top][bottom][index][help] */