]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/exception.c
xnu-344.23.tar.gz
[apple/xnu.git] / osfmk / kern / exception.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50 /*
51 */
52
53 #include <mach_kdb.h>
54
55 #include <mach/boolean.h>
56 #include <mach/kern_return.h>
57 #include <mach/message.h>
58 #include <mach/port.h>
59 #include <mach/mig_errors.h>
60 #include <mach/thread_status.h>
61 #include <mach/exception_types.h>
62 #include <ipc/port.h>
63 #include <ipc/ipc_entry.h>
64 #include <ipc/ipc_object.h>
65 #include <ipc/ipc_notify.h>
66 #include <ipc/ipc_space.h>
67 #include <ipc/ipc_pset.h>
68 #include <ipc/ipc_machdep.h>
69 #include <kern/etap_macros.h>
70 #include <kern/counters.h>
71 #include <kern/ipc_tt.h>
72 #include <kern/task.h>
73 #include <kern/thread.h>
74 #include <kern/thread_swap.h>
75 #include <kern/processor.h>
76 #include <kern/sched.h>
77 #include <kern/sched_prim.h>
78 #include <kern/host.h>
79 #include <kern/misc_protos.h>
80 #include <string.h>
81 #include <mach/exc.h>
82
83 #if MACH_KDB
84 #include <ddb/db_trap.h>
85 #endif /* MACH_KDB */
86
87 #if MACH_KDB
88
89 #include <ddb/db_output.h>
90
91 #if iPSC386 || iPSC860
92 boolean_t debug_user_with_kdb = TRUE;
93 #else
94 boolean_t debug_user_with_kdb = FALSE;
95 #endif
96
97 #endif /* MACH_KDB */
98
99 unsigned long c_thr_exc_raise = 0;
100 unsigned long c_thr_exc_raise_state = 0;
101 unsigned long c_thr_exc_raise_state_id = 0;
102 unsigned long c_tsk_exc_raise = 0;
103 unsigned long c_tsk_exc_raise_state = 0;
104 unsigned long c_tsk_exc_raise_state_id = 0;
105
106
107 /*
108 * Routine: exception_deliver
109 * Purpose:
110 * Make an upcall to the exception server provided.
111 * Conditions:
112 * Nothing locked and no resources held.
113 * Called from an exception context, so
114 * thread_exception_return and thread_kdb_return
115 * are possible.
116 * Returns:
117 * If the exception was not handled by this handler
118 */
119 void
120 exception_deliver(
121 exception_type_t exception,
122 exception_data_t code,
123 mach_msg_type_number_t codeCnt,
124 struct exception_action *excp,
125 mutex_t *mutex)
126 {
127 thread_act_t a_self = current_act();
128 ipc_port_t exc_port;
129 int behavior;
130 int flavor;
131 kern_return_t kr;
132
133 /*
134 * Save work if we are terminating.
135 * Just go back to our AST handler.
136 */
137 if (!a_self->active)
138 thread_exception_return();
139
140 /*
141 * Snapshot the exception action data under lock for consistency.
142 * Hold a reference to the port over the exception_raise_* calls
143 * so it can't be destroyed. This seems like overkill, but keeps
144 * the port from disappearing between now and when
145 * ipc_object_copyin_from_kernel is finally called.
146 */
147 mutex_lock(mutex);
148 exc_port = excp->port;
149 if (!IP_VALID(exc_port)) {
150 mutex_unlock(mutex);
151 return;
152 }
153 ip_lock(exc_port);
154 if (!ip_active(exc_port)) {
155 ip_unlock(exc_port);
156 mutex_unlock(mutex);
157 return;
158 }
159 ip_reference(exc_port);
160 exc_port->ip_srights++;
161 ip_unlock(exc_port);
162
163 flavor = excp->flavor;
164 behavior = excp->behavior;
165 mutex_unlock(mutex);
166
167 switch (behavior) {
168 case EXCEPTION_STATE: {
169 mach_msg_type_number_t state_cnt;
170 natural_t state[ THREAD_MACHINE_STATE_MAX ];
171
172 c_thr_exc_raise_state++;
173 state_cnt = state_count[flavor];
174 kr = thread_getstatus(a_self, flavor,
175 (thread_state_t)state,
176 &state_cnt);
177 if (kr == KERN_SUCCESS) {
178 kr = exception_raise_state(exc_port, exception,
179 code, codeCnt,
180 &flavor,
181 state, state_cnt,
182 state, &state_cnt);
183 if (kr == MACH_MSG_SUCCESS)
184 kr = thread_setstatus(a_self, flavor,
185 (thread_state_t)state,
186 state_cnt);
187 }
188
189 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
190 thread_exception_return();
191 /*NOTREACHED*/
192 return;
193 }
194
195 case EXCEPTION_DEFAULT:
196 c_thr_exc_raise++;
197 kr = exception_raise(exc_port,
198 retrieve_act_self_fast(a_self),
199 retrieve_task_self_fast(a_self->task),
200 exception,
201 code, codeCnt);
202
203 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
204 thread_exception_return();
205 /*NOTREACHED*/
206 return;
207
208 case EXCEPTION_STATE_IDENTITY: {
209 mach_msg_type_number_t state_cnt;
210 natural_t state[ THREAD_MACHINE_STATE_MAX ];
211
212 c_thr_exc_raise_state_id++;
213 state_cnt = state_count[flavor];
214 kr = thread_getstatus(a_self, flavor,
215 (thread_state_t)state,
216 &state_cnt);
217 if (kr == KERN_SUCCESS) {
218 kr = exception_raise_state_identity(exc_port,
219 retrieve_act_self_fast(a_self),
220 retrieve_task_self_fast(a_self->task),
221 exception,
222 code, codeCnt,
223 &flavor,
224 state, state_cnt,
225 state, &state_cnt);
226 if (kr == MACH_MSG_SUCCESS)
227 kr = thread_setstatus(a_self, flavor,
228 (thread_state_t)state,
229 state_cnt);
230 }
231
232 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
233 thread_exception_return();
234 /*NOTREACHED*/
235 return;
236 }
237
238 default:
239 panic ("bad exception behavior!");
240 }/* switch */
241 }
242
243 /*
244 * Routine: exception
245 * Purpose:
246 * The current thread caught an exception.
247 * We make an up-call to the thread's exception server.
248 * Conditions:
249 * Nothing locked and no resources held.
250 * Called from an exception context, so
251 * thread_exception_return and thread_kdb_return
252 * are possible.
253 * Returns:
254 * Doesn't return.
255 */
256 void
257 exception(
258 exception_type_t exception,
259 exception_data_t code,
260 mach_msg_type_number_t codeCnt)
261 {
262 thread_act_t thr_act;
263 task_t task;
264 host_priv_t host_priv;
265 struct exception_action *excp;
266 mutex_t *mutex;
267
268 assert(exception != EXC_RPC_ALERT);
269
270 if (exception == KERN_SUCCESS)
271 panic("exception");
272
273 /*
274 * Try to raise the exception at the activation level.
275 */
276 thr_act = current_act();
277 mutex = mutex_addr(thr_act->lock);
278 excp = &thr_act->exc_actions[exception];
279 exception_deliver(exception, code, codeCnt, excp, mutex);
280
281 /*
282 * Maybe the task level will handle it.
283 */
284 task = current_task();
285 mutex = mutex_addr(task->lock);
286 excp = &task->exc_actions[exception];
287 exception_deliver(exception, code, codeCnt, excp, mutex);
288
289 /*
290 * How about at the host level?
291 */
292 host_priv = host_priv_self();
293 mutex = mutex_addr(host_priv->lock);
294 excp = &host_priv->exc_actions[exception];
295 exception_deliver(exception, code, codeCnt, excp, mutex);
296
297 /*
298 * Nobody handled it, terminate the task.
299 */
300
301 #if MACH_KDB
302 if (debug_user_with_kdb) {
303 /*
304 * Debug the exception with kdb.
305 * If kdb handles the exception,
306 * then thread_kdb_return won't return.
307 */
308 db_printf("No exception server, calling kdb...\n");
309 thread_kdb_return();
310 }
311 #endif /* MACH_KDB */
312
313 (void) task_terminate(task);
314 thread_exception_return();
315 /*NOTREACHED*/
316 }
317
318 kern_return_t
319 bsd_exception(
320 exception_type_t exception,
321 exception_data_t code,
322 mach_msg_type_number_t codeCnt)
323 {
324 task_t task;
325 host_priv_t host_priv;
326 struct exception_action *excp;
327 mutex_t *mutex;
328 thread_act_t a_self = current_act();
329 ipc_port_t exc_port;
330 int behavior;
331 int flavor;
332 kern_return_t kr;
333
334 /*
335 * Maybe the task level will handle it.
336 */
337 task = current_task();
338 mutex = mutex_addr(task->lock);
339 excp = &task->exc_actions[exception];
340
341 /*
342 * Save work if we are terminating.
343 * Just go back to our AST handler.
344 */
345 if (!a_self->active) {
346 return(KERN_FAILURE);
347 }
348
349 /*
350 * Snapshot the exception action data under lock for consistency.
351 * Hold a reference to the port over the exception_raise_* calls
352 * so it can't be destroyed. This seems like overkill, but keeps
353 * the port from disappearing between now and when
354 * ipc_object_copyin_from_kernel is finally called.
355 */
356 mutex_lock(mutex);
357 exc_port = excp->port;
358 if (!IP_VALID(exc_port)) {
359 mutex_unlock(mutex);
360 return(KERN_FAILURE);
361 }
362 ip_lock(exc_port);
363 if (!ip_active(exc_port)) {
364 ip_unlock(exc_port);
365 mutex_unlock(mutex);
366 return(KERN_FAILURE);
367 }
368 ip_reference(exc_port);
369 exc_port->ip_srights++;
370 ip_unlock(exc_port);
371
372 flavor = excp->flavor;
373 behavior = excp->behavior;
374 mutex_unlock(mutex);
375
376 switch (behavior) {
377 case EXCEPTION_STATE: {
378 mach_msg_type_number_t state_cnt;
379 natural_t state[ THREAD_MACHINE_STATE_MAX ];
380
381 c_thr_exc_raise_state++;
382 state_cnt = state_count[flavor];
383 kr = thread_getstatus(a_self, flavor,
384 (thread_state_t)state,
385 &state_cnt);
386 if (kr == KERN_SUCCESS) {
387 kr = exception_raise_state(exc_port, exception,
388 code, codeCnt,
389 &flavor,
390 state, state_cnt,
391 state, &state_cnt);
392 if (kr == MACH_MSG_SUCCESS)
393 kr = thread_setstatus(a_self, flavor,
394 (thread_state_t)state,
395 state_cnt);
396 }
397
398 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
399 return(KERN_SUCCESS);
400
401 return(KERN_FAILURE);
402 }
403
404 case EXCEPTION_DEFAULT:
405 c_thr_exc_raise++;
406 kr = exception_raise(exc_port,
407 retrieve_act_self_fast(a_self),
408 retrieve_task_self_fast(a_self->task),
409 exception,
410 code, codeCnt);
411
412 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
413 return(KERN_SUCCESS);
414 return(KERN_FAILURE);
415
416 case EXCEPTION_STATE_IDENTITY: {
417 mach_msg_type_number_t state_cnt;
418 natural_t state[ THREAD_MACHINE_STATE_MAX ];
419
420 c_thr_exc_raise_state_id++;
421 state_cnt = state_count[flavor];
422 kr = thread_getstatus(a_self, flavor,
423 (thread_state_t)state,
424 &state_cnt);
425 if (kr == KERN_SUCCESS) {
426 kr = exception_raise_state_identity(exc_port,
427 retrieve_act_self_fast(a_self),
428 retrieve_task_self_fast(a_self->task),
429 exception,
430 code, codeCnt,
431 &flavor,
432 state, state_cnt,
433 state, &state_cnt);
434 if (kr == MACH_MSG_SUCCESS)
435 kr = thread_setstatus(a_self, flavor,
436 (thread_state_t)state,
437 state_cnt);
438 }
439
440 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
441 return(KERN_SUCCESS);
442 return(KERN_FAILURE);
443 }
444
445 default:
446
447 return(KERN_FAILURE);
448 }/* switch */
449 return(KERN_FAILURE);
450 }
451