diff options
author | Jeff Dike <jdike@addtoit.com> | 2007-05-06 17:51:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-07 15:13:02 -0400 |
commit | 377fad3acbb7e94ab9942a74e0d9ede8eeb2f039 (patch) | |
tree | 0bf8046bb1fa6ccb51df76b56819dee6b6d7487b /arch/um | |
parent | 5d86456d3852cb95a38d2b23fe01cede54984ba5 (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.h | 2 | ||||
-rw-r--r-- | arch/um/include/kern_util.h | 2 | ||||
-rw-r--r-- | arch/um/kernel/trap.c | 10 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/trap.c | 15 | ||||
-rw-r--r-- | arch/um/sys-i386/signal.c | 41 | ||||
-rw-r--r-- | arch/um/sys-x86_64/signal.c | 30 |
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); | |||
24 | DEFINE(UM_ELFCLASS32, ELFCLASS32); | 24 | DEFINE(UM_ELFCLASS32, ELFCLASS32); |
25 | DEFINE(UM_ELFCLASS64, ELFCLASS64); | 25 | DEFINE(UM_ELFCLASS64, ELFCLASS64); |
26 | 26 | ||
27 | DEFINE(UM_NR_CPUS, NR_CPUS); | ||
28 | |||
27 | /* For crypto assembler code. */ | 29 | /* For crypto assembler code. */ |
28 | DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); | 30 | DEFINE(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); | |||
115 | extern int __cant_sleep(void); | 115 | extern int __cant_sleep(void); |
116 | extern void sigio_handler(int sig, union uml_pt_regs *regs); | 116 | extern void sigio_handler(int sig, union uml_pt_regs *regs); |
117 | 117 | ||
118 | extern 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 | ||
18 | static union uml_pt_regs ksig_regs[UM_NR_CPUS]; | ||
19 | |||
18 | void sig_handler_common_skas(int sig, void *sc_ptr) | 20 | void 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 | ||
21 | void 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 | |||
21 | static int copy_sc_from_user_skas(struct pt_regs *regs, | 43 | static 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(®s->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 | ||
23 | void 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 | |||
23 | static int copy_sc_from_user_skas(struct pt_regs *regs, | 53 | static int copy_sc_from_user_skas(struct pt_regs *regs, |
24 | struct sigcontext __user *from) | 54 | struct sigcontext __user *from) |
25 | { | 55 | { |