Subject: Prototype for libc-provided signal trampolines
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 06/22/2002 15:10:14
--DO5DiztRLs659m5i
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
The following is a prototype implementation of the userland signal
trampoline I mentioned in my "nathanw_sa TODO list". This strategy
for signal trampolines can (and, I think, should) be used for the
SA upcall trampoline, as well.
Here are the rules of the new interface:
* Arch-dependent code in libc provides sigaction(2) entry point
(we get to keep the current entry point, __sigaction14()) and
the signal trampolines. The trampolines are arch-dependent.
* Signal trampolines are versioned, so that if arch-dependent
code in the kernel or in libc needs to change it at some point,
it can be handled without interfering with other architectures.
* Signal trampolines have a well-defined naming scheme:
__sigtramp_<flavor>_<version>
where:
<flavor> The flavor of the handler, the
traditional sigcontext type or
POSIX siginfo type.
<version> The version of the trampoline.
So, for example, all platforms right now would provide
a trampoline named "__sigtramp_sigcontext_1"
The reason for this naming scheme: Debuggers, like gdb,
need this info:
* They need to know if a PC is in a signal trampoline,
and having access to a symbol name REALLY helps in
this regard.
* They need to know if they have a sigcontext (for
sigcontext flavor) or a ucontext_t (for siginfo
flavor), so they can unwind the call graph through
the signal handler. Having this indicated by the
trampoline's name REALLY helps in this regard.
* They need the version info to know what format the
sigcontext/ucontext_t is in.
* The signal trampoline should be invoked with the arguments
already set up for the handler. For example, in the case of
Alpha, the 3 handler args should already been in registers
a0, a1, and a2. For the VAX, the args should already be pushed
onto the stack.
* The pointer to the signal handler should simply be passed in a
"4th argument" slot, for simplicity. This more or less mirrors
what the SA upcall trampoline does on the nathanw_sa branch. For
platforms which provide a special register for this (e.g. the "pv"
register on the Alpha), that register should be used instead.
Now, it so happens that the changes required to do this are quite small.
Attached are the changes for the Alpha port (I've left out changes to
the compat modules, which are simple adjustments to the sigaction1() call),
and all of the generated files.
I'd like to get feedback on this ASAP. It's a simple change we can make
to the mainline before bringing down the SA branch which will make dealing
with forward compatibility much easier.
--
-- Jason R. Thorpe <thorpej@wasabisystems.com>
--DO5DiztRLs659m5i
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=sigtramp-diffs
Index: lib/libc/arch/alpha/Makefile.inc
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/arch/alpha/Makefile.inc,v
retrieving revision 1.12
diff -c -r1.12 Makefile.inc
*** lib/libc/arch/alpha/Makefile.inc 2002/01/27 23:33:52 1.12
--- lib/libc/arch/alpha/Makefile.inc 2002/06/22 21:28:50
***************
*** 6,11 ****
--- 6,13 ----
memcpy.S memmove.S
#KMSRCS= bcmp.S strcat.S strcmp.S strcpy.S strlen.S
+ SRCS+= __sigtramp1.S sigaction_sigtramp.c
+
# `source' files built from m4 source
SRCS+= __divqu.S __divq.S __divlu.S __divl.S
SRCS+= __remqu.S __remq.S __remlu.S __reml.S
Index: lib/libc/arch/alpha/sys/__sigtramp1.S
===================================================================
RCS file: __sigtramp1.S
diff -N __sigtramp1.S
*** /dev/null Sun Jun 23 00:28:43 2002
--- __sigtramp1.S Sun Jun 23 00:28:50 2002
***************
*** 0 ****
--- 1,49 ----
+ /* $NetBSD$ */
+
+ /*
+ * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+ #include "SYS.h"
+
+ /*
+ * On entry, stack and registers look like:
+ *
+ * a0 signal number
+ * a1 signal specific code
+ * a2 pointer to signal context frame
+ * pv address of handler
+ */
+ NESTED_NOPROFILE(__sigtramp_sigcontext_1,0,0,ra,0,0)
+ lda sp, -16(sp) /* save the sigcontext pointer */
+ stq a2, 0(sp)
+ jsr ra, (pv) /* call the signal handler */
+ ldq a0, 0(sp) /* get the sigcontext pointer */
+ lda sp, 16(sp)
+ CALLSYS_NOERROR(__sigreturn14) /* and call sigreturn() with it */
+ mov v0, a0 /* if that failed, get error code */
+ CALLSYS_NOERROR(exit) /* and call exit() with it */
+ END(__sigtramp_sigcontext_1)
Index: lib/libc/arch/alpha/sys/sigaction_sigtramp.c
===================================================================
RCS file: sigaction_sigtramp.c
diff -N sigaction_sigtramp.c
*** /dev/null Sun Jun 23 00:28:43 2002
--- sigaction_sigtramp.c Sun Jun 23 00:28:51 2002
***************
*** 0 ****
--- 1,58 ----
+ /* $NetBSD$ */
+
+ /*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ #define __LIBC12_SOURCE__
+
+ #include <sys/types.h>
+ #include <signal.h>
+
+ #include "extern.h"
+
+ int
+ __sigaction14(int sig, const struct sigaction *act, struct sigaction *oact)
+ {
+ extern int __sigtramp_sigcontext_1[];
+
+ /*
+ * Right here we should select the SA_SIGINFO trampoline
+ * if SA_SIGINFO is set in the sigaction.
+ */
+
+ return (__sigaction_sigtramp(sig, act, oact,
+ __sigtramp_sigcontext_1, 1));
+ }
Index: lib/libc/include/extern.h
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/include/extern.h,v
retrieving revision 1.6
diff -c -r1.6 extern.h
*** lib/libc/include/extern.h 1999/03/26 22:23:57 1.6
--- lib/libc/include/extern.h 2002/06/22 21:28:53
***************
*** 37,40 ****
--- 37,44 ----
const char *__strsignal __P((int , char *, size_t));
char *__dtoa __P((double, int, int, int *, int *, char **));
int __sysctl __P((int *, unsigned int, void *, size_t *, void *, size_t));
+
+ struct sigaction;
+ int __sigaction_sigtramp __P((int, const struct sigaction *,
+ struct sigaction *, void *, int));
__END_DECLS
Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/sys/Makefile.inc,v
retrieving revision 1.124
diff -c -r1.124 Makefile.inc
*** lib/libc/sys/Makefile.inc 2002/01/29 19:01:18 1.124
--- lib/libc/sys/Makefile.inc 2002/06/22 21:28:54
***************
*** 64,72 ****
sendto.S setegid.S seteuid.S setgid.S setgroups.S setitimer.S \
setpgid.S setpriority.S setregid.S setreuid.S setrlimit.S \
setsid.S setsockopt.S setuid.S \
! __shmctl13.S shmdt.S shmget.S shutdown.S __sigaction14.S \
__sigaltstack14.S __sigpending14.S __sigprocmask14.S __sigsuspend14.S \
! socket.S socketpair.S __stat13.S statfs.S \
swapctl.S symlink.S umask.S undelete.S unlink.S \
unmount.S utimes.S utrace.S vadvise.S wait4.S write.S writev.S \
__sysctl.S \
--- 64,72 ----
sendto.S setegid.S seteuid.S setgid.S setgroups.S setitimer.S \
setpgid.S setpriority.S setregid.S setreuid.S setrlimit.S \
setsid.S setsockopt.S setuid.S \
! __shmctl13.S shmdt.S shmget.S shutdown.S \
__sigaltstack14.S __sigpending14.S __sigprocmask14.S __sigsuspend14.S \
! __sigaction_sigtramp.S socket.S socketpair.S __stat13.S statfs.S \
swapctl.S symlink.S umask.S undelete.S unlink.S \
unmount.S utimes.S utrace.S vadvise.S wait4.S write.S writev.S \
__sysctl.S \
Index: sys/arch/alpha/alpha/machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/alpha/alpha/machdep.c,v
retrieving revision 1.254
diff -c -r1.254 machdep.c
*** sys/arch/alpha/alpha/machdep.c 2002/03/18 22:57:53 1.254
--- sys/arch/alpha/alpha/machdep.c 2002/06/22 21:28:56
***************
*** 1497,1512 ****
* Send an interrupt to process.
*/
void
! sendsig(catcher, sig, mask, code)
! sig_t catcher;
int sig;
sigset_t *mask;
u_long code;
{
struct proc *p = curproc;
struct sigcontext *scp, ksc;
struct trapframe *frame;
int onstack, fsize, rndfsize;
frame = p->p_md.md_tf;
--- 1497,1513 ----
* Send an interrupt to process.
*/
void
! sendsig(sig, mask, code)
int sig;
sigset_t *mask;
u_long code;
{
struct proc *p = curproc;
+ struct sigacts *ps = p->p_sigacts;
struct sigcontext *scp, ksc;
struct trapframe *frame;
int onstack, fsize, rndfsize;
+ sig_t catcher = SIGACTION(p, sig).sa_handler;
frame = p->p_md.md_tf;
***************
*** 1598,1610 ****
scp, code);
#endif
! /* Set up the registers to return to sigcode. */
! frame->tf_regs[FRAME_PC] = (u_int64_t)p->p_sigctx.ps_sigcode;
! frame->tf_regs[FRAME_A0] = sig;
! frame->tf_regs[FRAME_A1] = code;
! frame->tf_regs[FRAME_A2] = (u_int64_t)scp;
! frame->tf_regs[FRAME_T12] = (u_int64_t)catcher; /* t12 is pv */
! alpha_pal_wrusp((unsigned long)scp);
/* Remember that we're now on the signal stack. */
if (onstack)
--- 1599,1635 ----
scp, code);
#endif
! /*
! * Set up the registers to return to the signal trampoline. Note
! * the trampoline version numbers are coordinated with machine-
! * dependent code in libc.
! */
! switch (ps->sa_sigdesc[sig].sd_vers) {
! #if 1 /* XXX COMPAT_16 */
! case 0: /* legacy on-stack sigtramp */
! frame->tf_regs[FRAME_PC] = (uint64_t)p->p_sigctx.ps_sigcode;
! frame->tf_regs[FRAME_A0] = sig;
! frame->tf_regs[FRAME_A1] = code;
! frame->tf_regs[FRAME_A2] = (uint64_t)scp;
! frame->tf_regs[FRAME_T12] = (uint64_t)catcher;
! alpha_pal_wrusp((unsigned long)scp);
! break;
! #endif
!
! case 1:
! frame->tf_regs[FRAME_PC] =
! (uint64_t)ps->sa_sigdesc[sig].sd_tramp;
! frame->tf_regs[FRAME_A0] = sig;
! frame->tf_regs[FRAME_A1] = code;
! frame->tf_regs[FRAME_A2] = (uint64_t)scp;
! frame->tf_regs[FRAME_T12] = (uint64_t)catcher;
! alpha_pal_wrusp((unsigned long)scp);
! break;
!
! default:
! /* Don't know what trampoline version; kill it. */
! sigexit(p, SIGILL);
! }
/* Remember that we're now on the signal stack. */
if (onstack)
Index: sys/kern/kern_sig.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_sig.c,v
retrieving revision 1.120
diff -c -r1.120 kern_sig.c
*** sys/kern/kern_sig.c 2002/03/08 20:48:40 1.120
--- sys/kern/kern_sig.c 2002/06/22 21:29:01
***************
*** 169,175 ****
int
sigaction1(struct proc *p, int signum, const struct sigaction *nsa,
! struct sigaction *osa)
{
struct sigacts *ps;
int prop;
--- 169,175 ----
int
sigaction1(struct proc *p, int signum, const struct sigaction *nsa,
! struct sigaction *osa, void *tramp, int vers)
{
struct sigacts *ps;
int prop;
***************
*** 178,183 ****
--- 178,193 ----
if (signum <= 0 || signum >= NSIG)
return (EINVAL);
+ /*
+ * Trampoline ABI version 0 is reserved for the legacy
+ * kernel-provided on-stack trampoline. Conversely, if
+ * we are using a non-0 ABI version, we must have a
+ * trampoline.
+ */
+ if ((vers != 0 && tramp == NULL) ||
+ (vers == 0 && tramp != NULL))
+ return (EINVAL);
+
if (osa)
*osa = SIGACTION_PS(ps, signum);
***************
*** 191,196 ****
--- 201,208 ----
(void) splsched(); /* XXXSMP */
SIGACTION_PS(ps, signum) = *nsa;
+ ps->sa_sigdesc[signum].sd_tramp = tramp;
+ ps->sa_sigdesc[signum].sd_vers = vers;
sigminusset(&sigcantmask, &SIGACTION_PS(ps, signum).sa_mask);
if ((prop & SA_NORESET) != 0)
SIGACTION_PS(ps, signum).sa_flags &= ~SA_RESETHAND;
***************
*** 262,269 ****
if (error)
return (error);
}
error = sigaction1(p, SCARG(uap, signum),
! SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0);
if (error)
return (error);
if (SCARG(uap, osa)) {
--- 274,314 ----
if (error)
return (error);
}
+ error = sigaction1(p, SCARG(uap, signum),
+ SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
+ NULL, 0);
+ if (error)
+ return (error);
+ if (SCARG(uap, osa)) {
+ error = copyout(&osa, SCARG(uap, osa), sizeof(osa));
+ if (error)
+ return (error);
+ }
+ return (0);
+ }
+
+ /* ARGSUSED */
+ int
+ sys___sigaction_sigtramp(struct proc *p, void *v, register_t *retval)
+ {
+ struct sys___sigaction_sigtramp_args /* {
+ syscallarg(int) signum;
+ syscallarg(const struct sigaction *) nsa;
+ syscallarg(struct sigaction *) osa;
+ syscallarg(void *) tramp;
+ syscallarg(int) vers;
+ } */ *uap = v;
+ struct sigaction nsa, osa;
+ int error;
+
+ if (SCARG(uap, nsa)) {
+ error = copyin(SCARG(uap, nsa), &nsa, sizeof(nsa));
+ if (error)
+ return (error);
+ }
error = sigaction1(p, SCARG(uap, signum),
! SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
! SCARG(uap, tramp), SCARG(uap, vers));
if (error)
return (error);
if (SCARG(uap, osa)) {
***************
*** 689,696 ****
SIGACTION_PS(ps, signum).sa_handler,
&p->p_sigctx.ps_sigmask, code);
#endif
! (*p->p_emul->e_sendsig)(SIGACTION_PS(ps, signum).sa_handler,
! signum, &p->p_sigctx.ps_sigmask, code);
(void) splsched(); /* XXXSMP */
sigplusset(&SIGACTION_PS(ps, signum).sa_mask,
&p->p_sigctx.ps_sigmask);
--- 734,741 ----
SIGACTION_PS(ps, signum).sa_handler,
&p->p_sigctx.ps_sigmask, code);
#endif
! (*p->p_emul->e_sendsig)(signum, &p->p_sigctx.ps_sigmask,
! code);
(void) splsched(); /* XXXSMP */
sigplusset(&SIGACTION_PS(ps, signum).sa_mask,
&p->p_sigctx.ps_sigmask);
***************
*** 1242,1248 ****
p->p_sigctx.ps_code = 0;
p->p_sigctx.ps_sig = 0;
}
! (*p->p_emul->e_sendsig)(action, signum, returnmask, code);
(void) splsched(); /* XXXSMP */
sigplusset(&SIGACTION_PS(ps, signum).sa_mask,
&p->p_sigctx.ps_sigmask);
--- 1287,1293 ----
p->p_sigctx.ps_code = 0;
p->p_sigctx.ps_sig = 0;
}
! (*p->p_emul->e_sendsig)(signum, returnmask, code);
(void) splsched(); /* XXXSMP */
sigplusset(&SIGACTION_PS(ps, signum).sa_mask,
&p->p_sigctx.ps_sigmask);
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/syscalls.master,v
retrieving revision 1.111
diff -c -r1.111 syscalls.master
*** sys/kern/syscalls.master 2002/05/03 00:20:56 1.111
--- sys/kern/syscalls.master 2002/06/22 21:29:02
***************
*** 649,651 ****
--- 649,655 ----
337 UNIMPL
338 UNIMPL
339 UNIMPL
+ 340 STD { int sys___sigaction_sigtramp(int signum, \
+ const struct sigaction *nsa, \
+ struct sigaction *osa, \
+ void *tramp, int vers); }
Index: sys/sys/proc.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/proc.h,v
retrieving revision 1.138
diff -c -r1.138 proc.h
*** sys/sys/proc.h 2002/06/17 16:23:58 1.138
--- sys/sys/proc.h 2002/06/22 21:29:04
***************
*** 101,107 ****
const struct sysent *e_sysent; /* System call array */
const char * const *e_syscallnames; /* System call name array */
/* Signal sending function */
! void (*e_sendsig) __P((sig_t, int, sigset_t *, u_long));
void (*e_trapsignal) __P((struct proc *, int, u_long));
char *e_sigcode; /* Start of sigcode */
char *e_esigcode; /* End of sigcode */
--- 101,107 ----
const struct sysent *e_sysent; /* System call array */
const char * const *e_syscallnames; /* System call name array */
/* Signal sending function */
! void (*e_sendsig) __P((int, sigset_t *, u_long));
void (*e_trapsignal) __P((struct proc *, int, u_long));
char *e_sigcode; /* Start of sigcode */
char *e_esigcode; /* End of sigcode */
Index: sys/sys/signalvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/signalvar.h,v
retrieving revision 1.32
diff -c -r1.32 signalvar.h
*** sys/sys/signalvar.h 2002/03/19 20:50:41 1.32
--- sys/sys/signalvar.h 2002/06/22 21:29:04
***************
*** 47,53 ****
* Process signal actions, possibly shared between threads.
*/
struct sigacts {
! struct sigaction sa_sigact[NSIG]; /* disposition of signals */
int sa_refcnt; /* reference count */
};
--- 47,57 ----
* Process signal actions, possibly shared between threads.
*/
struct sigacts {
! struct sigact_sigdesc {
! struct sigaction sd_sigact;
! void *sd_tramp;
! int sd_vers;
! } sa_sigdesc[NSIG]; /* disposition of signals */
int sa_refcnt; /* reference count */
};
***************
*** 83,90 ****
/*
* get signal action for process and signal; currently only for current process
*/
! #define SIGACTION(p, sig) (p->p_sigacts->sa_sigact[(sig)])
! #define SIGACTION_PS(ps, sig) (ps->sa_sigact[(sig)])
/*
* Mark that signals for a process need to be checked.
--- 87,94 ----
/*
* get signal action for process and signal; currently only for current process
*/
! #define SIGACTION(p, sig) (p->p_sigacts->sa_sigdesc[(sig)].sd_sigact)
! #define SIGACTION_PS(ps, sig) (ps->sa_sigdesc[(sig)].sd_sigact)
/*
* Mark that signals for a process need to be checked.
***************
*** 218,224 ****
int killpg1 __P((struct proc *, int, int, int));
int sigaction1 __P((struct proc *p, int signum, \
! const struct sigaction *nsa, struct sigaction *osa));
int sigprocmask1 __P((struct proc *p, int how, \
const sigset_t *nss, sigset_t *oss));
void sigpending1 __P((struct proc *p, sigset_t *ss));
--- 222,229 ----
int killpg1 __P((struct proc *, int, int, int));
int sigaction1 __P((struct proc *p, int signum, \
! const struct sigaction *nsa, struct sigaction *osa,
! void *, int));
int sigprocmask1 __P((struct proc *p, int how, \
const sigset_t *nss, sigset_t *oss));
void sigpending1 __P((struct proc *p, sigset_t *ss));
***************
*** 236,242 ****
/*
* Machine-dependent functions:
*/
! void sendsig __P((sig_t action, int sig, sigset_t *returnmask, u_long code));
struct core;
struct core32;
int cpu_coredump __P((struct proc *, struct vnode *, struct ucred *,
--- 241,247 ----
/*
* Machine-dependent functions:
*/
! void sendsig __P((int sig, sigset_t *returnmask, u_long code));
struct core;
struct core32;
int cpu_coredump __P((struct proc *, struct vnode *, struct ucred *,
--DO5DiztRLs659m5i--