]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/exception.c
xnu-3248.50.21.tar.gz
[apple/xnu.git] / osfmk / kern / exception.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
55e303ae 59#include <mach/mach_types.h>
1c79356b
A
60#include <mach/boolean.h>
61#include <mach/kern_return.h>
62#include <mach/message.h>
63#include <mach/port.h>
64#include <mach/mig_errors.h>
91447636 65#include <mach/task.h>
1c79356b
A
66#include <mach/thread_status.h>
67#include <mach/exception_types.h>
2d21ac55
A
68#include <mach/exc.h>
69#include <mach/mach_exc.h>
1c79356b
A
70#include <ipc/port.h>
71#include <ipc/ipc_entry.h>
72#include <ipc/ipc_object.h>
73#include <ipc/ipc_notify.h>
74#include <ipc/ipc_space.h>
75#include <ipc/ipc_pset.h>
76#include <ipc/ipc_machdep.h>
1c79356b
A
77#include <kern/counters.h>
78#include <kern/ipc_tt.h>
79#include <kern/task.h>
80#include <kern/thread.h>
1c79356b
A
81#include <kern/processor.h>
82#include <kern/sched.h>
83#include <kern/sched_prim.h>
84#include <kern/host.h>
85#include <kern/misc_protos.h>
86#include <string.h>
316670eb 87#include <pexpert/pexpert.h>
1c79356b 88
3e170ce0
A
89extern int panic_on_exception_triage;
90
1c79356b
A
91unsigned long c_thr_exc_raise = 0;
92unsigned long c_thr_exc_raise_state = 0;
93unsigned long c_thr_exc_raise_state_id = 0;
94unsigned long c_tsk_exc_raise = 0;
95unsigned long c_tsk_exc_raise_state = 0;
96unsigned long c_tsk_exc_raise_state_id = 0;
97
91447636 98/* forward declarations */
2d21ac55
A
99kern_return_t exception_deliver(
100 thread_t thread,
91447636 101 exception_type_t exception,
2d21ac55 102 mach_exception_data_t code,
91447636
A
103 mach_msg_type_number_t codeCnt,
104 struct exception_action *excp,
b0d623f7 105 lck_mtx_t *mutex);
91447636 106
fe8ab488 107static kern_return_t
3e170ce0 108check_exc_receiver_dependency(
fe8ab488
A
109 exception_type_t exception,
110 struct exception_action *excp,
111 lck_mtx_t *mutex);
112
91447636
A
113#ifdef MACH_BSD
114kern_return_t bsd_exception(
115 exception_type_t exception,
2d21ac55 116 mach_exception_data_t code,
91447636
A
117 mach_msg_type_number_t codeCnt);
118#endif /* MACH_BSD */
1c79356b
A
119
120/*
121 * Routine: exception_deliver
122 * Purpose:
123 * Make an upcall to the exception server provided.
124 * Conditions:
125 * Nothing locked and no resources held.
126 * Called from an exception context, so
127 * thread_exception_return and thread_kdb_return
128 * are possible.
129 * Returns:
2d21ac55 130 * KERN_SUCCESS if the exception was handled
1c79356b 131 */
2d21ac55 132kern_return_t
1c79356b 133exception_deliver(
2d21ac55 134 thread_t thread,
1c79356b 135 exception_type_t exception,
2d21ac55 136 mach_exception_data_t code,
1c79356b
A
137 mach_msg_type_number_t codeCnt,
138 struct exception_action *excp,
b0d623f7 139 lck_mtx_t *mutex)
1c79356b 140{
1c79356b 141 ipc_port_t exc_port;
2d21ac55
A
142 exception_data_type_t small_code[EXCEPTION_CODE_MAX];
143 int code64;
1c79356b
A
144 int behavior;
145 int flavor;
146 kern_return_t kr;
147
148 /*
149 * Save work if we are terminating.
150 * Just go back to our AST handler.
151 */
3e170ce0 152 if (!thread->active && !thread->inspection)
2d21ac55 153 return KERN_SUCCESS;
1c79356b 154
39236c6e
A
155 /*
156 * If there are no exception actions defined for this entity,
157 * we can't deliver here.
158 */
159 if (excp == NULL)
160 return KERN_FAILURE;
161
162 assert(exception < EXC_TYPES_COUNT);
163 if (exception >= EXC_TYPES_COUNT)
164 return KERN_FAILURE;
165
166 excp = &excp[exception];
167
1c79356b
A
168 /*
169 * Snapshot the exception action data under lock for consistency.
170 * Hold a reference to the port over the exception_raise_* calls
171 * so it can't be destroyed. This seems like overkill, but keeps
172 * the port from disappearing between now and when
173 * ipc_object_copyin_from_kernel is finally called.
174 */
b0d623f7 175 lck_mtx_lock(mutex);
1c79356b
A
176 exc_port = excp->port;
177 if (!IP_VALID(exc_port)) {
b0d623f7 178 lck_mtx_unlock(mutex);
2d21ac55 179 return KERN_FAILURE;
1c79356b
A
180 }
181 ip_lock(exc_port);
182 if (!ip_active(exc_port)) {
183 ip_unlock(exc_port);
b0d623f7 184 lck_mtx_unlock(mutex);
2d21ac55 185 return KERN_FAILURE;
1c79356b
A
186 }
187 ip_reference(exc_port);
188 exc_port->ip_srights++;
189 ip_unlock(exc_port);
190
191 flavor = excp->flavor;
192 behavior = excp->behavior;
b0d623f7 193 lck_mtx_unlock(mutex);
1c79356b 194
2d21ac55
A
195 code64 = (behavior & MACH_EXCEPTION_CODES);
196 behavior &= ~MACH_EXCEPTION_CODES;
197
198 if (!code64) {
b0d623f7
A
199 small_code[0] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[0]);
200 small_code[1] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[1]);
2d21ac55
A
201 }
202
203
1c79356b
A
204 switch (behavior) {
205 case EXCEPTION_STATE: {
206 mach_msg_type_number_t state_cnt;
55e303ae 207 thread_state_data_t state;
1c79356b
A
208
209 c_thr_exc_raise_state++;
91447636 210 state_cnt = _MachineStateCount[flavor];
2d21ac55 211 kr = thread_getstatus(thread, flavor,
1c79356b
A
212 (thread_state_t)state,
213 &state_cnt);
214 if (kr == KERN_SUCCESS) {
2d21ac55
A
215 if (code64) {
216 kr = mach_exception_raise_state(exc_port,
217 exception,
218 code,
219 codeCnt,
220 &flavor,
221 state, state_cnt,
222 state, &state_cnt);
223 } else {
224 kr = exception_raise_state(exc_port, exception,
225 small_code,
226 codeCnt,
227 &flavor,
228 state, state_cnt,
229 state, &state_cnt);
230 }
3e170ce0 231 if (kr == MACH_MSG_SUCCESS && exception != EXC_CORPSE_NOTIFY)
2d21ac55
A
232 kr = thread_setstatus(thread, flavor,
233 (thread_state_t)state,
234 state_cnt);
1c79356b
A
235 }
236
2d21ac55 237 return kr;
1c79356b
A
238 }
239
240 case EXCEPTION_DEFAULT:
241 c_thr_exc_raise++;
2d21ac55
A
242 if (code64) {
243 kr = mach_exception_raise(exc_port,
244 retrieve_thread_self_fast(thread),
245 retrieve_task_self_fast(thread->task),
246 exception,
247 code,
248 codeCnt);
249 } else {
250 kr = exception_raise(exc_port,
251 retrieve_thread_self_fast(thread),
252 retrieve_task_self_fast(thread->task),
253 exception,
254 small_code,
255 codeCnt);
256 }
1c79356b 257
2d21ac55 258 return kr;
1c79356b
A
259
260 case EXCEPTION_STATE_IDENTITY: {
261 mach_msg_type_number_t state_cnt;
55e303ae 262 thread_state_data_t state;
1c79356b
A
263
264 c_thr_exc_raise_state_id++;
91447636 265 state_cnt = _MachineStateCount[flavor];
2d21ac55 266 kr = thread_getstatus(thread, flavor,
1c79356b
A
267 (thread_state_t)state,
268 &state_cnt);
269 if (kr == KERN_SUCCESS) {
2d21ac55
A
270 if (code64) {
271 kr = mach_exception_raise_state_identity(
272 exc_port,
273 retrieve_thread_self_fast(thread),
274 retrieve_task_self_fast(thread->task),
275 exception,
276 code,
277 codeCnt,
278 &flavor,
279 state, state_cnt,
280 state, &state_cnt);
281 } else {
282 kr = exception_raise_state_identity(exc_port,
283 retrieve_thread_self_fast(thread),
284 retrieve_task_self_fast(thread->task),
285 exception,
286 small_code,
287 codeCnt,
288 &flavor,
289 state, state_cnt,
290 state, &state_cnt);
291 }
3e170ce0 292 if (kr == MACH_MSG_SUCCESS && exception != EXC_CORPSE_NOTIFY)
2d21ac55
A
293 kr = thread_setstatus(thread, flavor,
294 (thread_state_t)state,
295 state_cnt);
1c79356b
A
296 }
297
2d21ac55 298 return kr;
1c79356b 299 }
2d21ac55 300
1c79356b 301 default:
2d21ac55
A
302 panic ("bad exception behavior!");
303 return KERN_FAILURE;
1c79356b
A
304 }/* switch */
305}
306
fe8ab488 307/*
3e170ce0 308 * Routine: check_exc_receiver_dependency
fe8ab488
A
309 * Purpose:
310 * Verify that the port destined for receiving this exception is not
311 * on the current task. This would cause hang in kernel for
312 * EXC_CRASH primarily. Note: If port is transferred
313 * between check and delivery then deadlock may happen.
314 *
315 * Conditions:
316 * Nothing locked and no resources held.
317 * Called from an exception context.
318 * Returns:
319 * KERN_SUCCESS if its ok to send exception message.
320 */
321kern_return_t
3e170ce0 322check_exc_receiver_dependency(
fe8ab488
A
323 exception_type_t exception,
324 struct exception_action *excp,
325 lck_mtx_t *mutex)
326{
327 kern_return_t retval = KERN_SUCCESS;
328
329 if (excp == NULL || exception != EXC_CRASH)
330 return retval;
331
332 task_t task = current_task();
333 lck_mtx_lock(mutex);
334 ipc_port_t xport = excp[exception].port;
335 if ( IP_VALID(xport)
336 && ip_active(xport)
337 && task->itk_space == xport->ip_receiver)
338 retval = KERN_FAILURE;
339 lck_mtx_unlock(mutex);
340 return retval;
341}
342
1c79356b 343/*
3e170ce0 344 * Routine: exception_triage
1c79356b
A
345 * Purpose:
346 * The current thread caught an exception.
347 * We make an up-call to the thread's exception server.
348 * Conditions:
349 * Nothing locked and no resources held.
350 * Called from an exception context, so
351 * thread_exception_return and thread_kdb_return
352 * are possible.
353 * Returns:
3e170ce0 354 * KERN_SUCCESS if exception is handled by any of the handlers.
1c79356b 355 */
3e170ce0 356kern_return_t
91447636 357exception_triage(
1c79356b 358 exception_type_t exception,
2d21ac55 359 mach_exception_data_t code,
1c79356b
A
360 mach_msg_type_number_t codeCnt)
361{
91447636 362 thread_t thread;
1c79356b
A
363 task_t task;
364 host_priv_t host_priv;
39236c6e 365 lck_mtx_t *mutex;
3e170ce0 366 kern_return_t kr = KERN_FAILURE;
1c79356b
A
367
368 assert(exception != EXC_RPC_ALERT);
369
3e170ce0
A
370 /*
371 * If this behavior has been requested by the the kernel
372 * (due to the boot environment), we should panic if we
373 * enter this function. This is intended as a debugging
374 * aid; it should allow us to debug why we caught an
375 * exception in environments where debugging is especially
376 * difficult.
377 */
378 if (panic_on_exception_triage) {
379 panic("called exception_triage when it was forbidden by the boot environment");
380 }
381
316670eb 382 thread = current_thread();
1c79356b
A
383
384 /*
385 * Try to raise the exception at the activation level.
386 */
b0d623f7 387 mutex = &thread->mutex;
3e170ce0 388 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, thread->exc_actions, mutex))
fe8ab488
A
389 {
390 kr = exception_deliver(thread, exception, code, codeCnt, thread->exc_actions, mutex);
391 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
392 goto out;
393 }
1c79356b
A
394
395 /*
396 * Maybe the task level will handle it.
397 */
398 task = current_task();
b0d623f7 399 mutex = &task->lock;
3e170ce0 400 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, task->exc_actions, mutex))
fe8ab488
A
401 {
402 kr = exception_deliver(thread, exception, code, codeCnt, task->exc_actions, mutex);
403 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
404 goto out;
405 }
1c79356b
A
406
407 /*
408 * How about at the host level?
409 */
410 host_priv = host_priv_self();
b0d623f7 411 mutex = &host_priv->lock;
fe8ab488 412
3e170ce0 413 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, host_priv->exc_actions, mutex))
fe8ab488
A
414 {
415 kr = exception_deliver(thread, exception, code, codeCnt, host_priv->exc_actions, mutex);
416 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
417 goto out;
418 }
1c79356b 419
2d21ac55 420out:
39236c6e 421 if ((exception != EXC_CRASH) && (exception != EXC_RESOURCE) &&
3e170ce0 422 (exception != EXC_GUARD) && (exception != EXC_CORPSE_NOTIFY))
2d21ac55 423 thread_exception_return();
3e170ce0 424 return kr;
1c79356b 425}
9bccf70c
A
426
427kern_return_t
428bsd_exception(
429 exception_type_t exception,
2d21ac55 430 mach_exception_data_t code,
9bccf70c
A
431 mach_msg_type_number_t codeCnt)
432{
433 task_t task;
b0d623f7 434 lck_mtx_t *mutex;
91447636 435 thread_t self = current_thread();
9bccf70c
A
436 kern_return_t kr;
437
438 /*
439 * Maybe the task level will handle it.
440 */
441 task = current_task();
b0d623f7 442 mutex = &task->lock;
9bccf70c 443
39236c6e 444 kr = exception_deliver(self, exception, code, codeCnt, task->exc_actions, mutex);
9bccf70c 445
2d21ac55
A
446 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
447 return(KERN_SUCCESS);
448 return(KERN_FAILURE);
449}
9bccf70c 450
9bccf70c 451
2d21ac55 452/*
316670eb 453 * Raise an exception on a task.
2d21ac55
A
454 * This should tell launchd to launch Crash Reporter for this task.
455 */
316670eb
A
456kern_return_t task_exception_notify(exception_type_t exception,
457 mach_exception_data_type_t exccode, mach_exception_data_type_t excsubcode)
2d21ac55
A
458{
459 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
460 wait_interrupt_t wsave;
3e170ce0 461 kern_return_t kr = KERN_SUCCESS;
9bccf70c 462
2d21ac55
A
463 code[0] = exccode;
464 code[1] = excsubcode;
9bccf70c 465
2d21ac55 466 wsave = thread_interrupt_level(THREAD_UNINT);
3e170ce0 467 kr = exception_triage(exception, code, EXCEPTION_CODE_MAX);
2d21ac55 468 (void) thread_interrupt_level(wsave);
3e170ce0 469 return kr;
9bccf70c
A
470}
471
55e303ae 472
55e303ae 473/*
2d21ac55 474 * Handle interface for special performance monitoring
55e303ae
A
475 * This is a special case of the host exception handler
476 */
2d21ac55 477kern_return_t sys_perf_notify(thread_t thread, int pid)
55e303ae
A
478{
479 host_priv_t hostp;
55e303ae 480 ipc_port_t xport;
55e303ae 481 wait_interrupt_t wsave;
2d21ac55 482 kern_return_t ret;
55e303ae 483
2d21ac55
A
484 hostp = host_priv_self(); /* Get the host privileged ports */
485 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
486 code[0] = 0xFF000001; /* Set terminate code */
487 code[1] = pid; /* Pass out the pid */
55e303ae 488
2d21ac55 489 struct task *task = thread->task;
39236c6e 490 xport = hostp->exc_actions[EXC_RPC_ALERT].port;
55e303ae 491
2d21ac55
A
492 /* Make sure we're not catching our own exception */
493 if (!IP_VALID(xport) ||
494 !ip_active(xport) ||
495 task->itk_space == xport->data.receiver) {
55e303ae 496
2d21ac55 497 return(KERN_FAILURE);
55e303ae 498 }
2d21ac55
A
499
500 wsave = thread_interrupt_level(THREAD_UNINT);
501 ret = exception_deliver(
502 thread,
503 EXC_RPC_ALERT,
504 code,
505 2,
39236c6e 506 hostp->exc_actions,
2d21ac55
A
507 &hostp->lock);
508 (void)thread_interrupt_level(wsave);
509
510 return(ret);
55e303ae 511}
2d21ac55 512