2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1992 NeXT, Inc.
32 * 13 May 1992 ? at NeXT
36 #include <mach/mach_types.h>
37 #include <mach/exception.h>
39 #include <kern/thread.h>
41 #include <sys/systm.h>
42 #include <sys/param.h>
43 #include <sys/proc_internal.h>
45 #include <sys/sysproto.h>
46 #include <sys/sysent.h>
47 #include <sys/ucontext.h>
49 #include <mach/thread_act.h> /* for thread_abort_safely */
50 #include <mach/thread_status.h>
51 #include <i386/machine_routines.h>
53 #include <i386/eflags.h>
57 #include <sys/kdebug.h>
62 extern boolean_t
machine_exception(int, mach_exception_code_t
,
63 mach_exception_subcode_t
, int *, mach_exception_subcode_t
*);
64 extern kern_return_t
thread_getstatus(register thread_t act
, int flavor
,
65 thread_state_t tstate
, mach_msg_type_number_t
*count
);
66 extern kern_return_t
thread_setstatus(thread_t thread
, int flavor
,
67 thread_state_t tstate
, mach_msg_type_number_t count
);
69 /* Signal handler flavors supported */
70 /* These defns should match the Libc implmn */
73 #define UC_SET_ALT_STACK 0x40000000
74 #define UC_RESET_ALT_STACK 0x80000000
76 #define C_32_STK_ALIGN 16
77 #define C_64_STK_ALIGN 16
78 #define C_64_REDZONE_LEN 128
79 #define TRUNC_DOWN32(a,c) ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
80 #define TRUNC_DOWN64(a,c) ((((uint64_t)a)-(c)) & ((uint64_t)(-(c))))
83 * Send an interrupt to process.
85 * Stack is set up to allow sigcode stored
86 * in u. to call routine, followed by chmk
87 * to sigreturn routine below. After sigreturn
88 * resets the signal mask, the stack, the frame
89 * pointer, and the argument pointer, it returns
90 * to the user specified pc, psl.
98 struct ucontext
* uctx
;
104 sendsig(struct proc
*p
, user_addr_t ua_catcher
, int sig
, int mask
, __unused u_long code
)
107 struct mcontext32 mctx32
;
108 struct mcontext64 mctx64
;
114 user_addr_t ua_uctxp
;
115 user_addr_t ua_mctxp
;
116 user_siginfo_t sinfo64
;
118 struct sigacts
*ps
= p
->p_sigacts
;
119 int oonstack
, flavor
;
121 mach_msg_type_number_t state_count
;
126 int infostyle
= UC_TRAD
;
128 thread
= current_thread();
129 ut
= get_bsdthread_info(thread
);
131 if (p
->p_sigacts
->ps_siginfo
& sigmask(sig
))
132 infostyle
= UC_FLAVOR
;
134 oonstack
= ut
->uu_sigstk
.ss_flags
& SA_ONSTACK
;
141 bzero((caddr_t
)&sinfo64
, sizeof(user_siginfo_t
));
142 sinfo64
.si_signo
= sig
;
145 if (proc_is64bit(p
)) {
146 x86_thread_state64_t
*tstate64
;
147 struct user_ucontext64 uctx64
;
149 flavor
= x86_THREAD_STATE64
;
150 state_count
= x86_THREAD_STATE64_COUNT
;
151 state
= (void *)&mctx
.mctx64
.ss
;
152 if (thread_getstatus(thread
, flavor
, (thread_state_t
)state
, &state_count
) != KERN_SUCCESS
)
155 flavor
= x86_FLOAT_STATE64
;
156 state_count
= x86_FLOAT_STATE64_COUNT
;
157 state
= (void *)&mctx
.mctx64
.fs
;
158 if (thread_getstatus(thread
, flavor
, (thread_state_t
)state
, &state_count
) != KERN_SUCCESS
)
161 flavor
= x86_EXCEPTION_STATE64
;
162 state_count
= x86_EXCEPTION_STATE64_COUNT
;
163 state
= (void *)&mctx
.mctx64
.es
;
164 if (thread_getstatus(thread
, flavor
, (thread_state_t
)state
, &state_count
) != KERN_SUCCESS
)
167 tstate64
= &mctx
.mctx64
.ss
;
169 /* figure out where our new stack lives */
170 if ((ut
->uu_flag
& UT_ALTSTACK
) && !oonstack
&&
171 (ps
->ps_sigonstack
& sigmask(sig
))) {
172 ua_sp
= ut
->uu_sigstk
.ss_sp
;
173 stack_size
= ut
->uu_sigstk
.ss_size
;
175 ut
->uu_sigstk
.ss_flags
|= SA_ONSTACK
;
177 ua_sp
= tstate64
->rsp
;
179 ua_cr2
= mctx
.mctx64
.es
.faultvaddr
;
181 /* The x86_64 ABI defines a 128-byte red zone. */
182 ua_sp
-= C_64_REDZONE_LEN
;
184 ua_sp
-= sizeof (struct user_ucontext64
);
185 ua_uctxp
= ua_sp
; // someone tramples the first word!
187 ua_sp
-= sizeof (user_siginfo_t
);
190 ua_sp
-= sizeof (struct mcontext64
);
194 * Align the frame and stack pointers to 16 bytes for SSE.
195 * (Note that we use 'ua_fp' as the base of the stack going forward)
197 ua_fp
= TRUNC_DOWN64(ua_sp
, C_64_STK_ALIGN
);
200 * But we need to account for the return address so the alignment is
201 * truly "correct" at _sigtramp
203 ua_fp
-= sizeof(user_addr_t
);
206 * Build the signal context to be used by sigreturn.
208 bzero(&uctx64
, sizeof(uctx64
));
210 uctx64
.uc_onstack
= oonstack
;
211 uctx64
.uc_sigmask
= mask
;
212 uctx64
.uc_stack
.ss_sp
= ua_fp
;
213 uctx64
.uc_stack
.ss_size
= stack_size
;
216 uctx64
.uc_stack
.ss_flags
|= SS_ONSTACK
;
219 uctx64
.uc_mcsize
= sizeof(struct mcontext64
);
220 uctx64
.uc_mcontext64
= ua_mctxp
;
222 if (copyout((caddr_t
)&uctx64
, ua_uctxp
, sizeof (uctx64
)))
225 if (copyout((caddr_t
)&mctx
.mctx64
, ua_mctxp
, sizeof (struct mcontext64
)))
228 sinfo64
.pad
[0] = tstate64
->rsp
;
229 sinfo64
.si_addr
= tstate64
->rip
;
231 tstate64
->rip
= ps
->ps_trampact
[sig
];
232 tstate64
->rsp
= ua_fp
;
233 tstate64
->rflags
= get_eflags_exportmask();
235 * JOE - might not need to set these
237 tstate64
->cs
= USER64_CS
;
238 tstate64
->fs
= NULL_SEG
;
239 tstate64
->gs
= USER_CTHREAD
;
242 * Build the argument list for the signal handler.
243 * Handler should call sigreturn to get out of it
245 tstate64
->rdi
= ua_catcher
;
246 tstate64
->rsi
= infostyle
;
248 tstate64
->rcx
= ua_sip
;
249 tstate64
->r8
= ua_uctxp
;
252 x86_thread_state32_t
*tstate32
;
253 struct ucontext uctx32
;
254 struct sigframe32 frame32
;
256 flavor
= x86_THREAD_STATE32
;
257 state_count
= x86_THREAD_STATE32_COUNT
;
258 state
= (void *)&mctx
.mctx32
.ss
;
259 if (thread_getstatus(thread
, flavor
, (thread_state_t
)state
, &state_count
) != KERN_SUCCESS
)
262 flavor
= x86_FLOAT_STATE32
;
263 state_count
= x86_FLOAT_STATE32_COUNT
;
264 state
= (void *)&mctx
.mctx32
.fs
;
265 if (thread_getstatus(thread
, flavor
, (thread_state_t
)state
, &state_count
) != KERN_SUCCESS
)
268 flavor
= x86_EXCEPTION_STATE32
;
269 state_count
= x86_EXCEPTION_STATE32_COUNT
;
270 state
= (void *)&mctx
.mctx32
.es
;
271 if (thread_getstatus(thread
, flavor
, (thread_state_t
)state
, &state_count
) != KERN_SUCCESS
)
274 tstate32
= &mctx
.mctx32
.ss
;
276 /* figure out where our new stack lives */
277 if ((ut
->uu_flag
& UT_ALTSTACK
) && !oonstack
&&
278 (ps
->ps_sigonstack
& sigmask(sig
))) {
279 ua_sp
= ut
->uu_sigstk
.ss_sp
;
280 stack_size
= ut
->uu_sigstk
.ss_size
;
282 ut
->uu_sigstk
.ss_flags
|= SA_ONSTACK
;
284 ua_sp
= tstate32
->esp
;
286 ua_cr2
= mctx
.mctx32
.es
.faultvaddr
;
288 ua_sp
-= sizeof (struct ucontext
);
289 ua_uctxp
= ua_sp
; // someone tramples the first word!
291 ua_sp
-= sizeof (siginfo_t
);
294 ua_sp
-= sizeof (struct mcontext32
);
297 ua_sp
-= sizeof (struct sigframe32
);
301 * Align the frame and stack pointers to 16 bytes for SSE.
302 * (Note that we use 'fp' as the base of the stack going forward)
304 ua_fp
= TRUNC_DOWN32(ua_fp
, C_32_STK_ALIGN
);
307 * But we need to account for the return address so the alignment is
308 * truly "correct" at _sigtramp
310 ua_fp
-= sizeof(frame32
.retaddr
);
313 * Build the argument list for the signal handler.
314 * Handler should call sigreturn to get out of it
316 frame32
.retaddr
= -1;
317 frame32
.sigstyle
= infostyle
;
319 frame32
.catcher
= CAST_DOWN(sig_t
, ua_catcher
);
320 frame32
.sinfo
= CAST_DOWN(siginfo_t
*, ua_sip
);
321 frame32
.uctx
= CAST_DOWN(struct ucontext
*, ua_uctxp
);
323 if (copyout((caddr_t
)&frame32
, ua_fp
, sizeof (frame32
)))
327 * Build the signal context to be used by sigreturn.
329 bzero(&uctx32
, sizeof(uctx32
));
331 uctx32
.uc_onstack
= oonstack
;
332 uctx32
.uc_sigmask
= mask
;
333 uctx32
.uc_stack
.ss_sp
= CAST_DOWN(char *, ua_fp
);
334 uctx32
.uc_stack
.ss_size
= stack_size
;
337 uctx32
.uc_stack
.ss_flags
|= SS_ONSTACK
;
340 uctx32
.uc_mcsize
= sizeof(struct mcontext32
);
342 uctx32
.uc_mcontext
= CAST_DOWN(_STRUCT_MCONTEXT32
*, ua_mctxp
);
344 if (copyout((caddr_t
)&uctx32
, ua_uctxp
, sizeof (uctx32
)))
347 if (copyout((caddr_t
)&mctx
.mctx32
, ua_mctxp
, sizeof (struct mcontext32
)))
350 sinfo64
.pad
[0] = tstate32
->esp
;
351 sinfo64
.si_addr
= tstate32
->eip
;
356 switch (ut
->uu_code
) {
358 sinfo64
.si_code
= ILL_ILLOPC
;
361 printf("unknown SIGILL code %ld\n", (long) ut
->uu_code
);
362 sinfo64
.si_code
= ILL_NOOP
;
366 #define FP_IE 0 /* Invalid operation */
367 #define FP_DE 1 /* Denormalized operand */
368 #define FP_ZE 2 /* Zero divide */
369 #define FP_OE 3 /* overflow */
370 #define FP_UE 4 /* underflow */
371 #define FP_PE 5 /* precision */
372 if (ut
->uu_subcode
& (1 << FP_ZE
)) {
373 sinfo64
.si_code
= FPE_FLTDIV
;
374 } else if (ut
->uu_subcode
& (1 << FP_OE
)) {
375 sinfo64
.si_code
= FPE_FLTOVF
;
376 } else if (ut
->uu_subcode
& (1 << FP_UE
)) {
377 sinfo64
.si_code
= FPE_FLTUND
;
378 } else if (ut
->uu_subcode
& (1 << FP_PE
)) {
379 sinfo64
.si_code
= FPE_FLTRES
;
380 } else if (ut
->uu_subcode
& (1 << FP_IE
)) {
381 sinfo64
.si_code
= FPE_FLTINV
;
383 printf("unknown SIGFPE code %ld, subcode %lx\n",
384 (long) ut
->uu_code
, (long) ut
->uu_subcode
);
385 sinfo64
.si_code
= FPE_NOOP
;
389 sinfo64
.si_code
= BUS_ADRERR
;
390 sinfo64
.si_addr
= ua_cr2
;
393 sinfo64
.si_code
= TRAP_BRKPT
;
396 sinfo64
.si_addr
= ua_cr2
;
398 switch (ut
->uu_code
) {
400 /* CR2 is meaningless after GP fault */
401 /* XXX namespace clash! */
402 sinfo64
.si_addr
= 0ULL;
405 case KERN_PROTECTION_FAILURE
:
406 sinfo64
.si_code
= SEGV_ACCERR
;
408 case KERN_INVALID_ADDRESS
:
409 sinfo64
.si_code
= SEGV_MAPERR
;
412 printf("unknown SIGSEGV code %ld\n", (long) ut
->uu_code
);
413 sinfo64
.si_code
= FPE_NOOP
;
418 int status_and_exitcode
;
421 * All other signals need to fill out a minimum set of
422 * information for the siginfo structure passed into
423 * the signal handler, if SA_SIGINFO was specified.
425 * p->si_status actually contains both the status and
426 * the exit code; we save it off in its own variable
427 * for later breakdown.
430 sinfo64
.si_pid
= p
->si_pid
;
432 status_and_exitcode
= p
->si_status
;
434 sinfo64
.si_uid
= p
->si_uid
;
436 sinfo64
.si_code
= p
->si_code
;
439 if (sinfo64
.si_code
== CLD_EXITED
) {
440 if (WIFEXITED(status_and_exitcode
))
441 sinfo64
.si_code
= CLD_EXITED
;
442 else if (WIFSIGNALED(status_and_exitcode
)) {
443 if (WCOREDUMP(status_and_exitcode
)) {
444 sinfo64
.si_code
= CLD_DUMPED
;
445 status_and_exitcode
= W_EXITCODE(status_and_exitcode
,status_and_exitcode
);
447 sinfo64
.si_code
= CLD_KILLED
;
448 status_and_exitcode
= W_EXITCODE(status_and_exitcode
,status_and_exitcode
);
453 * The recorded status contains the exit code and the
454 * signal information, but the information to be passed
455 * in the siginfo to the handler is supposed to only
456 * contain the status, so we have to shift it out.
458 sinfo64
.si_status
= WEXITSTATUS(status_and_exitcode
);
462 if (proc_is64bit(p
)) {
464 /* XXX truncates catcher address to uintptr_t */
465 DTRACE_PROC3(signal__handle
, int, sig
, siginfo_t
*, &sinfo64
,
466 void (*)(void), CAST_DOWN(sig_t
, ua_catcher
));
468 if (copyout((caddr_t
)&sinfo64
, ua_sip
, sizeof (sinfo64
)))
471 flavor
= x86_THREAD_STATE64
;
472 state_count
= x86_THREAD_STATE64_COUNT
;
473 state
= (void *)&mctx
.mctx64
.ss
;
475 x86_thread_state32_t
*tstate32
;
478 bzero((caddr_t
)&sinfo32
, sizeof(siginfo_t
));
480 sinfo32
.si_signo
= sinfo64
.si_signo
;
481 sinfo32
.si_code
= sinfo64
.si_code
;
482 sinfo32
.si_pid
= sinfo64
.si_pid
;
483 sinfo32
.si_uid
= sinfo64
.si_uid
;
484 sinfo32
.si_status
= sinfo64
.si_status
;
485 sinfo32
.si_addr
= CAST_DOWN(void *, sinfo64
.si_addr
);
486 sinfo32
.__pad
[0] = sinfo64
.pad
[0];
488 DTRACE_PROC3(signal__handle
, int, sig
, siginfo_t
*, &sinfo32
,
489 void (*)(void), CAST_DOWN(sig_t
, ua_catcher
));
491 if (copyout((caddr_t
)&sinfo32
, ua_sip
, sizeof (sinfo32
)))
494 tstate32
= &mctx
.mctx32
.ss
;
495 tstate32
->eip
= CAST_DOWN(unsigned int, ps
->ps_trampact
[sig
]);
496 tstate32
->esp
= CAST_DOWN(unsigned int, ua_fp
);
498 tstate32
->eflags
= get_eflags_exportmask();
500 tstate32
->cs
= USER_CS
;
501 tstate32
->ss
= USER_DS
;
502 tstate32
->ds
= USER_DS
;
503 tstate32
->es
= USER_DS
;
504 tstate32
->fs
= NULL_SEG
;
505 tstate32
->gs
= USER_CTHREAD
;
507 flavor
= x86_THREAD_STATE32
;
508 state_count
= x86_THREAD_STATE32_COUNT
;
509 state
= (void *)tstate32
;
511 if (thread_setstatus(thread
, flavor
, (thread_state_t
)state
, state_count
) != KERN_SUCCESS
)
513 ml_fp_setvalid(FALSE
);
521 SIGACTION(p
, SIGILL
) = SIG_DFL
;
522 sig
= sigmask(SIGILL
);
523 p
->p_sigignore
&= ~sig
;
524 p
->p_sigcatch
&= ~sig
;
525 ut
->uu_sigmask
&= ~sig
;
526 /* sendsig is called with signal lock held */
528 psignal_locked(p
, SIGILL
);
534 * System call to cleanup state after a signal
535 * has been taken. Reset signal mask and
536 * stack state from context left by sendsig (above).
537 * Return to previous pc and psl as specified by
538 * context left by sendsig. Check carefully to
539 * make sure that the user has not modified the
540 * psl to gain improper priviledges or to cause
545 sigreturn(struct proc
*p
, struct sigreturn_args
*uap
, __unused
int *retval
)
548 struct mcontext32 mctx32
;
549 struct mcontext64 mctx64
;
551 thread_t thread
= current_thread();
556 mach_msg_type_number_t ts_count
;
557 unsigned int ts_flavor
;
559 mach_msg_type_number_t fs_count
;
560 unsigned int fs_flavor
;
563 ut
= (struct uthread
*)get_bsdthread_info(thread
);
566 * If we are being asked to change the altstack flag on the thread, we
567 * just set/reset it and return (the uap->uctx is not used).
569 if ((unsigned int)uap
->infostyle
== UC_SET_ALT_STACK
) {
570 ut
->uu_sigstk
.ss_flags
|= SA_ONSTACK
;
572 } else if ((unsigned int)uap
->infostyle
== UC_RESET_ALT_STACK
) {
573 ut
->uu_sigstk
.ss_flags
&= ~SA_ONSTACK
;
577 if (proc_is64bit(p
)) {
578 struct user_ucontext64 uctx64
;
580 if ((error
= copyin(uap
->uctx
, (void *)&uctx64
, sizeof (uctx64
))))
583 if ((error
= copyin(uctx64
.uc_mcontext64
, (void *)&mctx
.mctx64
, sizeof (struct mcontext64
))))
586 onstack
= uctx64
.uc_onstack
& 01;
587 ut
->uu_sigmask
= uctx64
.uc_sigmask
& ~sigcantmask
;
589 ts_flavor
= x86_THREAD_STATE64
;
590 ts_count
= x86_THREAD_STATE64_COUNT
;
591 ts
= (void *)&mctx
.mctx64
.ss
;
593 fs_flavor
= x86_FLOAT_STATE64
;
594 fs_count
= x86_FLOAT_STATE64_COUNT
;
595 fs
= (void *)&mctx
.mctx64
.fs
;
598 struct ucontext uctx32
;
600 if ((error
= copyin(uap
->uctx
, (void *)&uctx32
, sizeof (uctx32
))))
603 if ((error
= copyin(CAST_USER_ADDR_T(uctx32
.uc_mcontext
), (void *)&mctx
.mctx32
, sizeof (struct mcontext32
))))
606 onstack
= uctx32
.uc_onstack
& 01;
607 ut
->uu_sigmask
= uctx32
.uc_sigmask
& ~sigcantmask
;
609 ts_flavor
= x86_THREAD_STATE32
;
610 ts_count
= x86_THREAD_STATE32_COUNT
;
611 ts
= (void *)&mctx
.mctx32
.ss
;
613 fs_flavor
= x86_FLOAT_STATE32
;
614 fs_count
= x86_FLOAT_STATE32_COUNT
;
615 fs
= (void *)&mctx
.mctx32
.fs
;
619 ut
->uu_sigstk
.ss_flags
|= SA_ONSTACK
;
621 ut
->uu_sigstk
.ss_flags
&= ~SA_ONSTACK
;
623 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
624 signal_setast(thread
);
627 * thread_set_state() does all the needed checks for the passed in
630 if (thread_setstatus(thread
, ts_flavor
, ts
, ts_count
) != KERN_SUCCESS
)
633 ml_fp_setvalid(TRUE
);
635 if (thread_setstatus(thread
, fs_flavor
, fs
, fs_count
) != KERN_SUCCESS
)
638 return (EJUSTRETURN
);
643 * machine_exception() performs MD translation
644 * of a mach exception to a unix signal and code.
650 mach_exception_code_t code
,
651 __unused mach_exception_subcode_t subcode
,
653 mach_exception_code_t
*unix_code
)
659 /* Map GP fault to SIGSEGV, otherwise defer to caller */
660 if (code
== EXC_I386_GPFLT
) {
661 *unix_signal
= SIGSEGV
;
667 case EXC_BAD_INSTRUCTION
:
668 *unix_signal
= SIGILL
;
673 *unix_signal
= SIGFPE
;
678 if (code
== EXC_I386_BOUND
) {
680 * Map #BR, the Bound Range Exceeded exception, to
683 *unix_signal
= SIGTRAP
;