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