/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/sysconfig.h>
#include <sys/ucontext.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>
#include <s10_brand.h>
#include <brand_misc.h>
#include <s10_misc.h>
#include <s10_signal.h>
/*
* Theory of operation:
*
* As of now, Solaris 10 and solaris_nevada signal numbers match all the
* way through SIGJVM2 (1 - 40) and the first 8 realtime signals (41 - 48).
* However, solaris_nevada provides 32 realtime signals rather than 8 for S10.
*
* We do not assume that the current range of realtime signals is
* _SIGRTMIN - _SIGRTMAX. As a hedge against future changes,
* we obtain the realtime signal range via SIGRTMIN and SIGRTMAX.
*
* Therefore, we must interpose on the various signal calls to translate
* signal masks and signal handlers that deal with SIGRTMIN - SIGRTMAX to
* refer to a potentially different range and to intercenpt any "illegal"
* signals that might otherwise be sent to an S10 process.
*
* Important exception:
* We cannot interpose on the SYS_context system call in order to deal with the
* sigset_t contained within the ucontext_t structure because the getcontext()
* part of this system call trap would then return an incorrect set of machine
* registers. See the getcontext() functions in libc to get the gory details.
* The kernel code for getcontext() and setcontext() has been made brand-aware
* in order to deal with this.
*
* Simple translation is all that is required to handle most system calls,
* but signal handlers also must be interposed upon so that a user signal
* handler sees proper signal numbers in its arguments, any passed siginfo_t
* and in the signal mask reported in its ucontext_t.
*
* libc adds its own signal handler to handled signals such that the
* signal delivery mechanism looks like:
*
* signal ->
* libc sigacthandler() ->
* user signal handler()
*
* With interposition, this will instead look like:
*
* signal ->
* s10_sigacthandler() ->
* libc sigacthandler() ->
* user signal handler()
*/
/*
* A little exposition on SIGRTMIN and SIGRTMAX:
*
* For configurability reasons, in Solaris SIGRTMIN and SIGRTMAX are actually
* #defined to be routines:
*
* #define SIGRTMIN ((int)_sysconf(_SC_SIGRT_MIN))
* #define SIGRTMAX ((int)_sysconf(_SC_SIGRT_MAX))
*
* This means we need routines that will call the native sysconfig() system
* call to find out what the native values for SIGRTMIN and SIGRTMAX are, and
* those are native_sigrtmin() and native_sigrtmax(), respectively.
*
* To try and mitigate confusion this might cause, rather than use SIGRTMIN and
* SIGRTMAX directly, mnemonic convenience macros are #defined to clarify the
* matter:
*
* S10_SIGRTMIN
* S10_SIGRTMAX
* NATIVE_SIGRTMIN
* NATIVE_SIGRTMAX
*/
static int
{
static int sigrtmin;
if (sigrtmin)
return (sigrtmin);
return (sigrtmin);
}
static int
{
static int sigrtmax;
if (sigrtmax)
return (sigrtmax);
return (sigrtmax);
}
/*
* These #defines are setup to create the SIGADDSET and SIGISMEMBER macros,
* needed because the sigaddset(3C) and sigismember(3C) calls make function
* calls that end up being recursive in an interpositioned system call
* environment.
*/
/*
* Convert an S10 signal number to its native value.
*/
static int
{
/* signals 1 .. SIGJVM2 are the same between S10 and native */
return (sig);
/*
* If a signal is > SIGJVM2 but is < S10_SIGRTMIN, it's being used
* for some private purpose we likely wouldn't emulate properly.
*/
return (-1);
/*
* If an app passes in a signal that is out of range, it
* expects to get back EINVAL.
*/
if (sig > S10_MAXSIG)
return (-1);
/*
* Map S10 RT signals to their native counterparts to the degree
* possible. If the signal would be out of the native RT signal
* range, return an error to the caller.
*/
sig -= S10_SIGRTMIN;
return (-1);
return (NATIVE_SIGRTMIN + sig);
}
/*
* Convert an S10 sigset_t to its native version.
*/
int
{
int sig;
int nativesig;
return (EFAULT);
(void) sigemptyset(&newset);
/*
* Shortcut: we know the first 32 signals are the same in both
* s10 and native Solaris. Just assign the first word.
*/
/*
* Copy the remainder of the initial set of common signals.
*/
/* convert any S10 RT signals to their native equivalents */
}
return (EFAULT);
return (0);
}
/*
* Convert a native signal number to its S10 value.
*/
int
{
/* signals 1 .. SIGJVM2 are the same between native and S10 */
return (sig);
/*
* We have no way to emulate native signals between (SIGJVM2 + 1) and
* NATIVE_SIGRTMIN, so return an error to the caller.
*/
return (-1);
/*
* Map native RT signals to their S10 counterparts to the degree
* possible. If the signal would be out of range for S10, return
* an error to the caller.
*/
sig -= NATIVE_SIGRTMIN;
return (-1);
return (S10_SIGRTMIN + sig);
}
/*
* Convert a native sigset_t to its S10 version.
*/
int
{
int sig;
int s10sig;
return (EFAULT);
(void) sigemptyset(&newset);
/*
* Shortcut: we know the first 32 signals are the same in both
* s10 and native Solaris. Just assign the first word.
*/
/*
* Copy the remainder of the initial set of common signals.
*/
/* convert any RT signals to their S10 values */
}
return (EFAULT);
return (0);
}
/*
* This is our interposed signal handler.
* Fix up the arguments received from the kernel and jump
* to the s10 signal handler, normally libc's sigacthandler().
*/
static void
{
int s10_sig;
if (s10_sig <= 0) /* can't happen? */
/*
* All we really have to do is map the signal number,
* which changes only for the realtime signals,
* so all the rest of the siginfo structure is the
* same between s10 and native.
*/
}
}
/*
* Interposition upon SYS_lwp_sigmask
*/
int
{
int err;
how,
if (err != 0)
return (err);
return (0);
}
/*
* Interposition upon SYS_sigprocmask
*/
int
{
int err;
return (err);
return (err);
return (err);
return (0);
}
/*
* Interposition upon SYS_sigsuspend
*/
int
{
int err;
return (err);
}
}
/*
* Interposition upon SYS_sigaction
*
* There is a fair amount of complexity here due to the need to interpose
* on any registered user signal handler.
*
* The idea is that if a user signal handler is installed, we must install
* our own signal handler between the system and the signal handler being
* registered. If the signal handler to be registered is SIG_DFL or SIG_IGN,
* we should remove our interpositioned handler as it's no longer needed.
*
* The way we do this is we set the signal handler to call s10_sigacthandler(),
* and then store the address of the passed signal handler in a global
* per-process array, s10_handlers[].
*
* We rely on the fact that the s10 libc blocks all signals during
* its call to the sigaction() system call to guarantee atomicity.
*/
int
{
void (*handler)();
void (*ohandler)();
return (EINVAL);
}
} else {
return (EFAULT);
return (err);
}
}
/*
* Do not store SIG_DFL or SIG_IGN into the array of remembered
* signal handlers. Only store bona-fide function addresses.
* This is to avoid a race condition in which some thread
* sets the signal handler to SIG_DFL or SIG_IGN while some
* other thread is fielding the signal but has not yet reached
* s10_sigacthandler(). s10_sigacthandler() will unconditionally
* call the remembered signal handler and it calls SIG_DFL or
* SIG_IGN, the process will incur a SIGSEGV or SIGBUS signal.
* This also allows a vfork() child to set signal handlers
* to SIG_DFL or SIG_IGN without corrupting the parent's
* address space. store the handler in s10_handlers[] array
* before the sigaction system call to avoid the window for race
* condition with receiving signal. restore the previous handler
* if system call fails.
*/
}
}
return (err);
}
/*
* Translate the old signal mask if we are supposed to return the old
* struct sigaction.
*
* Note that we may have set the signal handler, but may return EFAULT
* here if the oact parameter is bad.
*
* That's OK, because the direct system call acts the same way.
*/
sizeof (struct sigaction)) != 0)
}
return (err);
}
/*
* Interposition upon SYS_sigpending
*/
int
{
int err;
flag, &sigset_set)) != 0)
return (err);
return (err);
return (0);
}
/*
* Interposition upon SYS_sigsendsys
*/
int
{
int nativesig;
return (EINVAL);
}
}
/*
* Convert the siginfo_t code and status fields to an old style
* wait status for s10_wait(), below.
*/
static int
{
switch (code) {
case CLD_EXITED:
stat <<= 8;
break;
case CLD_DUMPED:
break;
case CLD_KILLED:
break;
case CLD_TRAPPED:
case CLD_STOPPED:
stat <<= 8;
break;
case CLD_CONTINUED:
break;
}
return (stat);
}
/*
* Interposition upon SYS_wait
*/
int
{
int err;
if (err != 0)
return (err);
return (0);
}
/*
* Interposition upon SYS_waitid
*/
int
{
if (err != 0)
return (err);
/*
* If the process being waited for terminated or stopped due to a
* signal, translate the signal number from its native value to its
* S10 equivalent.
*
* If we can't legally translate the signal number, just sort of punt
* and leave it untranslated.
*
* We shouldn't return EINVAL as the syscall didn't technically fail.
*/
return (0);
}
/*
* Interposition upon SYS_sigtimedwait
*/
int
{
return (err);
}
return (err);
/*
* If we can't legally translate the signal number in the
* siginfo_t, just sort of punt and leave it untranslated.
*
* We shouldn't return EINVAL as the syscall didn't technically
* fail.
*/
}
/*
* If we can't legally translate the signal number returned by the
* sigtimedwait syscall, just sort of punt and leave it untranslated.
*
* We shouldn't return EINVAL as the syscall didn't technically
* fail.
*/
return (0);
}
/*
* Interposition upon SYS_sigqueue
*/
int
{
int nativesig;
return (EINVAL);
}
if (pid == 1)
pid = zone_init_pid;
/*
* The native version of this syscall takes an extra argument.
* The extra arg is a pointer to a timeout and the timeout specified
* should be zero for sigqueue(3C). The timeout is used by
* sigqueue_wait(3C) and the Opensolaris AIO implementation which is
* part of libc.
*/
}
/*
* Interposition upon SYS_signotify
*/
int
{
/* only check for a valid siginfo pointer in the case of SN_PROC */
int nativesig;
return (EFAULT);
return (EINVAL);
}
}
}
/*
* Interposition upon SYS_kill
*/
int
{
int nativesig;
return (EINVAL);
}
if (pid == 1)
pid = zone_init_pid;
}
/*
* Interposition upon SYS_lwp_create
*
* See also the s10_lwp_create_correct_fs() function in s10_brand.c
* for the special case of creating an lwp in a 64-bit x86 process.
*/
int
{
return (EFAULT);
&s10_uc.uc_sigmask);
}
/*
* Interposition upon SYS_lwp_kill
*/
int
{
int nativesig;
return (EINVAL);
}
}