]> git.saurik.com Git - apple/xnu.git/blob - bsd/uxkern/ux_exception.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / uxkern / ux_exception.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1987 Carnegie-Mellon University
28 * All rights reserved. The CMU software License Agreement specifies
29 * the terms and conditions for use and redistribution.
30 */
31
32 /*
33 *********************************************************************
34 * HISTORY
35 **********************************************************************
36 */
37
38 #include <sys/param.h>
39
40 #include <mach/boolean.h>
41 #include <mach/exception.h>
42 #include <mach/kern_return.h>
43 #include <mach/message.h>
44 #include <mach/port.h>
45 #include <mach/mig_errors.h>
46 #include <kern/task.h>
47 #include <kern/thread.h>
48 #include <kern/sched_prim.h>
49 #include <kern/thread_act.h>
50 #include <kern/kalloc.h>
51
52 #include <sys/proc.h>
53 #include <sys/user.h>
54 #include <sys/systm.h>
55 #include <sys/ux_exception.h>
56
57 /*
58 * Unix exception handler.
59 */
60
61 static void ux_exception();
62
63 decl_simple_lock_data(static, ux_handler_init_lock)
64 mach_port_name_t ux_exception_port;
65 static task_t ux_handler_self;
66
67 static
68 void
69 ux_handler(void)
70 {
71 task_t self = current_task();
72 mach_port_name_t exc_port_name;
73 mach_port_name_t exc_set_name;
74
75 (void) thread_funnel_set(kernel_flock, TRUE);
76
77 /* self->kernel_vm_space = TRUE; */
78 ux_handler_self = self;
79
80
81 /*
82 * Allocate a port set that we will receive on.
83 */
84 if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_PORT_SET, &exc_set_name) != MACH_MSG_SUCCESS)
85 panic("ux_handler: port_set_allocate failed");
86
87 /*
88 * Allocate an exception port and use object_copyin to
89 * translate it to the global name. Put it into the set.
90 */
91 if (mach_port_allocate(get_task_ipcspace(ux_handler_self), MACH_PORT_RIGHT_RECEIVE, &exc_port_name) != MACH_MSG_SUCCESS)
92 panic("ux_handler: port_allocate failed");
93 if (mach_port_move_member(get_task_ipcspace(ux_handler_self),
94 exc_port_name, exc_set_name) != MACH_MSG_SUCCESS)
95 panic("ux_handler: port_set_add failed");
96
97 if (ipc_object_copyin(get_task_ipcspace(self), exc_port_name,
98 MACH_MSG_TYPE_MAKE_SEND,
99 (void *) &ux_exception_port) != MACH_MSG_SUCCESS)
100 panic("ux_handler: object_copyin(ux_exception_port) failed");
101
102 thread_wakeup(&ux_exception_port);
103
104 /* Message handling loop. */
105
106 for (;;) {
107 struct rep_msg {
108 mach_msg_header_t Head;
109 NDR_record_t NDR;
110 kern_return_t RetCode;
111 } rep_msg;
112 struct exc_msg {
113 mach_msg_header_t Head;
114 /* start of the kernel processed data */
115 mach_msg_body_t msgh_body;
116 mach_msg_port_descriptor_t thread;
117 mach_msg_port_descriptor_t task;
118 /* end of the kernel processed data */
119 NDR_record_t NDR;
120 exception_type_t exception;
121 mach_msg_type_number_t codeCnt;
122 exception_data_t code;
123 /* some times RCV_TO_LARGE probs */
124 char pad[512];
125 } exc_msg;
126 mach_port_name_t reply_port;
127 kern_return_t result;
128
129 exc_msg.Head.msgh_local_port = (mach_port_t)exc_set_name;
130 exc_msg.Head.msgh_size = sizeof (exc_msg);
131 #if 0
132 result = mach_msg_receive(&exc_msg.Head);
133 #else
134 result = mach_msg_receive(&exc_msg.Head, MACH_RCV_MSG,
135 sizeof (exc_msg), exc_set_name,
136 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
137 0);
138 #endif
139 if (result == MACH_MSG_SUCCESS) {
140 reply_port = (mach_port_name_t)exc_msg.Head.msgh_remote_port;
141
142 if (exc_server(&exc_msg.Head, &rep_msg.Head))
143 (void) mach_msg_send(&rep_msg.Head, MACH_SEND_MSG,
144 sizeof (rep_msg),MACH_MSG_TIMEOUT_NONE,MACH_PORT_NULL);
145
146 if (reply_port != MACH_PORT_NULL)
147 (void) mach_port_deallocate(get_task_ipcspace(ux_handler_self), reply_port);
148 }
149 else if (result == MACH_RCV_TOO_LARGE)
150 /* ignore oversized messages */;
151 else
152 panic("exception_handler");
153 }
154 thread_funnel_set(kernel_flock, FALSE);
155 }
156
157 void
158 ux_handler_init(void)
159 {
160 task_t handler_task;
161
162 simple_lock_init(&ux_handler_init_lock);
163 ux_exception_port = MACH_PORT_NULL;
164 if (kernel_task_create(kernel_task,
165 0, 0, &handler_task) != MACH_MSG_SUCCESS) {
166 panic("Failed to created ux handler task\n");
167 }
168 (void) kernel_thread(handler_task, ux_handler);
169 simple_lock(&ux_handler_init_lock);
170 if (ux_exception_port == MACH_PORT_NULL) {
171 simple_unlock(&ux_handler_init_lock);
172 assert_wait(&ux_exception_port, THREAD_UNINT);
173 thread_block(THREAD_CONTINUE_NULL);
174 }
175 else
176 simple_unlock(&ux_handler_init_lock);
177 }
178
179 kern_return_t
180 catch_exception_raise(
181 mach_port_name_t exception_port,
182 mach_port_name_t thread_name,
183 mach_port_name_t task_name,
184 int exception,
185 exception_data_t code,
186 mach_msg_type_number_t codecnt
187 )
188 {
189 task_t self = current_task();
190 thread_act_t th_act;
191 ipc_port_t thread_port;
192 ipc_port_t task_port;
193 kern_return_t result = MACH_MSG_SUCCESS;
194 int signal = 0;
195 u_long ucode = 0;
196 struct uthread *ut;
197
198 /*
199 * Convert local thread name to global port.
200 */
201 if (MACH_PORT_VALID(thread_name) &&
202 (ipc_object_copyin(get_task_ipcspace(self), thread_name,
203 MACH_MSG_TYPE_PORT_SEND,
204 (void *) &thread_port) == MACH_MSG_SUCCESS)) {
205 if (IPC_PORT_VALID(thread_port)) {
206 th_act = (thread_act_t)convert_port_to_act(thread_port);
207 ipc_port_release(thread_port);
208 } else {
209 th_act = THR_ACT_NULL;
210 }
211
212 /*
213 * Catch bogus ports
214 */
215 if (th_act != THR_ACT_NULL) {
216
217 /*
218 * Convert exception to unix signal and code.
219 */
220 ut = get_bsdthread_info(th_act);
221 ux_exception(exception, code[0], code[1],
222 &signal, &ucode);
223
224 /*
225 * Send signal.
226 */
227 if (signal != 0)
228 threadsignal(th_act, signal, ucode);
229
230 act_deallocate(th_act);
231 }
232 else
233 result = KERN_INVALID_ARGUMENT;
234 }
235 else
236 result = KERN_INVALID_ARGUMENT;
237
238 /*
239 * Delete our send rights to the task and thread ports.
240 */
241 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), task_name);
242 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self),thread_name);
243
244 return (result);
245 }
246 kern_return_t
247 catch_exception_raise_state(mach_port_name_t exception_port, int exception, exception_data_t code, mach_msg_type_number_t codeCnt, int flavor, thread_state_t old_state, int old_stateCnt, thread_state_t new_state, int new_stateCnt)
248 {
249 return(KERN_INVALID_ARGUMENT);
250 }
251 kern_return_t
252 catch_exception_raise_state_identity(mach_port_name_t exception_port, mach_port_t thread, mach_port_t task, int exception, exception_data_t code, mach_msg_type_number_t codeCnt, int flavor, thread_state_t old_state, int old_stateCnt, thread_state_t new_state, int new_stateCnt)
253 {
254 return(KERN_INVALID_ARGUMENT);
255 }
256
257 boolean_t machine_exception();
258
259 /*
260 * ux_exception translates a mach exception, code and subcode to
261 * a signal and u.u_code. Calls machine_exception (machine dependent)
262 * to attempt translation first.
263 */
264
265 static
266 void ux_exception(
267 int exception,
268 int code,
269 int subcode,
270 int *ux_signal,
271 int *ux_code
272 )
273 {
274 /*
275 * Try machine-dependent translation first.
276 */
277 if (machine_exception(exception, code, subcode, ux_signal, ux_code))
278 return;
279
280 switch(exception) {
281
282 case EXC_BAD_ACCESS:
283 if (code == KERN_INVALID_ADDRESS)
284 *ux_signal = SIGSEGV;
285 else
286 *ux_signal = SIGBUS;
287 break;
288
289 case EXC_BAD_INSTRUCTION:
290 *ux_signal = SIGILL;
291 break;
292
293 case EXC_ARITHMETIC:
294 *ux_signal = SIGFPE;
295 break;
296
297 case EXC_EMULATION:
298 *ux_signal = SIGEMT;
299 break;
300
301 case EXC_SOFTWARE:
302 switch (code) {
303
304 case EXC_UNIX_BAD_SYSCALL:
305 *ux_signal = SIGSYS;
306 break;
307 case EXC_UNIX_BAD_PIPE:
308 *ux_signal = SIGPIPE;
309 break;
310 case EXC_UNIX_ABORT:
311 *ux_signal = SIGABRT;
312 break;
313 case EXC_SOFT_SIGNAL:
314 *ux_signal = SIGKILL;
315 break;
316 }
317 break;
318
319 case EXC_BREAKPOINT:
320 *ux_signal = SIGTRAP;
321 break;
322 }
323 }