aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-05-06 17:51:25 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:13:02 -0400
commit377fad3acbb7e94ab9942a74e0d9ede8eeb2f039 (patch)
tree0bf8046bb1fa6ccb51df76b56819dee6b6d7487b /arch/um
parent5d86456d3852cb95a38d2b23fe01cede54984ba5 (diff)
uml: kernel segfaults should dump proper registers
If there's a segfault inside the kernel, we want a dump of the registers at the point of the segfault, not the registers at the point of calling panic or the last userspace registers. sig_handler_common_skas now uses a static register set in the case of a SIGSEGV to avoid messing up the process registers if the segfault turns out to be non-fatal. The architecture sigcontext-to-pt_regs copying code was repurposed to copy data out of the SEGV stack frame. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/include/common-offsets.h2
-rw-r--r--arch/um/include/kern_util.h2
-rw-r--r--arch/um/kernel/trap.c10
-rw-r--r--arch/um/os-Linux/skas/trap.c15
-rw-r--r--arch/um/sys-i386/signal.c41
-rw-r--r--arch/um/sys-x86_64/signal.c30
6 files changed, 78 insertions, 22 deletions
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 461175f8b1d9..5593a8027083 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -24,5 +24,7 @@ DEFINE(UM_ELF_CLASS, ELF_CLASS);
24DEFINE(UM_ELFCLASS32, ELFCLASS32); 24DEFINE(UM_ELFCLASS32, ELFCLASS32);
25DEFINE(UM_ELFCLASS64, ELFCLASS64); 25DEFINE(UM_ELFCLASS64, ELFCLASS64);
26 26
27DEFINE(UM_NR_CPUS, NR_CPUS);
28
27/* For crypto assembler code. */ 29/* For crypto assembler code. */
28DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); 30DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 092a2841556f..50a49691e0e6 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -115,4 +115,6 @@ extern void time_init_kern(void);
115extern int __cant_sleep(void); 115extern int __cant_sleep(void);
116extern void sigio_handler(int sig, union uml_pt_regs *regs); 116extern void sigio_handler(int sig, union uml_pt_regs *regs);
117 117
118extern void copy_sc(union uml_pt_regs *regs, void *from);
119
118#endif 120#endif
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index c3e62e634c0a..0c467fa08870 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -170,8 +170,10 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
170 flush_tlb_kernel_vm(); 170 flush_tlb_kernel_vm();
171 return 0; 171 return 0;
172 } 172 }
173 else if(current->mm == NULL) 173 else if(current->mm == NULL) {
174 panic("Segfault with no mm"); 174 show_regs(container_of(regs, struct pt_regs, regs));
175 panic("Segfault with no mm");
176 }
175 177
176 if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi)) 178 if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
177 err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); 179 err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
@@ -194,9 +196,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
194 else if(!is_user && arch_fixup(ip, regs)) 196 else if(!is_user && arch_fixup(ip, regs))
195 return 0; 197 return 0;
196 198
197 if(!is_user) 199 if(!is_user) {
200 show_regs(container_of(regs, struct pt_regs, regs));
198 panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 201 panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
199 address, ip); 202 address, ip);
203 }
200 204
201 if (err == -EACCES) { 205 if (err == -EACCES) {
202 si.si_signo = SIGBUS; 206 si.si_signo = SIGBUS;
diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c
index 6a20d08caf91..5110eff51b90 100644
--- a/arch/um/os-Linux/skas/trap.c
+++ b/arch/um/os-Linux/skas/trap.c
@@ -15,6 +15,8 @@
15#include "sysdep/ptrace_user.h" 15#include "sysdep/ptrace_user.h"
16#include "os.h" 16#include "os.h"
17 17
18static union uml_pt_regs ksig_regs[UM_NR_CPUS];
19
18void sig_handler_common_skas(int sig, void *sc_ptr) 20void sig_handler_common_skas(int sig, void *sc_ptr)
19{ 21{
20 struct sigcontext *sc = sc_ptr; 22 struct sigcontext *sc = sc_ptr;
@@ -27,10 +29,19 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
27 * the process will die. 29 * the process will die.
28 * XXX Figure out why this is better than SA_NODEFER 30 * XXX Figure out why this is better than SA_NODEFER
29 */ 31 */
30 if(sig == SIGSEGV) 32 if(sig == SIGSEGV) {
31 change_sig(SIGSEGV, 1); 33 change_sig(SIGSEGV, 1);
34 /* For segfaults, we want the data from the
35 * sigcontext. In this case, we don't want to mangle
36 * the process registers, so use a static set of
37 * registers. For other signals, the process
38 * registers are OK.
39 */
40 r = &ksig_regs[cpu()];
41 copy_sc(r, sc_ptr);
42 }
43 else r = TASK_REGS(get_current());
32 44
33 r = TASK_REGS(get_current());
34 save_user = r->skas.is_user; 45 save_user = r->skas.is_user;
35 r->skas.is_user = 0; 46 r->skas.is_user = 0;
36 if ( sig == SIGFPE || sig == SIGSEGV || 47 if ( sig == SIGFPE || sig == SIGSEGV ||
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 42ecf8e8ad08..1cbf95f6858a 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -18,6 +18,28 @@
18 18
19#include "skas.h" 19#include "skas.h"
20 20
21void copy_sc(union uml_pt_regs *regs, void *from)
22{
23 struct sigcontext *sc = from;
24
25 REGS_GS(regs->skas.regs) = sc->gs;
26 REGS_FS(regs->skas.regs) = sc->fs;
27 REGS_ES(regs->skas.regs) = sc->es;
28 REGS_DS(regs->skas.regs) = sc->ds;
29 REGS_EDI(regs->skas.regs) = sc->edi;
30 REGS_ESI(regs->skas.regs) = sc->esi;
31 REGS_EBP(regs->skas.regs) = sc->ebp;
32 REGS_SP(regs->skas.regs) = sc->esp;
33 REGS_EBX(regs->skas.regs) = sc->ebx;
34 REGS_EDX(regs->skas.regs) = sc->edx;
35 REGS_ECX(regs->skas.regs) = sc->ecx;
36 REGS_EAX(regs->skas.regs) = sc->eax;
37 REGS_IP(regs->skas.regs) = sc->eip;
38 REGS_CS(regs->skas.regs) = sc->cs;
39 REGS_EFLAGS(regs->skas.regs) = sc->eflags;
40 REGS_SS(regs->skas.regs) = sc->ss;
41}
42
21static int copy_sc_from_user_skas(struct pt_regs *regs, 43static int copy_sc_from_user_skas(struct pt_regs *regs,
22 struct sigcontext __user *from) 44 struct sigcontext __user *from)
23{ 45{
@@ -30,25 +52,10 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
30 if(err) 52 if(err)
31 return err; 53 return err;
32 54
33 REGS_GS(regs->regs.skas.regs) = sc.gs; 55 copy_sc(&regs->regs, &sc);
34 REGS_FS(regs->regs.skas.regs) = sc.fs;
35 REGS_ES(regs->regs.skas.regs) = sc.es;
36 REGS_DS(regs->regs.skas.regs) = sc.ds;
37 REGS_EDI(regs->regs.skas.regs) = sc.edi;
38 REGS_ESI(regs->regs.skas.regs) = sc.esi;
39 REGS_EBP(regs->regs.skas.regs) = sc.ebp;
40 REGS_SP(regs->regs.skas.regs) = sc.esp;
41 REGS_EBX(regs->regs.skas.regs) = sc.ebx;
42 REGS_EDX(regs->regs.skas.regs) = sc.edx;
43 REGS_ECX(regs->regs.skas.regs) = sc.ecx;
44 REGS_EAX(regs->regs.skas.regs) = sc.eax;
45 REGS_IP(regs->regs.skas.regs) = sc.eip;
46 REGS_CS(regs->regs.skas.regs) = sc.cs;
47 REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
48 REGS_SS(regs->regs.skas.regs) = sc.ss;
49 56
50 err = restore_fp_registers(userspace_pid[0], fpregs); 57 err = restore_fp_registers(userspace_pid[0], fpregs);
51 if(err < 0){ 58 if(err < 0) {
52 printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, " 59 printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
53 "errno = %d\n", -err); 60 "errno = %d\n", -err);
54 return err; 61 return err;
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 068006213598..fe8ec04d35bb 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -20,6 +20,36 @@
20 20
21#include "skas.h" 21#include "skas.h"
22 22
23void copy_sc(union uml_pt_regs *regs, void *from)
24{
25 struct sigcontext *sc = from;
26
27#define GETREG(regs, regno, sc, regname) \
28 (regs)->skas.regs[(regno) / sizeof(unsigned long)] = (sc)->regname
29
30 GETREG(regs, R8, sc, r8);
31 GETREG(regs, R9, sc, r9);
32 GETREG(regs, R10, sc, r10);
33 GETREG(regs, R11, sc, r11);
34 GETREG(regs, R12, sc, r12);
35 GETREG(regs, R13, sc, r13);
36 GETREG(regs, R14, sc, r14);
37 GETREG(regs, R15, sc, r15);
38 GETREG(regs, RDI, sc, rdi);
39 GETREG(regs, RSI, sc, rsi);
40 GETREG(regs, RBP, sc, rbp);
41 GETREG(regs, RBX, sc, rbx);
42 GETREG(regs, RDX, sc, rdx);
43 GETREG(regs, RAX, sc, rax);
44 GETREG(regs, RCX, sc, rcx);
45 GETREG(regs, RSP, sc, rsp);
46 GETREG(regs, RIP, sc, rip);
47 GETREG(regs, EFLAGS, sc, eflags);
48 GETREG(regs, CS, sc, cs);
49
50#undef GETREG
51}
52
23static int copy_sc_from_user_skas(struct pt_regs *regs, 53static int copy_sc_from_user_skas(struct pt_regs *regs,
24 struct sigcontext __user *from) 54 struct sigcontext __user *from)
25{ 55{