]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/exception.c
xnu-2782.20.48.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
A
88
89unsigned long c_thr_exc_raise = 0;
90unsigned long c_thr_exc_raise_state = 0;
91unsigned long c_thr_exc_raise_state_id = 0;
92unsigned long c_tsk_exc_raise = 0;
93unsigned long c_tsk_exc_raise_state = 0;
94unsigned long c_tsk_exc_raise_state_id = 0;
95
91447636 96/* forward declarations */
2d21ac55
A
97kern_return_t exception_deliver(
98 thread_t thread,
91447636 99 exception_type_t exception,
2d21ac55 100 mach_exception_data_t code,
91447636
A
101 mach_msg_type_number_t codeCnt,
102 struct exception_action *excp,
b0d623f7 103 lck_mtx_t *mutex);
91447636 104
fe8ab488
A
105static kern_return_t
106check_exc_receiver_dependancy(
107 exception_type_t exception,
108 struct exception_action *excp,
109 lck_mtx_t *mutex);
110
91447636
A
111#ifdef MACH_BSD
112kern_return_t bsd_exception(
113 exception_type_t exception,
2d21ac55 114 mach_exception_data_t code,
91447636
A
115 mach_msg_type_number_t codeCnt);
116#endif /* MACH_BSD */
1c79356b
A
117
118/*
119 * Routine: exception_deliver
120 * Purpose:
121 * Make an upcall to the exception server provided.
122 * Conditions:
123 * Nothing locked and no resources held.
124 * Called from an exception context, so
125 * thread_exception_return and thread_kdb_return
126 * are possible.
127 * Returns:
2d21ac55 128 * KERN_SUCCESS if the exception was handled
1c79356b 129 */
2d21ac55 130kern_return_t
1c79356b 131exception_deliver(
2d21ac55 132 thread_t thread,
1c79356b 133 exception_type_t exception,
2d21ac55 134 mach_exception_data_t code,
1c79356b
A
135 mach_msg_type_number_t codeCnt,
136 struct exception_action *excp,
b0d623f7 137 lck_mtx_t *mutex)
1c79356b 138{
1c79356b 139 ipc_port_t exc_port;
2d21ac55
A
140 exception_data_type_t small_code[EXCEPTION_CODE_MAX];
141 int code64;
1c79356b
A
142 int behavior;
143 int flavor;
144 kern_return_t kr;
145
146 /*
147 * Save work if we are terminating.
148 * Just go back to our AST handler.
149 */
2d21ac55
A
150 if (!thread->active)
151 return KERN_SUCCESS;
1c79356b 152
39236c6e
A
153 /*
154 * If there are no exception actions defined for this entity,
155 * we can't deliver here.
156 */
157 if (excp == NULL)
158 return KERN_FAILURE;
159
160 assert(exception < EXC_TYPES_COUNT);
161 if (exception >= EXC_TYPES_COUNT)
162 return KERN_FAILURE;
163
164 excp = &excp[exception];
165
1c79356b
A
166 /*
167 * Snapshot the exception action data under lock for consistency.
168 * Hold a reference to the port over the exception_raise_* calls
169 * so it can't be destroyed. This seems like overkill, but keeps
170 * the port from disappearing between now and when
171 * ipc_object_copyin_from_kernel is finally called.
172 */
b0d623f7 173 lck_mtx_lock(mutex);
1c79356b
A
174 exc_port = excp->port;
175 if (!IP_VALID(exc_port)) {
b0d623f7 176 lck_mtx_unlock(mutex);
2d21ac55 177 return KERN_FAILURE;
1c79356b
A
178 }
179 ip_lock(exc_port);
180 if (!ip_active(exc_port)) {
181 ip_unlock(exc_port);
b0d623f7 182 lck_mtx_unlock(mutex);
2d21ac55 183 return KERN_FAILURE;
1c79356b
A
184 }
185 ip_reference(exc_port);
186 exc_port->ip_srights++;
187 ip_unlock(exc_port);
188
189 flavor = excp->flavor;
190 behavior = excp->behavior;
b0d623f7 191 lck_mtx_unlock(mutex);
1c79356b 192
2d21ac55
A
193 code64 = (behavior & MACH_EXCEPTION_CODES);
194 behavior &= ~MACH_EXCEPTION_CODES;
195
196 if (!code64) {
b0d623f7
A
197 small_code[0] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[0]);
198 small_code[1] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[1]);
2d21ac55
A
199 }
200
201
1c79356b
A
202 switch (behavior) {
203 case EXCEPTION_STATE: {
204 mach_msg_type_number_t state_cnt;
55e303ae 205 thread_state_data_t state;
1c79356b
A
206
207 c_thr_exc_raise_state++;
91447636 208 state_cnt = _MachineStateCount[flavor];
2d21ac55 209 kr = thread_getstatus(thread, flavor,
1c79356b
A
210 (thread_state_t)state,
211 &state_cnt);
212 if (kr == KERN_SUCCESS) {
2d21ac55
A
213 if (code64) {
214 kr = mach_exception_raise_state(exc_port,
215 exception,
216 code,
217 codeCnt,
218 &flavor,
219 state, state_cnt,
220 state, &state_cnt);
221 } else {
222 kr = exception_raise_state(exc_port, exception,
223 small_code,
224 codeCnt,
225 &flavor,
226 state, state_cnt,
227 state, &state_cnt);
228 }
1c79356b 229 if (kr == MACH_MSG_SUCCESS)
2d21ac55
A
230 kr = thread_setstatus(thread, flavor,
231 (thread_state_t)state,
232 state_cnt);
1c79356b
A
233 }
234
2d21ac55 235 return kr;
1c79356b
A
236 }
237
238 case EXCEPTION_DEFAULT:
239 c_thr_exc_raise++;
2d21ac55
A
240 if (code64) {
241 kr = mach_exception_raise(exc_port,
242 retrieve_thread_self_fast(thread),
243 retrieve_task_self_fast(thread->task),
244 exception,
245 code,
246 codeCnt);
247 } else {
248 kr = exception_raise(exc_port,
249 retrieve_thread_self_fast(thread),
250 retrieve_task_self_fast(thread->task),
251 exception,
252 small_code,
253 codeCnt);
254 }
1c79356b 255
2d21ac55 256 return kr;
1c79356b
A
257
258 case EXCEPTION_STATE_IDENTITY: {
259 mach_msg_type_number_t state_cnt;
55e303ae 260 thread_state_data_t state;
1c79356b
A
261
262 c_thr_exc_raise_state_id++;
91447636 263 state_cnt = _MachineStateCount[flavor];
2d21ac55 264 kr = thread_getstatus(thread, flavor,
1c79356b
A
265 (thread_state_t)state,
266 &state_cnt);
267 if (kr == KERN_SUCCESS) {
2d21ac55
A
268 if (code64) {
269 kr = mach_exception_raise_state_identity(
270 exc_port,
271 retrieve_thread_self_fast(thread),
272 retrieve_task_self_fast(thread->task),
273 exception,
274 code,
275 codeCnt,
276 &flavor,
277 state, state_cnt,
278 state, &state_cnt);
279 } else {
280 kr = exception_raise_state_identity(exc_port,
281 retrieve_thread_self_fast(thread),
282 retrieve_task_self_fast(thread->task),
283 exception,
284 small_code,
285 codeCnt,
286 &flavor,
287 state, state_cnt,
288 state, &state_cnt);
289 }
290 if (kr == MACH_MSG_SUCCESS)
291 kr = thread_setstatus(thread, flavor,
292 (thread_state_t)state,
293 state_cnt);
1c79356b
A
294 }
295
2d21ac55 296 return kr;
1c79356b 297 }
2d21ac55 298
1c79356b 299 default:
2d21ac55
A
300 panic ("bad exception behavior!");
301 return KERN_FAILURE;
1c79356b
A
302 }/* switch */
303}
304
fe8ab488
A
305/*
306 * Routine: check_exc_receiver_dependancy
307 * Purpose:
308 * Verify that the port destined for receiving this exception is not
309 * on the current task. This would cause hang in kernel for
310 * EXC_CRASH primarily. Note: If port is transferred
311 * between check and delivery then deadlock may happen.
312 *
313 * Conditions:
314 * Nothing locked and no resources held.
315 * Called from an exception context.
316 * Returns:
317 * KERN_SUCCESS if its ok to send exception message.
318 */
319kern_return_t
320check_exc_receiver_dependancy(
321 exception_type_t exception,
322 struct exception_action *excp,
323 lck_mtx_t *mutex)
324{
325 kern_return_t retval = KERN_SUCCESS;
326
327 if (excp == NULL || exception != EXC_CRASH)
328 return retval;
329
330 task_t task = current_task();
331 lck_mtx_lock(mutex);
332 ipc_port_t xport = excp[exception].port;
333 if ( IP_VALID(xport)
334 && ip_active(xport)
335 && task->itk_space == xport->ip_receiver)
336 retval = KERN_FAILURE;
337 lck_mtx_unlock(mutex);
338 return retval;
339}
340
1c79356b
A
341/*
342 * Routine: exception
343 * Purpose:
344 * The current thread caught an exception.
345 * We make an up-call to the thread's exception server.
346 * Conditions:
347 * Nothing locked and no resources held.
348 * Called from an exception context, so
349 * thread_exception_return and thread_kdb_return
350 * are possible.
351 * Returns:
352 * Doesn't return.
353 */
354void
91447636 355exception_triage(
1c79356b 356 exception_type_t exception,
2d21ac55 357 mach_exception_data_t code,
1c79356b
A
358 mach_msg_type_number_t codeCnt)
359{
91447636 360 thread_t thread;
1c79356b
A
361 task_t task;
362 host_priv_t host_priv;
39236c6e
A
363 lck_mtx_t *mutex;
364 kern_return_t kr;
1c79356b
A
365
366 assert(exception != EXC_RPC_ALERT);
367
316670eb 368 thread = current_thread();
1c79356b
A
369
370 /*
371 * Try to raise the exception at the activation level.
372 */
b0d623f7 373 mutex = &thread->mutex;
fe8ab488
A
374 if (KERN_SUCCESS == check_exc_receiver_dependancy(exception, thread->exc_actions, mutex))
375 {
376 kr = exception_deliver(thread, exception, code, codeCnt, thread->exc_actions, mutex);
377 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
378 goto out;
379 }
1c79356b
A
380
381 /*
382 * Maybe the task level will handle it.
383 */
384 task = current_task();
b0d623f7 385 mutex = &task->lock;
fe8ab488
A
386 if (KERN_SUCCESS == check_exc_receiver_dependancy(exception, task->exc_actions, mutex))
387 {
388 kr = exception_deliver(thread, exception, code, codeCnt, task->exc_actions, mutex);
389 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
390 goto out;
391 }
1c79356b
A
392
393 /*
394 * How about at the host level?
395 */
396 host_priv = host_priv_self();
b0d623f7 397 mutex = &host_priv->lock;
fe8ab488
A
398
399 if (KERN_SUCCESS == check_exc_receiver_dependancy(exception, host_priv->exc_actions, mutex))
400 {
401 kr = exception_deliver(thread, exception, code, codeCnt, host_priv->exc_actions, mutex);
402 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
403 goto out;
404 }
1c79356b
A
405
406 /*
407 * Nobody handled it, terminate the task.
408 */
409
1c79356b 410 (void) task_terminate(task);
2d21ac55
A
411
412out:
39236c6e
A
413 if ((exception != EXC_CRASH) && (exception != EXC_RESOURCE) &&
414 (exception != EXC_GUARD))
2d21ac55
A
415 thread_exception_return();
416 return;
1c79356b 417}
9bccf70c
A
418
419kern_return_t
420bsd_exception(
421 exception_type_t exception,
2d21ac55 422 mach_exception_data_t code,
9bccf70c
A
423 mach_msg_type_number_t codeCnt)
424{
425 task_t task;
b0d623f7 426 lck_mtx_t *mutex;
91447636 427 thread_t self = current_thread();
9bccf70c
A
428 kern_return_t kr;
429
430 /*
431 * Maybe the task level will handle it.
432 */
433 task = current_task();
b0d623f7 434 mutex = &task->lock;
9bccf70c 435
39236c6e 436 kr = exception_deliver(self, exception, code, codeCnt, task->exc_actions, mutex);
9bccf70c 437
2d21ac55
A
438 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED)
439 return(KERN_SUCCESS);
440 return(KERN_FAILURE);
441}
9bccf70c 442
9bccf70c 443
2d21ac55 444/*
316670eb 445 * Raise an exception on a task.
2d21ac55
A
446 * This should tell launchd to launch Crash Reporter for this task.
447 */
316670eb
A
448kern_return_t task_exception_notify(exception_type_t exception,
449 mach_exception_data_type_t exccode, mach_exception_data_type_t excsubcode)
2d21ac55
A
450{
451 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
452 wait_interrupt_t wsave;
9bccf70c 453
2d21ac55
A
454 code[0] = exccode;
455 code[1] = excsubcode;
9bccf70c 456
2d21ac55 457 wsave = thread_interrupt_level(THREAD_UNINT);
316670eb 458 exception_triage(exception, code, EXCEPTION_CODE_MAX);
2d21ac55
A
459 (void) thread_interrupt_level(wsave);
460 return (KERN_SUCCESS);
9bccf70c
A
461}
462
55e303ae 463
55e303ae 464/*
2d21ac55 465 * Handle interface for special performance monitoring
55e303ae
A
466 * This is a special case of the host exception handler
467 */
2d21ac55 468kern_return_t sys_perf_notify(thread_t thread, int pid)
55e303ae
A
469{
470 host_priv_t hostp;
55e303ae 471 ipc_port_t xport;
55e303ae 472 wait_interrupt_t wsave;
2d21ac55 473 kern_return_t ret;
55e303ae 474
2d21ac55
A
475 hostp = host_priv_self(); /* Get the host privileged ports */
476 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
477 code[0] = 0xFF000001; /* Set terminate code */
478 code[1] = pid; /* Pass out the pid */
55e303ae 479
2d21ac55 480 struct task *task = thread->task;
39236c6e 481 xport = hostp->exc_actions[EXC_RPC_ALERT].port;
55e303ae 482
2d21ac55
A
483 /* Make sure we're not catching our own exception */
484 if (!IP_VALID(xport) ||
485 !ip_active(xport) ||
486 task->itk_space == xport->data.receiver) {
55e303ae 487
2d21ac55 488 return(KERN_FAILURE);
55e303ae 489 }
2d21ac55
A
490
491 wsave = thread_interrupt_level(THREAD_UNINT);
492 ret = exception_deliver(
493 thread,
494 EXC_RPC_ALERT,
495 code,
496 2,
39236c6e 497 hostp->exc_actions,
2d21ac55
A
498 &hostp->lock);
499 (void)thread_interrupt_level(wsave);
500
501 return(ret);
55e303ae 502}
2d21ac55 503