+++ /dev/null
-/*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * 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.
- *
- * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- */
-
-#include <mach/mach_types.h>
-#include <mach/exception_types.h>
-
-#include <sys/param.h>
-#include <sys/proc_internal.h>
-#include <sys/user.h>
-#include <sys/ucontext.h>
-#include <sys/sysproto.h>
-#include <sys/systm.h>
-#include <sys/ux_exception.h>
-
-#include <ppc/signal.h>
-#include <sys/signalvar.h>
-#include <sys/kdebug.h>
-#include <sys/wait.h>
-#include <kern/thread.h>
-#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 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);
-extern void ppc_checkthreadstate(void *, int);
-extern struct savearea_vec *find_user_vec_curr(void);
-extern int thread_enable_fpe(thread_t act, int onoff);
-
-
-
-#define C_32_REDZONE_LEN 224
-#define C_32_STK_ALIGN 16
-#define C_32_PARAMSAVE_LEN 64
-#define C_32_LINKAGE_LEN 48
-
-#define C_64_REDZONE_LEN 320
-#define C_64_STK_ALIGN 32
-#define C_64_PARAMSAVE_LEN 64
-#define C_64_LINKAGE_LEN 48
-
-#define TRUNC_DOWN32(a,b,c) ((((uint32_t)a)-(b)) & ((uint32_t)(-(c))))
-#define TRUNC_DOWN64(a,b,c) ((((uint64_t)a)-(b)) & ((uint64_t)(-(c))))
-
-/*
- * The stack layout possibilities (info style); This needs to mach with signal trampoline code
- *
- * Traditional: 1
- * Traditional64: 20
- * Traditional64with vec: 25
- * 32bit context 30
- * 32bit context with vector 35
- * 64bit context 40
- * 64bit context with vector 45
- * Dual context 50
- * Dual context with vector 55
- *
- */
-
-#define UC_TRAD 1
-#define UC_TRAD_VEC 6
-#define UC_TRAD64 20
-#define UC_TRAD64_VEC 25
-#define UC_FLAVOR 30
-#define UC_FLAVOR_VEC 35
-#define UC_FLAVOR64 40
-#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))
-
-#define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
-
-#define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
-
-#define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
-
-
-/*
- * NOTE: Source and target may *NOT* overlap!
- */
-static void
-ucontext_32to64(struct ucontext64 *in, struct user_ucontext64 *out)
-{
- out->uc_onstack = in->uc_onstack;
- out->uc_sigmask = in->uc_sigmask;
-
- /* internal "structure assign" */
- out->uc_stack.ss_sp = CAST_USER_ADDR_T(in->uc_stack.ss_sp);
- out->uc_stack.ss_size = in->uc_stack.ss_size;
- out->uc_stack.ss_flags = in->uc_stack.ss_flags;
-
- out->uc_link = CAST_USER_ADDR_T(in->uc_link);
- out->uc_mcsize = in->uc_mcsize;
- out->uc_mcontext64 = CAST_USER_ADDR_T(in->uc_mcontext64);
-}
-
-/*
- * This conversion is safe, since if we are converting for a 32 bit process,
- * then it's values of uc-stack.ss_size and uc_mcsize will never exceed 4G.
- *
- * NOTE: Source and target may *NOT* overlap!
- */
-static void
-ucontext_64to32(struct user_ucontext64 *in, struct ucontext64 *out)
-{
- out->uc_onstack = in->uc_onstack;
- out->uc_sigmask = in->uc_sigmask;
-
- /* internal "structure assign" */
- out->uc_stack.ss_sp = CAST_DOWN(void *,in->uc_stack.ss_sp);
- out->uc_stack.ss_size = in->uc_stack.ss_size; /* range reduction */
- out->uc_stack.ss_flags = in->uc_stack.ss_flags;
-
- out->uc_link = CAST_DOWN(void *,in->uc_link);
- out->uc_mcsize = in->uc_mcsize; /* range reduction */
- out->uc_mcontext64 = CAST_DOWN(void *,in->uc_mcontext64);
-}
-
-/*
- * NOTE: Source and target may *NOT* overlap!
- */
-static void
-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_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 = 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_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 */
-}
-
-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 */
-}
-
-
-/*
- * Arrange for this process to run a signal handler
- */
-
-void
-sendsig(struct proc *p, user_addr_t catcher, int sig, int mask, __unused uint32_t code)
-{
- kern_return_t kretn;
- struct mcontext mctx;
- user_addr_t p_mctx = USER_ADDR_NULL; /* mcontext dest. */
- struct mcontext64 mctx64;
- user_addr_t p_mctx64 = USER_ADDR_NULL; /* mcontext dest. */
- struct user_ucontext64 uctx;
- user_addr_t p_uctx; /* user stack addr top copy ucontext */
- user_siginfo_t sinfo;
- user_addr_t p_sinfo; /* user stack addr top copy siginfo */
- struct sigacts *ps = p->p_sigacts;
- int oonstack;
- user_addr_t sp;
- mach_msg_type_number_t state_count;
- thread_t th_act;
- struct uthread *ut;
- int infostyle = UC_TRAD;
- int dualcontext =0;
- user_addr_t trampact;
- int vec_used = 0;
- int stack_size = 0;
- void * tstate;
- int flavor;
- int ctx32 = 1;
-
- 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)) {
- /*
- * 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;
- state_count = PPC_THREAD_STATE_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
-
- if ((ctx32 == 0) || dualcontext) {
- flavor = PPC_THREAD_STATE64;
- tstate = (void *)&mctx64.ss;
- state_count = PPC_THREAD_STATE64_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
- }
-
- if ((ctx32 == 1) || dualcontext) {
- flavor = PPC_EXCEPTION_STATE;
- tstate = (void *)&mctx.es;
- state_count = PPC_EXCEPTION_STATE_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
- }
-
- if ((ctx32 == 0) || dualcontext) {
- flavor = PPC_EXCEPTION_STATE64;
- tstate = (void *)&mctx64.es;
- state_count = PPC_EXCEPTION_STATE64_COUNT;
-
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
-
- }
-
-
- if ((ctx32 == 1) || dualcontext) {
- flavor = PPC_FLOAT_STATE;
- tstate = (void *)&mctx.fs;
- state_count = PPC_FLOAT_STATE_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
- }
-
- if ((ctx32 == 0) || dualcontext) {
- flavor = PPC_FLOAT_STATE;
- tstate = (void *)&mctx64.fs;
- state_count = PPC_FLOAT_STATE_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
-
- }
-
-
- if (find_user_vec_curr()) {
- vec_used = 1;
-
- if ((ctx32 == 1) || dualcontext) {
- flavor = PPC_VECTOR_STATE;
- tstate = (void *)&mctx.vs;
- state_count = PPC_VECTOR_STATE_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
- infostyle += 5;
- }
-
- if ((ctx32 == 0) || dualcontext) {
- flavor = PPC_VECTOR_STATE;
- tstate = (void *)&mctx64.vs;
- state_count = PPC_VECTOR_STATE_COUNT;
- if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
- goto bad;
- infostyle += 5;
- }
- }
-
- trampact = ps->ps_trampact[sig];
- oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
-
- /* figure out where our new stack lives */
- if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
- (ps->ps_sigonstack & sigmask(sig))) {
- 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)
- sp = mctx64.ss.r1;
- else
- sp = CAST_USER_ADDR_T(mctx.ss.r1);
- }
-
-
- /* put siginfo on top */
-
- /* preserve RED ZONE area */
- if (IS_64BIT_PROCESS(p))
- sp = TRUNC_DOWN64(sp, C_64_REDZONE_LEN, C_64_STK_ALIGN);
- else
- sp = TRUNC_DOWN32(sp, C_32_REDZONE_LEN, C_32_STK_ALIGN);
-
- /* next are the saved registers */
- if ((ctx32 == 0) || dualcontext) {
- sp -= sizeof(struct mcontext64);
- p_mctx64 = sp;
- }
- if ((ctx32 == 1) || dualcontext) {
- sp -= sizeof(struct mcontext);
- p_mctx = sp;
- }
-
- if (IS_64BIT_PROCESS(p)) {
- /* context goes first on stack */
- sp -= sizeof(struct user_ucontext64);
- p_uctx = sp;
-
- /* this is where siginfo goes on stack */
- sp -= sizeof(user64_siginfo_t);
- p_sinfo = sp;
-
- sp = TRUNC_DOWN64(sp, C_64_PARAMSAVE_LEN+C_64_LINKAGE_LEN, C_64_STK_ALIGN);
- } else {
- /*
- * struct ucontext and struct ucontext64 are identical in
- * size and content; the only difference is the internal
- * pointer type for the last element, which makes no
- * difference for the copyout().
- */
-
- /* context goes first on stack */
- sp -= sizeof(struct ucontext64);
- p_uctx = sp;
-
- /* this is where siginfo goes on stack */
- 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_onstack = oonstack;
- uctx.uc_sigmask = mask;
- uctx.uc_stack.ss_sp = sp;
- uctx.uc_stack.ss_size = stack_size;
- if (oonstack)
- uctx.uc_stack.ss_flags |= SS_ONSTACK;
-
- uctx.uc_link = 0;
- if (ctx32 == 0)
- uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE64_COUNT + PPC_THREAD_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
- else
- uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
-
- if (vec_used)
- uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int));
-
- if (ctx32 == 0)
- uctx.uc_mcontext64 = p_mctx64;
- else
- uctx.uc_mcontext64 = p_mctx;
-
- /* setup siginfo */
- bzero((caddr_t)&sinfo, sizeof(sinfo));
- sinfo.si_signo = sig;
- if (ctx32 == 0) {
- sinfo.si_addr = mctx64.ss.srr0;
- sinfo.pad[0] = mctx64.ss.r1;
- } else {
- sinfo.si_addr = CAST_USER_ADDR_T(mctx.ss.srr0);
- sinfo.pad[0] = CAST_USER_ADDR_T(mctx.ss.r1);
- }
-
- switch (sig) {
- case SIGILL:
- /*
- * If it's 64 bit and not a dual context, mctx will
- * contain uninitialized data, so we have to use
- * mctx64 here.
- */
- if(ctx32 == 0) {
- if (mctx64.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT)))
- sinfo.si_code = ILL_ILLOPC;
- else if (mctx64.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT)))
- sinfo.si_code = ILL_PRVOPC;
- else if (mctx64.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT)))
- sinfo.si_code = ILL_ILLTRP;
- else
- sinfo.si_code = ILL_NOOP;
- } else {
- if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT)))
- sinfo.si_code = ILL_ILLOPC;
- else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT)))
- sinfo.si_code = ILL_PRVOPC;
- else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT)))
- sinfo.si_code = ILL_ILLTRP;
- else
- sinfo.si_code = ILL_NOOP;
- }
- break;
- case SIGFPE:
-#define FPSCR_VX 2
-#define FPSCR_OX 3
-#define FPSCR_UX 4
-#define FPSCR_ZX 5
-#define FPSCR_XX 6
- /*
- * If it's 64 bit and not a dual context, mctx will
- * contain uninitialized data, so we have to use
- * mctx64 here.
- */
- if(ctx32 == 0) {
- if (mctx64.fs.fpscr & (1 << (31 - FPSCR_VX)))
- sinfo.si_code = FPE_FLTINV;
- else if (mctx64.fs.fpscr & (1 << (31 - FPSCR_OX)))
- sinfo.si_code = FPE_FLTOVF;
- else if (mctx64.fs.fpscr & (1 << (31 - FPSCR_UX)))
- sinfo.si_code = FPE_FLTUND;
- else if (mctx64.fs.fpscr & (1 << (31 - FPSCR_ZX)))
- sinfo.si_code = FPE_FLTDIV;
- else if (mctx64.fs.fpscr & (1 << (31 - FPSCR_XX)))
- sinfo.si_code = FPE_FLTRES;
- else
- sinfo.si_code = FPE_NOOP;
- } else {
- if (mctx.fs.fpscr & (1 << (31 - FPSCR_VX)))
- sinfo.si_code = FPE_FLTINV;
- else if (mctx.fs.fpscr & (1 << (31 - FPSCR_OX)))
- sinfo.si_code = FPE_FLTOVF;
- else if (mctx.fs.fpscr & (1 << (31 - FPSCR_UX)))
- sinfo.si_code = FPE_FLTUND;
- else if (mctx.fs.fpscr & (1 << (31 - FPSCR_ZX)))
- sinfo.si_code = FPE_FLTDIV;
- else if (mctx.fs.fpscr & (1 << (31 - FPSCR_XX)))
- sinfo.si_code = FPE_FLTRES;
- else
- sinfo.si_code = FPE_NOOP;
- }
- break;
-
- case SIGBUS:
- if (ctx32 == 0) {
- sinfo.si_addr = mctx64.es.dar;
- } else {
- sinfo.si_addr = CAST_USER_ADDR_T(mctx.es.dar);
- }
- /* on ppc we generate only if EXC_PPC_UNALIGNED */
- sinfo.si_code = BUS_ADRALN;
- break;
-
- case SIGSEGV:
- /*
- * If it's 64 bit and not a dual context, mctx will
- * contain uninitialized data, so we have to use
- * mctx64 here.
- */
- if (ctx32 == 0) {
- sinfo.si_addr = mctx64.es.dar;
- /* First check in srr1 and then in dsisr */
- if (mctx64.ss.srr1 & (1 << (31 - DSISR_PROT_BIT)))
- sinfo.si_code = SEGV_ACCERR;
- else if (mctx64.es.dsisr & (1 << (31 - DSISR_PROT_BIT)))
- sinfo.si_code = SEGV_ACCERR;
- else
- sinfo.si_code = SEGV_MAPERR;
- } else {
- sinfo.si_addr = CAST_USER_ADDR_T(mctx.es.dar);
- /* First check in srr1 and then in dsisr */
- if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT)))
- sinfo.si_code = SEGV_ACCERR;
- else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT)))
- sinfo.si_code = SEGV_ACCERR;
- else
- sinfo.si_code = SEGV_MAPERR;
- }
- 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(&sinfo64, p_sinfo, sizeof(sinfo64)))
- goto bad;
- } else {
- struct ucontext64 uctx32;
- 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;
-
- if (copyout(&sinfo32, p_sinfo, sizeof(sinfo32)))
- goto bad;
- }
- if ((ctx32 == 0) || dualcontext) {
- /*
- * NOTE: Size of mcontext is not variant between 64bit and
- * 32bit programs usng 64bit registers.
- */
- if (copyout(&mctx64, p_mctx64, (vec_used? UC_FLAVOR64_VEC_SIZE: UC_FLAVOR64_SIZE)))
- goto bad;
- }
- if ((ctx32 == 1) || dualcontext) {
- if (copyout(&mctx, p_mctx, uctx.uc_mcsize))
- goto bad;
- }
-
-
- /* Place our arguments in arg registers: rtm dependent */
- if(IS_64BIT_PROCESS(p)) {
- mctx64.ss.r3 = catcher;
- mctx64.ss.r4 = CAST_USER_ADDR_T(infostyle);
- mctx64.ss.r5 = CAST_USER_ADDR_T(sig);
- mctx64.ss.r6 = p_sinfo;
- mctx64.ss.r7 = p_uctx;
-
- mctx64.ss.srr0 = trampact;
- /* MSR_EXPORT_MASK_SET */
- mctx64.ss.srr1 = CAST_USER_ADDR_T(get_msr_exportmask());
- mctx64.ss.r1 = sp;
- state_count = PPC_THREAD_STATE64_COUNT;
- if ((kretn = thread_setstatus(th_act, PPC_THREAD_STATE64, (void *)&mctx64.ss, state_count)) != KERN_SUCCESS) {
- panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn);
- }
- } else {
- 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(uint32_t,trampact);
- /* MSR_EXPORT_MASK_SET */
- mctx.ss.srr1 = get_msr_exportmask();
- 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 */
- proc_unlock(p);
- psignal_locked(p, SIGILL);
- proc_lock(p);
- return;
-}
-
-/*
- * System call to cleanup state after a signal
- * has been taken. Reset signal mask and
- * stack state from context left by sendsig (above).
- * Return to previous pc and psl as specified by
- * context left by sendsig. Check carefully to
- * make sure that the user has not modified the
- * psl to gain improper priviledges or to cause
- * a machine fault.
- */
-
-/* ARGSUSED */
-int
-sigreturn(struct proc *p, struct sigreturn_args *uap, __unused int *retval)
-{
- struct user_ucontext64 uctx;
-
- char mactx[sizeof(struct mcontext64)];
- struct mcontext *p_mctx;
- struct mcontext64 *p_64mctx;
- int error;
- thread_t th_act;
- struct sigacts *ps = p->p_sigacts;
- sigset_t mask;
- user_addr_t action;
- uint32_t state_count;
- unsigned int state_flavor;
- struct uthread * ut;
- int vec_used = 0;
- void *tsptr, *fptr, *vptr;
- int infostyle = uap->infostyle;
-
- 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);
- } else {
- struct ucontext64 uctx32;
-
- /*
- * struct ucontext and struct ucontext64 are identical in
- * size and content; the only difference is the internal
- * pointer type for the last element, which makes no
- * difference for the copyin().
- */
- error = copyin(uap->uctx, &uctx32, sizeof(struct ucontext));
- if (error)
- return(error);
- ucontext_32to64(&uctx32, &uctx);
- }
-
-
- /* validate the machine context size */
- switch (uctx.uc_mcsize) {
- case UC_FLAVOR64_VEC_SIZE:
- case UC_FLAVOR64_SIZE:
- case UC_FLAVOR_VEC_SIZE:
- case UC_FLAVOR_SIZE:
- break;
- default:
- return(EINVAL);
- }
-
- /*
- * The 64 bit process mcontext is identical to the mcontext64, so
- * there is no conversion necessary.
- */
- error = copyin(uctx.uc_mcontext64, mactx, uctx.uc_mcsize);
- if (error)
- return(error);
-
- if ((uctx.uc_onstack & 01))
- ut->uu_sigstk.ss_flags |= SA_ONSTACK;
- else
- ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
-
- ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
- if (ut->uu_siglist & ~ut->uu_sigmask)
- signal_setast(current_thread());
-
- vec_used = 0;
- switch (infostyle) {
- case UC_FLAVOR64_VEC:
- case UC_TRAD64_VEC:
- vec_used = 1;
- case UC_TRAD64:
- case UC_FLAVOR64: {
- p_64mctx = (struct mcontext64 *)mactx;
- tsptr = (void *)&p_64mctx->ss;
- fptr = (void *)&p_64mctx->fs;
- vptr = (void *)&p_64mctx->vs;
- state_flavor = PPC_THREAD_STATE64;
- state_count = PPC_THREAD_STATE64_COUNT;
- }
- break;
- case UC_FLAVOR_VEC :
- case UC_TRAD_VEC :
- vec_used = 1;
- case UC_FLAVOR :
- case UC_TRAD :
- default: {
- p_mctx = (struct mcontext *)mactx;
- tsptr = (void *)&p_mctx->ss;
- fptr = (void *)&p_mctx->fs;
- vptr = (void *)&p_mctx->vs;
- state_flavor = PPC_THREAD_STATE;
- state_count = PPC_THREAD_STATE_COUNT;
- }
- break;
- } /* switch () */
-
- /* validate the thread state, set/reset appropriate mode bits in srr1 */
- (void)ppc_checkthreadstate(tsptr, state_flavor);
-
- if (thread_setstatus(th_act, state_flavor, tsptr, state_count) != KERN_SUCCESS) {
- return(EINVAL);
- }
-
- state_count = PPC_FLOAT_STATE_COUNT;
- if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, state_count) != KERN_SUCCESS) {
- return(EINVAL);
- }
-
- mask = sigmask(SIGFPE);
- if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) {
- action = ps->ps_sigact[SIGFPE];
- if((action != SIG_DFL) && (action != SIG_IGN)) {
- thread_enable_fpe(th_act, 1);
- }
- }
-
- if (vec_used) {
- state_count = PPC_VECTOR_STATE_COUNT;
- if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, state_count) != KERN_SUCCESS) {
- return(EINVAL);
- }
- }
- return (EJUSTRETURN);
-}
-
-/*
- * machine_exception() performs MD translation
- * of a mach exception to a unix signal and code.
- */
-
-boolean_t
-machine_exception(
- int exception,
- mach_exception_code_t code,
- __unused mach_exception_subcode_t subcode,
- int *unix_signal,
- mach_exception_code_t *unix_code)
-{
- switch(exception) {
-
- case EXC_BAD_INSTRUCTION:
- *unix_signal = SIGILL;
- *unix_code = code;
- break;
-
- case EXC_ARITHMETIC:
- *unix_signal = SIGFPE;
- *unix_code = code;
- break;
-
- case EXC_SOFTWARE:
- if (code == EXC_PPC_TRAP) {
- *unix_signal = SIGTRAP;
- *unix_code = code;
- break;
- } else
- return(FALSE);
-
- default:
- return(FALSE);
- }
-
- return(TRUE);
-}
-