make trap information available to die notification handlers From: Jan Beulich This adjusts things so that handlers of the die() notifier will have sufficient information about the trap currently being handled. It also adjusts the notify_die() prototype to (again) match that of i386. Signed-off-by: Andi Kleen Index: linux/arch/x86_64/kernel/traps.c =================================================================== --- linux.orig/arch/x86_64/kernel/traps.c +++ linux/arch/x86_64/kernel/traps.c @@ -382,7 +382,7 @@ void __die(const char * str, struct pt_r printk("DEBUG_PAGEALLOC"); #endif printk("\n"); - notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); + notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); show_registers(regs); /* Executive summary in case the oops scrolled away */ printk(KERN_ALERT "RIP "); @@ -421,19 +421,20 @@ static void __kprobes do_trap(int trapnr struct pt_regs * regs, long error_code, siginfo_t *info) { + struct task_struct *tsk = current; + conditional_sti(regs); - if (user_mode(regs)) { - struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + if (user_mode(regs)) { 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 @@ -493,19 +494,20 @@ DO_ERROR( 8, SIGSEGV, "double fault", do asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, long error_code) { + struct task_struct *tsk = current; + conditional_sti(regs); - if (user_mode(regs)) { - struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = 13; + if (user_mode(regs)) { 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; } @@ -568,7 +570,7 @@ asmlinkage void default_do_nmi(struct pt reason = get_nmi_reason(); if (!(reason & 0xc0)) { - if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) == NOTIFY_STOP) return; #ifdef CONFIG_X86_LOCAL_APIC @@ -584,7 +586,7 @@ asmlinkage void default_do_nmi(struct pt unknown_nmi_error(reason, regs); return; } - if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) return; /* AK: following checks seem to be broken on modern chipsets. FIXME */ @@ -693,7 +695,7 @@ clear_TF_reenable: regs->eflags &= ~TF_MASK; } -static int kernel_math_error(struct pt_regs *regs, char *str) +static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->rip); @@ -701,8 +703,9 @@ static int kernel_math_error(struct pt_r regs->rip = fixup->fixup; return 1; } - notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE); + notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE); /* Illegal floating point operation in the kernel */ + current->thread.trap_no = trapnr; die(str, regs, 0); return 0; } @@ -721,7 +724,7 @@ asmlinkage void do_coprocessor_error(str conditional_sti(regs); if (!user_mode(regs) && - kernel_math_error(regs, "kernel x87 math error")) + kernel_math_error(regs, "kernel x87 math error", 16)) return; /* @@ -790,7 +793,7 @@ asmlinkage void do_simd_coprocessor_erro conditional_sti(regs); if (!user_mode(regs) && - kernel_math_error(regs, "kernel simd math error")) + kernel_math_error(regs, "kernel simd math error", 19)) return; /* Index: linux/arch/x86_64/mm/fault.c =================================================================== --- linux.orig/arch/x86_64/mm/fault.c +++ linux/arch/x86_64/mm/fault.c @@ -222,10 +222,15 @@ static noinline void pgtable_bad(unsigne unsigned long error_code) { unsigned long flags = oops_begin(); + struct task_struct *tsk; printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", current->comm, address); dump_pagetable(address); + tsk = current; + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; + tsk->thread.error_code = error_code; __die("Bad pagetable", regs, error_code); oops_end(flags); do_exit(SIGKILL); @@ -521,6 +526,9 @@ no_context: printk_address(regs->rip); printk("\n"); dump_pagetable(address); + tsk->thread.cr2 = address; + tsk->thread.trap_no = 14; + tsk->thread.error_code = error_code; __die("Oops", regs, error_code); /* Executive summary in case the body of the oops scrolled away */ printk(KERN_EMERG "CR2: %016lx\n", address); Index: linux/arch/x86_64/kernel/mce.c =================================================================== --- linux.orig/arch/x86_64/kernel/mce.c +++ linux/arch/x86_64/kernel/mce.c @@ -168,7 +168,7 @@ void do_machine_check(struct pt_regs * r int panicm_found = 0; if (regs) - notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL); + notify_die(DIE_NMI, "machine check", regs, error_code, 18, SIGKILL); if (!banks) return; Index: linux/include/asm-x86_64/kdebug.h =================================================================== --- linux.orig/include/asm-x86_64/kdebug.h +++ linux/include/asm-x86_64/kdebug.h @@ -35,9 +35,16 @@ enum die_val { DIE_PAGE_FAULT, }; -static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) -{ - struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; +static inline int notify_die(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .str = str, + .err = err, + .trapnr = trap, + .signr = sig + }; return notifier_call_chain(&die_chain, val, &args); }