Skip to content

Commit

Permalink
[PATCH] x86_64: make trap information available to die notification h…
Browse files Browse the repository at this point in the history
…andlers

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>
  • Loading branch information
Jan Beulich authored and Linus Torvalds committed Jan 12, 2006
1 parent 5c617cf commit 6e3f361
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 19 deletions.
2 changes: 1 addition & 1 deletion arch/x86_64/kernel/mce.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ void do_machine_check(struct pt_regs * regs, long error_code)
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;

Expand Down
33 changes: 18 additions & 15 deletions arch/x86_64/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ void __die(const char * str, struct pt_regs * regs, long err)
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 ");
Expand Down Expand Up @@ -421,19 +421,20 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
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
Expand Down Expand Up @@ -493,19 +494,20 @@ DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
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;
}
Expand Down Expand Up @@ -568,7 +570,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs)
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
Expand All @@ -584,7 +586,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs)
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 */
Expand Down Expand Up @@ -693,16 +695,17 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,
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);
if (fixup) {
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;
}
Expand All @@ -721,7 +724,7 @@ asmlinkage void do_coprocessor_error(struct pt_regs *regs)

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;

/*
Expand Down Expand Up @@ -790,7 +793,7 @@ asmlinkage void do_simd_coprocessor_error(struct pt_regs *regs)

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;

/*
Expand Down
8 changes: 8 additions & 0 deletions arch/x86_64/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,15 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
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);
Expand Down Expand Up @@ -521,6 +526,9 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
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);
Expand Down
13 changes: 10 additions & 3 deletions include/asm-x86_64/kdebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit 6e3f361

Please sign in to comment.