]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/exception.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / kern / exception.c
CommitLineData
1c79356b 1/*
f427ee49 2 * Copyright (c) 2000-2020 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 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.
0a7de745 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.
0a7de745 17 *
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
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.
0a7de745 41 *
1c79356b
A
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.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
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>
d9a64523 70
1c79356b
A
71#include <ipc/port.h>
72#include <ipc/ipc_entry.h>
73#include <ipc/ipc_object.h>
74#include <ipc/ipc_notify.h>
75#include <ipc/ipc_space.h>
76#include <ipc/ipc_pset.h>
77#include <ipc/ipc_machdep.h>
d9a64523 78
1c79356b
A
79#include <kern/ipc_tt.h>
80#include <kern/task.h>
81#include <kern/thread.h>
1c79356b
A
82#include <kern/processor.h>
83#include <kern/sched.h>
84#include <kern/sched_prim.h>
85#include <kern/host.h>
86#include <kern/misc_protos.h>
d9a64523
A
87#include <kern/ux_handler.h>
88
f427ee49
A
89#include <vm/vm_map.h>
90
39037602 91#include <security/mac_mach_internal.h>
1c79356b 92#include <string.h>
d9a64523 93
316670eb 94#include <pexpert/pexpert.h>
1c79356b 95
cb323159 96bool panic_on_exception_triage = false;
3e170ce0 97
1c79356b
A
98unsigned long c_thr_exc_raise = 0;
99unsigned long c_thr_exc_raise_state = 0;
100unsigned long c_thr_exc_raise_state_id = 0;
101unsigned long c_tsk_exc_raise = 0;
102unsigned long c_tsk_exc_raise_state = 0;
103unsigned long c_tsk_exc_raise_state_id = 0;
104
91447636 105/* forward declarations */
2d21ac55 106kern_return_t exception_deliver(
0a7de745
A
107 thread_t thread,
108 exception_type_t exception,
109 mach_exception_data_t code,
91447636
A
110 mach_msg_type_number_t codeCnt,
111 struct exception_action *excp,
0a7de745 112 lck_mtx_t *mutex);
91447636 113
fe8ab488 114static kern_return_t
3e170ce0 115check_exc_receiver_dependency(
0a7de745
A
116 exception_type_t exception,
117 struct exception_action *excp,
fe8ab488
A
118 lck_mtx_t *mutex);
119
91447636
A
120#ifdef MACH_BSD
121kern_return_t bsd_exception(
0a7de745
A
122 exception_type_t exception,
123 mach_exception_data_t code,
91447636
A
124 mach_msg_type_number_t codeCnt);
125#endif /* MACH_BSD */
1c79356b 126
eb6b6ca3
A
127#if __has_feature(ptrauth_calls)
128extern int exit_with_pac_exception(
129 void *proc,
130 exception_type_t exception,
131 mach_exception_code_t code,
132 mach_exception_subcode_t subcode);
133
134extern bool proc_is_traced(void *p);
135#endif /* __has_feature(ptrauth_calls) */
136
cb323159
A
137/*
138 * Routine: exception_init
139 * Purpose:
140 * Global initialization of state for exceptions.
141 * Conditions:
142 * None.
143 */
144void
145exception_init(void)
146{
147 int tmp = 0;
148
149 if (PE_parse_boot_argn("-panic_on_exception_triage", &tmp, sizeof(tmp))) {
150 panic_on_exception_triage = true;
151 }
152}
153
1c79356b
A
154/*
155 * Routine: exception_deliver
156 * Purpose:
157 * Make an upcall to the exception server provided.
158 * Conditions:
159 * Nothing locked and no resources held.
160 * Called from an exception context, so
161 * thread_exception_return and thread_kdb_return
162 * are possible.
163 * Returns:
2d21ac55 164 * KERN_SUCCESS if the exception was handled
1c79356b 165 */
0a7de745 166kern_return_t
1c79356b 167exception_deliver(
0a7de745
A
168 thread_t thread,
169 exception_type_t exception,
170 mach_exception_data_t code,
1c79356b
A
171 mach_msg_type_number_t codeCnt,
172 struct exception_action *excp,
0a7de745 173 lck_mtx_t *mutex)
1c79356b 174{
0a7de745
A
175 ipc_port_t exc_port = IPC_PORT_NULL;
176 exception_data_type_t small_code[EXCEPTION_CODE_MAX];
177 int code64;
178 int behavior;
179 int flavor;
180 kern_return_t kr;
39037602 181 task_t task;
5ba3f43e 182 ipc_port_t thread_port = IPC_PORT_NULL, task_port = IPC_PORT_NULL;
1c79356b
A
183
184 /*
185 * Save work if we are terminating.
186 * Just go back to our AST handler.
187 */
0a7de745 188 if (!thread->active && !thread->inspection) {
2d21ac55 189 return KERN_SUCCESS;
0a7de745 190 }
1c79356b 191
39236c6e
A
192 /*
193 * If there are no exception actions defined for this entity,
194 * we can't deliver here.
195 */
0a7de745 196 if (excp == NULL) {
39236c6e 197 return KERN_FAILURE;
0a7de745 198 }
39236c6e
A
199
200 assert(exception < EXC_TYPES_COUNT);
0a7de745 201 if (exception >= EXC_TYPES_COUNT) {
39236c6e 202 return KERN_FAILURE;
0a7de745 203 }
39236c6e
A
204
205 excp = &excp[exception];
206
1c79356b
A
207 /*
208 * Snapshot the exception action data under lock for consistency.
209 * Hold a reference to the port over the exception_raise_* calls
210 * so it can't be destroyed. This seems like overkill, but keeps
211 * the port from disappearing between now and when
212 * ipc_object_copyin_from_kernel is finally called.
213 */
b0d623f7 214 lck_mtx_lock(mutex);
1c79356b
A
215 exc_port = excp->port;
216 if (!IP_VALID(exc_port)) {
b0d623f7 217 lck_mtx_unlock(mutex);
2d21ac55 218 return KERN_FAILURE;
1c79356b
A
219 }
220 ip_lock(exc_port);
221 if (!ip_active(exc_port)) {
222 ip_unlock(exc_port);
b0d623f7 223 lck_mtx_unlock(mutex);
2d21ac55 224 return KERN_FAILURE;
1c79356b 225 }
0a7de745 226 ip_reference(exc_port);
1c79356b
A
227 exc_port->ip_srights++;
228 ip_unlock(exc_port);
229
230 flavor = excp->flavor;
231 behavior = excp->behavior;
b0d623f7 232 lck_mtx_unlock(mutex);
1c79356b 233
2d21ac55 234 code64 = (behavior & MACH_EXCEPTION_CODES);
cb323159 235 behavior &= ~MACH_EXCEPTION_MASK;
2d21ac55
A
236
237 if (!code64) {
b0d623f7
A
238 small_code[0] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[0]);
239 small_code[1] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[1]);
2d21ac55
A
240 }
241
39037602
A
242 task = thread->task;
243
244#if CONFIG_MACF
245 /* Now is a reasonably good time to check if the exception action is
246 * permitted for this process, because after this point we will send
247 * the message out almost certainly.
248 * As with other failures, exception_triage_thread will go on
249 * to the next level.
250 */
d9a64523
A
251
252 /* The global exception-to-signal translation port is safe to be an exception handler. */
253 if (is_ux_handler_port(exc_port) == FALSE &&
254 mac_exc_action_check_exception_send(task, excp) != 0) {
5ba3f43e
A
255 kr = KERN_FAILURE;
256 goto out_release_right;
39037602
A
257 }
258#endif
259
5ba3f43e 260 if (behavior != EXCEPTION_STATE) {
cb323159
A
261 task_reference(task);
262 task_port = convert_task_to_port(task);
263 /* task ref consumed */
264 thread_reference(thread);
265 thread_port = convert_thread_to_port(thread);
266 /* thread ref consumed */
39037602 267 }
2d21ac55 268
1c79356b
A
269 switch (behavior) {
270 case EXCEPTION_STATE: {
271 mach_msg_type_number_t state_cnt;
55e303ae 272 thread_state_data_t state;
1c79356b
A
273
274 c_thr_exc_raise_state++;
91447636 275 state_cnt = _MachineStateCount[flavor];
d9a64523 276 kr = thread_getstatus_to_user(thread, flavor,
0a7de745
A
277 (thread_state_t)state,
278 &state_cnt);
1c79356b 279 if (kr == KERN_SUCCESS) {
2d21ac55 280 if (code64) {
0a7de745
A
281 kr = mach_exception_raise_state(exc_port,
282 exception,
283 code,
284 codeCnt,
285 &flavor,
286 state, state_cnt,
287 state, &state_cnt);
2d21ac55
A
288 } else {
289 kr = exception_raise_state(exc_port, exception,
0a7de745
A
290 small_code,
291 codeCnt,
292 &flavor,
293 state, state_cnt,
294 state, &state_cnt);
2d21ac55 295 }
5ba3f43e 296 if (kr == KERN_SUCCESS) {
0a7de745 297 if (exception != EXC_CORPSE_NOTIFY) {
d9a64523 298 kr = thread_setstatus_from_user(thread, flavor,
0a7de745
A
299 (thread_state_t)state,
300 state_cnt);
301 }
5ba3f43e
A
302 goto out_release_right;
303 }
1c79356b
A
304 }
305
5ba3f43e 306 goto out_release_right;
1c79356b
A
307 }
308
309 case EXCEPTION_DEFAULT:
310 c_thr_exc_raise++;
2d21ac55
A
311 if (code64) {
312 kr = mach_exception_raise(exc_port,
0a7de745
A
313 thread_port,
314 task_port,
315 exception,
316 code,
317 codeCnt);
2d21ac55
A
318 } else {
319 kr = exception_raise(exc_port,
0a7de745
A
320 thread_port,
321 task_port,
322 exception,
323 small_code,
324 codeCnt);
2d21ac55 325 }
1c79356b 326
5ba3f43e 327 goto out_release_right;
1c79356b
A
328
329 case EXCEPTION_STATE_IDENTITY: {
330 mach_msg_type_number_t state_cnt;
55e303ae 331 thread_state_data_t state;
1c79356b
A
332
333 c_thr_exc_raise_state_id++;
91447636 334 state_cnt = _MachineStateCount[flavor];
d9a64523 335 kr = thread_getstatus_to_user(thread, flavor,
0a7de745
A
336 (thread_state_t)state,
337 &state_cnt);
1c79356b 338 if (kr == KERN_SUCCESS) {
2d21ac55
A
339 if (code64) {
340 kr = mach_exception_raise_state_identity(
0a7de745
A
341 exc_port,
342 thread_port,
343 task_port,
344 exception,
345 code,
346 codeCnt,
347 &flavor,
348 state, state_cnt,
349 state, &state_cnt);
2d21ac55
A
350 } else {
351 kr = exception_raise_state_identity(exc_port,
0a7de745
A
352 thread_port,
353 task_port,
354 exception,
355 small_code,
356 codeCnt,
357 &flavor,
358 state, state_cnt,
359 state, &state_cnt);
2d21ac55 360 }
5ba3f43e
A
361
362 if (kr == KERN_SUCCESS) {
0a7de745 363 if (exception != EXC_CORPSE_NOTIFY) {
d9a64523 364 kr = thread_setstatus_from_user(thread, flavor,
0a7de745
A
365 (thread_state_t)state,
366 state_cnt);
367 }
5ba3f43e
A
368 goto out_release_right;
369 }
1c79356b
A
370 }
371
5ba3f43e 372 goto out_release_right;
1c79356b 373 }
2d21ac55 374
1c79356b 375 default:
0a7de745
A
376 panic("bad exception behavior!");
377 return KERN_FAILURE;
1c79356b 378 }/* switch */
5ba3f43e
A
379
380out_release_right:
381
382 if (task_port) {
383 ipc_port_release_send(task_port);
384 }
385
386 if (thread_port) {
387 ipc_port_release_send(thread_port);
388 }
389
390 if (exc_port) {
391 ipc_port_release_send(exc_port);
392 }
393
394 return kr;
1c79356b
A
395}
396
fe8ab488 397/*
3e170ce0 398 * Routine: check_exc_receiver_dependency
fe8ab488
A
399 * Purpose:
400 * Verify that the port destined for receiving this exception is not
401 * on the current task. This would cause hang in kernel for
402 * EXC_CRASH primarily. Note: If port is transferred
403 * between check and delivery then deadlock may happen.
404 *
405 * Conditions:
406 * Nothing locked and no resources held.
407 * Called from an exception context.
408 * Returns:
409 * KERN_SUCCESS if its ok to send exception message.
410 */
411kern_return_t
3e170ce0 412check_exc_receiver_dependency(
fe8ab488
A
413 exception_type_t exception,
414 struct exception_action *excp,
415 lck_mtx_t *mutex)
416{
417 kern_return_t retval = KERN_SUCCESS;
418
0a7de745 419 if (excp == NULL || exception != EXC_CRASH) {
fe8ab488 420 return retval;
0a7de745 421 }
fe8ab488
A
422
423 task_t task = current_task();
424 lck_mtx_lock(mutex);
425 ipc_port_t xport = excp[exception].port;
0a7de745
A
426 if (IP_VALID(xport)
427 && ip_active(xport)
428 && task->itk_space == xport->ip_receiver) {
fe8ab488 429 retval = KERN_FAILURE;
0a7de745 430 }
fe8ab488
A
431 lck_mtx_unlock(mutex);
432 return retval;
433}
434
39037602 435
1c79356b 436/*
39037602 437 * Routine: exception_triage_thread
1c79356b 438 * Purpose:
39037602 439 * The thread caught an exception.
1c79356b
A
440 * We make an up-call to the thread's exception server.
441 * Conditions:
442 * Nothing locked and no resources held.
443 * Called from an exception context, so
444 * thread_exception_return and thread_kdb_return
445 * are possible.
446 * Returns:
3e170ce0 447 * KERN_SUCCESS if exception is handled by any of the handlers.
1c79356b 448 */
3e170ce0 449kern_return_t
39037602 450exception_triage_thread(
0a7de745
A
451 exception_type_t exception,
452 mach_exception_data_t code,
39037602 453 mach_msg_type_number_t codeCnt,
0a7de745 454 thread_t thread)
1c79356b 455{
0a7de745
A
456 task_t task;
457 host_priv_t host_priv;
458 lck_mtx_t *mutex;
459 kern_return_t kr = KERN_FAILURE;
1c79356b 460
f427ee49 461
1c79356b
A
462 assert(exception != EXC_RPC_ALERT);
463
3e170ce0
A
464 /*
465 * If this behavior has been requested by the the kernel
466 * (due to the boot environment), we should panic if we
467 * enter this function. This is intended as a debugging
468 * aid; it should allow us to debug why we caught an
469 * exception in environments where debugging is especially
470 * difficult.
471 */
472 if (panic_on_exception_triage) {
473 panic("called exception_triage when it was forbidden by the boot environment");
474 }
475
1c79356b
A
476 /*
477 * Try to raise the exception at the activation level.
478 */
b0d623f7 479 mutex = &thread->mutex;
0a7de745 480 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, thread->exc_actions, mutex)) {
fe8ab488 481 kr = exception_deliver(thread, exception, code, codeCnt, thread->exc_actions, mutex);
0a7de745 482 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
fe8ab488 483 goto out;
0a7de745 484 }
fe8ab488 485 }
1c79356b
A
486
487 /*
488 * Maybe the task level will handle it.
489 */
39037602
A
490 task = thread->task;
491 mutex = &task->itk_lock_data;
0a7de745 492 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, task->exc_actions, mutex)) {
fe8ab488 493 kr = exception_deliver(thread, exception, code, codeCnt, task->exc_actions, mutex);
0a7de745 494 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
fe8ab488 495 goto out;
0a7de745 496 }
fe8ab488 497 }
1c79356b
A
498
499 /*
500 * How about at the host level?
501 */
502 host_priv = host_priv_self();
b0d623f7 503 mutex = &host_priv->lock;
5ba3f43e 504
0a7de745 505 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, host_priv->exc_actions, mutex)) {
fe8ab488 506 kr = exception_deliver(thread, exception, code, codeCnt, host_priv->exc_actions, mutex);
0a7de745 507 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
fe8ab488 508 goto out;
0a7de745 509 }
fe8ab488 510 }
1c79356b 511
2d21ac55 512out:
39236c6e 513 if ((exception != EXC_CRASH) && (exception != EXC_RESOURCE) &&
0a7de745 514 (exception != EXC_GUARD) && (exception != EXC_CORPSE_NOTIFY)) {
2d21ac55 515 thread_exception_return();
0a7de745 516 }
3e170ce0 517 return kr;
1c79356b 518}
9bccf70c 519
39037602
A
520/*
521 * Routine: exception_triage
522 * Purpose:
523 * The current thread caught an exception.
524 * We make an up-call to the thread's exception server.
525 * Conditions:
526 * Nothing locked and no resources held.
527 * Called from an exception context, so
528 * thread_exception_return and thread_kdb_return
529 * are possible.
530 * Returns:
531 * KERN_SUCCESS if exception is handled by any of the handlers.
532 */
f427ee49 533int debug4k_panic_on_exception = 0;
39037602
A
534kern_return_t
535exception_triage(
0a7de745
A
536 exception_type_t exception,
537 mach_exception_data_t code,
39037602
A
538 mach_msg_type_number_t codeCnt)
539{
540 thread_t thread = current_thread();
f427ee49
A
541 if (VM_MAP_PAGE_SIZE(thread->task->map) < PAGE_SIZE) {
542 DEBUG4K_EXC("thread %p task %p map %p exception %d codes 0x%llx 0x%llx \n", thread, thread->task, thread->task->map, exception, code[0], code[1]);
543 if (debug4k_panic_on_exception) {
544 panic("DEBUG4K %s:%d thread %p task %p map %p exception %d codes 0x%llx 0x%llx \n", __FUNCTION__, __LINE__, thread, thread->task, thread->task->map, exception, code[0], code[1]);
545 }
546 }
eb6b6ca3
A
547#if __has_feature(ptrauth_calls)
548 /*
549 * If it is a ptrauth violation, then check if the task has the TF_PAC_EXC_FATAL
550 * flag set and isn't being ptraced. If so, terminate the task via exit_with_reason
551 */
552 if (exception & EXC_PTRAUTH_BIT) {
553 exception &= ~EXC_PTRAUTH_BIT;
554
555 boolean_t traced_flag = FALSE;
556 task_t task = thread->task;
557 void *proc = task->bsd_info;
558
559 if (task->bsd_info) {
560 traced_flag = proc_is_traced(proc);
561 }
562
563 if (task_is_pac_exception_fatal(current_task()) && !traced_flag) {
564 exit_with_pac_exception(proc, exception, code[0], code[1]);
565 thread_exception_return();
566 /* NOT_REACHABLE */
567 }
568 }
569#endif /* __has_feature(ptrauth_calls) */
39037602
A
570 return exception_triage_thread(exception, code, codeCnt, thread);
571}
572
9bccf70c
A
573kern_return_t
574bsd_exception(
0a7de745
A
575 exception_type_t exception,
576 mach_exception_data_t code,
9bccf70c
A
577 mach_msg_type_number_t codeCnt)
578{
0a7de745
A
579 task_t task;
580 lck_mtx_t *mutex;
581 thread_t self = current_thread();
582 kern_return_t kr;
9bccf70c
A
583
584 /*
585 * Maybe the task level will handle it.
586 */
587 task = current_task();
39037602 588 mutex = &task->itk_lock_data;
9bccf70c 589
39236c6e 590 kr = exception_deliver(self, exception, code, codeCnt, task->exc_actions, mutex);
9bccf70c 591
0a7de745
A
592 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
593 return KERN_SUCCESS;
594 }
595 return KERN_FAILURE;
2d21ac55 596}
9bccf70c 597
9bccf70c 598
2d21ac55 599/*
316670eb 600 * Raise an exception on a task.
2d21ac55
A
601 * This should tell launchd to launch Crash Reporter for this task.
602 */
0a7de745
A
603kern_return_t
604task_exception_notify(exception_type_t exception,
605 mach_exception_data_type_t exccode, mach_exception_data_type_t excsubcode)
2d21ac55 606{
0a7de745
A
607 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
608 wait_interrupt_t wsave;
3e170ce0 609 kern_return_t kr = KERN_SUCCESS;
9bccf70c 610
2d21ac55
A
611 code[0] = exccode;
612 code[1] = excsubcode;
9bccf70c 613
2d21ac55 614 wsave = thread_interrupt_level(THREAD_UNINT);
3e170ce0 615 kr = exception_triage(exception, code, EXCEPTION_CODE_MAX);
2d21ac55 616 (void) thread_interrupt_level(wsave);
3e170ce0 617 return kr;
9bccf70c
A
618}
619
55e303ae 620
55e303ae 621/*
2d21ac55 622 * Handle interface for special performance monitoring
55e303ae
A
623 * This is a special case of the host exception handler
624 */
0a7de745
A
625kern_return_t
626sys_perf_notify(thread_t thread, int pid)
55e303ae 627{
0a7de745
A
628 host_priv_t hostp;
629 ipc_port_t xport;
630 wait_interrupt_t wsave;
631 kern_return_t ret;
55e303ae 632
0a7de745
A
633 hostp = host_priv_self(); /* Get the host privileged ports */
634 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
635 code[0] = 0xFF000001; /* Set terminate code */
636 code[1] = pid; /* Pass out the pid */
55e303ae 637
2d21ac55 638 struct task *task = thread->task;
0a7de745 639 xport = hostp->exc_actions[EXC_RPC_ALERT].port;
55e303ae 640
2d21ac55
A
641 /* Make sure we're not catching our own exception */
642 if (!IP_VALID(xport) ||
0a7de745
A
643 !ip_active(xport) ||
644 task->itk_space == xport->data.receiver) {
645 return KERN_FAILURE;
55e303ae 646 }
2d21ac55 647
0a7de745 648 wsave = thread_interrupt_level(THREAD_UNINT);
2d21ac55 649 ret = exception_deliver(
0a7de745
A
650 thread,
651 EXC_RPC_ALERT,
652 code,
653 2,
654 hostp->exc_actions,
655 &hostp->lock);
2d21ac55
A
656 (void)thread_interrupt_level(wsave);
657
0a7de745 658 return ret;
55e303ae 659}