[PATCH] x86_64: make trap information available to die notification handlers

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 <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index ee5f65c..63777b8 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -169,7 +169,7 @@
 	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;
 
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 0fd17e0..0266b52 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -382,7 +382,7 @@
 	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 @@
 			      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 @@
 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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 
 	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 @@
 
 	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;
 
 	/*
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 3a63707..21d1596 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -222,10 +222,15 @@
 				 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 @@
 	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);
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
index f604e84..b9ed4c0 100644
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -35,9 +35,16 @@
 	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); 
 }