Commit 5d86456d authored by Jeff Dike's avatar Jeff Dike Committed by Linus Torvalds

uml: tidy fault code

Tidying in preparation for the segfault register dumping patch which follows.

void * pointers are changed to union uml_pt_regs *.  This makes the types
match reality, except in arch_fixup, which is changed to operate on a union
uml_pt_regs.  This fixes a bug in the call from segv_handler, which passes a
union uml_pt_regs, to segv, which expects to pass a struct sigcontext to
arch_fixup.

Whitespace and other style fixes.

There's also a errno printk fix.
Signed-off-by: default avatarJeff Dike <jdike@linux.intel.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ccdddb57
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include "sysdep/ptrace.h" #include "sysdep/ptrace.h"
extern void arch_check_bugs(void); extern void arch_check_bugs(void);
extern int arch_fixup(unsigned long address, void *sc_ptr); extern int arch_fixup(unsigned long address, union uml_pt_regs *regs);
extern int arch_handle_signal(int sig, union uml_pt_regs *regs); extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
#endif #endif
...@@ -44,7 +44,7 @@ extern unsigned long alloc_stack(int order, int atomic); ...@@ -44,7 +44,7 @@ extern unsigned long alloc_stack(int order, int atomic);
extern int do_signal(void); extern int do_signal(void);
extern int is_stack_fault(unsigned long sp); extern int is_stack_fault(unsigned long sp);
extern unsigned long segv(struct faultinfo fi, unsigned long ip, extern unsigned long segv(struct faultinfo fi, unsigned long ip,
int is_user, void *sc); int is_user, union uml_pt_regs *regs);
extern int handle_page_fault(unsigned long address, unsigned long ip, extern int handle_page_fault(unsigned long address, unsigned long ip,
int is_write, int is_user, int *code_out); int is_write, int is_user, int *code_out);
extern void syscall_ready(void); extern void syscall_ready(void);
......
...@@ -72,8 +72,8 @@ int handle_page_fault(unsigned long address, unsigned long ip, ...@@ -72,8 +72,8 @@ int handle_page_fault(unsigned long address, unsigned long ip,
goto out; goto out;
/* Don't require VM_READ|VM_EXEC for write faults! */ /* Don't require VM_READ|VM_EXEC for write faults! */
if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC))) if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
goto out; goto out;
do { do {
survive: survive:
...@@ -157,18 +157,19 @@ static void segv_handler(int sig, union uml_pt_regs *regs) ...@@ -157,18 +157,19 @@ static void segv_handler(int sig, union uml_pt_regs *regs)
* the info in the regs. A pointer to the info then would * the info in the regs. A pointer to the info then would
* give us bad data! * give us bad data!
*/ */
unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
union uml_pt_regs *regs)
{ {
struct siginfo si; struct siginfo si;
void *catcher; void *catcher;
int err; int err;
int is_write = FAULT_WRITE(fi); int is_write = FAULT_WRITE(fi);
unsigned long address = FAULT_ADDRESS(fi); unsigned long address = FAULT_ADDRESS(fi);
if(!is_user && (address >= start_vm) && (address < end_vm)){ if(!is_user && (address >= start_vm) && (address < end_vm)){
flush_tlb_kernel_vm(); flush_tlb_kernel_vm();
return(0); return 0;
} }
else if(current->mm == NULL) else if(current->mm == NULL)
panic("Segfault with no mm"); panic("Segfault with no mm");
...@@ -183,17 +184,17 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) ...@@ -183,17 +184,17 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
catcher = current->thread.fault_catcher; catcher = current->thread.fault_catcher;
if(!err) if(!err)
return(0); return 0;
else if(catcher != NULL){ else if(catcher != NULL){
current->thread.fault_addr = (void *) address; current->thread.fault_addr = (void *) address;
do_longjmp(catcher, 1); do_longjmp(catcher, 1);
} }
else if(current->thread.fault_addr != NULL) else if(current->thread.fault_addr != NULL)
panic("fault_addr set but no fault catcher"); panic("fault_addr set but no fault catcher");
else if(!is_user && arch_fixup(ip, sc)) else if(!is_user && arch_fixup(ip, regs))
return(0); return 0;
if(!is_user) if(!is_user)
panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
address, ip); address, ip);
...@@ -202,7 +203,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) ...@@ -202,7 +203,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
si.si_errno = 0; si.si_errno = 0;
si.si_code = BUS_ADRERR; si.si_code = BUS_ADRERR;
si.si_addr = (void __user *)address; si.si_addr = (void __user *)address;
current->thread.arch.faultinfo = fi; current->thread.arch.faultinfo = fi;
force_sig_info(SIGBUS, &si, current); force_sig_info(SIGBUS, &si, current);
} else if (err == -ENOMEM) { } else if (err == -ENOMEM) {
printk("VM: killing process %s\n", current->comm); printk("VM: killing process %s\n", current->comm);
...@@ -211,10 +212,10 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) ...@@ -211,10 +212,10 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
BUG_ON(err != -EFAULT); BUG_ON(err != -EFAULT);
si.si_signo = SIGSEGV; si.si_signo = SIGSEGV;
si.si_addr = (void __user *) address; si.si_addr = (void __user *) address;
current->thread.arch.faultinfo = fi; current->thread.arch.faultinfo = fi;
force_sig_info(SIGSEGV, &si, current); force_sig_info(SIGSEGV, &si, current);
} }
return(0); return 0;
} }
void relay_signal(int sig, union uml_pt_regs *regs) void relay_signal(int sig, union uml_pt_regs *regs)
...@@ -229,7 +230,7 @@ void relay_signal(int sig, union uml_pt_regs *regs) ...@@ -229,7 +230,7 @@ void relay_signal(int sig, union uml_pt_regs *regs)
panic("Kernel mode signal %d", sig); panic("Kernel mode signal %d", sig);
} }
current->thread.arch.faultinfo = *UPT_FAULTINFO(regs); current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
force_sig(sig, current); force_sig(sig, current);
} }
......
...@@ -18,10 +18,9 @@ ...@@ -18,10 +18,9 @@
void sig_handler_common_skas(int sig, void *sc_ptr) void sig_handler_common_skas(int sig, void *sc_ptr)
{ {
struct sigcontext *sc = sc_ptr; struct sigcontext *sc = sc_ptr;
struct skas_regs *r; union uml_pt_regs *r;
void (*handler)(int, union uml_pt_regs *); void (*handler)(int, union uml_pt_regs *);
int save_errno = errno; int save_user, save_errno = errno;
int save_user;
/* This is done because to allow SIGSEGV to be delivered inside a SEGV /* This is done because to allow SIGSEGV to be delivered inside a SEGV
* handler. This can happen in copy_user, and if SEGV is disabled, * handler. This can happen in copy_user, and if SEGV is disabled,
...@@ -31,13 +30,13 @@ void sig_handler_common_skas(int sig, void *sc_ptr) ...@@ -31,13 +30,13 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
if(sig == SIGSEGV) if(sig == SIGSEGV)
change_sig(SIGSEGV, 1); change_sig(SIGSEGV, 1);
r = &TASK_REGS(get_current())->skas; r = TASK_REGS(get_current());
save_user = r->is_user; save_user = r->skas.is_user;
r->is_user = 0; r->skas.is_user = 0;
if ( sig == SIGFPE || sig == SIGSEGV || if ( sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGILL || sig == SIGBUS || sig == SIGILL ||
sig == SIGTRAP ) { sig == SIGTRAP ) {
GET_FAULTINFO_FROM_SC(r->faultinfo, sc); GET_FAULTINFO_FROM_SC(r->skas.faultinfo, sc);
} }
change_sig(SIGUSR1, 1); change_sig(SIGUSR1, 1);
...@@ -49,10 +48,10 @@ void sig_handler_common_skas(int sig, void *sc_ptr) ...@@ -49,10 +48,10 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
sig != SIGVTALRM && sig != SIGALRM) sig != SIGVTALRM && sig != SIGALRM)
unblock_signals(); unblock_signals();
handler(sig, (union uml_pt_regs *) r); handler(sig, r);
errno = save_errno; errno = save_errno;
r->is_user = save_user; r->skas.is_user = save_user;
} }
extern int ptrace_faultinfo; extern int ptrace_faultinfo;
......
...@@ -3,9 +3,7 @@ ...@@ -3,9 +3,7 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include <signal.h>
#include "sysdep/ptrace.h" #include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
/* These two are from asm-um/uaccess.h and linux/module.h, check them. */ /* These two are from asm-um/uaccess.h and linux/module.h, check them. */
struct exception_table_entry struct exception_table_entry
...@@ -17,26 +15,14 @@ struct exception_table_entry ...@@ -17,26 +15,14 @@ struct exception_table_entry
const struct exception_table_entry *search_exception_tables(unsigned long add); const struct exception_table_entry *search_exception_tables(unsigned long add);
/* Compare this to arch/i386/mm/extable.c:fixup_exception() */ /* Compare this to arch/i386/mm/extable.c:fixup_exception() */
int arch_fixup(unsigned long address, void *sc_ptr) int arch_fixup(unsigned long address, union uml_pt_regs *regs)
{ {
struct sigcontext *sc = sc_ptr;
const struct exception_table_entry *fixup; const struct exception_table_entry *fixup;
fixup = search_exception_tables(address); fixup = search_exception_tables(address);
if(fixup != 0){ if(fixup != 0){
sc->eip = fixup->fixup; UPT_IP(regs) = fixup->fixup;
return(1); return(1);
} }
return(0); return(0);
} }
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -28,7 +28,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, ...@@ -28,7 +28,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
err = copy_from_user(&sc, from, sizeof(sc)); err = copy_from_user(&sc, from, sizeof(sc));
err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs)); err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
if(err) if(err)
return(err); return err;
REGS_GS(regs->regs.skas.regs) = sc.gs; REGS_GS(regs->regs.skas.regs) = sc.gs;
REGS_FS(regs->regs.skas.regs) = sc.fs; REGS_FS(regs->regs.skas.regs) = sc.fs;
...@@ -50,11 +50,11 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, ...@@ -50,11 +50,11 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
err = restore_fp_registers(userspace_pid[0], fpregs); err = restore_fp_registers(userspace_pid[0], fpregs);
if(err < 0){ if(err < 0){
printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, " printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
"errno = %d\n", err); "errno = %d\n", -err);
return(1); return err;
} }
return(0); return 0;
} }
int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp, int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp,
...@@ -90,16 +90,16 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *t ...@@ -90,16 +90,16 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *t
if(err < 0){ if(err < 0){
printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, " printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
"errno = %d\n", err); "errno = %d\n", err);
return(1); return 1;
} }
to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
sc.fpstate = to_fp; sc.fpstate = to_fp;
if(err) if(err)
return(err); return err;
return(copy_to_user(to, &sc, sizeof(sc)) || return copy_to_user(to, &sc, sizeof(sc)) ||
copy_to_user(to_fp, fpregs, sizeof(fpregs))); copy_to_user(to_fp, fpregs, sizeof(fpregs));
} }
#endif #endif
...@@ -129,7 +129,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, ...@@ -129,7 +129,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from,
to->fpstate = to_fp; to->fpstate = to_fp;
if(to_fp != NULL) if(to_fp != NULL)
err |= copy_from_user(to_fp, from_fp, fpsize); err |= copy_from_user(to_fp, from_fp, fpsize);
return(err); return err;
} }
int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp, int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
...@@ -164,15 +164,15 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) ...@@ -164,15 +164,15 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from)
ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
sizeof(struct _fpstate)), sizeof(struct _fpstate)),
copy_sc_from_user_skas(to, from)); copy_sc_from_user_skas(to, from));
return(ret); return ret;
} }
static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp, static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp,
struct pt_regs *from, unsigned long sp) struct pt_regs *from, unsigned long sp)
{ {
return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), return CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
sizeof(*fp), sp), sizeof(*fp), sp),
copy_sc_to_user_skas(to, fp, from, sp))); copy_sc_to_user_skas(to, fp, from, sp));
} }
static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp,
...@@ -185,7 +185,7 @@ static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __u ...@@ -185,7 +185,7 @@ static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __u
err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp); err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
return(err); return err;
} }
struct sigframe struct sigframe
...@@ -359,7 +359,7 @@ long sys_sigreturn(struct pt_regs regs) ...@@ -359,7 +359,7 @@ long sys_sigreturn(struct pt_regs regs)
/* Avoid ERESTART handling */ /* Avoid ERESTART handling */
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1; PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
return(PT_REGS_SYSCALL_RET(&current->thread.regs)); return PT_REGS_SYSCALL_RET(&current->thread.regs);
segfault: segfault:
force_sig(SIGSEGV, current); force_sig(SIGSEGV, current);
...@@ -389,20 +389,9 @@ long sys_rt_sigreturn(struct pt_regs regs) ...@@ -389,20 +389,9 @@ long sys_rt_sigreturn(struct pt_regs regs)
/* Avoid ERESTART handling */ /* Avoid ERESTART handling */
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1; PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
return(PT_REGS_SYSCALL_RET(&current->thread.regs)); return PT_REGS_SYSCALL_RET(&current->thread.regs);
segfault: segfault:
force_sig(SIGSEGV, current); force_sig(SIGSEGV, current);
return 0; return 0;
} }
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -4,20 +4,24 @@ ...@@ -4,20 +4,24 @@
* Licensed under the GPL * Licensed under the GPL
*/ */
#include "user.h" #include "sysdep/ptrace.h"
int arch_fixup(unsigned long address, void *sc_ptr) /* These two are from asm-um/uaccess.h and linux/module.h, check them. */
struct exception_table_entry
{ {
/* XXX search_exception_tables() */ unsigned long insn;
unsigned long fixup;
};
const struct exception_table_entry *search_exception_tables(unsigned long add);
int arch_fixup(unsigned long address, union uml_pt_regs *regs)
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(address);
if(fixup != 0){
UPT_IP(regs) = fixup->fixup;
return(1);
}
return(0); return(0);
} }
/* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
...@@ -51,7 +51,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, ...@@ -51,7 +51,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
#undef GETREG #undef GETREG
return(err); return err;
} }
int copy_sc_to_user_skas(struct sigcontext __user *to, int copy_sc_to_user_skas(struct sigcontext __user *to,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment