diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-01-11 16:42:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-11 22:01:10 -0500 |
commit | 6e3f361781573a27296c77a79c9892dec8f2e36c (patch) | |
tree | b08ff3ed470d0e21ce3d462f16d6d3f0a6965a9c | |
parent | 5c617cfa6422bfba9e79d8d004303a6cc3d2e7d7 (diff) |
[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>
-rw-r--r-- | arch/x86_64/kernel/mce.c | 2 | ||||
-rw-r--r-- | arch/x86_64/kernel/traps.c | 33 | ||||
-rw-r--r-- | arch/x86_64/mm/fault.c | 8 | ||||
-rw-r--r-- | include/asm-x86_64/kdebug.h | 13 |
4 files changed, 37 insertions, 19 deletions
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index ee5f65c44214..63777b8cb8c1 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c | |||
@@ -169,7 +169,7 @@ void do_machine_check(struct pt_regs * regs, long error_code) | |||
169 | int panicm_found = 0; | 169 | int panicm_found = 0; |
170 | 170 | ||
171 | if (regs) | 171 | if (regs) |
172 | notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL); | 172 | notify_die(DIE_NMI, "machine check", regs, error_code, 18, SIGKILL); |
173 | if (!banks) | 173 | if (!banks) |
174 | return; | 174 | return; |
175 | 175 | ||
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 0fd17e01de06..0266b523e8d0 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -382,7 +382,7 @@ void __die(const char * str, struct pt_regs * regs, long err) | |||
382 | printk("DEBUG_PAGEALLOC"); | 382 | printk("DEBUG_PAGEALLOC"); |
383 | #endif | 383 | #endif |
384 | printk("\n"); | 384 | printk("\n"); |
385 | notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); | 385 | notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); |
386 | show_registers(regs); | 386 | show_registers(regs); |
387 | /* Executive summary in case the oops scrolled away */ | 387 | /* Executive summary in case the oops scrolled away */ |
388 | printk(KERN_ALERT "RIP "); | 388 | printk(KERN_ALERT "RIP "); |
@@ -421,19 +421,20 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, | |||
421 | struct pt_regs * regs, long error_code, | 421 | struct pt_regs * regs, long error_code, |
422 | siginfo_t *info) | 422 | siginfo_t *info) |
423 | { | 423 | { |
424 | struct task_struct *tsk = current; | ||
425 | |||
424 | conditional_sti(regs); | 426 | conditional_sti(regs); |
425 | 427 | ||
426 | if (user_mode(regs)) { | 428 | tsk->thread.error_code = error_code; |
427 | struct task_struct *tsk = current; | 429 | tsk->thread.trap_no = trapnr; |
428 | 430 | ||
431 | if (user_mode(regs)) { | ||
429 | if (exception_trace && unhandled_signal(tsk, signr)) | 432 | if (exception_trace && unhandled_signal(tsk, signr)) |
430 | printk(KERN_INFO | 433 | printk(KERN_INFO |
431 | "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", | 434 | "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", |
432 | tsk->comm, tsk->pid, str, | 435 | tsk->comm, tsk->pid, str, |
433 | regs->rip,regs->rsp,error_code); | 436 | regs->rip,regs->rsp,error_code); |
434 | 437 | ||
435 | tsk->thread.error_code = error_code; | ||
436 | tsk->thread.trap_no = trapnr; | ||
437 | if (info) | 438 | if (info) |
438 | force_sig_info(signr, info, tsk); | 439 | force_sig_info(signr, info, tsk); |
439 | else | 440 | else |
@@ -493,19 +494,20 @@ DO_ERROR( 8, SIGSEGV, "double fault", double_fault) | |||
493 | asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, | 494 | asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, |
494 | long error_code) | 495 | long error_code) |
495 | { | 496 | { |
497 | struct task_struct *tsk = current; | ||
498 | |||
496 | conditional_sti(regs); | 499 | conditional_sti(regs); |
497 | 500 | ||
498 | if (user_mode(regs)) { | 501 | tsk->thread.error_code = error_code; |
499 | struct task_struct *tsk = current; | 502 | tsk->thread.trap_no = 13; |
500 | 503 | ||
504 | if (user_mode(regs)) { | ||
501 | if (exception_trace && unhandled_signal(tsk, SIGSEGV)) | 505 | if (exception_trace && unhandled_signal(tsk, SIGSEGV)) |
502 | printk(KERN_INFO | 506 | printk(KERN_INFO |
503 | "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", | 507 | "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", |
504 | tsk->comm, tsk->pid, | 508 | tsk->comm, tsk->pid, |
505 | regs->rip,regs->rsp,error_code); | 509 | regs->rip,regs->rsp,error_code); |
506 | 510 | ||
507 | tsk->thread.error_code = error_code; | ||
508 | tsk->thread.trap_no = 13; | ||
509 | force_sig(SIGSEGV, tsk); | 511 | force_sig(SIGSEGV, tsk); |
510 | return; | 512 | return; |
511 | } | 513 | } |
@@ -568,7 +570,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs) | |||
568 | reason = get_nmi_reason(); | 570 | reason = get_nmi_reason(); |
569 | 571 | ||
570 | if (!(reason & 0xc0)) { | 572 | if (!(reason & 0xc0)) { |
571 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT) | 573 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) |
572 | == NOTIFY_STOP) | 574 | == NOTIFY_STOP) |
573 | return; | 575 | return; |
574 | #ifdef CONFIG_X86_LOCAL_APIC | 576 | #ifdef CONFIG_X86_LOCAL_APIC |
@@ -584,7 +586,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs) | |||
584 | unknown_nmi_error(reason, regs); | 586 | unknown_nmi_error(reason, regs); |
585 | return; | 587 | return; |
586 | } | 588 | } |
587 | if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP) | 589 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) |
588 | return; | 590 | return; |
589 | 591 | ||
590 | /* AK: following checks seem to be broken on modern chipsets. FIXME */ | 592 | /* AK: following checks seem to be broken on modern chipsets. FIXME */ |
@@ -693,7 +695,7 @@ clear_TF_reenable: | |||
693 | regs->eflags &= ~TF_MASK; | 695 | regs->eflags &= ~TF_MASK; |
694 | } | 696 | } |
695 | 697 | ||
696 | static int kernel_math_error(struct pt_regs *regs, char *str) | 698 | static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) |
697 | { | 699 | { |
698 | const struct exception_table_entry *fixup; | 700 | const struct exception_table_entry *fixup; |
699 | fixup = search_exception_tables(regs->rip); | 701 | fixup = search_exception_tables(regs->rip); |
@@ -701,8 +703,9 @@ static int kernel_math_error(struct pt_regs *regs, char *str) | |||
701 | regs->rip = fixup->fixup; | 703 | regs->rip = fixup->fixup; |
702 | return 1; | 704 | return 1; |
703 | } | 705 | } |
704 | notify_die(DIE_GPF, str, regs, 0, 16, SIGFPE); | 706 | notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE); |
705 | /* Illegal floating point operation in the kernel */ | 707 | /* Illegal floating point operation in the kernel */ |
708 | current->thread.trap_no = trapnr; | ||
706 | die(str, regs, 0); | 709 | die(str, regs, 0); |
707 | return 0; | 710 | return 0; |
708 | } | 711 | } |
@@ -721,7 +724,7 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs) | |||
721 | 724 | ||
722 | conditional_sti(regs); | 725 | conditional_sti(regs); |
723 | if (!user_mode(regs) && | 726 | if (!user_mode(regs) && |
724 | kernel_math_error(regs, "kernel x87 math error")) | 727 | kernel_math_error(regs, "kernel x87 math error", 16)) |
725 | return; | 728 | return; |
726 | 729 | ||
727 | /* | 730 | /* |
@@ -790,7 +793,7 @@ asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs) | |||
790 | 793 | ||
791 | conditional_sti(regs); | 794 | conditional_sti(regs); |
792 | if (!user_mode(regs) && | 795 | if (!user_mode(regs) && |
793 | kernel_math_error(regs, "kernel simd math error")) | 796 | kernel_math_error(regs, "kernel simd math error", 19)) |
794 | return; | 797 | return; |
795 | 798 | ||
796 | /* | 799 | /* |
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 3a63707a698b..21d1596946d6 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c | |||
@@ -222,10 +222,15 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, | |||
222 | unsigned long error_code) | 222 | unsigned long error_code) |
223 | { | 223 | { |
224 | unsigned long flags = oops_begin(); | 224 | unsigned long flags = oops_begin(); |
225 | struct task_struct *tsk; | ||
225 | 226 | ||
226 | printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", | 227 | printk(KERN_ALERT "%s: Corrupted page table at address %lx\n", |
227 | current->comm, address); | 228 | current->comm, address); |
228 | dump_pagetable(address); | 229 | dump_pagetable(address); |
230 | tsk = current; | ||
231 | tsk->thread.cr2 = address; | ||
232 | tsk->thread.trap_no = 14; | ||
233 | tsk->thread.error_code = error_code; | ||
229 | __die("Bad pagetable", regs, error_code); | 234 | __die("Bad pagetable", regs, error_code); |
230 | oops_end(flags); | 235 | oops_end(flags); |
231 | do_exit(SIGKILL); | 236 | do_exit(SIGKILL); |
@@ -521,6 +526,9 @@ no_context: | |||
521 | printk_address(regs->rip); | 526 | printk_address(regs->rip); |
522 | printk("\n"); | 527 | printk("\n"); |
523 | dump_pagetable(address); | 528 | dump_pagetable(address); |
529 | tsk->thread.cr2 = address; | ||
530 | tsk->thread.trap_no = 14; | ||
531 | tsk->thread.error_code = error_code; | ||
524 | __die("Oops", regs, error_code); | 532 | __die("Oops", regs, error_code); |
525 | /* Executive summary in case the body of the oops scrolled away */ | 533 | /* Executive summary in case the body of the oops scrolled away */ |
526 | printk(KERN_EMERG "CR2: %016lx\n", address); | 534 | printk(KERN_EMERG "CR2: %016lx\n", address); |
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h index f604e84c5303..b9ed4c0c8783 100644 --- a/include/asm-x86_64/kdebug.h +++ b/include/asm-x86_64/kdebug.h | |||
@@ -35,9 +35,16 @@ enum die_val { | |||
35 | DIE_PAGE_FAULT, | 35 | DIE_PAGE_FAULT, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig) | 38 | static inline int notify_die(enum die_val val, const char *str, |
39 | { | 39 | struct pt_regs *regs, long err, int trap, int sig) |
40 | struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig }; | 40 | { |
41 | struct die_args args = { | ||
42 | .regs = regs, | ||
43 | .str = str, | ||
44 | .err = err, | ||
45 | .trapnr = trap, | ||
46 | .signr = sig | ||
47 | }; | ||
41 | return notifier_call_chain(&die_chain, val, &args); | 48 | return notifier_call_chain(&die_chain, val, &args); |
42 | } | 49 | } |
43 | 50 | ||