sendsig.c revision a3c558251a68374a017f360afdc6c4f377a667ea
/*
* 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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/archsystm.h>
#include <sys/ucontext.h>
#include <sys/debugreg.h>
#include <sys/privregs.h>
#include <vm/seg_kmem.h>
#include <sys/tuneable.h>
#include <sys/bootconf.h>
#include <sys/systeminfo.h>
#include <sys/contract_impl.h>
#include <sys/x86_archext.h>
/*
* Construct the execution environment for the user's signal
* handler and arrange for control to be given to it on return
* to userland. The library code now calls setcontext() to
* clean up after the signal handler, so sigret() is no longer
* needed.
*
* (The various 'volatile' declarations are need to ensure that values
* are correct on the error return from on_fault().)
*/
#if defined(__amd64)
/*
* An amd64 signal frame looks like this on the stack:
*
* old %rsp:
* <128 bytes of untouched stack space>
* <a siginfo_t [optional]>
* <a ucontext_t>
* <siginfo_t *>
* <signal number>
* new %rsp: <return address (deliberately invalid)>
*
* The signal number and siginfo_t pointer are only pushed onto the stack in
* order to allow stack backtraces. The actual signal handling code expects the
* arguments in registers.
*/
struct sigframe {
long signo;
};
int
{
volatile int minstacksz;
int newstack;
ucontext_t *uc;
volatile int watched;
/*
* This routine is utterly dependent upon STACK_ALIGN being
* 16 and STACK_ENTRY_ALIGN being 8. Let's just acknowledge
* that and require it.
*/
#error "sendsig() amd64 did not find the expected stack alignments"
#endif
/*
* Since we're setting up to run the signal handler we have to
* arrange that the stack at entry to the handler is (only)
* STACK_ENTRY_ALIGN (i.e. 8) byte aligned so that when the handler
* executes its push of %rbp, the stack realigns to STACK_ALIGN
* (i.e. 16) correctly.
*
* The new sp will point to the sigframe and the ucontext_t. The
* above means that sp (and thus sigframe) will be 8-byte aligned,
* but not 16-byte aligned. ucontext_t, however, contains %xmm regs
* which must be 16-byte aligned. Because of this, for correct
* alignment, sigframe must be a multiple of 8-bytes in length, but
* not 16-bytes. This will place ucontext_t at a nice 16-byte boundary.
*/
/* LINTED: logical expression always true: op "||" */
/*
* Figure out whether we will be handling this signal on
* an alternate stack specified by the user. Then allocate
* and validate the stack requirements for the signal handler
* context. on_fault will catch any faults.
*/
if (newstack) {
} else {
/*
* Drop below the 128-byte reserved region of the stack frame
* we're interrupting.
*/
}
/*
* Force proper stack pointer alignment, even in the face of a
* misaligned stack pointer from user-level before the signal.
*/
/*
* Most of the time during normal execution, the stack pointer
* is aligned on a STACK_ALIGN (i.e. 16 byte) boundary. However,
* (for example) just after a call instruction (which pushes
* the return address), the callers stack misaligns until the
* 'push %rbp' happens in the callee prolog. So while we should
* expect the stack pointer to be always at least STACK_ENTRY_ALIGN
* aligned, we should -not- expect it to always be STACK_ALIGN aligned.
* We now adjust to ensure that the new sp is aligned to
* STACK_ENTRY_ALIGN but not to STACK_ALIGN.
*/
sp -= STACK_ENTRY_ALIGN;
}
/*
* Now, make sure the resulting signal frame address is sane
*/
#ifdef DEBUG
printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
printf("sp above USERLIMIT\n");
#endif
return (0);
}
goto badstack;
if (SI_FROMUSER(sip) &&
} else
/*
* We stand on our head to deal with
* the real time profiling signal.
* Fill in the stuff that doesn't fit
* in a normal k_siginfo structure.
*/
int i = sip->si_nsysarg;
while (--i >= 0)
}
} else
/*
* save the current context on the user stack directly after the
* sigframe. Since sigframe is 8-byte-but-not-16-byte aligned,
* and since sizeof (struct sigframe) is 24, this guarantees
* 16-byte alignment for ucontext_t and its %xmm registers.
*/
if (newstack) {
if (lwp->lwp_ustack)
}
/*
* Set up signal handler return and stack linkage
*/
{
/*
* ensure we never return "normally"
*/
}
no_fault();
if (watched)
/*
* Set up user registers for execution of signal handler.
*/
/*
* Try our best to deliver the signal.
*/
}
/*
* Don't set lwp_eosys here. sendsig() is called via psig() after
* lwp_eosys is handled, so setting it here would affect the next
* system call.
*/
return (1);
no_fault();
if (watched)
if (tuc)
#ifdef DEBUG
printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
#endif
return (0);
}
#ifdef _SYSCALL32_IMPL
/*
*
* old %esp:
* <a siginfo32_t [optional]>
* <a ucontext32_t>
* <pointer to that ucontext32_t>
* <pointer to that siginfo32_t>
* <signo>
* new %esp: <return address (deliberately invalid)>
*/
struct sigframe32 {
};
int
{
volatile int minstacksz;
int newstack;
volatile int watched;
/*
* Figure out whether we will be handling this signal on
* an alternate stack specified by the user. Then allocate
* and validate the stack requirements for the signal handler
* context. on_fault will catch any faults.
*/
if (newstack) {
/*
* If the stack segment selector is -not- pointing at
* the UDS_SEL descriptor and we have an LDT entry for
* it instead, add the base address to find the effective va.
*/
else
} else
/*
* Force proper stack pointer alignment, even in the face of a
* misaligned stack pointer from user-level before the signal.
* Don't use the SA32() macro because that rounds up, not down.
*/
/*
* Make sure lwp hasn't trashed its stack
*/
#ifdef DEBUG
printf("sendsig32: bad signal stack cmd=%s, pid=%d, sig=%d\n",
printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
printf("sp above USERLIMIT\n");
#endif
return (0);
}
goto badstack;
if (SI_FROMUSER(sip) &&
}
/*
* We stand on our head to deal with
* the real-time profiling signal.
* Fill in the stuff that doesn't fit
* in a normal k_siginfo structure.
*/
int i = sip->si_nsysarg;
while (--i >= 0)
}
} else
/* save the current context on the user stack */
if (newstack) {
if (lwp->lwp_ustack) {
}
}
/*
* Set up signal handler arguments
*/
{
struct sigframe32 frame32;
}
no_fault();
if (watched)
/*
* Try our best to deliver the signal.
*/
}
/*
* Don't set lwp_eosys here. sendsig() is called via psig() after
* lwp_eosys is handled, so setting it here would affect the next
* system call.
*/
return (1);
no_fault();
if (watched)
if (tuc)
#ifdef DEBUG
printf("sendsig32: bad signal stack cmd=%s pid=%d, sig=%d\n",
printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
#endif
return (0);
}
#endif /* _SYSCALL32_IMPL */
/*
*
* old %esp:
* <a siginfo32_t [optional]>
* <a ucontext32_t>
* <pointer to that ucontext32_t>
* <pointer to that siginfo32_t>
* <signo>
* new %esp: <return address (deliberately invalid)>
*/
struct sigframe {
void (*retaddr)();
};
int
{
volatile int minstacksz;
int newstack;
ucontext_t *uc;
volatile int watched;
/*
* Figure out whether we will be handling this signal on
* an alternate stack specified by the user. Then allocate
* and validate the stack requirements for the signal handler
* context. on_fault will catch any faults.
*/
if (newstack) {
/*
* If the stack segment selector is -not- pointing at
* the UDS_SEL descriptor and we have an LDT entry for
* it instead, add the base address to find the effective va.
*/
else
} else
/*
* Force proper stack pointer alignment, even in the face of a
* misaligned stack pointer from user-level before the signal.
* Don't use the SA() macro because that rounds up, not down.
*/
/*
* Make sure lwp hasn't trashed its stack.
*/
#ifdef DEBUG
printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
printf("sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
printf("sp above USERLIMIT\n");
#endif
return (0);
}
goto badstack;
if (SI_FROMUSER(sip) &&
} else
/*
* We stand on our head to deal with
* the real time profiling signal.
* Fill in the stuff that doesn't fit
* in a normal k_siginfo structure.
*/
int i = sip->si_nsysarg;
while (--i >= 0)
}
} else
/* save the current context on the user stack */
if (newstack) {
if (lwp->lwp_ustack)
}
/*
* Set up signal handler arguments
*/
{
}
no_fault();
if (watched)
}
/*
* Don't set lwp_eosys here. sendsig() is called via psig() after
* lwp_eosys is handled, so setting it here would affect the next
* system call.
*/
return (1);
no_fault();
if (watched)
if (tuc)
#ifdef DEBUG
printf("sendsig: bad signal stack cmd=%s, pid=%d, sig=%d\n",
printf("on fault, sigsp = 0x%p, action = 0x%p, upc = 0x%lx\n",
#endif
return (0);
}
#endif /* __i386 */