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