X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/91447636331957f3d9b5ca5b508f07c526b0074d..8a3053a07cee346dca737a5670e546fd26a7c9d6:/bsd/uxkern/ux_exception.c diff --git a/bsd/uxkern/ux_exception.c b/bsd/uxkern/ux_exception.c index e576ad299..3175c3163 100644 --- a/bsd/uxkern/ux_exception.c +++ b/bsd/uxkern/ux_exception.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Mach Operating System @@ -42,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -51,9 +58,9 @@ #include #include #include +#include /* MAXSSIZ */ #include /* get_task_ipcspace() */ - /* * XXX Things that should be retrieved from Mach headers, but aren't */ @@ -74,14 +81,21 @@ extern void ipc_port_release(ipc_port_t); + /* * Unix exception handler. */ -static void ux_exception(int exception, int code, int subcode, - int *ux_signal, int *ux_code); +static void ux_exception(int exception, mach_exception_code_t code, + mach_exception_subcode_t subcode, + int *ux_signal, mach_exception_code_t *ux_code); +#if defined(__x86_64__) +mach_port_t ux_exception_port; +#else mach_port_name_t ux_exception_port; +#endif /* __x86_64__ */ + static task_t ux_handler_self; static @@ -92,8 +106,6 @@ ux_handler(void) mach_port_name_t exc_port_name; mach_port_name_t exc_set_name; - (void) thread_funnel_set(kernel_flock, TRUE); - /* self->kernel_vm_space = TRUE; */ ux_handler_self = self; @@ -119,7 +131,9 @@ ux_handler(void) (void *) &ux_exception_port) != MACH_MSG_SUCCESS) panic("ux_handler: object_copyin(ux_exception_port) failed"); + proc_list_lock(); thread_wakeup(&ux_exception_port); + proc_list_unlock(); /* Message handling loop. */ @@ -139,14 +153,14 @@ ux_handler(void) NDR_record_t NDR; exception_type_t exception; mach_msg_type_number_t codeCnt; - exception_data_t code; + mach_exception_data_t code; /* some times RCV_TO_LARGE probs */ char pad[512]; } exc_msg; mach_port_name_t reply_port; kern_return_t result; - exc_msg.Head.msgh_local_port = (mach_port_t)exc_set_name; + exc_msg.Head.msgh_local_port = CAST_MACH_NAME_TO_PORT(exc_set_name); exc_msg.Head.msgh_size = sizeof (exc_msg); #if 0 result = mach_msg_receive(&exc_msg.Head); @@ -157,32 +171,36 @@ ux_handler(void) 0); #endif if (result == MACH_MSG_SUCCESS) { - reply_port = (mach_port_name_t)exc_msg.Head.msgh_remote_port; + reply_port = CAST_MACH_PORT_TO_NAME(exc_msg.Head.msgh_remote_port); - if (exc_server(&exc_msg.Head, &rep_msg.Head)) - (void) mach_msg_send(&rep_msg.Head, MACH_SEND_MSG, + if (mach_exc_server(&exc_msg.Head, &rep_msg.Head)) { + result = mach_msg_send(&rep_msg.Head, MACH_SEND_MSG, sizeof (rep_msg),MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL); + if (reply_port != 0 && result != MACH_MSG_SUCCESS) + mach_port_deallocate(get_task_ipcspace(ux_handler_self), reply_port); + } - if (reply_port != MACH_PORT_NULL) - (void) mach_port_deallocate(get_task_ipcspace(ux_handler_self), reply_port); } else if (result == MACH_RCV_TOO_LARGE) /* ignore oversized messages */; else panic("exception_handler"); } - thread_funnel_set(kernel_flock, FALSE); } void ux_handler_init(void) { + thread_t thread = THREAD_NULL; + ux_exception_port = MACH_PORT_NULL; - (void) kernel_thread(kernel_task, ux_handler); + (void) kernel_thread_start((thread_continue_t)ux_handler, NULL, &thread); + thread_deallocate(thread); + proc_list_lock(); if (ux_exception_port == MACH_PORT_NULL) { - assert_wait(&ux_exception_port, THREAD_UNINT); - thread_block(THREAD_CONTINUE_NULL); - } + (void)msleep(&ux_exception_port, proc_list_mlock, 0, "ux_handler_wait", 0); + } + proc_list_unlock(); } kern_return_t @@ -195,19 +213,43 @@ catch_exception_raise( __unused mach_msg_type_number_t codeCnt ) { - task_t self = current_task(); - thread_t th_act; - ipc_port_t thread_port; - kern_return_t result = MACH_MSG_SUCCESS; - int ux_signal = 0; - u_long ucode = 0; - struct uthread *ut; - mach_port_name_t thread_name = (mach_port_name_t)thread; /* XXX */ - mach_port_name_t task_name = (mach_port_name_t)task; /* XXX */ - - /* - * Convert local thread name to global port. - */ + mach_exception_data_type_t big_code[EXCEPTION_CODE_MAX]; + big_code[0] = code[0]; + big_code[1] = code[1]; + + return catch_mach_exception_raise(exception_port, + thread, + task, + exception, + big_code, + codeCnt); + +} + +kern_return_t +catch_mach_exception_raise( + __unused mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + __unused mach_msg_type_number_t codeCnt +) +{ + task_t self = current_task(); + thread_t th_act; + ipc_port_t thread_port; + struct proc *p; + kern_return_t result = MACH_MSG_SUCCESS; + int ux_signal = 0; + mach_exception_code_t ucode = 0; + struct uthread *ut; + mach_port_name_t thread_name = CAST_MACH_PORT_TO_NAME(thread); + mach_port_name_t task_name = CAST_MACH_PORT_TO_NAME(task); + + /* + * Convert local thread name to global port. + */ if (MACH_PORT_VALID(thread_name) && (ipc_object_copyin(get_task_ipcspace(self), thread_name, MACH_MSG_TYPE_PORT_SEND, @@ -223,20 +265,79 @@ catch_exception_raise( * Catch bogus ports */ if (th_act != THREAD_NULL) { - + /* * Convert exception to unix signal and code. */ - ut = get_bsdthread_info(th_act); - ux_exception(exception, code[0], code[1], - &ux_signal, (int *)&ucode); + ux_exception(exception, code[0], code[1], &ux_signal, &ucode); + + ut = get_bsdthread_info(th_act); + p = proc_findthread(th_act); + + /* Can't deliver a signal without a bsd process reference */ + if (p == NULL) { + ux_signal = 0; + result = KERN_FAILURE; + } + /* + * Stack overflow should result in a SIGSEGV signal + * on the alternate stack. + * but we have one or more guard pages after the + * stack top, so we would get a KERN_PROTECTION_FAILURE + * exception instead of KERN_INVALID_ADDRESS, resulting in + * a SIGBUS signal. + * Detect that situation and select the correct signal. + */ + if (code[0] == KERN_PROTECTION_FAILURE && + ux_signal == SIGBUS) { + user_addr_t sp, stack_min, stack_max; + int mask; + struct sigacts *ps; + + sp = code[1]; + + stack_max = p->user_stack; + stack_min = p->user_stack - MAXSSIZ; + if (sp >= stack_min && + sp < stack_max) { + /* + * This is indeed a stack overflow. Deliver a + * SIGSEGV signal. + */ + ux_signal = SIGSEGV; + + /* + * If the thread/process is not ready to handle + * SIGSEGV on an alternate stack, force-deliver + * SIGSEGV with a SIG_DFL handler. + */ + mask = sigmask(ux_signal); + ps = p->p_sigacts; + if ((p->p_sigignore & mask) || + (ut->uu_sigwait & mask) || + (ut->uu_sigmask & mask) || + (ps->ps_sigact[SIGSEGV] == SIG_IGN) || + (! (ps->ps_sigonstack & mask))) { + p->p_sigignore &= ~mask; + p->p_sigcatch &= ~mask; + ps->ps_sigact[SIGSEGV] = SIG_DFL; + ut->uu_sigwait &= ~mask; + ut->uu_sigmask &= ~mask; + } + } + } /* * Send signal. */ - if (ux_signal != 0) - threadsignal(th_act, ux_signal, ucode); - + if (ux_signal != 0) { + ut->uu_exception = exception; + //ut->uu_code = code[0]; // filled in by threadsignal + ut->uu_subcode = code[1]; + threadsignal(th_act, ux_signal, code[0]); + } + if (p != NULL) + proc_rele(p); thread_deallocate(th_act); } else @@ -246,10 +347,9 @@ catch_exception_raise( result = KERN_INVALID_ARGUMENT; /* - * Delete our send rights to the task and thread ports. + * Delete our send rights to the task port. */ (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), task_name); - (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), thread_name); return (result); } @@ -269,6 +369,21 @@ catch_exception_raise_state( return(KERN_INVALID_ARGUMENT); } +kern_return_t +catch_mach_exception_raise_state( + __unused mach_port_t exception_port, + __unused exception_type_t exception, + __unused const mach_exception_data_t code, + __unused mach_msg_type_number_t codeCnt, + __unused int *flavor, + __unused const thread_state_t old_state, + __unused mach_msg_type_number_t old_stateCnt, + __unused thread_state_t new_state, + __unused mach_msg_type_number_t *new_stateCnt) +{ + return(KERN_INVALID_ARGUMENT); +} + kern_return_t catch_exception_raise_state_identity( __unused mach_port_t exception_port, @@ -286,6 +401,24 @@ catch_exception_raise_state_identity( return(KERN_INVALID_ARGUMENT); } +kern_return_t +catch_mach_exception_raise_state_identity( + __unused mach_port_t exception_port, + __unused mach_port_t thread, + __unused mach_port_t task, + __unused exception_type_t exception, + __unused mach_exception_data_t code, + __unused mach_msg_type_number_t codeCnt, + __unused int *flavor, + __unused thread_state_t old_state, + __unused mach_msg_type_number_t old_stateCnt, + __unused thread_state_t new_state, + __unused mach_msg_type_number_t *new_stateCnt) +{ + return(KERN_INVALID_ARGUMENT); +} + + /* * ux_exception translates a mach exception, code and subcode to * a signal and u.u_code. Calls machine_exception (machine dependent) @@ -294,12 +427,11 @@ catch_exception_raise_state_identity( static void ux_exception( - int exception, - int code, - int subcode, - int *ux_signal, - int *ux_code -) + int exception, + mach_exception_code_t code, + mach_exception_subcode_t subcode, + int *ux_signal, + mach_exception_code_t *ux_code) { /* * Try machine-dependent translation first.