2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
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.
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.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
61 #include <mach/mach_types.h>
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>
67 #include <mach/task.h>
68 #include <mach/thread_status.h>
69 #include <mach/exception_types.h>
71 #include <mach/mach_exc.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>
79 #include <kern/counters.h>
80 #include <kern/ipc_tt.h>
81 #include <kern/task.h>
82 #include <kern/thread.h>
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>
91 #include <ddb/db_trap.h>
96 #include <ddb/db_output.h>
98 #if iPSC386 || iPSC860
99 boolean_t debug_user_with_kdb
= TRUE
;
101 boolean_t debug_user_with_kdb
= FALSE
;
104 #endif /* MACH_KDB */
106 unsigned long c_thr_exc_raise
= 0;
107 unsigned long c_thr_exc_raise_state
= 0;
108 unsigned long c_thr_exc_raise_state_id
= 0;
109 unsigned long c_tsk_exc_raise
= 0;
110 unsigned long c_tsk_exc_raise_state
= 0;
111 unsigned long c_tsk_exc_raise_state_id
= 0;
113 /* forward declarations */
114 kern_return_t
exception_deliver(
116 exception_type_t exception
,
117 mach_exception_data_t code
,
118 mach_msg_type_number_t codeCnt
,
119 struct exception_action
*excp
,
123 kern_return_t
bsd_exception(
124 exception_type_t exception
,
125 mach_exception_data_t code
,
126 mach_msg_type_number_t codeCnt
);
127 #endif /* MACH_BSD */
130 * Routine: exception_deliver
132 * Make an upcall to the exception server provided.
134 * Nothing locked and no resources held.
135 * Called from an exception context, so
136 * thread_exception_return and thread_kdb_return
139 * KERN_SUCCESS if the exception was handled
144 exception_type_t exception
,
145 mach_exception_data_t code
,
146 mach_msg_type_number_t codeCnt
,
147 struct exception_action
*excp
,
151 exception_data_type_t small_code
[EXCEPTION_CODE_MAX
];
158 * Save work if we are terminating.
159 * Just go back to our AST handler.
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.
172 exc_port
= excp
->port
;
173 if (!IP_VALID(exc_port
)) {
174 lck_mtx_unlock(mutex
);
178 if (!ip_active(exc_port
)) {
180 lck_mtx_unlock(mutex
);
183 ip_reference(exc_port
);
184 exc_port
->ip_srights
++;
187 flavor
= excp
->flavor
;
188 behavior
= excp
->behavior
;
189 lck_mtx_unlock(mutex
);
191 code64
= (behavior
& MACH_EXCEPTION_CODES
);
192 behavior
&= ~MACH_EXCEPTION_CODES
;
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]);
201 case EXCEPTION_STATE
: {
202 mach_msg_type_number_t state_cnt
;
203 thread_state_data_t state
;
205 c_thr_exc_raise_state
++;
206 state_cnt
= _MachineStateCount
[flavor
];
207 kr
= thread_getstatus(thread
, flavor
,
208 (thread_state_t
)state
,
210 if (kr
== KERN_SUCCESS
) {
212 kr
= mach_exception_raise_state(exc_port
,
220 kr
= exception_raise_state(exc_port
, exception
,
227 if (kr
== MACH_MSG_SUCCESS
)
228 kr
= thread_setstatus(thread
, flavor
,
229 (thread_state_t
)state
,
236 case EXCEPTION_DEFAULT
:
239 kr
= mach_exception_raise(exc_port
,
240 retrieve_thread_self_fast(thread
),
241 retrieve_task_self_fast(thread
->task
),
246 kr
= exception_raise(exc_port
,
247 retrieve_thread_self_fast(thread
),
248 retrieve_task_self_fast(thread
->task
),
256 case EXCEPTION_STATE_IDENTITY
: {
257 mach_msg_type_number_t state_cnt
;
258 thread_state_data_t state
;
260 c_thr_exc_raise_state_id
++;
261 state_cnt
= _MachineStateCount
[flavor
];
262 kr
= thread_getstatus(thread
, flavor
,
263 (thread_state_t
)state
,
265 if (kr
== KERN_SUCCESS
) {
267 kr
= mach_exception_raise_state_identity(
269 retrieve_thread_self_fast(thread
),
270 retrieve_task_self_fast(thread
->task
),
278 kr
= exception_raise_state_identity(exc_port
,
279 retrieve_thread_self_fast(thread
),
280 retrieve_task_self_fast(thread
->task
),
288 if (kr
== MACH_MSG_SUCCESS
)
289 kr
= thread_setstatus(thread
, flavor
,
290 (thread_state_t
)state
,
298 panic ("bad exception behavior!");
306 * The current thread caught an exception.
307 * We make an up-call to the thread's exception server.
309 * Nothing locked and no resources held.
310 * Called from an exception context, so
311 * thread_exception_return and thread_kdb_return
318 exception_type_t exception
,
319 mach_exception_data_t code
,
320 mach_msg_type_number_t codeCnt
)
324 host_priv_t host_priv
;
325 struct exception_action
*excp
;
329 assert(exception
!= EXC_RPC_ALERT
);
331 if (exception
== KERN_SUCCESS
)
335 * Try to raise the exception at the activation level.
337 thread
= current_thread();
338 mutex
= &thread
->mutex
;
339 excp
= &thread
->exc_actions
[exception
];
340 kr
= exception_deliver(thread
, exception
, code
, codeCnt
, excp
, mutex
);
341 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
345 * Maybe the task level will handle it.
347 task
= current_task();
349 excp
= &task
->exc_actions
[exception
];
350 kr
= exception_deliver(thread
, exception
, code
, codeCnt
, excp
, mutex
);
351 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
355 * How about at the host level?
357 host_priv
= host_priv_self();
358 mutex
= &host_priv
->lock
;
359 excp
= &host_priv
->exc_actions
[exception
];
360 kr
= exception_deliver(thread
, exception
, code
, codeCnt
, excp
, mutex
);
361 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
365 * Nobody handled it, terminate the task.
369 if (debug_user_with_kdb
) {
371 * Debug the exception with kdb.
372 * If kdb handles the exception,
373 * then thread_kdb_return won't return.
375 db_printf("No exception server, calling kdb...\n");
378 #endif /* MACH_KDB */
380 (void) task_terminate(task
);
383 if (exception
!= EXC_CRASH
)
384 thread_exception_return();
390 exception_type_t exception
,
391 mach_exception_data_t code
,
392 mach_msg_type_number_t codeCnt
)
395 struct exception_action
*excp
;
397 thread_t self
= current_thread();
401 * Maybe the task level will handle it.
403 task
= current_task();
405 excp
= &task
->exc_actions
[exception
];
407 kr
= exception_deliver(self
, exception
, code
, codeCnt
, excp
, mutex
);
409 if (kr
== KERN_SUCCESS
|| kr
== MACH_RCV_PORT_DIED
)
410 return(KERN_SUCCESS
);
411 return(KERN_FAILURE
);
416 * Raise an EXC_CRASH exception on the dying task.
417 * This should tell launchd to launch Crash Reporter for this task.
419 kern_return_t
abnormal_exit_notify(mach_exception_data_type_t exccode
,
420 mach_exception_data_type_t excsubcode
)
422 mach_exception_data_type_t code
[EXCEPTION_CODE_MAX
];
423 wait_interrupt_t wsave
;
426 code
[1] = excsubcode
;
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
);
436 * Handle interface for special performance monitoring
437 * This is a special case of the host exception handler
439 kern_return_t
sys_perf_notify(thread_t thread
, int pid
)
442 struct exception_action
*excp
;
444 wait_interrupt_t wsave
;
447 hostp
= host_priv_self(); /* Get the host privileged ports */
448 mach_exception_data_type_t code
[EXCEPTION_CODE_MAX
];
449 code
[0] = 0xFF000001; /* Set terminate code */
450 code
[1] = pid
; /* Pass out the pid */
452 struct task
*task
= thread
->task
;
453 excp
= &hostp
->exc_actions
[EXC_RPC_ALERT
];
456 /* Make sure we're not catching our own exception */
457 if (!IP_VALID(xport
) ||
459 task
->itk_space
== xport
->data
.receiver
) {
461 return(KERN_FAILURE
);
464 wsave
= thread_interrupt_level(THREAD_UNINT
);
465 ret
= exception_deliver(
472 (void)thread_interrupt_level(wsave
);