+ x86_thread_state32_t *tstate32;
+ struct user_ucontext32 uctx32;
+ struct sigframe32 frame32;
+ user32_addr_t token;
+
+ flavor = x86_THREAD_STATE32;
+ state_count = x86_THREAD_STATE32_COUNT;
+ state = (void *)&mctxp->mctx_avx32.ss;
+ if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
+
+ flavor = thread_state32[sig_xstate].flavor;
+ state_count = thread_state32[sig_xstate].state_count;
+ state = (void *)&mctxp->mctx_avx32.fs;
+ if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
+
+ flavor = x86_EXCEPTION_STATE32;
+ state_count = x86_EXCEPTION_STATE32_COUNT;
+ state = (void *)&mctxp->mctx_avx32.es;
+ if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
+
+ tstate32 = &mctxp->mctx_avx32.ss;
+
+ /* figure out where our new stack lives */
+ if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
+ (sigonstack)) {
+ ua_sp = ut->uu_sigstk.ss_sp;
+ stack_size = ut->uu_sigstk.ss_size;
+ ua_sp += stack_size;
+ ut->uu_sigstk.ss_flags |= SA_ONSTACK;
+ } else {
+ ua_sp = tstate32->esp;
+ }
+ ua_cr2 = mctxp->mctx_avx32.es.faultvaddr;
+
+ ua_sp -= sizeof(struct user_ucontext32);
+ ua_uctxp = ua_sp; // someone tramples the first word!
+
+ ua_sp -= sizeof(user32_siginfo_t);
+ ua_sip = ua_sp;
+
+ ua_sp -= thread_state32[sig_xstate].mcontext_size;
+ ua_mctxp = ua_sp;
+
+ ua_sp -= sizeof(struct sigframe32);
+ ua_fp = ua_sp;
+
+ /*
+ * Align the frame and stack pointers to 16 bytes for SSE.
+ * (Note that we use 'fp' as the base of the stack going forward)
+ */
+ ua_fp = TRUNC_DOWN32(ua_fp, C_32_STK_ALIGN);
+
+ /*
+ * But we need to account for the return address so the alignment is
+ * truly "correct" at _sigtramp
+ */
+ ua_fp -= sizeof(frame32.retaddr);
+
+ /*
+ * Generate the validation token for sigreturn
+ */
+ token_uctx = ua_uctxp;
+ kr = machine_thread_siguctx_pointer_convert_to_user(thread, &token_uctx);
+ assert(kr == KERN_SUCCESS);
+ token = CAST_DOWN_EXPLICIT(user32_addr_t, token_uctx) ^
+ CAST_DOWN_EXPLICIT(user32_addr_t, ps->ps_sigreturn_token);
+
+ /*
+ * Build the argument list for the signal handler.
+ * Handler should call sigreturn to get out of it
+ */
+ frame32.retaddr = -1;
+ frame32.sigstyle = infostyle;
+ frame32.sig = sig;
+ frame32.catcher = CAST_DOWN_EXPLICIT(user32_addr_t, ua_catcher);
+ frame32.sinfo = CAST_DOWN_EXPLICIT(user32_addr_t, ua_sip);
+ frame32.uctx = CAST_DOWN_EXPLICIT(user32_addr_t, ua_uctxp);
+ frame32.token = token;
+
+ if (copyout((caddr_t)&frame32, ua_fp, sizeof(frame32))) {
+ goto bad;
+ }
+
+ /*
+ * Build the signal context to be used by sigreturn.
+ */
+ bzero(&uctx32, sizeof(uctx32));
+
+ uctx32.uc_onstack = oonstack;
+ uctx32.uc_sigmask = mask;
+ uctx32.uc_stack.ss_sp = CAST_DOWN_EXPLICIT(user32_addr_t, ua_fp);
+ uctx32.uc_stack.ss_size = stack_size;
+
+ if (oonstack) {
+ uctx32.uc_stack.ss_flags |= SS_ONSTACK;
+ }
+ uctx32.uc_link = 0;
+
+ uctx32.uc_mcsize = thread_state64[sig_xstate].mcontext_size;
+
+ uctx32.uc_mcontext = CAST_DOWN_EXPLICIT(user32_addr_t, ua_mctxp);
+
+ if (copyout((caddr_t)&uctx32, ua_uctxp, sizeof(uctx32))) {
+ goto bad;
+ }
+
+ if (copyout((caddr_t)&mctx_store, ua_mctxp, thread_state32[sig_xstate].mcontext_size)) {
+ goto bad;
+ }
+
+ sinfo64.pad[0] = tstate32->esp;
+ sinfo64.si_addr = tstate32->eip;
+ }
+
+ switch (sig) {
+ case SIGILL:
+ switch (ut->uu_code) {
+ case EXC_I386_INVOP:
+ sinfo64.si_code = ILL_ILLOPC;
+ break;
+ default:
+ sinfo64.si_code = ILL_NOOP;
+ }
+ break;
+ case SIGFPE:
+#define FP_IE 0 /* Invalid operation */
+#define FP_DE 1 /* Denormalized operand */
+#define FP_ZE 2 /* Zero divide */
+#define FP_OE 3 /* overflow */
+#define FP_UE 4 /* underflow */
+#define FP_PE 5 /* precision */
+ if (ut->uu_code == EXC_I386_DIV) {
+ sinfo64.si_code = FPE_INTDIV;
+ } else if (ut->uu_code == EXC_I386_INTO) {
+ sinfo64.si_code = FPE_INTOVF;
+ } else if (ut->uu_subcode & (1 << FP_ZE)) {
+ sinfo64.si_code = FPE_FLTDIV;
+ } else if (ut->uu_subcode & (1 << FP_OE)) {
+ sinfo64.si_code = FPE_FLTOVF;
+ } else if (ut->uu_subcode & (1 << FP_UE)) {
+ sinfo64.si_code = FPE_FLTUND;
+ } else if (ut->uu_subcode & (1 << FP_PE)) {
+ sinfo64.si_code = FPE_FLTRES;
+ } else if (ut->uu_subcode & (1 << FP_IE)) {
+ sinfo64.si_code = FPE_FLTINV;
+ } else {
+ sinfo64.si_code = FPE_NOOP;
+ }
+ break;
+ case SIGBUS:
+ sinfo64.si_code = BUS_ADRERR;
+ sinfo64.si_addr = ua_cr2;
+ break;
+ case SIGTRAP:
+ sinfo64.si_code = TRAP_BRKPT;
+ break;
+ case SIGSEGV:
+ sinfo64.si_addr = ua_cr2;
+
+ switch (ut->uu_code) {
+ case EXC_I386_GPFLT:
+ /* CR2 is meaningless after GP fault */
+ /* XXX namespace clash! */
+ sinfo64.si_addr = 0ULL;
+ sinfo64.si_code = 0;
+ break;
+ case KERN_PROTECTION_FAILURE:
+ sinfo64.si_code = SEGV_ACCERR;
+ break;
+ case KERN_INVALID_ADDRESS:
+ sinfo64.si_code = SEGV_MAPERR;
+ break;
+ default:
+ sinfo64.si_code = FPE_NOOP;
+ }
+ 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);
+ sinfo64.si_pid = p->si_pid;
+ p->si_pid = 0;
+ status_and_exitcode = p->si_status;
+ p->si_status = 0;
+ sinfo64.si_uid = p->si_uid;
+ p->si_uid = 0;
+ sinfo64.si_code = p->si_code;
+ p->si_code = 0;
+ proc_unlock(p);
+ if (sinfo64.si_code == CLD_EXITED) {
+ if (WIFEXITED(status_and_exitcode)) {
+ sinfo64.si_code = CLD_EXITED;
+ } else if (WIFSIGNALED(status_and_exitcode)) {
+ if (WCOREDUMP(status_and_exitcode)) {
+ sinfo64.si_code = CLD_DUMPED;
+ status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
+ } else {
+ sinfo64.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.
+ */
+ sinfo64.si_status = (WEXITSTATUS(status_and_exitcode) & 0x00FFFFFF) | (((uint32_t)(p->p_xhighbits) << 24) & 0xFF000000);
+ p->p_xhighbits = 0;
+ break;
+ }