diff options
Diffstat (limited to 'arch/um/kernel')
-rw-r--r-- | arch/um/kernel/sysrq.c | 32 | ||||
-rw-r--r-- | arch/um/kernel/trap.c | 14 |
2 files changed, 34 insertions, 12 deletions
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index 33cc72e26c6e..7122bf9c753e 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/sched.h> #include <asm/sysrq.h> +#include <os.h> struct stack_frame { struct stack_frame *next_frame; @@ -48,29 +49,42 @@ static void print_stack_trace(unsigned long *sp, unsigned long bp) /*Stolen from arch/i386/kernel/traps.c */ static const int kstack_depth_to_print = 24; -static unsigned long get_frame_pointer(struct task_struct *task) +static unsigned long get_frame_pointer(struct task_struct *task, + struct pt_regs *segv_regs) { if (!task || task == current) - return current_bp(); + return segv_regs ? PT_REGS_BP(segv_regs) : current_bp(); else return KSTK_EBP(task); } +static unsigned long *get_stack_pointer(struct task_struct *task, + struct pt_regs *segv_regs) +{ + if (!task || task == current) + return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp(); + else + return (unsigned long *)KSTK_ESP(task); +} + void show_stack(struct task_struct *task, unsigned long *stack) { unsigned long *sp = stack, bp = 0; + struct pt_regs *segv_regs = current->thread.segv_regs; int i; + if (!segv_regs && os_is_signal_stack()) { + printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler," + " aborting stack trace!\n"); + return; + } + #ifdef CONFIG_FRAME_POINTER - bp = get_frame_pointer(task); + bp = get_frame_pointer(task, segv_regs); #endif - if (!stack) { - if (!task || task == current) - sp = current_sp(); - else - sp = (unsigned long *)KSTK_ESP(task); - } + if (!stack) + sp = get_stack_pointer(task, segv_regs); printk(KERN_INFO "Stack:\n"); stack = sp; diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index 5c3aef74237f..974b87474a99 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -206,9 +206,12 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, int is_write = FAULT_WRITE(fi); unsigned long address = FAULT_ADDRESS(fi); + if (regs) + current->thread.segv_regs = container_of(regs, struct pt_regs, regs); + if (!is_user && (address >= start_vm) && (address < end_vm)) { flush_tlb_kernel_vm(); - return 0; + goto out; } else if (current->mm == NULL) { show_regs(container_of(regs, struct pt_regs, regs)); @@ -230,7 +233,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, catcher = current->thread.fault_catcher; if (!err) - return 0; + goto out; else if (catcher != NULL) { current->thread.fault_addr = (void *) address; UML_LONGJMP(catcher, 1); @@ -238,7 +241,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, else if (current->thread.fault_addr != NULL) panic("fault_addr set but no fault catcher"); else if (!is_user && arch_fixup(ip, regs)) - return 0; + goto out; if (!is_user) { show_regs(container_of(regs, struct pt_regs, regs)); @@ -262,6 +265,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } + +out: + if (regs) + current->thread.segv_regs = NULL; + return 0; } |