0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/sched/signal.h>
0014 #include <linux/kdebug.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/ptrace.h>
0017 #include <linux/kprobes.h>
0018 #include <linux/kgdb.h>
0019 #include <asm/setup.h>
0020 #include <asm/unaligned.h>
0021 #include <asm/kprobes.h>
0022
0023 void die(const char *str, struct pt_regs *regs, unsigned long address)
0024 {
0025 show_kernel_fault_diag(str, regs, address);
0026
0027
0028 __asm__("flag 1");
0029 }
0030
0031
0032
0033
0034
0035
0036 static noinline int
0037 unhandled_exception(const char *str, struct pt_regs *regs,
0038 int signo, int si_code, void __user *addr)
0039 {
0040 if (user_mode(regs)) {
0041 struct task_struct *tsk = current;
0042
0043 tsk->thread.fault_address = (__force unsigned int)addr;
0044
0045 force_sig_fault(signo, si_code, addr);
0046
0047 } else {
0048
0049 if (fixup_exception(regs))
0050 return 0;
0051
0052 die(str, regs, (unsigned long)addr);
0053 }
0054
0055 return 1;
0056 }
0057
0058 #define DO_ERROR_INFO(signr, str, name, sicode) \
0059 int name(unsigned long address, struct pt_regs *regs) \
0060 { \
0061 return unhandled_exception(str, regs, signr, sicode, \
0062 (void __user *)address); \
0063 }
0064
0065
0066
0067
0068 DO_ERROR_INFO(SIGILL, "Priv Op/Disabled Extn", do_privilege_fault, ILL_PRVOPC)
0069 DO_ERROR_INFO(SIGILL, "Invalid Extn Insn", do_extension_fault, ILL_ILLOPC)
0070 DO_ERROR_INFO(SIGILL, "Illegal Insn (or Seq)", insterror_is_error, ILL_ILLOPC)
0071 DO_ERROR_INFO(SIGBUS, "Invalid Mem Access", __weak do_memory_error, BUS_ADRERR)
0072 DO_ERROR_INFO(SIGTRAP, "Breakpoint Set", trap_is_brkpt, TRAP_BRKPT)
0073 DO_ERROR_INFO(SIGBUS, "Misaligned Access", do_misaligned_error, BUS_ADRALN)
0074 DO_ERROR_INFO(SIGSEGV, "gcc generated __builtin_trap", do_trap5_error, 0)
0075
0076
0077
0078
0079 int do_misaligned_access(unsigned long address, struct pt_regs *regs,
0080 struct callee_regs *cregs)
0081 {
0082
0083 if (misaligned_fixup(address, regs, cregs) != 0)
0084 return do_misaligned_error(address, regs);
0085
0086 return 0;
0087 }
0088
0089
0090
0091
0092
0093 void do_machine_check_fault(unsigned long address, struct pt_regs *regs)
0094 {
0095 die("Unhandled Machine Check Exception", regs, address);
0096 }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
0111 {
0112 unsigned int param = regs->ecr_param;
0113
0114 switch (param) {
0115 case 1:
0116 trap_is_brkpt(address, regs);
0117 break;
0118
0119 case 2:
0120 trap_is_kprobe(address, regs);
0121 break;
0122
0123 case 3:
0124 case 4:
0125 kgdb_trap(regs);
0126 break;
0127
0128 case 5:
0129 do_trap5_error(address, regs);
0130 break;
0131 default:
0132 break;
0133 }
0134 }
0135
0136
0137
0138
0139
0140
0141 void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs)
0142 {
0143 int rc;
0144
0145
0146 rc = notify_die(DIE_IERR, "kprobe_ierr", regs, address, 0, SIGILL);
0147 if (rc == NOTIFY_STOP)
0148 return;
0149
0150 insterror_is_error(address, regs);
0151 }
0152
0153
0154
0155
0156 void abort(void)
0157 {
0158 __asm__ __volatile__("trap_s 5\n");
0159 }