]> git.saurik.com Git - apple/xnu.git/blame - bsd/uxkern/ux_exception.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / uxkern / ux_exception.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
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>
9bccf70c 48#include <kern/sched_prim.h>
1c79356b
A
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
61static void ux_exception();
62
63decl_simple_lock_data(static, ux_handler_init_lock)
64mach_port_name_t ux_exception_port;
65static task_t ux_handler_self;
66
67static
68void
69ux_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
157void
158ux_handler_init(void)
159{
1c79356b
A
160 simple_lock_init(&ux_handler_init_lock);
161 ux_exception_port = MACH_PORT_NULL;
55e303ae 162 (void) kernel_thread(kernel_task, ux_handler);
1c79356b
A
163 simple_lock(&ux_handler_init_lock);
164 if (ux_exception_port == MACH_PORT_NULL) {
165 simple_unlock(&ux_handler_init_lock);
166 assert_wait(&ux_exception_port, THREAD_UNINT);
9bccf70c 167 thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
168 }
169 else
170 simple_unlock(&ux_handler_init_lock);
171}
172
173kern_return_t
174catch_exception_raise(
175 mach_port_name_t exception_port,
176 mach_port_name_t thread_name,
177 mach_port_name_t task_name,
178 int exception,
179 exception_data_t code,
180 mach_msg_type_number_t codecnt
181)
182{
183 task_t self = current_task();
184 thread_act_t th_act;
185 ipc_port_t thread_port;
186 ipc_port_t task_port;
187 kern_return_t result = MACH_MSG_SUCCESS;
188 int signal = 0;
189 u_long ucode = 0;
190 struct uthread *ut;
191
192 /*
193 * Convert local thread name to global port.
194 */
195 if (MACH_PORT_VALID(thread_name) &&
196 (ipc_object_copyin(get_task_ipcspace(self), thread_name,
197 MACH_MSG_TYPE_PORT_SEND,
198 (void *) &thread_port) == MACH_MSG_SUCCESS)) {
9bccf70c 199 if (IPC_PORT_VALID(thread_port)) {
1c79356b
A
200 th_act = (thread_act_t)convert_port_to_act(thread_port);
201 ipc_port_release(thread_port);
202 } else {
203 th_act = THR_ACT_NULL;
204 }
205
206 /*
207 * Catch bogus ports
208 */
209 if (th_act != THR_ACT_NULL) {
210
211 /*
212 * Convert exception to unix signal and code.
213 */
214 ut = get_bsdthread_info(th_act);
215 ux_exception(exception, code[0], code[1],
216 &signal, &ucode);
217
218 /*
219 * Send signal.
220 */
221 if (signal != 0)
222 threadsignal(th_act, signal, ucode);
223
224 act_deallocate(th_act);
225 }
226 else
227 result = KERN_INVALID_ARGUMENT;
228 }
229 else
230 result = KERN_INVALID_ARGUMENT;
231
232 /*
233 * Delete our send rights to the task and thread ports.
234 */
235 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self), task_name);
236 (void)mach_port_deallocate(get_task_ipcspace(ux_handler_self),thread_name);
237
238 return (result);
239}
240kern_return_t
241catch_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)
242{
243 return(KERN_INVALID_ARGUMENT);
244}
245kern_return_t
246catch_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)
247{
248 return(KERN_INVALID_ARGUMENT);
249}
250
251boolean_t machine_exception();
252
253/*
254 * ux_exception translates a mach exception, code and subcode to
255 * a signal and u.u_code. Calls machine_exception (machine dependent)
256 * to attempt translation first.
257 */
258
259static
260void ux_exception(
261 int exception,
262 int code,
263 int subcode,
264 int *ux_signal,
265 int *ux_code
266)
267{
268 /*
269 * Try machine-dependent translation first.
270 */
271 if (machine_exception(exception, code, subcode, ux_signal, ux_code))
272 return;
273
274 switch(exception) {
275
276 case EXC_BAD_ACCESS:
277 if (code == KERN_INVALID_ADDRESS)
278 *ux_signal = SIGSEGV;
279 else
280 *ux_signal = SIGBUS;
281 break;
282
283 case EXC_BAD_INSTRUCTION:
284 *ux_signal = SIGILL;
285 break;
286
287 case EXC_ARITHMETIC:
288 *ux_signal = SIGFPE;
289 break;
290
291 case EXC_EMULATION:
292 *ux_signal = SIGEMT;
293 break;
294
295 case EXC_SOFTWARE:
296 switch (code) {
297
298 case EXC_UNIX_BAD_SYSCALL:
299 *ux_signal = SIGSYS;
300 break;
301 case EXC_UNIX_BAD_PIPE:
302 *ux_signal = SIGPIPE;
303 break;
304 case EXC_UNIX_ABORT:
305 *ux_signal = SIGABRT;
306 break;
9bccf70c
A
307 case EXC_SOFT_SIGNAL:
308 *ux_signal = SIGKILL;
309 break;
1c79356b
A
310 }
311 break;
312
313 case EXC_BREAKPOINT:
314 *ux_signal = SIGTRAP;
315 break;
316 }
317}