/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
#include <mach/ppc/thread_status.h>
#include <ppc/proc_reg.h>
+#include <sys/sdt.h>
+
// #include <machine/thread.h> XXX include path messed up for some reason...
/* XXX functions not in a Mach headers */
extern kern_return_t thread_getstatus(register thread_t act, int flavor,
thread_state_t tstate, mach_msg_type_number_t *count);
-extern int is_64signalregset(void);
extern unsigned int get_msr_exportmask(void);
extern kern_return_t thread_setstatus(thread_t thread, int flavor,
thread_state_t tstate, mach_msg_type_number_t count);
#define UC_FLAVOR64_VEC 45
#define UC_DUAL 50
#define UC_DUAL_VEC 55
+#define UC_SET_ALT_STACK 0x40000000
+#define UC_RESET_ALT_STACK 0x80000000
/* The following are valid mcontext sizes */
#define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
* NOTE: Source and target may *NOT* overlap!
*/
static void
-siginfo_64to32(user_siginfo_t *in, siginfo_t *out)
+siginfo_user_to_user32(user_siginfo_t *in, user32_siginfo_t *out)
{
out->si_signo = in->si_signo;
out->si_errno = in->si_errno;
out->si_pid = in->si_pid;
out->si_uid = in->si_uid;
out->si_status = in->si_status;
- out->si_addr = CAST_DOWN(void *,in->si_addr);
+ out->si_addr = CAST_DOWN_EXPLICIT(user32_addr_t,in->si_addr);
/* following cast works for sival_int because of padding */
- out->si_value.sival_ptr = CAST_DOWN(void *,in->si_value.sival_ptr);
+ out->si_value.sival_ptr = CAST_DOWN_EXPLICIT(user32_addr_t,in->si_value.sival_ptr);
out->si_band = in->si_band; /* range reduction */
- out->pad[0] = in->pad[0]; /* mcontext.ss.r1 */
+ out->__pad[0] = in->pad[0]; /* mcontext.ss.r1 */
+}
+
+static void
+siginfo_user_to_user64(user_siginfo_t *in, user64_siginfo_t *out)
+{
+ out->si_signo = in->si_signo;
+ out->si_errno = in->si_errno;
+ out->si_code = in->si_code;
+ out->si_pid = in->si_pid;
+ out->si_uid = in->si_uid;
+ out->si_status = in->si_status;
+ out->si_addr = in->si_addr;
+ out->si_value.sival_ptr = in->si_value.sival_ptr;
+ out->si_band = in->si_band; /* range reduction */
+ out->__pad[0] = in->pad[0]; /* mcontext.ss.r1 */
}
*/
void
-sendsig(struct proc *p, user_addr_t catcher, int sig, int mask, __unused u_long code)
+sendsig(struct proc *p, user_addr_t catcher, int sig, int mask, __unused uint32_t code)
{
kern_return_t kretn;
struct mcontext mctx;
th_act = current_thread();
ut = get_bsdthread_info(th_act);
-
+ /*
+ * XXX We conditionalize type passed here based on SA_SIGINFO, but
+ * XXX we always send up all the information, regardless; perhaps
+ * XXX this should not be conditionalized? Defer making this change
+ * XXX now, due to possible tools impact.
+ */
if (p->p_sigacts->ps_siginfo & sigmask(sig)) {
- infostyle = UC_FLAVOR;
- }
- if(is_64signalregset() && (infostyle == UC_FLAVOR)) {
- dualcontext = 1;
- infostyle = UC_DUAL;
- }
- if (p->p_sigacts->ps_64regset & sigmask(sig)) {
- dualcontext = 0;
- ctx32 = 0;
- infostyle = UC_FLAVOR64;
- }
- /* treat 64 bit processes as having used 64 bit registers */
- if ((IS_64BIT_PROCESS(p) || is_64signalregset()) &&
- (infostyle == UC_TRAD)) {
- ctx32=0;
- infostyle = UC_TRAD64;
- }
- if (IS_64BIT_PROCESS(p)) {
- ctx32=0;
- dualcontext = 0;
+ /*
+ * If SA_SIGINFO is set, then we must provide the user
+ * process both a siginfo_t and a context argument. We call
+ * this "FLAVORED", as opposed to "TRADITIONAL", which doesn't
+ * expect a context. "DUAL" is a type of "FLAVORED".
+ */
+ if (is_64signalregset()) {
+ /*
+ * If this is a 64 bit CPU, we must include a 64 bit
+ * context in the data we pass to user space; we may
+ * or may not also include a 32 bit context at the
+ * same time, for non-leaf functions.
+ *
+ * The user may also explicitly choose to not receive
+ * a 32 bit context, at their option; we only allow
+ * this to happen on 64 bit processors, for obvious
+ * reasons.
+ */
+ if (IS_64BIT_PROCESS(p) ||
+ (p->p_sigacts->ps_64regset & sigmask(sig))) {
+ /*
+ * For a 64 bit process, there is no 32 bit
+ * context.
+ */
+ ctx32 = 0;
+ infostyle = UC_FLAVOR64;
+ } else {
+ /*
+ * For a 32 bit process on a 64 bit CPU, we
+ * may have 64 bit leaf functions, so we need
+ * both contexts.
+ */
+ dualcontext = 1;
+ infostyle = UC_DUAL;
+ }
+ } else {
+ /*
+ * If this is a 32 bit CPU, then we only have a 32 bit
+ * context to contend with.
+ */
+ infostyle = UC_FLAVOR;
+ }
+ } else {
+ /*
+ * If SA_SIGINFO is not set, then we have a traditional style
+ * call which does not need additional context passed. The
+ * default is 32 bit traditional.
+ *
+ * XXX The second check is redundant on PPC32; keep it anyway.
+ */
+ if (is_64signalregset() || IS_64BIT_PROCESS(p)) {
+ /*
+ * However, if this is a 64 bit CPU, we need to change
+ * this to 64 bit traditional, and drop the 32 bit
+ * context.
+ */
+ ctx32 = 0;
+ infostyle = UC_TRAD64;
+ }
}
-
+
+ proc_unlock(p);
+
/* I need this for SIGINFO anyway */
flavor = PPC_THREAD_STATE;
tstate = (void *)&mctx.ss;
}
trampact = ps->ps_trampact[sig];
- oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
+ oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
/* figure out where our new stack lives */
- if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
+ if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
(ps->ps_sigonstack & sigmask(sig))) {
- sp = ps->ps_sigstk.ss_sp;
- sp += ps->ps_sigstk.ss_size;
- stack_size = ps->ps_sigstk.ss_size;
- ps->ps_sigstk.ss_flags |= SA_ONSTACK;
+ sp = ut->uu_sigstk.ss_sp;
+ sp += ut->uu_sigstk.ss_size;
+ stack_size = ut->uu_sigstk.ss_size;
+ ut->uu_sigstk.ss_flags |= SA_ONSTACK;
}
else {
if (ctx32 == 0)
p_uctx = sp;
/* this is where siginfo goes on stack */
- sp -= sizeof(user_siginfo_t);
+ sp -= sizeof(user64_siginfo_t);
p_sinfo = sp;
sp = TRUNC_DOWN64(sp, C_64_PARAMSAVE_LEN+C_64_LINKAGE_LEN, C_64_STK_ALIGN);
p_uctx = sp;
/* this is where siginfo goes on stack */
- sp -= sizeof(siginfo_t);
+ sp -= sizeof(user32_siginfo_t);
p_sinfo = sp;
sp = TRUNC_DOWN32(sp, C_32_PARAMSAVE_LEN+C_32_LINKAGE_LEN, C_32_STK_ALIGN);
uctx.uc_mcontext64 = p_mctx;
/* setup siginfo */
- bzero((caddr_t)&sinfo, sizeof(user_siginfo_t));
+ bzero((caddr_t)&sinfo, sizeof(sinfo));
sinfo.si_signo = sig;
if (ctx32 == 0) {
sinfo.si_addr = mctx64.ss.srr0;
}
switch (sig) {
- case SIGCHLD:
- sinfo.si_pid = p->si_pid;
- p->si_pid =0;
- sinfo.si_status = p->si_status;
- p->si_status = 0;
- sinfo.si_uid = p->si_uid;
- p->si_uid =0;
- sinfo.si_code = p->si_code;
- p->si_code = 0;
- if (sinfo.si_code == CLD_EXITED) {
- if (WIFEXITED(sinfo.si_status))
- sinfo.si_code = CLD_EXITED;
- else if (WIFSIGNALED(sinfo.si_status)) {
- if (WCOREDUMP(sinfo.si_status))
- sinfo.si_code = CLD_DUMPED;
- else
- sinfo.si_code = CLD_KILLED;
- }
- }
- break;
case SIGILL:
/*
* If it's 64 bit and not a dual context, mctx will
}
break;
default:
+ {
+ int status_and_exitcode;
+
+ /*
+ * All other signals need to fill out a minimum set of
+ * information for the siginfo structure passed into
+ * the signal handler, if SA_SIGINFO was specified.
+ *
+ * p->si_status actually contains both the status and
+ * the exit code; we save it off in its own variable
+ * for later breakdown.
+ */
+ proc_lock(p);
+ sinfo.si_pid = p->si_pid;
+ p->si_pid = 0;
+ status_and_exitcode = p->si_status;
+ p->si_status = 0;
+ sinfo.si_uid = p->si_uid;
+ p->si_uid = 0;
+ sinfo.si_code = p->si_code;
+ p->si_code = 0;
+ proc_unlock(p);
+ if (sinfo.si_code == CLD_EXITED) {
+ if (WIFEXITED(status_and_exitcode))
+ sinfo.si_code = CLD_EXITED;
+ else if (WIFSIGNALED(status_and_exitcode)) {
+ if (WCOREDUMP(status_and_exitcode)) {
+ sinfo.si_code = CLD_DUMPED;
+ status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode);
+ } else {
+ sinfo.si_code = CLD_KILLED;
+ status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode);
+ }
+ }
+ }
+ /*
+ * The recorded status contains the exit code and the
+ * signal information, but the information to be passed
+ * in the siginfo to the handler is supposed to only
+ * contain the status, so we have to shift it out.
+ */
+ sinfo.si_status = WEXITSTATUS(status_and_exitcode);
break;
+ }
}
/* copy info out to user space */
if (IS_64BIT_PROCESS(p)) {
+ user64_siginfo_t sinfo64;
+
+ siginfo_user_to_user64(&sinfo,&sinfo64);
+
+#if CONFIG_DTRACE
+ bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+
+ ut->t_dtrace_siginfo.si_signo = sinfo.si_signo;
+ ut->t_dtrace_siginfo.si_code = sinfo.si_code;
+ ut->t_dtrace_siginfo.si_pid = sinfo.si_pid;
+ ut->t_dtrace_siginfo.si_uid = sinfo.si_uid;
+ ut->t_dtrace_siginfo.si_status = sinfo.si_status;
+ /* XXX truncates faulting address to void * on K32 */
+ ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo.si_addr);
+
+
+ /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
+ switch (sig) {
+ case SIGILL: case SIGBUS: case SIGSEGV: case SIGFPE: case SIGTRAP:
+ DTRACE_PROC2(fault, int, (int)(ut->uu_code), siginfo_t *, &(ut->t_dtrace_siginfo));
+ break;
+ default:
+ break;
+ }
+
+ /* XXX truncates catcher address to uintptr_t */
+ DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
+ void (*)(void), CAST_DOWN(sig_t, catcher));
+#endif /* CONFIG_DTRACE */
+
if (copyout(&uctx, p_uctx, sizeof(struct user_ucontext64)))
goto bad;
- if (copyout(&sinfo, p_sinfo, sizeof(user_siginfo_t)))
+ if (copyout(&sinfo64, p_sinfo, sizeof(sinfo64)))
goto bad;
} else {
struct ucontext64 uctx32;
- siginfo_t sinfo32;
+ user32_siginfo_t sinfo32;
ucontext_64to32(&uctx, &uctx32);
+ siginfo_user_to_user32(&sinfo,&sinfo32);
+
+#if CONFIG_DTRACE
+ bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+
+ ut->t_dtrace_siginfo.si_signo = sinfo.si_signo;
+ ut->t_dtrace_siginfo.si_code = sinfo.si_code;
+ ut->t_dtrace_siginfo.si_pid = sinfo.si_pid;
+ ut->t_dtrace_siginfo.si_uid = sinfo.si_uid;
+ ut->t_dtrace_siginfo.si_status = sinfo.si_status;
+ ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo.si_addr);
+
+
+ /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
+ switch (sig) {
+ case SIGILL: case SIGBUS: case SIGSEGV: case SIGFPE: case SIGTRAP:
+ DTRACE_PROC2(fault, int, (int)(ut->uu_code), siginfo_t *, &(ut->t_dtrace_siginfo));
+ break;
+ default:
+ break;
+ }
+
+ DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
+ void (*)(void), CAST_DOWN(sig_t, catcher));
+#endif /* CONFIG_DTRACE */
+
if (copyout(&uctx32, p_uctx, sizeof(struct ucontext64)))
goto bad;
- siginfo_64to32(&sinfo,&sinfo32);
- if (copyout(&sinfo32, p_sinfo, sizeof(siginfo_t)))
+ if (copyout(&sinfo32, p_sinfo, sizeof(sinfo32)))
goto bad;
}
if ((ctx32 == 0) || dualcontext) {
panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn);
}
} else {
- mctx.ss.r3 = CAST_DOWN(unsigned long,catcher);
- mctx.ss.r4 = (unsigned long)infostyle;
- mctx.ss.r5 = (unsigned long)sig;
- mctx.ss.r6 = CAST_DOWN(unsigned long,p_sinfo);
- mctx.ss.r7 = CAST_DOWN(unsigned long,p_uctx);
+ mctx.ss.r3 = CAST_DOWN(uint32_t,catcher);
+ mctx.ss.r4 = (uint32_t)infostyle;
+ mctx.ss.r5 = (uint32_t)sig;
+ mctx.ss.r6 = CAST_DOWN(uint32_t,p_sinfo);
+ mctx.ss.r7 = CAST_DOWN(uint32_t,p_uctx);
- mctx.ss.srr0 = CAST_DOWN(unsigned long,trampact);
+ mctx.ss.srr0 = CAST_DOWN(uint32_t,trampact);
/* MSR_EXPORT_MASK_SET */
mctx.ss.srr1 = get_msr_exportmask();
- mctx.ss.r1 = CAST_DOWN(unsigned long,sp);
+ mctx.ss.r1 = CAST_DOWN(uint32_t,sp);
state_count = PPC_THREAD_STATE_COUNT;
if ((kretn = thread_setstatus(th_act, PPC_THREAD_STATE, (void *)&mctx.ss, state_count)) != KERN_SUCCESS) {
panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn);
}
}
+
+ proc_lock(p);
return;
bad:
+ proc_lock(p);
SIGACTION(p, SIGILL) = SIG_DFL;
sig = sigmask(SIGILL);
p->p_sigignore &= ~sig;
p->p_sigcatch &= ~sig;
ut->uu_sigmask &= ~sig;
/* sendsig is called with signal lock held */
- psignal_lock(p, SIGILL, 0);
+ proc_unlock(p);
+ psignal_locked(p, SIGILL);
+ proc_lock(p);
return;
}
struct sigacts *ps = p->p_sigacts;
sigset_t mask;
user_addr_t action;
- unsigned long state_count;
+ uint32_t state_count;
unsigned int state_flavor;
struct uthread * ut;
int vec_used = 0;
th_act = current_thread();
ut = (struct uthread *)get_bsdthread_info(th_act);
+
+ /*
+ * If we are being asked to change the altstack flag on the thread, we
+ * just rest it and return (the uap->uctx is not used).
+ */
+ if (infostyle == UC_SET_ALT_STACK) {
+ ut->uu_sigstk.ss_flags |= SA_ONSTACK;
+ return (0);
+ } else if ((unsigned int)infostyle == UC_RESET_ALT_STACK) {
+ ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
+ return (0);
+ }
+
if (IS_64BIT_PROCESS(p)) {
error = copyin(uap->uctx, &uctx, sizeof(struct user_ucontext64));
if (error)
return(error);
if ((uctx.uc_onstack & 01))
- p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
+ ut->uu_sigstk.ss_flags |= SA_ONSTACK;
else
- p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
+ ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
if (ut->uu_siglist & ~ut->uu_sigmask)
boolean_t
machine_exception(
- int exception,
- int code,
- __unused int subcode,
- int *unix_signal,
- int *unix_code
-)
+ int exception,
+ mach_exception_code_t code,
+ __unused mach_exception_subcode_t subcode,
+ int *unix_signal,
+ mach_exception_code_t *unix_code)
{
switch(exception) {