aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/include/asm/processor-generic.h1
-rw-r--r--arch/um/include/shared/os.h1
-rw-r--r--arch/um/kernel/sysrq.c32
-rw-r--r--arch/um/kernel/trap.c14
-rw-r--r--arch/um/os-Linux/signal.c8
5 files changed, 44 insertions, 12 deletions
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index c03cd5a02364..90469031297b 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -21,6 +21,7 @@ struct mm_struct;
21struct thread_struct { 21struct thread_struct {
22 struct task_struct *saved_task; 22 struct task_struct *saved_task;
23 struct pt_regs regs; 23 struct pt_regs regs;
24 struct pt_regs *segv_regs;
24 int singlestep_syscall; 25 int singlestep_syscall;
25 void *fault_addr; 26 void *fault_addr;
26 jmp_buf *fault_catcher; 27 jmp_buf *fault_catcher;
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index 021104d98cb3..75298d3358e7 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -227,6 +227,7 @@ extern void block_signals(void);
227extern void unblock_signals(void); 227extern void unblock_signals(void);
228extern int get_signals(void); 228extern int get_signals(void);
229extern int set_signals(int enable); 229extern int set_signals(int enable);
230extern int os_is_signal_stack(void);
230 231
231/* util.c */ 232/* util.c */
232extern void stack_protections(unsigned long address); 233extern void stack_protections(unsigned long address);
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 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <asm/sysrq.h> 14#include <asm/sysrq.h>
15#include <os.h>
15 16
16struct stack_frame { 17struct stack_frame {
17 struct stack_frame *next_frame; 18 struct stack_frame *next_frame;
@@ -48,29 +49,42 @@ static void print_stack_trace(unsigned long *sp, unsigned long bp)
48/*Stolen from arch/i386/kernel/traps.c */ 49/*Stolen from arch/i386/kernel/traps.c */
49static const int kstack_depth_to_print = 24; 50static const int kstack_depth_to_print = 24;
50 51
51static unsigned long get_frame_pointer(struct task_struct *task) 52static unsigned long get_frame_pointer(struct task_struct *task,
53 struct pt_regs *segv_regs)
52{ 54{
53 if (!task || task == current) 55 if (!task || task == current)
54 return current_bp(); 56 return segv_regs ? PT_REGS_BP(segv_regs) : current_bp();
55 else 57 else
56 return KSTK_EBP(task); 58 return KSTK_EBP(task);
57} 59}
58 60
61static unsigned long *get_stack_pointer(struct task_struct *task,
62 struct pt_regs *segv_regs)
63{
64 if (!task || task == current)
65 return segv_regs ? (unsigned long *)PT_REGS_SP(segv_regs) : current_sp();
66 else
67 return (unsigned long *)KSTK_ESP(task);
68}
69
59void show_stack(struct task_struct *task, unsigned long *stack) 70void show_stack(struct task_struct *task, unsigned long *stack)
60{ 71{
61 unsigned long *sp = stack, bp = 0; 72 unsigned long *sp = stack, bp = 0;
73 struct pt_regs *segv_regs = current->thread.segv_regs;
62 int i; 74 int i;
63 75
76 if (!segv_regs && os_is_signal_stack()) {
77 printk(KERN_ERR "Received SIGSEGV in SIGSEGV handler,"
78 " aborting stack trace!\n");
79 return;
80 }
81
64#ifdef CONFIG_FRAME_POINTER 82#ifdef CONFIG_FRAME_POINTER
65 bp = get_frame_pointer(task); 83 bp = get_frame_pointer(task, segv_regs);
66#endif 84#endif
67 85
68 if (!stack) { 86 if (!stack)
69 if (!task || task == current) 87 sp = get_stack_pointer(task, segv_regs);
70 sp = current_sp();
71 else
72 sp = (unsigned long *)KSTK_ESP(task);
73 }
74 88
75 printk(KERN_INFO "Stack:\n"); 89 printk(KERN_INFO "Stack:\n");
76 stack = sp; 90 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,
206 int is_write = FAULT_WRITE(fi); 206 int is_write = FAULT_WRITE(fi);
207 unsigned long address = FAULT_ADDRESS(fi); 207 unsigned long address = FAULT_ADDRESS(fi);
208 208
209 if (regs)
210 current->thread.segv_regs = container_of(regs, struct pt_regs, regs);
211
209 if (!is_user && (address >= start_vm) && (address < end_vm)) { 212 if (!is_user && (address >= start_vm) && (address < end_vm)) {
210 flush_tlb_kernel_vm(); 213 flush_tlb_kernel_vm();
211 return 0; 214 goto out;
212 } 215 }
213 else if (current->mm == NULL) { 216 else if (current->mm == NULL) {
214 show_regs(container_of(regs, struct pt_regs, regs)); 217 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,
230 233
231 catcher = current->thread.fault_catcher; 234 catcher = current->thread.fault_catcher;
232 if (!err) 235 if (!err)
233 return 0; 236 goto out;
234 else if (catcher != NULL) { 237 else if (catcher != NULL) {
235 current->thread.fault_addr = (void *) address; 238 current->thread.fault_addr = (void *) address;
236 UML_LONGJMP(catcher, 1); 239 UML_LONGJMP(catcher, 1);
@@ -238,7 +241,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
238 else if (current->thread.fault_addr != NULL) 241 else if (current->thread.fault_addr != NULL)
239 panic("fault_addr set but no fault catcher"); 242 panic("fault_addr set but no fault catcher");
240 else if (!is_user && arch_fixup(ip, regs)) 243 else if (!is_user && arch_fixup(ip, regs))
241 return 0; 244 goto out;
242 245
243 if (!is_user) { 246 if (!is_user) {
244 show_regs(container_of(regs, struct pt_regs, regs)); 247 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,
262 current->thread.arch.faultinfo = fi; 265 current->thread.arch.faultinfo = fi;
263 force_sig_info(SIGSEGV, &si, current); 266 force_sig_info(SIGSEGV, &si, current);
264 } 267 }
268
269out:
270 if (regs)
271 current->thread.segv_regs = NULL;
272
265 return 0; 273 return 0;
266} 274}
267 275
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 905924b773d3..7b605e4dfffa 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -304,3 +304,11 @@ int set_signals(int enable)
304 304
305 return ret; 305 return ret;
306} 306}
307
308int os_is_signal_stack(void)
309{
310 stack_t ss;
311 sigaltstack(NULL, &ss);
312
313 return ss.ss_flags & SS_ONSTACK;
314}