* Copyright (c) 2000-2006 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
* 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,
* 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) 1992 NeXT, Inc.
*
* HISTORY
#include <mach/exception.h>
#include <kern/thread.h>
+#include <kern/ast.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/ux_exception.h>
-#include <mach/thread_act.h> /* for thread_abort_safely */
-#include <mach/thread_status.h>
+#include <mach/thread_act.h> /* for thread_abort_safely */
+#include <mach/thread_status.h>
#include <i386/eflags.h>
#include <i386/psl.h>
/* Forward: */
extern kern_return_t thread_getstatus(thread_t act, int flavor,
- thread_state_t tstate, mach_msg_type_number_t *count);
+ thread_state_t tstate, mach_msg_type_number_t *count);
extern kern_return_t thread_setstatus(thread_t thread, int flavor,
- thread_state_t tstate, mach_msg_type_number_t count);
+ thread_state_t tstate, mach_msg_type_number_t count);
/* Signal handler flavors supported */
/* These defns should match the Libc implmn */
-#define UC_TRAD 1
-#define UC_FLAVOR 30
-#define UC_SET_ALT_STACK 0x40000000
-#define UC_RESET_ALT_STACK 0x80000000
+#define UC_TRAD 1
+#define UC_FLAVOR 30
+#define UC_SET_ALT_STACK 0x40000000
+#define UC_RESET_ALT_STACK 0x80000000
-#define C_32_STK_ALIGN 16
-#define C_64_STK_ALIGN 16
-#define C_64_REDZONE_LEN 128
-#define TRUNC_DOWN32(a,c) ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
-#define TRUNC_DOWN64(a,c) ((((uint64_t)a)-(c)) & ((uint64_t)(-(c))))
+#define C_32_STK_ALIGN 16
+#define C_64_STK_ALIGN 16
+#define C_64_REDZONE_LEN 128
+#define TRUNC_DOWN32(a, c) ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
+#define TRUNC_DOWN64(a, c) ((((uint64_t)a)-(c)) & ((uint64_t)(-(c))))
/*
* Send an interrupt to process.
* Stack is set up to allow sigcode stored
* in u. to call routine, followed by chmk
* to sigreturn routine below. After sigreturn
- * resets the signal mask, the stack, the frame
+ * resets the signal mask, the stack, the frame
* pointer, and the argument pointer, it returns
* to the user specified pc, psl.
*/
struct sigframe32 {
- int retaddr;
- user32_addr_t catcher; /* sig_t */
- int sigstyle;
- int sig;
- user32_addr_t sinfo; /* siginfo32_t* */
- user32_addr_t uctx; /* struct ucontext32 */
- user32_addr_t token;
+ int retaddr;
+ user32_addr_t catcher; /* sig_t */
+ int sigstyle;
+ int sig;
+ user32_addr_t sinfo; /* siginfo32_t* */
+ user32_addr_t uctx; /* struct ucontext32 */
+ user32_addr_t token;
};
/*
* for the cases of extended states (plain FP, or AVX):
*/
typedef struct {
- int flavor; natural_t state_count; size_t mcontext_size;
-} xstate_info_t;
+ int flavor; natural_t state_count; size_t mcontext_size;
+} xstate_info_t;
static const xstate_info_t thread_state64[] = {
- [FP] = { x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT, sizeof(struct mcontext64) },
- [AVX] = { x86_AVX_STATE64, x86_AVX_STATE64_COUNT, sizeof(struct mcontext_avx64) },
-#if !defined(RC_HIDE_XNU_J137)
- [AVX512] = { x86_AVX512_STATE64, x86_AVX512_STATE64_COUNT, sizeof(struct mcontext_avx512_64) }
-#endif
+ [FP] = { x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT, sizeof(struct mcontext64) },
+ [FP_FULL] = { x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT, sizeof(struct mcontext64_full) },
+ [AVX] = { x86_AVX_STATE64, x86_AVX_STATE64_COUNT, sizeof(struct mcontext_avx64) },
+ [AVX_FULL] = { x86_AVX_STATE64, x86_AVX_STATE64_COUNT, sizeof(struct mcontext_avx64_full) },
+ [AVX512] = { x86_AVX512_STATE64, x86_AVX512_STATE64_COUNT, sizeof(struct mcontext_avx512_64) },
+ [AVX512_FULL] = { x86_AVX512_STATE64, x86_AVX512_STATE64_COUNT, sizeof(struct mcontext_avx512_64_full) }
};
static const xstate_info_t thread_state32[] = {
- [FP] = { x86_FLOAT_STATE32, x86_FLOAT_STATE32_COUNT, sizeof(struct mcontext32) },
- [AVX] = { x86_AVX_STATE32, x86_AVX_STATE32_COUNT, sizeof(struct mcontext_avx32) },
-#if !defined(RC_HIDE_XNU_J137)
- [AVX512] = { x86_AVX512_STATE32, x86_AVX512_STATE32_COUNT, sizeof(struct mcontext_avx512_32) }
-#endif
+ [FP] = { x86_FLOAT_STATE32, x86_FLOAT_STATE32_COUNT, sizeof(struct mcontext32) },
+ [AVX] = { x86_AVX_STATE32, x86_AVX_STATE32_COUNT, sizeof(struct mcontext_avx32) },
+ [AVX512] = { x86_AVX512_STATE32, x86_AVX512_STATE32_COUNT, sizeof(struct mcontext_avx512_32) }
};
/*
static void
siginfo_user_to_user32_x86(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);
+ 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 */
+ 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_x86(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 */
+ 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 ua_catcher, int sig, int mask, __unused uint32_t code)
+sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint32_t code, sigset_t siginfo)
{
union {
- struct mcontext_avx32 mctx_avx32;
- struct mcontext_avx64 mctx_avx64;
-#if !defined(RC_HIDE_XNU_J137)
- struct mcontext_avx512_32 mctx_avx512_32;
- struct mcontext_avx512_64 mctx_avx512_64;
-#endif
+ struct mcontext_avx32 mctx_avx32;
+ struct mcontext_avx64 mctx_avx64;
+ struct mcontext_avx64_full mctx_avx64_full;
+ struct mcontext_avx512_32 mctx_avx512_32;
+ struct mcontext_avx512_64 mctx_avx512_64;
+ struct mcontext_avx512_64_full mctx_avx512_64_full;
} mctx_store, *mctxp = &mctx_store;
- user_addr_t ua_sp;
- user_addr_t ua_fp;
- user_addr_t ua_cr2;
- user_addr_t ua_sip;
- user_addr_t ua_uctxp;
- user_addr_t ua_mctxp;
- user_siginfo_t sinfo64;
+ user_addr_t ua_sp;
+ user_addr_t ua_fp;
+ user_addr_t ua_cr2;
+ user_addr_t ua_sip;
+ user_addr_t ua_uctxp;
+ user_addr_t ua_mctxp;
+ user_siginfo_t sinfo64;
struct sigacts *ps = p->p_sigacts;
- int oonstack, flavor;
+ int oonstack, flavor;
user_addr_t trampact;
int sigonstack;
- void * state;
+ void * state, *fpstate;
mach_msg_type_number_t state_count;
thread_t thread;
struct uthread * ut;
int stack_size = 0;
int infostyle = UC_TRAD;
- xstate_t sig_xstate;
+ xstate_t sig_xstate;
user_addr_t token_uctx;
kern_return_t kr;
+ boolean_t reset_ss = TRUE;
thread = current_thread();
ut = get_bsdthread_info(thread);
- if (p->p_sigacts->ps_siginfo & sigmask(sig))
+ if (siginfo & sigmask(sig)) {
infostyle = UC_FLAVOR;
+ }
oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
trampact = ps->ps_trampact[sig];
sig_xstate = current_xstate();
if (proc_is64bit(p)) {
- x86_thread_state64_t *tstate64;
- struct user_ucontext64 uctx64;
+ x86_thread_state64_t *tstate64;
+ struct user_ucontext64 uctx64;
user64_addr_t token;
+ int task_has_ldt = thread_task_has_ldt(thread);
- flavor = x86_THREAD_STATE64;
- state_count = x86_THREAD_STATE64_COUNT;
+ if (task_has_ldt) {
+ flavor = x86_THREAD_FULL_STATE64;
+ state_count = x86_THREAD_FULL_STATE64_COUNT;
+ fpstate = (void *)&mctxp->mctx_avx64_full.fs;
+ sig_xstate |= STATE64_FULL;
+ } else {
+ flavor = x86_THREAD_STATE64;
+ state_count = x86_THREAD_STATE64_COUNT;
+ fpstate = (void *)&mctxp->mctx_avx64.fs;
+ }
state = (void *)&mctxp->mctx_avx64.ss;
- if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
- goto bad;
+
+ /*
+ * The state copying is performed with pointers to fields in the state
+ * struct. This works specifically because the mcontext is layed-out with the
+ * variable-sized FP-state as the last member. However, with the requirement
+ * to support passing "full" 64-bit state to the signal handler, that layout has now
+ * changed (since the "full" state has a larger "ss" member than the non-"full"
+ * structure. Because of this, and to retain the array-lookup method of determining
+ * structure sizes, we OR-in STATE64_FULL to sig_xstate to ensure the proper mcontext
+ * size is passed.
+ */
+
+ if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
+
+ if ((sig_xstate & STATE64_FULL) && mctxp->mctx_avx64.ss.cs != USER64_CS) {
+ if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
+ (sigonstack)) {
+ reset_ss = TRUE;
+ } else {
+ reset_ss = FALSE;
+ }
+ } else {
+ reset_ss = FALSE;
+ }
flavor = thread_state64[sig_xstate].flavor;
state_count = thread_state64[sig_xstate].state_count;
- state = (void *)&mctxp->mctx_avx64.fs;
- if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
- goto bad;
+ if (thread_getstatus(thread, flavor, (thread_state_t)fpstate, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
flavor = x86_EXCEPTION_STATE64;
state_count = x86_EXCEPTION_STATE64_COUNT;
state = (void *)&mctxp->mctx_avx64.es;
- if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
- goto bad;
+ if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
tstate64 = &mctxp->mctx_avx64.ss;
ua_sp += stack_size;
ut->uu_sigstk.ss_flags |= SA_ONSTACK;
} else {
- ua_sp = tstate64->rsp;
+ if ((sig_xstate & STATE64_FULL) && tstate64->cs != USER64_CS) {
+ reset_ss = FALSE;
+ }
+ ua_sp = tstate64->rsp;
}
ua_cr2 = mctxp->mctx_avx64.es.faultvaddr;
/* The x86_64 ABI defines a 128-byte red zone. */
ua_sp -= C_64_REDZONE_LEN;
- ua_sp -= sizeof (struct user_ucontext64);
- ua_uctxp = ua_sp; // someone tramples the first word!
+ ua_sp -= sizeof(struct user_ucontext64);
+ ua_uctxp = ua_sp; // someone tramples the first word!
- ua_sp -= sizeof (user64_siginfo_t);
+ ua_sp -= sizeof(user64_siginfo_t);
ua_sip = ua_sp;
ua_sp -= thread_state64[sig_xstate].mcontext_size;
uctx64.uc_stack.ss_sp = ua_fp;
uctx64.uc_stack.ss_size = stack_size;
- if (oonstack)
- uctx64.uc_stack.ss_flags |= SS_ONSTACK;
+ if (oonstack) {
+ uctx64.uc_stack.ss_flags |= SS_ONSTACK;
+ }
uctx64.uc_link = 0;
uctx64.uc_mcsize = thread_state64[sig_xstate].mcontext_size;
uctx64.uc_mcontext64 = ua_mctxp;
-
- if (copyout((caddr_t)&uctx64, ua_uctxp, sizeof (uctx64)))
- goto bad;
- if (copyout((caddr_t)&mctx_store, ua_mctxp, thread_state64[sig_xstate].mcontext_size))
- goto bad;
+ if (copyout((caddr_t)&uctx64, ua_uctxp, sizeof(uctx64))) {
+ goto bad;
+ }
+
+ if (copyout((caddr_t)&mctx_store, ua_mctxp, thread_state64[sig_xstate].mcontext_size)) {
+ goto bad;
+ }
sinfo64.pad[0] = tstate64->rsp;
sinfo64.si_addr = tstate64->rip;
tstate64->rip = trampact;
tstate64->rsp = ua_fp;
tstate64->rflags = get_eflags_exportmask();
+
/*
- * JOE - might not need to set these
+ * SETH - need to set these for processes with LDTs
*/
tstate64->cs = USER64_CS;
tstate64->fs = NULL_SEG;
- tstate64->gs = USER_CTHREAD;
+ /*
+ * Set gs to 0 here to prevent restoration of %gs on return-to-user. If we
+ * did NOT do that here and %gs was non-zero, we'd blow away gsbase when
+ * we restore %gs in the kernel exit trampoline.
+ */
+ tstate64->gs = 0;
+
+ if (sig_xstate & STATE64_FULL) {
+ /* Reset DS, ES, and possibly SS */
+ if (reset_ss) {
+ /*
+ * Restore %ss if (a) an altstack was used for signal delivery
+ * or (b) %cs at the time of the signal was the default
+ * (USER64_CS)
+ */
+ mctxp->mctx_avx64_full.ss.ss = USER64_DS;
+ }
+ mctxp->mctx_avx64_full.ss.ds = USER64_DS;
+ mctxp->mctx_avx64_full.ss.es = 0;
+ }
- /*
+ /*
* Build the argument list for the signal handler.
* Handler should call sigreturn to get out of it
*/
tstate64->r8 = ua_uctxp;
tstate64->r9 = token;
} else {
- x86_thread_state32_t *tstate32;
- struct user_ucontext32 uctx32;
- struct sigframe32 frame32;
+ x86_thread_state32_t *tstate32;
+ struct user_ucontext32 uctx32;
+ struct sigframe32 frame32;
user32_addr_t token;
- flavor = x86_THREAD_STATE32;
+ 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;
+ 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;
+ 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;
+ if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
tstate32 = &mctxp->mctx_avx32.ss;
ua_sp += stack_size;
ut->uu_sigstk.ss_flags |= SA_ONSTACK;
} else {
- ua_sp = tstate32->esp;
+ 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(struct user_ucontext32);
+ ua_uctxp = ua_sp; // someone tramples the first word!
- ua_sp -= sizeof (user32_siginfo_t);
+ 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_sp -= sizeof(struct sigframe32);
ua_fp = ua_sp;
/*
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);
+ 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.retaddr = -1;
frame32.sigstyle = infostyle;
frame32.sig = sig;
frame32.catcher = CAST_DOWN_EXPLICIT(user32_addr_t, ua_catcher);
frame32.uctx = CAST_DOWN_EXPLICIT(user32_addr_t, ua_uctxp);
frame32.token = token;
- if (copyout((caddr_t)&frame32, ua_fp, sizeof (frame32)))
- goto bad;
+ if (copyout((caddr_t)&frame32, ua_fp, sizeof(frame32))) {
+ goto bad;
+ }
/*
* Build the signal context to be used by sigreturn.
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;
+ 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;
+ 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;
- }
+ case SIGILL:
+ switch (ut->uu_code) {
+ case EXC_I386_INVOP:
+ sinfo64.si_code = ILL_ILLOPC;
break;
- case SIGFPE:
+ 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;
- }
+ 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 SIGBUS:
- sinfo64.si_code = BUS_ADRERR;
- sinfo64.si_addr = ua_cr2;
+ case KERN_PROTECTION_FAILURE:
+ sinfo64.si_code = SEGV_ACCERR;
break;
- case SIGTRAP:
- sinfo64.si_code = TRAP_BRKPT;
+ case KERN_INVALID_ADDRESS:
+ sinfo64.si_code = SEGV_MAPERR;
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;
+ 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);
- }
+ /*
+ * 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;
}
+ /*
+ * 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;
+ }
}
if (proc_is64bit(p)) {
user64_siginfo_t sinfo64_user64;
-
+
bzero((caddr_t)&sinfo64_user64, sizeof(sinfo64_user64));
-
- siginfo_user_to_user64_x86(&sinfo64,&sinfo64_user64);
+
+ siginfo_user_to_user64_x86(&sinfo64, &sinfo64_user64);
#if CONFIG_DTRACE
- bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+ bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
- ut->t_dtrace_siginfo.si_signo = sinfo64.si_signo;
- ut->t_dtrace_siginfo.si_code = sinfo64.si_code;
- ut->t_dtrace_siginfo.si_pid = sinfo64.si_pid;
- ut->t_dtrace_siginfo.si_uid = sinfo64.si_uid;
- ut->t_dtrace_siginfo.si_status = sinfo64.si_status;
+ ut->t_dtrace_siginfo.si_signo = sinfo64.si_signo;
+ ut->t_dtrace_siginfo.si_code = sinfo64.si_code;
+ ut->t_dtrace_siginfo.si_pid = sinfo64.si_pid;
+ ut->t_dtrace_siginfo.si_uid = sinfo64.si_uid;
+ ut->t_dtrace_siginfo.si_status = sinfo64.si_status;
/* XXX truncates faulting address to void * on K32 */
- ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo64.si_addr);
+ ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo64.si_addr);
/* Fire DTrace proc:::fault probe when signal is generated by hardware. */
switch (sig) {
/* 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, ua_catcher));
+ void (*)(void), CAST_DOWN(sig_t, ua_catcher));
#endif /* CONFIG_DTRACE */
- if (copyout((caddr_t)&sinfo64_user64, ua_sip, sizeof (sinfo64_user64)))
+ if (copyout((caddr_t)&sinfo64_user64, ua_sip, sizeof(sinfo64_user64))) {
goto bad;
+ }
- flavor = x86_THREAD_STATE64;
- state_count = x86_THREAD_STATE64_COUNT;
+ if (sig_xstate & STATE64_FULL) {
+ flavor = x86_THREAD_FULL_STATE64;
+ state_count = x86_THREAD_FULL_STATE64_COUNT;
+ } else {
+ flavor = x86_THREAD_STATE64;
+ state_count = x86_THREAD_STATE64_COUNT;
+ }
state = (void *)&mctxp->mctx_avx64.ss;
} else {
- x86_thread_state32_t *tstate32;
+ x86_thread_state32_t *tstate32;
user32_siginfo_t sinfo32;
bzero((caddr_t)&sinfo32, sizeof(sinfo32));
- siginfo_user_to_user32_x86(&sinfo64,&sinfo32);
+ siginfo_user_to_user32_x86(&sinfo64, &sinfo32);
#if CONFIG_DTRACE
- bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+ bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
- ut->t_dtrace_siginfo.si_signo = sinfo32.si_signo;
- ut->t_dtrace_siginfo.si_code = sinfo32.si_code;
- ut->t_dtrace_siginfo.si_pid = sinfo32.si_pid;
- ut->t_dtrace_siginfo.si_uid = sinfo32.si_uid;
- ut->t_dtrace_siginfo.si_status = sinfo32.si_status;
- ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo32.si_addr);
+ ut->t_dtrace_siginfo.si_signo = sinfo32.si_signo;
+ ut->t_dtrace_siginfo.si_code = sinfo32.si_code;
+ ut->t_dtrace_siginfo.si_pid = sinfo32.si_pid;
+ ut->t_dtrace_siginfo.si_uid = sinfo32.si_uid;
+ ut->t_dtrace_siginfo.si_status = sinfo32.si_status;
+ ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo32.si_addr);
/* Fire DTrace proc:::fault probe when signal is generated by hardware. */
switch (sig) {
}
DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
- void (*)(void), CAST_DOWN(sig_t, ua_catcher));
+ void (*)(void), CAST_DOWN(sig_t, ua_catcher));
#endif /* CONFIG_DTRACE */
- if (copyout((caddr_t)&sinfo32, ua_sip, sizeof (sinfo32)))
+ if (copyout((caddr_t)&sinfo32, ua_sip, sizeof(sinfo32))) {
goto bad;
-
+ }
+
tstate32 = &mctxp->mctx_avx32.ss;
tstate32->eip = CAST_DOWN_EXPLICIT(user32_addr_t, trampact);
state_count = x86_THREAD_STATE32_COUNT;
state = (void *)tstate32;
}
- if (thread_setstatus(thread, flavor, (thread_state_t)state, state_count) != KERN_SUCCESS)
- goto bad;
+ if (thread_setstatus(thread, flavor, (thread_state_t)state, state_count) != KERN_SUCCESS) {
+ goto bad;
+ }
ml_fp_setvalid(FALSE);
/* Tell the PAL layer about the signal */
sigreturn(struct proc *p, struct sigreturn_args *uap, __unused int *retval)
{
union {
- struct mcontext_avx32 mctx_avx32;
- struct mcontext_avx64 mctx_avx64;
-#if !defined(RC_HIDE_XNU_J137)
- struct mcontext_avx512_32 mctx_avx512_32;
- struct mcontext_avx512_64 mctx_avx512_64;
-#endif
+ struct mcontext_avx32 mctx_avx32;
+ struct mcontext_avx64 mctx_avx64;
+ struct mcontext_avx64_full mctx_avx64_full;
+ struct mcontext_avx512_32 mctx_avx512_32;
+ struct mcontext_avx512_64 mctx_avx512_64;
+ struct mcontext_avx512_64_full mctx_avx512_64_full;
} mctx_store, *mctxp = &mctx_store;
thread_t thread = current_thread();
struct uthread * ut;
struct sigacts *ps = p->p_sigacts;
- int error;
- int onstack = 0;
+ int error;
+ int onstack = 0;
mach_msg_type_number_t ts_count;
unsigned int ts_flavor;
- void * ts;
+ void * ts;
mach_msg_type_number_t fs_count;
unsigned int fs_flavor;
- void * fs;
- int rval = EJUSTRETURN;
- xstate_t sig_xstate;
+ void * fs;
+ int rval = EJUSTRETURN;
+ xstate_t sig_xstate;
uint32_t sigreturn_validation;
user_addr_t token_uctx;
kern_return_t kr;
*/
if ((unsigned int)uap->infostyle == UC_SET_ALT_STACK) {
ut->uu_sigstk.ss_flags |= SA_ONSTACK;
- return (0);
+ return 0;
} else if ((unsigned int)uap->infostyle == UC_RESET_ALT_STACK) {
ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
- return (0);
+ return 0;
}
+ /* see osfmk/kern/restartable.c */
+ act_set_ast_reset_pcs(thread);
+
bzero(mctxp, sizeof(*mctxp));
sig_xstate = current_xstate();
sigreturn_validation = atomic_load_explicit(
- &ps->ps_sigreturn_validation, memory_order_relaxed);
+ &ps->ps_sigreturn_validation, memory_order_relaxed);
token_uctx = uap->uctx;
kr = machine_thread_siguctx_pointer_convert_to_user(thread, &token_uctx);
assert(kr == KERN_SUCCESS);
if (proc_is64bit(p)) {
- struct user_ucontext64 uctx64;
+ struct user_ucontext64 uctx64;
user64_addr_t token;
+ int task_has_ldt = thread_task_has_ldt(thread);
- if ((error = copyin(uap->uctx, (void *)&uctx64, sizeof (uctx64))))
- return(error);
-
- if ((error = copyin(uctx64.uc_mcontext64, (void *)mctxp, thread_state64[sig_xstate].mcontext_size)))
- return(error);
+ if ((error = copyin(uap->uctx, (void *)&uctx64, sizeof(uctx64)))) {
+ return error;
+ }
onstack = uctx64.uc_onstack & 01;
ut->uu_sigmask = uctx64.uc_sigmask & ~sigcantmask;
- ts_flavor = x86_THREAD_STATE64;
- ts_count = x86_THREAD_STATE64_COUNT;
+ if (task_has_ldt) {
+ ts_flavor = x86_THREAD_FULL_STATE64;
+ ts_count = x86_THREAD_FULL_STATE64_COUNT;
+ fs = (void *)&mctxp->mctx_avx64_full.fs;
+ sig_xstate |= STATE64_FULL;
+ } else {
+ ts_flavor = x86_THREAD_STATE64;
+ ts_count = x86_THREAD_STATE64_COUNT;
+ fs = (void *)&mctxp->mctx_avx64.fs;
+ }
+
+ if ((error = copyin(uctx64.uc_mcontext64, (void *)mctxp, thread_state64[sig_xstate].mcontext_size))) {
+ return error;
+ }
+
ts = (void *)&mctxp->mctx_avx64.ss;
fs_flavor = thread_state64[sig_xstate].flavor;
fs_count = thread_state64[sig_xstate].state_count;
- fs = (void *)&mctxp->mctx_avx64.fs;
token = (user64_addr_t)token_uctx ^ (user64_addr_t)ps->ps_sigreturn_token;
if ((user64_addr_t)uap->token != token) {
#if DEVELOPMENT || DEBUG
printf("process %s[%d] sigreturn token mismatch: received 0x%llx expected 0x%llx\n",
- p->p_comm, p->p_pid, (user64_addr_t)uap->token, token);
+ p->p_comm, p->p_pid, (user64_addr_t)uap->token, token);
#endif /* DEVELOPMENT || DEBUG */
if (sigreturn_validation != PS_SIGRETURN_VALIDATION_DISABLED) {
rval = EINVAL;
}
}
- } else {
- struct user_ucontext32 uctx32;
+ } else {
+ struct user_ucontext32 uctx32;
user32_addr_t token;
- if ((error = copyin(uap->uctx, (void *)&uctx32, sizeof (uctx32))))
- return(error);
+ if ((error = copyin(uap->uctx, (void *)&uctx32, sizeof(uctx32)))) {
+ return error;
+ }
- if ((error = copyin(CAST_USER_ADDR_T(uctx32.uc_mcontext), (void *)mctxp, thread_state32[sig_xstate].mcontext_size)))
- return(error);
+ if ((error = copyin(CAST_USER_ADDR_T(uctx32.uc_mcontext), (void *)mctxp, thread_state32[sig_xstate].mcontext_size))) {
+ return error;
+ }
onstack = uctx32.uc_onstack & 01;
ut->uu_sigmask = uctx32.uc_sigmask & ~sigcantmask;
- ts_flavor = x86_THREAD_STATE32;
+ ts_flavor = x86_THREAD_STATE32;
ts_count = x86_THREAD_STATE32_COUNT;
ts = (void *)&mctxp->mctx_avx32.ss;
fs = (void *)&mctxp->mctx_avx32.fs;
token = CAST_DOWN_EXPLICIT(user32_addr_t, uap->uctx) ^
- CAST_DOWN_EXPLICIT(user32_addr_t, ps->ps_sigreturn_token);
+ CAST_DOWN_EXPLICIT(user32_addr_t, ps->ps_sigreturn_token);
if ((user32_addr_t)uap->token != token) {
#if DEVELOPMENT || DEBUG
printf("process %s[%d] sigreturn token mismatch: received 0x%x expected 0x%x\n",
- p->p_comm, p->p_pid, (user32_addr_t)uap->token, token);
+ p->p_comm, p->p_pid, (user32_addr_t)uap->token, token);
#endif /* DEVELOPMENT || DEBUG */
if (sigreturn_validation != PS_SIGRETURN_VALIDATION_DISABLED) {
rval = EINVAL;
}
}
- if (onstack)
+ if (onstack) {
ut->uu_sigstk.ss_flags |= SA_ONSTACK;
- else
+ } else {
ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
+ }
- if (ut->uu_siglist & ~ut->uu_sigmask)
+ if (ut->uu_siglist & ~ut->uu_sigmask) {
signal_setast(thread);
+ }
if (rval == EINVAL) {
goto error_ret;
rval = EINVAL;
#if DEVELOPMENT || DEBUG
printf("process %s[%d] sigreturn thread_setstatus error %d\n",
- p->p_comm, p->p_pid, rval);
+ p->p_comm, p->p_pid, rval);
#endif /* DEVELOPMENT || DEBUG */
goto error_ret;
}
-
+
ml_fp_setvalid(TRUE);
- if (thread_setstatus(thread, fs_flavor, fs, fs_count) != KERN_SUCCESS) {
+ if (thread_setstatus(thread, fs_flavor, fs, fs_count) != KERN_SUCCESS) {
rval = EINVAL;
#if DEVELOPMENT || DEBUG
printf("process %s[%d] sigreturn thread_setstatus error %d\n",
- p->p_comm, p->p_pid, rval);
+ p->p_comm, p->p_pid, rval);
#endif /* DEVELOPMENT || DEBUG */
goto error_ret;
-
}
error_ret:
return rval;
*/
int
machine_exception(int exception,
- mach_exception_code_t code,
- __unused mach_exception_subcode_t subcode)
+ mach_exception_code_t code,
+ __unused mach_exception_subcode_t subcode)
{
- switch(exception) {
- case EXC_BAD_ACCESS:
- /* Map GP fault to SIGSEGV, otherwise defer to caller */
- if (code == EXC_I386_GPFLT) {
- return SIGSEGV;
- }
- break;
+ switch (exception) {
+ case EXC_BAD_ACCESS:
+ /* Map GP fault to SIGSEGV, otherwise defer to caller */
+ if (code == EXC_I386_GPFLT) {
+ return SIGSEGV;
+ }
+ break;
- case EXC_BAD_INSTRUCTION:
- return SIGILL;
+ case EXC_BAD_INSTRUCTION:
+ return SIGILL;
- case EXC_ARITHMETIC:
- return SIGFPE;
+ case EXC_ARITHMETIC:
+ return SIGFPE;
- case EXC_SOFTWARE:
- if (code == EXC_I386_BOUND) {
- /*
- * Map #BR, the Bound Range Exceeded exception, to
- * SIGTRAP.
- */
- return SIGTRAP;
- }
- break;
+ case EXC_SOFTWARE:
+ if (code == EXC_I386_BOUND) {
+ /*
+ * Map #BR, the Bound Range Exceeded exception, to
+ * SIGTRAP.
+ */
+ return SIGTRAP;
+ }
+ break;
}
return 0;
}
-