diff options
Diffstat (limited to 'arch/um/kernel/trap_user.c')
-rw-r--r-- | arch/um/kernel/trap_user.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c new file mode 100644 index 00000000000..50a4042a509 --- /dev/null +++ b/arch/um/kernel/trap_user.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include <stdlib.h> +#include <errno.h> +#include <setjmp.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <asm/page.h> +#include <asm/unistd.h> +#include <asm/ptrace.h> +#include "init.h" +#include "sysdep/ptrace.h" +#include "sigcontext.h" +#include "sysdep/sigcontext.h" +#include "irq_user.h" +#include "signal_user.h" +#include "time_user.h" +#include "task.h" +#include "mode.h" +#include "choose-mode.h" +#include "kern_util.h" +#include "user_util.h" +#include "os.h" + +void kill_child_dead(int pid) +{ + kill(pid, SIGKILL); + kill(pid, SIGCONT); + do { + int n; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + if (n > 0) + kill(pid, SIGCONT); + else + break; + } while(1); +} + +/* Unlocked - don't care if this is a bit off */ +int nsegfaults = 0; + +struct { + unsigned long address; + int is_write; + int pid; + unsigned long sp; + int is_user; +} segfault_record[1024]; + +void segv_handler(int sig, union uml_pt_regs *regs) +{ + int index, max; + + if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){ + bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), + UPT_FAULT_WRITE(regs)); + return; + } + max = sizeof(segfault_record)/sizeof(segfault_record[0]); + index = next_trap_index(max); + + nsegfaults++; + segfault_record[index].address = UPT_FAULT_ADDR(regs); + segfault_record[index].pid = os_getpid(); + segfault_record[index].is_write = UPT_FAULT_WRITE(regs); + segfault_record[index].sp = UPT_SP(regs); + segfault_record[index].is_user = UPT_IS_USER(regs); + segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), + UPT_IS_USER(regs), regs); +} + +void usr2_handler(int sig, union uml_pt_regs *regs) +{ + CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); +} + +struct signal_info sig_info[] = { + [ SIGTRAP ] { .handler = relay_signal, + .is_irq = 0 }, + [ SIGFPE ] { .handler = relay_signal, + .is_irq = 0 }, + [ SIGILL ] { .handler = relay_signal, + .is_irq = 0 }, + [ SIGWINCH ] { .handler = winch, + .is_irq = 1 }, + [ SIGBUS ] { .handler = bus_handler, + .is_irq = 0 }, + [ SIGSEGV] { .handler = segv_handler, + .is_irq = 0 }, + [ SIGIO ] { .handler = sigio_handler, + .is_irq = 1 }, + [ SIGVTALRM ] { .handler = timer_handler, + .is_irq = 1 }, + [ SIGALRM ] { .handler = timer_handler, + .is_irq = 1 }, + [ SIGUSR2 ] { .handler = usr2_handler, + .is_irq = 0 }, +}; + +void do_longjmp(void *b, int val) +{ + sigjmp_buf *buf = b; + + siglongjmp(*buf, val); +} + +/* + * 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: + */ |