dotraplinkage void __kprobes do_device_not_available(struct pt_regs *regs, long error) { #ifdef CONFIG_X86_32 if (read_cr0() & X86_CR0_EM) { conditional_sti(regs); math_emulate(0); } else { math_state_restore(); /* interrupts still off */ conditional_sti(regs); } #else math_state_restore(); #endif }
dotraplinkage void do_simd_coprocessor_error(struct pt_regs *regs, long error_code) { conditional_sti(regs); #ifdef CONFIG_X86_32 if (cpu_has_xmm) { /* Handle SIMD FPU exceptions on PIII+ processors. */ ignore_fpu_irq = 1; simd_math_error((void __user *)regs->ip); return; } /* * Handle strange cache flush from user space exception * in all other cases. This is undocumented behaviour. */ if (regs->flags & X86_VM_MASK) { handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code); return; } current->thread.trap_no = 19; current->thread.error_code = error_code; die_if_kernel("cache flush denied", regs, error_code); force_sig(SIGSEGV, current); #else if (!user_mode(regs) && kernel_math_error(regs, "kernel simd math error", 19)) return; simd_math_error((void __user *)regs->ip); #endif }
asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, long error_code) { conditional_sti(regs); if (user_mode(regs)) { struct task_struct *tsk = current; if (exception_trace && unhandled_signal(tsk, SIGSEGV)) printk(KERN_INFO "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", tsk->comm, tsk->pid, regs->rip,regs->rsp,error_code); tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; force_sig(SIGSEGV, tsk); return; } /* kernel gp */ { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->rip); if (fixup) { regs->rip = fixup->fixup; return; } if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; die("general protection fault", regs, error_code); } }
dotraplinkage void __kprobes do_device_not_available(struct pt_regs regs) { #ifdef CONFIG_X86_32 if (read_cr0() & X86_CR0_EM) { struct math_emu_info info = { }; conditional_sti(®s); info.regs = ®s; math_emulate(&info); } else { math_state_restore(); /* interrupts still off */ conditional_sti(®s); } #else math_state_restore(); #endif }
dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) { conditional_sti(regs); #if 0 /* No need to warn about this any longer. */ printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); #endif }
dotraplinkage void __kprobes do_general_protection(struct pt_regs *regs, long error_code) { struct task_struct *tsk; conditional_sti(regs); #ifdef CONFIG_X86_32 if (lazy_iobitmap_copy()) { /* restart the faulting instruction */ return; } if (regs->flags & X86_VM_MASK) goto gp_in_vm86; #endif tsk = current; if (!user_mode(regs)) goto gp_in_kernel; tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && printk_ratelimit()) { printk(KERN_INFO "%s[%d] general protection ip:%lx sp:%lx error:%lx", tsk->comm, task_pid_nr(tsk), regs->ip, regs->sp, error_code); print_vma_addr(" in ", regs->ip); printk("\n"); } force_sig(SIGSEGV, tsk); return; #ifdef CONFIG_X86_32 gp_in_vm86: local_irq_enable(); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); return; #endif gp_in_kernel: if (fixup_exception(regs)) return; tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; die("general protection fault", regs, error_code); }
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); }
dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) { conditional_sti(regs); #ifdef CONFIG_X86_32 ignore_fpu_irq = 1; #else if (!user_mode(regs) && kernel_math_error(regs, "kernel x87 math error", 16)) return; #endif math_error((void __user *)regs->ip); }
static void __kprobes do_trap(int trapnr, int signr, char *str, struct pt_regs * regs, long error_code, siginfo_t *info) { conditional_sti(regs); if (user_mode(regs)) { struct task_struct *tsk = current; if (exception_trace && unhandled_signal(tsk, signr)) printk(KERN_INFO "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", tsk->comm, tsk->pid, str, regs->rip,regs->rsp,error_code); tsk->thread.error_code = error_code; tsk->thread.trap_no = trapnr; if (info) force_sig_info(signr, info, tsk); else force_sig(signr, tsk); return; } /* kernel trap */ { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->rip); if (fixup) { regs->rip = fixup->fixup; } else die(str, regs, error_code); return; } }
dotraplinkage void __kprobes do_general_protection(struct pt_regs *regs, long error_code) { struct task_struct *tsk; conditional_sti(regs); #ifdef CONFIG_X86_32 if (regs->flags & X86_VM_MASK) goto gp_in_vm86; #endif tsk = current; if (!user_mode(regs)) goto gp_in_kernel; #ifdef CONFIG_X86_32 { int cpu; int ok; cpu = get_cpu(); ok = check_lazy_exec_limit(cpu, regs, error_code); put_cpu(); if (ok) return; if (print_fatal_signals) { printk(KERN_ERR "#GPF(%ld[seg:%lx]) at %08lx, CPU#%d.\n", error_code, error_code/8, regs->ip, smp_processor_id()); printk(KERN_ERR "exec_limit: %08lx, user_cs: %08x/%08x.\n", current->mm->context.exec_limit, current->mm->context.user_cs.a, current->mm->context.user_cs.b); } } #endif /*CONFIG_X86_32*/ tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && printk_ratelimit()) { printk(KERN_INFO "%s[%d] general protection ip:%lx sp:%lx error:%lx", tsk->comm, task_pid_nr(tsk), regs->ip, regs->sp, error_code); print_vma_addr(" in ", regs->ip); printk("\n"); } force_sig(SIGSEGV, tsk); return; #ifdef CONFIG_X86_32 gp_in_vm86: local_irq_enable(); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); return; #endif gp_in_kernel: if (fixup_exception(regs)) return; tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; die("general protection fault", regs, error_code); }
dotraplinkage void __kprobes do_general_protection(struct pt_regs *regs, long error_code) { struct task_struct *tsk; conditional_sti(regs); #ifdef CONFIG_X86_32 if (v8086_mode(regs)) goto gp_in_vm86; #endif tsk = current; if (!user_mode_novm(regs)) goto gp_in_kernel; #if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) if (!nx_enabled && tsk->mm && (tsk->mm->pax_flags & MF_PAX_PAGEEXEC)) { struct mm_struct *mm = tsk->mm; unsigned long limit; down_write(&mm->mmap_sem); limit = mm->context.user_cs_limit; if (limit < TASK_SIZE) { track_exec_limit(mm, limit, TASK_SIZE, VM_EXEC); up_write(&mm->mmap_sem); return; } up_write(&mm->mmap_sem); } #endif tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && printk_ratelimit()) { printk(KERN_INFO "%s[%d] general protection ip:%lx sp:%lx error:%lx", tsk->comm, task_pid_nr(tsk), regs->ip, regs->sp, error_code); print_vma_addr(" in ", regs->ip); printk("\n"); } force_sig(SIGSEGV, tsk); return; #ifdef CONFIG_X86_32 gp_in_vm86: local_irq_enable(); handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); return; #endif gp_in_kernel: if (fixup_exception(regs)) return; tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; #if defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) if ((regs->cs & 0xFFFF) == __KERNEL_CS) die("PAX: suspicious general protection fault", regs, error_code); else #endif die("general protection fault", regs, error_code); }
/* * 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 */ asmlinkage void do_coprocessor_error(struct pt_regs *regs) { void __user *rip = (void __user *)(regs->rip); struct task_struct * task; siginfo_t info; unsigned short cwd, swd; conditional_sti(regs); if (!user_mode(regs) && kernel_math_error(regs, "kernel x87 math error")) return; /* * 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_code = __SI_FAULT; info.si_addr = rip; /* * (~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); switch (swd & ~cwd & 0x3f) { case 0x000: default: break; case 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; 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); }
/* runs on IST stack. */ asmlinkage void __kprobes do_debug(struct pt_regs * regs, unsigned long error_code) { unsigned long condition; struct task_struct *tsk = current; siginfo_t info; get_debugreg(condition, 6); if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, SIGTRAP) == NOTIFY_STOP) return; conditional_sti(regs); /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg7) { goto clear_dr7; } } tsk->thread.debugreg6 = condition; /* Mask out spurious TF errors due to lazy TF clearing */ if (condition & DR_STEP) { /* * The TF error should be masked out only if the current * process is not traced and if the TRAP flag has been set * previously by a tracing process (condition detected by * the PT_DTRACE flag); remember that the i386 TRAP flag * can be modified by the process itself in user mode, * allowing programs to debug themselves without the ptrace() * interface. */ if (!user_mode(regs)) goto clear_TF_reenable; /* * Was the TF flag set by a debugger? If so, clear it now, * so that register information is correct. */ if (tsk->ptrace & PT_DTRACE) { regs->eflags &= ~TF_MASK; tsk->ptrace &= ~PT_DTRACE; } } /* Ok, finally something we can handle */ tsk->thread.trap_no = 1; tsk->thread.error_code = error_code; info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; if (!user_mode(regs)) goto clear_dr7; info.si_addr = (void __user *)regs->rip; force_sig_info(SIGTRAP, &info, tsk); clear_dr7: set_debugreg(0UL, 7); return; clear_TF_reenable: set_tsk_thread_flag(tsk, TIF_SINGLESTEP); regs->eflags &= ~TF_MASK; }
dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error) { conditional_sti(regs); machine_check_vector(regs, error); }