/* * Note that we play around with the 'TS' bit in an attempt to get * the correct behaviour even in the presence of the asynchronous * IRQ13 behaviour */ void math_error(void __user *ip) { struct task_struct *task; siginfo_t info; unsigned short cwd, swd, err; /* * Save the info for the exception handler and clear the error. */ task = current; save_init_fpu(task); task->thread.trap_no = 16; task->thread.error_code = 0; info.si_signo = SIGFPE; info.si_errno = 0; info.si_addr = ip; /* * (~cwd & swd) will mask out exceptions that are not set to unmasked * status. 0x3f is the exception bits in these regs, 0x200 is the * C1 reg you need in case of a stack fault, 0x040 is the stack * fault bit. We should only be taking one exception at a time, * so if this combination doesn't produce any single exception, * then we have a bad program that isn't synchronizing its FPU usage * and it will suffer the consequences since we won't be able to * fully reproduce the context of the exception */ cwd = get_fpu_cwd(task); swd = get_fpu_swd(task); err = swd & ~cwd; if (err & 0x001) { /* Invalid op */ /* * swd & 0x240 == 0x040: Stack Underflow * swd & 0x240 == 0x240: Stack Overflow * User must clear the SF bit (0x40) if set */ info.si_code = FPE_FLTINV; } else if (err & 0x004) { /* Divide by Zero */ info.si_code = FPE_FLTDIV; } else if (err & 0x008) { /* Overflow */ info.si_code = FPE_FLTOVF; } else if (err & 0x012) { /* Denormal, Underflow */ info.si_code = FPE_FLTUND; } else if (err & 0x020) { /* Precision */ info.si_code = FPE_FLTRES; } else { /* * If we're using IRQ 13, or supposedly even some trap 16 * implementations, it's possible we get a spurious trap... */ return; /* Spurious trap, no error */ } force_sig_info(SIGFPE, &info, task); }
void __rk_force_signal(struct task_struct *tsk, unsigned long addr, unsigned int sig, int code ) { struct siginfo si; printk("%s::send sig %d to task %s\n" , __func__ , sig , tsk->comm ); si.si_signo = sig; si.si_errno = 0; si.si_code = code; si.si_addr = (void __user *)addr; force_sig_info(sig, &si, tsk); }
/* * Send SIGSEGV to task. This is an external routine * to keep the stack usage of do_page_fault small. */ static noinline void do_sigsegv(struct pt_regs *regs, int si_code) { struct siginfo si; report_user_fault(regs, SIGSEGV, 1); si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = si_code; si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); force_sig_info(SIGSEGV, &si, current); }
/* * Handle hitting a breakpoint. */ void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) { siginfo_t info; info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; info.si_addr = (void __user *)instruction_pointer(regs); force_sig_info(SIGTRAP, &info, tsk); }
static noinline void do_sigbus(struct pt_regs *regs) { struct task_struct *tsk = current; struct siginfo si; si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRERR; si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); force_sig_info(SIGBUS, &si, tsk); }
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) { siginfo_t info; memset(&info, 0, sizeof(info)); info.si_signo = SIGTRAP; info.si_code = TRAP_TRACE; info.si_addr = (void *)address; force_sig_info(SIGTRAP, &info, current); regs->pc += 4; }
void arm64_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, int err) { if (user_mode(regs)) { current->thread.fault_address = 0; current->thread.fault_code = err; force_sig_info(info->si_signo, info, current); } else { die(str, regs, err); } }
asmlinkage void do_ov(struct pt_regs *regs) { siginfo_t info; die_if_kernel("do_ov execution Exception", regs); info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; info.si_addr = (void *)regs->cp0_epc; force_sig_info(SIGFPE, &info, current); }
/** * seccomp_send_sigsys - signals the task to allow in-process syscall emulation * @syscall: syscall number to send to userland * @reason: filter-supplied reason code to send to userland (via si_errno) * * Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info. */ static void seccomp_send_sigsys(int syscall, int reason) { struct siginfo info; memset(&info, 0, sizeof(info)); info.si_signo = SIGSYS; info.si_code = SYS_SECCOMP; info.si_call_addr = (void __user *)KSTK_EIP(current); info.si_errno = reason; info.si_arch = syscall_get_arch(current, task_pt_regs(current)); info.si_syscall = syscall; force_sig_info(SIGSYS, &info, current); }
void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) { struct siginfo info; memset(&info, 0, sizeof(info)); info.si_signo = SIGTRAP; info.si_code = TRAP_BRKPT; info.si_addr = (void __user *) regs->pc; /* */ force_sig_info(SIGTRAP, &info, tsk); }
asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) { void __user *rip = (void __user *)(regs->rip); struct task_struct * task; siginfo_t info; unsigned short mxcsr; conditional_sti(regs); if (!user_mode(regs) && kernel_math_error(regs, "kernel simd math error")) return; /* * Save the info for the exception handler and clear the error. */ task = current; save_init_fpu(task); task->thread.trap_no = 19; task->thread.error_code = 0; info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = __SI_FAULT; info.si_addr = rip; /* * The SIMD FPU exceptions are handled a little differently, as there * is only a single status/control register. Thus, to determine which * unmasked exception was caught we must mask the exception mask bits * at 0x1f80, and then use these to mask the exception bits at 0x3f. */ mxcsr = get_fpu_mxcsr(task); switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { case 0x000: default: break; case 0x001: /* Invalid Op */ info.si_code = FPE_FLTINV; break; case 0x002: /* Denormalize */ case 0x010: /* Underflow */ info.si_code = FPE_FLTUND; break; case 0x004: /* Zero Divide */ info.si_code = FPE_FLTDIV; break; case 0x008: /* Overflow */ info.si_code = FPE_FLTOVF; break; case 0x020: /* Precision */ info.si_code = FPE_FLTRES; break; } force_sig_info(SIGFPE, &info, task); }
void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs) { struct siginfo info; current->thread.trap_nr = TRAP_BRKPT; memset(&info, 0, sizeof(info)); info.si_signo = SIGTRAP; info.si_code = TRAP_BRKPT; info.si_addr = (void __user *) regs->pc; /* Send us the fakey SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); }
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { siginfo_t info; if (kernel_mode(regs)) { die("Exception in kernel mode", regs, signr); } info.si_signo = signr; info.si_errno = 0; info.si_code = code; info.si_addr = (void __user *) addr; force_sig_info(signr, &info, current); }
asmlinkage void do_entDbg(struct pt_regs *regs) { siginfo_t info; die_if_kernel("Instruction fault", regs, 0, NULL); info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; info.si_addr = (void __user *) regs->pc; force_sig_info(SIGILL, &info, current); }
/* * Handle hitting a breakpoint */ static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) { siginfo_t info; info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; info.si_addr = (void __user *)instruction_pointer(regs); pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n", tsk->pid, info.si_addr); force_sig_info(SIGTRAP, &info, tsk); }
void handle_break(unsigned iir, struct pt_regs *regs) { struct siginfo si; switch(iir) { case 0x00: #ifdef PRINT_USER_FAULTS printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n", current->pid, current->comm); #endif die_if_kernel("Breakpoint", regs, 0); #ifdef PRINT_USER_FAULTS show_regs(regs); #endif si.si_code = TRAP_BRKPT; si.si_addr = (void *) (regs->iaoq[0] & ~3); si.si_signo = SIGTRAP; force_sig_info(SIGTRAP, &si, current); break; case GDB_BREAK_INSN: die_if_kernel("Breakpoint", regs, 0); handle_gdb_break(regs, TRAP_BRKPT); break; default: #ifdef PRINT_USER_FAULTS printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n", iir, current->pid, current->comm); show_regs(regs); #endif si.si_signo = SIGTRAP; si.si_code = TRAP_BRKPT; si.si_addr = (void *) (regs->iaoq[0] & ~3); force_sig_info(SIGTRAP, &si, current); return; } }
int send_fault_sig(struct pt_regs *regs) { siginfo_t siginfo = { 0, 0, 0, }; siginfo.si_signo = current->thread.signo; siginfo.si_code = current->thread.code; siginfo.si_addr = (void *)current->thread.faddr; #ifdef DEBUG printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code); #endif if (user_mode(regs)) { force_sig_info(siginfo.si_signo, &siginfo, current); } else { const struct exception_table_entry *fixup; /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_tables(regs->pc))) { struct pt_regs *tregs; /* Create a new four word stack frame, discarding the old one. */ regs->stkadj = frame_extra_sizes[regs->format]; tregs = (struct pt_regs *)((ulong)regs + regs->stkadj); tregs->vector = regs->vector; tregs->format = 0; tregs->pc = fixup->fixup; tregs->sr = regs->sr; return -1; } //if (siginfo.si_signo == SIGBUS) // force_sig_info(siginfo.si_signo, // &siginfo, current); /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. */ if ((unsigned long)siginfo.si_addr < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); else printk(KERN_ALERT "Unable to handle kernel access"); printk(" at virtual address %p\n", siginfo.si_addr); die_if_kernel("Oops", regs, 0 /*error_code*/); do_exit(SIGKILL); } return 1; }
/* * Send SIGSEGV to task. This is an external routine * to keep the stack usage of do_page_fault small. */ static noinline void do_sigsegv(struct pt_regs *regs, long int_code, int si_code, unsigned long trans_exc_code) { struct siginfo si; unsigned long address; address = trans_exc_code & __FAIL_ADDR_MASK; current->thread.prot_addr = address; current->thread.trap_no = int_code; report_user_fault(regs, int_code, SIGSEGV, address); si.si_signo = SIGSEGV; si.si_code = si_code; si.si_addr = (void __user *) address; force_sig_info(SIGSEGV, &si, current); }
static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, int error_code) { struct siginfo info; memset(&info, 0, sizeof(info)); info.si_signo = SIGTRAP; info.si_code = TRAP_BRKPT; /* User-mode eip? */ info.si_addr = UPT_IS_USER(regs) ? (void __user *) UPT_IP(regs) : NULL; /* Send us the fake SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); }
static noinline void do_sigbus(struct pt_regs *regs) { struct task_struct *tsk = current; struct siginfo si; /* * Send a sigbus, regardless of whether we were in kernel * or user mode. */ si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRERR; si.si_addr = (void __user *)(regs->int_parm_long & __FAIL_ADDR_MASK); force_sig_info(SIGBUS, &si, tsk); }
void do_per_trap(struct pt_regs *regs) { siginfo_t info; if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP) return; if (!current->ptrace) return; info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_HWBKPT; info.si_addr = (void __force __user *) current->thread.per_event.address; force_sig_info(SIGTRAP, &info, current); }
void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { siginfo_t info; #ifdef TRAP_DEBUG printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); #endif info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_OBJERR; info.si_addr = (void *)pc; info.si_trapno = 0; force_sig_info(SIGBUS, &info, current); }
asmlinkage void media_exception(unsigned long msr0, unsigned long msr1) { siginfo_t info; die_if_kernel("-- Media Exception --\n" "MSR0 : %08lx\n" "MSR1 : %08lx\n", msr0, msr1); info.si_signo = SIGFPE; info.si_code = FPE_MDAOVF; info.si_errno = 0; info.si_addr = (void *) __frame->pc; force_sig_info(info.si_signo, &info, current); } /* end media_exception() */
void do_send_trap(struct pt_regs *regs, unsigned long address, unsigned long error_code, int signal_code, int breakpt) { siginfo_t info; if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, 11, SIGSEGV) == NOTIFY_STOP) return; /* Deliver the signal to userspace */ info.si_signo = SIGTRAP; info.si_errno = breakpt; /* breakpoint or watchpoint id */ info.si_code = signal_code; info.si_addr = (void __user *)address; force_sig_info(SIGTRAP, &info, current); }
/* * instruction access error */ asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0) { siginfo_t info; die_if_kernel("-- Insn Access Error --\n" "EPCR0 : %08lx\n" "ESR0 : %08lx\n", epcr0, esr0); info.si_signo = SIGSEGV; info.si_code = SEGV_ACCERR; info.si_errno = 0; info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); force_sig_info(info.si_signo, &info, current); } /* end insn_access_error() */
asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr) { siginfo_t info; die_if_kernel("-- Division Exception --\n" "ESR0 : %08lx\n" "ISR : %08lx\n", esr0, isr); info.si_signo = SIGFPE; info.si_code = FPE_INTDIV; info.si_errno = 0; info.si_addr = (void *) __frame->pc; force_sig_info(info.si_signo, &info, current); } /* end division_exception() */
/* * Handle bad IA32 interrupt via syscall */ void ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) { siginfo_t siginfo; die_if_kernel("Bad IA-32 interrupt", regs, int_num); siginfo.si_signo = SIGTRAP; siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */ siginfo.si_flags = 0; siginfo.si_isr = 0; siginfo.si_addr = NULL; siginfo.si_imm = 0; siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); }
/* Handle a floating point exception. Return zero if the faulting instruction can be completed successfully. */ int handle_fpe(struct pt_regs *regs) { extern void printbinary(unsigned long x, int nbits); struct siginfo si; unsigned int orig_sw, sw; int signalcode; /* need an intermediate copy of float regs because FPU emulation * code expects an artificial last entry which contains zero * * also, the passed in fr registers contain one word that defines * the fpu type. the fpu type information is constructed * inside the emulation code */ __u64 frcopy[36]; memcpy(frcopy, regs->fr, sizeof regs->fr); frcopy[32] = 0; memcpy(&orig_sw, frcopy, sizeof(orig_sw)); if (FPUDEBUG) { printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n "); printbinary(orig_sw, 32); printk(KERN_DEBUG "\n"); } signalcode = decode_fpu(frcopy, 0x666); /* Status word = FR0L. */ memcpy(&sw, frcopy, sizeof(sw)); if (FPUDEBUG) { printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n", signalcode >> 24, signalcode & 0xffffff); printbinary(sw, 32); printk(KERN_DEBUG "\n"); } memcpy(regs->fr, frcopy, sizeof regs->fr); if (signalcode != 0) { si.si_signo = signalcode >> 24; si.si_errno = 0; si.si_code = signalcode & 0xffffff; si.si_addr = (void *) regs->iaoq[0]; force_sig_info(si.si_signo, &si, current); return -1; }
/* * data access error * - double-word data load from CPU control area (0xFExxxxxx) * - read performed on inactive or self-refreshing SDRAM * - error notification from slave device * - misaligned address * - access to out of bounds memory region * - user mode accessing privileged memory region * - write to R/O memory region */ asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15) { siginfo_t info; die_if_kernel("-- Data Access Error --\n" "ESR15 : %08lx\n" "EAR15 : %08lx\n", esr15, ear15); info.si_signo = SIGSEGV; info.si_code = SEGV_ACCERR; info.si_errno = 0; info.si_addr = (void *) (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0); force_sig_info(info.si_signo, &info, current); } /* end data_access_error() */
asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address) { siginfo_t info; if (user_mode(regs)) { /* Send a SIGBUS */ info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; info.si_addr = (void *)address; force_sig_info(SIGBUS, &info, current); } else { /* Kernel mode */ printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address); show_registers(regs); die("Die:", regs, address); } }