From: Andy P. <at...@us...> - 2001-08-27 23:39:31
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel In directory usw-pr-cvs1:/tmp/cvs-serv3881 Modified Files: signal.c Log Message: Add trampoline code to make user signal handlers work. Index: signal.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/signal.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- signal.c 2001/08/17 20:20:41 1.4 +++ signal.c 2001/08/27 23:39:28 1.5 @@ -40,7 +40,7 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); +int do_signal(sigset_t *oldset, struct pt_regs *regs); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) { @@ -96,7 +96,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(0, &saveset, regs)) + if (do_signal(&saveset, regs)) return -EINTR; } } @@ -128,7 +128,7 @@ while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(0, &saveset, regs)) + if (do_signal(&saveset, regs)) return -EINTR; } } @@ -178,12 +178,13 @@ */ struct sigframe { - char *pretcode; + int sig; struct sigcontext sc; unsigned long extramask[_NSIG_WORDS-1]; - unsigned char retcode[8]; /* trampoline code */ + unsigned char retcode[20]; /* trampoline code */ }; +/* FIXME: this dont work ... */ struct rt_sigframe { char *pretcode; struct siginfo *pinfo; @@ -241,7 +242,7 @@ if (((long)frame) & 3) goto badframe; - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 @@ -267,6 +268,8 @@ return 0; } + +/* FIXME: _rt_ stuff is completely unchecked + probably does not work */ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe *frame = (struct rt_sigframe *)(regs->sp); @@ -342,7 +345,7 @@ } /* make sure the frame is dword-aligned */ - + sp &= ~3; return (void *)(sp - frame_size); @@ -360,14 +363,20 @@ sigset_t *set, struct pt_regs * regs) { struct sigframe *frame; - unsigned long return_ip; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); - + + +#ifdef DEBUG_SIG + printk("setup_frame: pid %d, sig %d, regs %p, frame %p, sigaction %p\n",current->pid,sig,regs,frame,ka); + show_regs(regs); +#endif if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; + /* write the signal onto the stack */ + err |= __put_user(sig, (unsigned int *)&frame->sig); err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); if (err) goto give_sigsegv; @@ -381,27 +390,127 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ + + /* We do this differently to other ports. Each function has a two byte RSM. + * (due to the calling convention). Each sighandler will expect to be + * CALLS'd and will RET from that. So we cant just muck about with PC's on the + * stack like the i386. So we use the trampoline code on the stack a bit more. + * The easiest way to skip around all this is to calls the signal + * handler, and then either calls the restorer, or chmk to sys_sigreturn */ + + /* CALLS $1, */ + err |= __put_user(0xfb, (char *)(frame->retcode+0)); + err |= __put_user(0x01, (char *)(frame->retcode+1)); + /* (absolute address)*/ + err |= __put_user(0x9f, (char *)(frame->retcode+2)); + /* sighandler */ + err |= __put_user(((unsigned long) ka->sa.sa_handler), (unsigned long *)(frame->retcode + 3)); + if (ka->sa.sa_flags & SA_RESTORER) { - return_ip = (unsigned long)ka->sa.sa_restorer; + /* CALLS $0,*/ + err |= __put_user(0xfb, (char *)(frame->retcode+7)); + err |= __put_user(0x00, (char *)(frame->retcode+8)); + /* (absolute address)*/ + err |= __put_user(0x9f, (char *)(frame->retcode+9)); + /* restorer */ + err |= __put_user(((unsigned long) ka->sa.sa_restorer), (unsigned long *)(frame->retcode + 10)); + /* plus a halt */ + err |= __put_user(0x00, (char *)(frame->retcode+14)); } else { - /* trampoline - the desired return ip is the retcode itself */ - return_ip = (unsigned long)&frame->retcode; - /* This is chmk __NR_sigreturn; */ - /* TODO: check byteorder */ - err |= __put_user(0xbc8f, (short *)(frame->retcode+0)); - err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); + /* perform a syscall to sys_sigreturn. First set up the + * argument list to avoid confusing it */ + + /* pushl $0x0 */ + err |= __put_user(0xdd, (char *)(frame->retcode+7)); + err |= __put_user(0x00, (char *)(frame->retcode+8)); + /* movl sp, ap */ + err |= __put_user(0xd0, (char *)(frame->retcode+9)); + err |= __put_user(0x5e, (char *)(frame->retcode+10)); + err |= __put_user(0x5c, (char *)(frame->retcode+11)); + /* chmk __NR_sigreturn; */ + err |= __put_user(0xbc, (char *)(frame->retcode+12)); + err |= __put_user(0x8f, (char *)(frame->retcode+13)); + err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+14)); + /* plus a halt */ + err |= __put_user(0x00, (char *)(frame->retcode+16)); } - err |= __put_user(return_ip, &frame->pretcode); - if (err) goto give_sigsegv; +#ifdef DEBUG_SIG + printk("setup_frame: pid %d, frame->retcode %p, sa_handler %p\n",current->pid,frame->retcode,ka->sa.sa_handler); +#endif /* Set up registers for signal handler */ - - regs->pc = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ - regs->sp = frame; - + + regs->pc = (unsigned long) frame->retcode; /* what we enter NOW */ + regs->fp = regs->sp; + regs->sp = frame; + __mtpr(frame,PR_USP); /* and into to the register, ready for REI */ + +#ifdef DEBUG_SIG + printk("setup_frame: pid %d, regs->pc %8lx, regs->sp %8lx, regs->ap %8lx\n",current->pid,regs->pc,regs->sp,regs->ap); + { + unsigned char c[4]; + __get_user(c[0], (char *)&frame->sig); + __get_user(c[1], (char *)&frame->sig+1); + __get_user(c[2], (char *)&frame->sig+2); + __get_user(c[3], (char *)&frame->sig+3); + printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n", + &frame->sig, c[0], + &frame->sig+1, c[1], + &frame->sig+2, c[2], + &frame->sig+3, c[3]); + } + { + unsigned char c[4]; + __get_user(c[0], (char *)frame->retcode); + __get_user(c[1], (char *)frame->retcode+1); + __get_user(c[2], (char *)frame->retcode+2); + __get_user(c[3], (char *)frame->retcode+3); + printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n", + frame->retcode, c[0], + frame->retcode+1, c[1], + frame->retcode+2, c[2], + frame->retcode+3, c[3]); + } + { + unsigned char c[4]; + __get_user(c[0], (char *)frame->retcode+4); + __get_user(c[1], (char *)frame->retcode+5); + __get_user(c[2], (char *)frame->retcode+6); + __get_user(c[3], (char *)frame->retcode+7); + printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n", + frame->retcode+4, c[0], + frame->retcode+5, c[1], + frame->retcode+6, c[2], + frame->retcode+7, c[3]); + } + { + unsigned char c[4]; + __get_user(c[0], (char *)frame->retcode+8); + __get_user(c[1], (char *)frame->retcode+9); + __get_user(c[2], (char *)frame->retcode+10); + __get_user(c[3], (char *)frame->retcode+11); + printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n", + frame->retcode+8, c[0], + frame->retcode+9, c[1], + frame->retcode+10, c[2], + frame->retcode+11, c[3]); + } + { + unsigned char c[4]; + __get_user(c[0], (char *)frame->retcode+12); + __get_user(c[1], (char *)frame->retcode+13); + __get_user(c[2], (char *)frame->retcode+14); + __get_user(c[3], (char *)frame->retcode+15); + printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n", + frame->retcode+12, c[0], + frame->retcode+13, c[1], + frame->retcode+14, c[2], + frame->retcode+15, c[3]); + } +#endif return; give_sigsegv: @@ -410,6 +519,7 @@ force_sig(SIGSEGV, current); } +/* FIXME: this is bogus */ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { @@ -504,7 +614,10 @@ } /* Set up the stack frame */ - if (ka->sa.sa_flags & SA_SIGINFO) +#ifdef DEBUG_SIG + printk("handle_signal: setup_frame(sig=%d,ka=%p,oldset=%d,regs=%p)\n",sig,ka,oldset,regs); +#endif + if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(sig, ka, info, oldset, regs); else setup_frame(sig, ka, oldset, regs); @@ -526,11 +639,11 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) +int do_signal(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; struct k_sigaction *ka; - + int canrestart; /* * We want the common case to go fast, which * is why we may in certain cases get here from @@ -540,16 +653,24 @@ if (!user_mode(regs)) return 1; + /* FIXME: */ + canrestart=0; +#ifdef DEBUG_SIG + printk("do_signal: pid %d,canrestart %d, current->sigpending %d,current->blocked %d ", current->pid,canrestart,current->sigpending,current->blocked); +#endif if (!oldset) oldset = ¤t->blocked; + for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); - +#ifdef DEBUG_SIG + printk(" sig %d\n",signr); +#endif if (!signr) break; @@ -589,6 +710,9 @@ if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; +#ifdef DEBUG_SIG + printk("do_signal: waiting for sigchld\n"); +#endif /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; @@ -597,7 +721,9 @@ if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; - +#ifdef DEBUG_SIG + printk("do_signal: invoking default handler for sig %d\n",signr); +#endif /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; @@ -631,11 +757,16 @@ sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; +#ifdef DEBUG_SIG + printk("handle_sig: do_exit exit_code=%d\n",exit_code); +#endif do_exit(exit_code); /* NOTREACHED */ } } - +#ifdef DEBUG_SIG + printk("do_signal: handle_signal(canrestart=%d,signr=%d,info=%p,ka->sa.sa_handler=%p)\n",canrestart,signr,info,ka->sa.sa_handler); +#endif /* Whee! Actually deliver the signal. */ handle_signal(canrestart, signr, ka, &info, oldset, regs); return 1; |