2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Mach Operating System
25 * Copyright (c) 1987 Carnegie-Mellon University
26 * All rights reserved. The CMU software License Agreement specifies
27 * the terms and conditions for use and redistribution.
31 *********************************************************************
33 **********************************************************************
36 #include <sys/param.h>
38 #include <mach/boolean.h>
39 #include <mach/exception.h>
40 #include <mach/kern_return.h>
41 #include <mach/message.h>
42 #include <mach/port.h>
43 #include <mach/mach_port.h>
44 #include <mach/mig_errors.h>
45 #include <mach/exc_server.h>
46 #include <kern/task.h>
47 #include <kern/thread.h>
48 #include <kern/sched_prim.h>
49 #include <kern/kalloc.h>
53 #include <sys/systm.h>
54 #include <sys/ux_exception.h>
56 #include <vm/vm_protos.h> /* get_task_ipcspace() */
59 * XXX Things that should be retrieved from Mach headers, but aren't
62 extern kern_return_t
ipc_object_copyin(ipc_space_t space
, mach_port_name_t name
,
63 mach_msg_type_name_t msgt_name
, struct ipc_object
**objectp
);
64 extern mach_msg_return_t
mach_msg_receive(mach_msg_header_t
*msg
,
65 mach_msg_option_t option
, mach_msg_size_t rcv_size
,
66 mach_port_name_t rcv_name
, mach_msg_timeout_t rcv_timeout
,
67 void (*continuation
)(mach_msg_return_t
),
68 mach_msg_size_t slist_size
);
69 extern mach_msg_return_t
mach_msg_send(mach_msg_header_t
*msg
,
70 mach_msg_option_t option
, mach_msg_size_t send_size
,
71 mach_msg_timeout_t send_timeout
, mach_port_name_t notify
);
72 extern thread_t
convert_port_to_thread(ipc_port_t port
);
73 extern void ipc_port_release(ipc_port_t
);
79 * Unix exception handler.
82 static void ux_exception(int exception
, int code
, int subcode
,
83 int *ux_signal
, int *ux_code
);
85 mach_port_name_t ux_exception_port
;
86 static task_t ux_handler_self
;
92 task_t self
= current_task();
93 mach_port_name_t exc_port_name
;
94 mach_port_name_t exc_set_name
;
96 (void) thread_funnel_set(kernel_flock
, TRUE
);
98 /* self->kernel_vm_space = TRUE; */
99 ux_handler_self
= self
;
103 * Allocate a port set that we will receive on.
105 if (mach_port_allocate(get_task_ipcspace(ux_handler_self
), MACH_PORT_RIGHT_PORT_SET
, &exc_set_name
) != MACH_MSG_SUCCESS
)
106 panic("ux_handler: port_set_allocate failed");
109 * Allocate an exception port and use object_copyin to
110 * translate it to the global name. Put it into the set.
112 if (mach_port_allocate(get_task_ipcspace(ux_handler_self
), MACH_PORT_RIGHT_RECEIVE
, &exc_port_name
) != MACH_MSG_SUCCESS
)
113 panic("ux_handler: port_allocate failed");
114 if (mach_port_move_member(get_task_ipcspace(ux_handler_self
),
115 exc_port_name
, exc_set_name
) != MACH_MSG_SUCCESS
)
116 panic("ux_handler: port_set_add failed");
118 if (ipc_object_copyin(get_task_ipcspace(self
), exc_port_name
,
119 MACH_MSG_TYPE_MAKE_SEND
,
120 (void *) &ux_exception_port
) != MACH_MSG_SUCCESS
)
121 panic("ux_handler: object_copyin(ux_exception_port) failed");
123 thread_wakeup(&ux_exception_port
);
125 /* Message handling loop. */
129 mach_msg_header_t Head
;
131 kern_return_t RetCode
;
134 mach_msg_header_t Head
;
135 /* start of the kernel processed data */
136 mach_msg_body_t msgh_body
;
137 mach_msg_port_descriptor_t thread
;
138 mach_msg_port_descriptor_t task
;
139 /* end of the kernel processed data */
141 exception_type_t exception
;
142 mach_msg_type_number_t codeCnt
;
143 exception_data_t code
;
144 /* some times RCV_TO_LARGE probs */
147 mach_port_name_t reply_port
;
148 kern_return_t result
;
150 exc_msg
.Head
.msgh_local_port
= (mach_port_t
)exc_set_name
;
151 exc_msg
.Head
.msgh_size
= sizeof (exc_msg
);
153 result
= mach_msg_receive(&exc_msg
.Head
);
155 result
= mach_msg_receive(&exc_msg
.Head
, MACH_RCV_MSG
,
156 sizeof (exc_msg
), exc_set_name
,
157 MACH_MSG_TIMEOUT_NONE
, MACH_PORT_NULL
,
160 if (result
== MACH_MSG_SUCCESS
) {
161 reply_port
= (mach_port_name_t
)exc_msg
.Head
.msgh_remote_port
;
163 if (exc_server(&exc_msg
.Head
, &rep_msg
.Head
))
164 (void) mach_msg_send(&rep_msg
.Head
, MACH_SEND_MSG
,
165 sizeof (rep_msg
),MACH_MSG_TIMEOUT_NONE
,MACH_PORT_NULL
);
167 if (reply_port
!= MACH_PORT_NULL
)
168 (void) mach_port_deallocate(get_task_ipcspace(ux_handler_self
), reply_port
);
170 else if (result
== MACH_RCV_TOO_LARGE
)
171 /* ignore oversized messages */;
173 panic("exception_handler");
175 thread_funnel_set(kernel_flock
, FALSE
);
179 ux_handler_init(void)
181 ux_exception_port
= MACH_PORT_NULL
;
182 (void) kernel_thread(kernel_task
, ux_handler
);
183 if (ux_exception_port
== MACH_PORT_NULL
) {
184 assert_wait(&ux_exception_port
, THREAD_UNINT
);
185 thread_block(THREAD_CONTINUE_NULL
);
190 catch_exception_raise(
191 __unused mach_port_t exception_port
,
194 exception_type_t exception
,
195 exception_data_t code
,
196 __unused mach_msg_type_number_t codeCnt
199 task_t self
= current_task();
201 ipc_port_t thread_port
;
202 kern_return_t result
= MACH_MSG_SUCCESS
;
206 mach_port_name_t thread_name
= (mach_port_name_t
)thread
; /* XXX */
207 mach_port_name_t task_name
= (mach_port_name_t
)task
; /* XXX */
210 * Convert local thread name to global port.
212 if (MACH_PORT_VALID(thread_name
) &&
213 (ipc_object_copyin(get_task_ipcspace(self
), thread_name
,
214 MACH_MSG_TYPE_PORT_SEND
,
215 (void *) &thread_port
) == MACH_MSG_SUCCESS
)) {
216 if (IPC_PORT_VALID(thread_port
)) {
217 th_act
= convert_port_to_thread(thread_port
);
218 ipc_port_release(thread_port
);
220 th_act
= THREAD_NULL
;
226 if (th_act
!= THREAD_NULL
) {
229 * Convert exception to unix signal and code.
231 ut
= get_bsdthread_info(th_act
);
232 ux_exception(exception
, code
[0], code
[1],
233 &ux_signal
, (int *)&ucode
);
239 threadsignal(th_act
, ux_signal
, ucode
);
241 thread_deallocate(th_act
);
244 result
= KERN_INVALID_ARGUMENT
;
247 result
= KERN_INVALID_ARGUMENT
;
250 * Delete our send rights to the task and thread ports.
252 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self
), task_name
);
253 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self
), thread_name
);
259 catch_exception_raise_state(
260 __unused mach_port_t exception_port
,
261 __unused exception_type_t exception
,
262 __unused
const exception_data_t code
,
263 __unused mach_msg_type_number_t codeCnt
,
264 __unused
int *flavor
,
265 __unused
const thread_state_t old_state
,
266 __unused mach_msg_type_number_t old_stateCnt
,
267 __unused thread_state_t new_state
,
268 __unused mach_msg_type_number_t
*new_stateCnt
)
270 return(KERN_INVALID_ARGUMENT
);
274 catch_exception_raise_state_identity(
275 __unused mach_port_t exception_port
,
276 __unused mach_port_t thread
,
277 __unused mach_port_t task
,
278 __unused exception_type_t exception
,
279 __unused exception_data_t code
,
280 __unused mach_msg_type_number_t codeCnt
,
281 __unused
int *flavor
,
282 __unused thread_state_t old_state
,
283 __unused mach_msg_type_number_t old_stateCnt
,
284 __unused thread_state_t new_state
,
285 __unused mach_msg_type_number_t
*new_stateCnt
)
287 return(KERN_INVALID_ARGUMENT
);
291 * ux_exception translates a mach exception, code and subcode to
292 * a signal and u.u_code. Calls machine_exception (machine dependent)
293 * to attempt translation first.
306 * Try machine-dependent translation first.
308 if (machine_exception(exception
, code
, subcode
, ux_signal
, ux_code
))
314 if (code
== KERN_INVALID_ADDRESS
)
315 *ux_signal
= SIGSEGV
;
320 case EXC_BAD_INSTRUCTION
:
335 case EXC_UNIX_BAD_SYSCALL
:
338 case EXC_UNIX_BAD_PIPE
:
339 *ux_signal
= SIGPIPE
;
342 *ux_signal
= SIGABRT
;
344 case EXC_SOFT_SIGNAL
:
345 *ux_signal
= SIGKILL
;
351 *ux_signal
= SIGTRAP
;