]>
Commit | Line | Data |
---|---|---|
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 | ||
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); | |
9bccf70c | 173 | thread_block(THREAD_CONTINUE_NULL); |
1c79356b A |
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)) { | |
9bccf70c | 205 | if (IPC_PORT_VALID(thread_port)) { |
1c79356b A |
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; | |
9bccf70c A |
313 | case EXC_SOFT_SIGNAL: |
314 | *ux_signal = SIGKILL; | |
315 | break; | |
1c79356b A |
316 | } |
317 | break; | |
318 | ||
319 | case EXC_BREAKPOINT: | |
320 | *ux_signal = SIGTRAP; | |
321 | break; | |
322 | } | |
323 | } |