#include <sys/kdebug.h>
+#include <sys/sdt.h>
+
/* Forward: */
-extern boolean_t machine_exception(int, int, int, int *, int *);
+extern boolean_t machine_exception(int, mach_exception_code_t,
+ mach_exception_subcode_t, int *, mach_exception_subcode_t *);
extern kern_return_t thread_getstatus(register thread_t act, int flavor,
thread_state_t tstate, mach_msg_type_number_t *count);
extern kern_return_t thread_setstatus(thread_t thread, int flavor,
/* 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 C_32_STK_ALIGN 16
#define C_64_STK_ALIGN 16
int oonstack, flavor;
void * state;
mach_msg_type_number_t state_count;
- int uthsigaltstack = 0;
- int altstack = 0;
- thread_t thread = current_thread();
+ thread_t thread;
struct uthread * ut;
int stack_size = 0;
int infostyle = UC_TRAD;
+ thread = current_thread();
+ ut = get_bsdthread_info(thread);
+
if (p->p_sigacts->ps_siginfo & sigmask(sig))
infostyle = UC_FLAVOR;
- ut = get_bsdthread_info(thread);
-
- uthsigaltstack = p->p_lflag & P_LTHSIGSTACK;
+ oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
- if (uthsigaltstack != 0 ) {
- oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
- altstack = ut->uu_flag & UT_ALTSTACK;
- } else {
- oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
- altstack = ps->ps_flags & SAS_ALTSTACK;
- }
/*
* init siginfo
*/
+ proc_unlock(p);
+
bzero((caddr_t)&sinfo64, sizeof(user_siginfo_t));
sinfo64.si_signo = sig;
+
if (proc_is64bit(p)) {
x86_thread_state64_t *tstate64;
struct user_ucontext64 uctx64;
tstate64 = &mctx.mctx64.ss;
- if (altstack && !oonstack && (ps->ps_sigonstack & sigmask(sig))) {
- if (uthsigaltstack != 0) {
- 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 = ps->ps_sigstk.ss_sp;
- stack_size = ps->ps_sigstk.ss_size;
- ua_sp += stack_size;
- ps->ps_sigstk.ss_flags |= SA_ONSTACK;
- }
- } else
+ /* figure out where our new stack lives */
+ if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
+ (ps->ps_sigonstack & sigmask(sig))) {
+ 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 = tstate64->rsp;
+ }
ua_cr2 = mctx.mctx64.es.faultvaddr;
/* The x86_64 ABI defines a 128-byte red zone. */
tstate32 = &mctx.mctx32.ss;
- if (altstack && !oonstack && (ps->ps_sigonstack & sigmask(sig))) {
- if (uthsigaltstack != 0) {
- 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 = ps->ps_sigstk.ss_sp;
- stack_size = ps->ps_sigstk.ss_size;
- ua_sp += stack_size;
- ps->ps_sigstk.ss_flags |= SA_ONSTACK;
- }
- } else
+ /* figure out where our new stack lives */
+ if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
+ (ps->ps_sigonstack & sigmask(sig))) {
+ 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 = mctx.mctx32.es.faultvaddr;
ua_sp -= sizeof (struct ucontext);
uctx32.uc_mcsize = sizeof(struct mcontext32);
- uctx32.uc_mcontext = CAST_DOWN(struct mcontext *, ua_mctxp);
+ uctx32.uc_mcontext = CAST_DOWN(_STRUCT_MCONTEXT32 *, ua_mctxp);
if (copyout((caddr_t)&uctx32, ua_uctxp, sizeof (uctx32)))
goto bad;
}
switch (sig) {
- case SIGCHLD:
- sinfo64.si_pid = p->si_pid;
- p->si_pid =0;
- sinfo64.si_status = 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;
- if (sinfo64.si_code == CLD_EXITED) {
- if (WIFEXITED(sinfo64.si_status))
- sinfo64.si_code = CLD_EXITED;
- else if (WIFSIGNALED(sinfo64.si_status)) {
- if (WCOREDUMP(sinfo64.si_status))
- sinfo64.si_code = CLD_DUMPED;
- else
- sinfo64.si_code = CLD_KILLED;
- }
- }
- break;
case SIGILL:
switch (ut->uu_code) {
case EXC_I386_INVOP:
sinfo64.si_code = ILL_ILLOPC;
break;
- case EXC_I386_GPFLT:
- sinfo64.si_code = ILL_PRVOPC;
- break;
default:
- printf("unknown SIGILL code %d\n", ut->uu_code);
+ printf("unknown SIGILL code %ld\n", (long) ut->uu_code);
sinfo64.si_code = ILL_NOOP;
}
break;
} else if (ut->uu_subcode & (1 << FP_IE)) {
sinfo64.si_code = FPE_FLTINV;
} else {
- printf("unknown SIGFPE code %d, subcode %x\n",
- ut->uu_code, ut->uu_subcode);
+ printf("unknown SIGFPE code %ld, subcode %lx\n",
+ (long) ut->uu_code, (long) ut->uu_subcode);
sinfo64.si_code = FPE_NOOP;
}
break;
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;
sinfo64.si_code = SEGV_MAPERR;
break;
default:
- printf("unknown SIGSEGV code %d\n", ut->uu_code);
+ printf("unknown SIGSEGV code %ld\n", (long) ut->uu_code);
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);
break;
+ }
}
if (proc_is64bit(p)) {
+
+ /* XXX truncates catcher address to uintptr_t */
+ DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &sinfo64,
+ void (*)(void), CAST_DOWN(sig_t, ua_catcher));
+
if (copyout((caddr_t)&sinfo64, ua_sip, sizeof (sinfo64)))
goto bad;
sinfo32.si_uid = sinfo64.si_uid;
sinfo32.si_status = sinfo64.si_status;
sinfo32.si_addr = CAST_DOWN(void *, sinfo64.si_addr);
- sinfo32.pad[0] = sinfo64.pad[0];
+ sinfo32.__pad[0] = sinfo64.pad[0];
+
+ DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &sinfo32,
+ void (*)(void), CAST_DOWN(sig_t, ua_catcher));
if (copyout((caddr_t)&sinfo32, ua_sip, sizeof (sinfo32)))
goto bad;
goto bad;
ml_fp_setvalid(FALSE);
+ 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;
}
*/
int
-sigreturn(
- struct proc *p,
- struct sigreturn_args *uap,
- __unused int *retval)
+sigreturn(struct proc *p, struct sigreturn_args *uap, __unused int *retval)
{
union {
struct mcontext32 mctx32;
thread_t thread = current_thread();
struct uthread * ut;
int error;
- int uthsigaltstack = 0;
int onstack = 0;
mach_msg_type_number_t ts_count;
void * fs;
ut = (struct uthread *)get_bsdthread_info(thread);
- uthsigaltstack = p->p_lflag & P_LTHSIGSTACK;
+
+ /*
+ * If we are being asked to change the altstack flag on the thread, we
+ * just set/reset it and return (the uap->uctx is not used).
+ */
+ if ((unsigned int)uap->infostyle == UC_SET_ALT_STACK) {
+ ut->uu_sigstk.ss_flags |= SA_ONSTACK;
+ return (0);
+ } else if ((unsigned int)uap->infostyle == UC_RESET_ALT_STACK) {
+ ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
+ return (0);
+ }
if (proc_is64bit(p)) {
struct user_ucontext64 uctx64;
fs_count = x86_FLOAT_STATE32_COUNT;
fs = (void *)&mctx.mctx32.fs;
}
- if (onstack) {
- if (uthsigaltstack != 0)
- ut->uu_sigstk.ss_flags |= SA_ONSTACK;
- else
- p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
- } else {
- if (uthsigaltstack != 0)
- ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
- else
- p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
- }
+
+ if (onstack)
+ ut->uu_sigstk.ss_flags |= SA_ONSTACK;
+ else
+ ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
+
if (ut->uu_siglist & ~ut->uu_sigmask)
signal_setast(thread);
/*
- * thread_set_state() does all the needed checks for the passed in content
+ * thread_set_state() does all the needed checks for the passed in
+ * content
*/
if (thread_setstatus(thread, ts_flavor, ts, ts_count) != KERN_SUCCESS)
return(EINVAL);
boolean_t
machine_exception(
- int exception,
- int code,
- __unused int subcode,
- int *unix_signal,
- int *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;
-
- default:
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-#include <sys/systm.h>
-#include <sys/sysent.h>
-
-int __pthread_cset(struct sysent *);
-void __pthread_creset(struct sysent *);
-
-int
-__pthread_cset(struct sysent *callp)
+ int exception,
+ mach_exception_code_t code,
+ __unused mach_exception_subcode_t subcode,
+ int *unix_signal,
+ mach_exception_code_t *unix_code)
{
- unsigned int cancel_enable;
- thread_t thread;
- struct uthread * uthread;
- thread = current_thread();
- uthread = get_bsdthread_info(thread);
+ switch(exception) {
- cancel_enable = callp->sy_cancel;
- if (cancel_enable == _SYSCALL_CANCEL_NONE) {
- uthread->uu_flag |= UT_NOTCANCELPT;
- } else {
- if((uthread->uu_flag & (UT_CANCELDISABLE | UT_CANCEL | UT_CANCELED)) == UT_CANCEL) {
- if (cancel_enable == _SYSCALL_CANCEL_PRE)
- return(EINTR);
- else
- thread_abort_safely(thread);
+ case EXC_BAD_ACCESS:
+ /* Map GP fault to SIGSEGV, otherwise defer to caller */
+ if (code == EXC_I386_GPFLT) {
+ *unix_signal = SIGSEGV;
+ *unix_code = code;
+ break;
+ }
+ return(FALSE);
+
+ 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_I386_BOUND) {
+ /*
+ * Map #BR, the Bound Range Exceeded exception, to
+ * SIGTRAP.
+ */
+ *unix_signal = SIGTRAP;
+ *unix_code = code;
+ break;
}
- }
- return(0);
-}
-
-
-void
-__pthread_creset(struct sysent *callp)
-{
-
- unsigned int cancel_enable;
- thread_t thread;
- struct uthread * uthread;
-
- thread = current_thread();
- uthread = get_bsdthread_info(thread);
-
- cancel_enable = callp->sy_cancel;
- if (!cancel_enable)
- uthread->uu_flag &= ~UT_NOTCANCELPT;
+ default:
+ return(FALSE);
+ }
+
+ return(TRUE);
}