1 /*
2 * Copyright 1991-1998 by Open Software Foundation, Inc.
3 * All Rights Reserved
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both the copyright notice and this permission notice appear in
9 * supporting documentation.
10 *
11 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
12 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
16 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
18 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
19 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21 /*
22 * MkLinux
23 */
24 /* CMU_HIST */
25 /*
26 * Revision 2.12 91/06/25 10:28:49 rpd
27 * Changed the convert_foo_to_bar functions
28 * to use ipc_port_t instead of mach_port_t.
29 * [91/05/27 rpd]
30 *
31 * Revision 2.11 91/06/17 15:47:09 jsb
32 * Renamed NORMA conditionals. Moved norma code to norma/kern_task.c.
33 * [91/06/17 10:50:57 jsb]
34 *
35 * Revision 2.10 91/06/06 17:07:15 jsb
36 * NORMA_TASK support.
37 * [91/05/14 09:17:09 jsb]
38 *
39 * Revision 2.9 91/05/14 16:42:54 mrt
40 * Correcting copyright
41 *
42 * Revision 2.8 91/03/16 14:50:24 rpd
43 * Removed ith_saved.
44 * [91/02/16 rpd]
45 *
46 * Revision 2.7 91/02/05 17:27:08 mrt
47 * Changed to new Mach copyright
48 * [91/02/01 16:13:42 mrt]
49 *
50 * Revision 2.6 91/01/08 15:16:05 rpd
51 * Added retrieve_task_self_fast, retrieve_thread_self_fast.
52 * [90/12/27 rpd]
53 *
54 * Revision 2.5 90/11/05 14:31:08 rpd
55 * Changed ip_reference to ipc_port_reference.
56 * Use new ip_reference and ip_release.
57 * [90/10/29 rpd]
58 *
59 * Revision 2.4 90/06/02 14:54:33 rpd
60 * Converted to new IPC.
61 * [90/03/26 22:05:07 rpd]
62 *
63 *
64 * Condensed history:
65 * Modified for pure kernel (dbg).
66 * Support thread_exception_abort (dlb).
67 * Added kernel monitor support (tfl).
68 * Added task/thread kernel port interposing (rpd).
69 * Improvements/fixes for task_secure (rpd).
70 * New translation cache (rpd).
71 * Move old stuff under MACH_IPC_XXXHACK (rpd).
72 * Created from mach_ipc.c (rpd).
73 */
74 /* CMU_ENDHIST */
75 /*
76 * Mach Operating System
77 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
78 * All Rights Reserved.
79 *
80 * Permission to use, copy, modify and distribute this software and its
81 * documentation is hereby granted, provided that both the copyright
82 * notice and this permission notice appear in all copies of the
83 * software, derivative works or modified versions, and any portions
84 * thereof, and that both notices appear in supporting documentation.
85 *
86 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
87 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
88 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
89 *
90 * Carnegie Mellon requests users of this software to return to
91 *
92 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
93 * School of Computer Science
94 * Carnegie Mellon University
95 * Pittsburgh PA 15213-3890
96 *
97 * any improvements or extensions that they make and grant Carnegie Mellon
98 * the rights to redistribute these changes.
99 */
100 /*
101 */
102
103 /*
104 * File: ipc_tt.c
105 * Purpose:
106 * Task and thread related IPC functions.
107 */
108
109 #include <sys/cdefs.h>
110 #include <sys/types.h>
111 #include <sys/syslog.h>
112 #include <sys/mach/mach_types.h>
113 #include <sys/mach/kern_return.h>
114 #include <sys/mach/mach_param.h>
115 #include <sys/mach/task_special_ports.h>
116 #include <sys/mach/thread_special_ports.h>
117 #include <sys/mach/thread_status.h>
118 #include <sys/mach/exception.h>
119 #if 0
120 #include <sys/mach/mach_traps.h>
121 #include <sys/mach/mach_server.h>
122 #endif
123 #include <sys/mach/mach_host_server.h>
124 #include <sys/mach/ipc_tt.h>
125 #if 0
126 #include <kern/thread_act.h>
127 #include <kern/misc_protos.h>
128 #endif
129 #include <sys/mach/host_special_ports.h>
130 #include <sys/mach/host.h>
131 #include <sys/mach/thread.h>
132 #include <sys/mach/mach_init.h>
133 #include <sys/mach/task_server.h>
134 #include <sys/mach/host_priv_server.h>
135
136 #define THR_ACT_NULL NULL
137
138
139
140 /*
141 * Routine: ipc_task_init
142 * Purpose:
143 * Initialize a task's IPC state.
144 *
145 * If non-null, some state will be inherited from the parent.
146 * The parent must be appropriately initialized.
147 * Conditions:
148 * Nothing locked.
149 */
150
151 void
ipc_task_create(task_t task)152 ipc_task_create(
153 task_t task)
154 {
155 ipc_space_t space;
156 kern_return_t kr;
157 ipc_port_t kport;
158
159 kr = ipc_space_create(&ipc_table_entries[0], &space);
160 if (kr != KERN_SUCCESS)
161 panic("ipc_task_init");
162
163 kport = ipc_port_alloc_kernel();
164 if (kport == IP_NULL)
165 panic("ipc_task_init");
166
167 task->itk_self = kport;
168 task->itk_sself = ipc_port_make_send(kport);
169 task->itk_space = space;
170 space->is_task = task;
171 }
172
173 void
ipc_task_init(task_t task,task_t parent)174 ipc_task_init(
175 task_t task,
176 task_t parent)
177 {
178 int i;
179
180 if (parent == TASK_NULL) {
181 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
182 task->exc_actions[i].port = IP_NULL;
183 }/* for */
184 task->exc_actions[EXC_MACH_SYSCALL].port =
185 ipc_port_make_send(realhost.host_self);
186 task->itk_bootstrap = IP_NULL;
187 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
188 task->itk_registered[i] = IP_NULL;
189 } else {
190 itk_lock(parent);
191 assert(parent->itk_self != IP_NULL);
192
193 /* inherit registered ports */
194
195 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
196 task->itk_registered[i] =
197 ipc_port_copy_send(parent->itk_registered[i]);
198
199 /* inherit exception and bootstrap ports */
200
201 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
202 task->exc_actions[i].port =
203 ipc_port_copy_send(parent->exc_actions[i].port);
204 task->exc_actions[i].flavor =
205 parent->exc_actions[i].flavor;
206 task->exc_actions[i].behavior =
207 parent->exc_actions[i].behavior;
208 }/* for */
209 task->itk_bootstrap =
210 ipc_port_copy_send(parent->itk_bootstrap);
211
212 itk_unlock(parent);
213 }
214 }
215
216 /*
217 * Routine: ipc_task_enable
218 * Purpose:
219 * Enable a task for IPC access.
220 * Conditions:
221 * Nothing locked.
222 */
223
224 void
ipc_task_enable(task_t task)225 ipc_task_enable(
226 task_t task)
227 {
228 ipc_port_t kport;
229
230 itk_lock(task);
231 kport = task->itk_self;
232 if (kport != IP_NULL)
233 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
234 itk_unlock(task);
235 }
236
237 /*
238 * Routine: ipc_task_disable
239 * Purpose:
240 * Disable IPC access to a task.
241 * Conditions:
242 * Nothing locked.
243 */
244
245 void
ipc_task_disable(task_t task)246 ipc_task_disable(
247 task_t task)
248 {
249 ipc_port_t kport;
250
251 itk_lock(task);
252 kport = task->itk_self;
253 if (kport != IP_NULL)
254 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
255 itk_unlock(task);
256 }
257
258 /*
259 * Routine: ipc_task_terminate
260 * Purpose:
261 * Clean up and destroy a task's IPC state.
262 * Conditions:
263 * Nothing locked. The task must be suspended.
264 * (Or the current thread must be in the task.)
265 */
266
267 void
ipc_task_terminate(task_t task)268 ipc_task_terminate(
269 task_t task)
270 {
271 ipc_port_t kport;
272 int i;
273
274 itk_lock(task);
275 kport = task->itk_self;
276
277 if (kport == IP_NULL) {
278 /* the task is already terminated (can this happen?) */
279 itk_unlock(task);
280 return;
281 }
282
283 task->itk_self = IP_NULL;
284 itk_unlock(task);
285
286 /* release the naked send rights */
287
288 if (IP_VALID(task->itk_sself))
289 ipc_port_release_send(task->itk_sself);
290
291 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
292 if (IP_VALID(task->exc_actions[i].port)) {
293 ipc_port_release_send(task->exc_actions[i].port);
294 }
295 }/* for */
296 if (IP_VALID(task->itk_bootstrap))
297 ipc_port_release_send(task->itk_bootstrap);
298
299 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
300 if (IP_VALID(task->itk_registered[i]))
301 ipc_port_release_send(task->itk_registered[i]);
302
303 /* destroy the space, leaving just a reference for it */
304
305 if (!task->kernel_loaded)
306 ipc_space_destroy(task->itk_space);
307
308 /* destroy the kernel port */
309
310 ipc_port_dealloc_kernel(kport);
311 }
312
313 /*
314 * Routine: ipc_thread_init
315 * Purpose:
316 * Initialize a thread's IPC state.
317 * Conditions:
318 * Nothing locked.
319 */
320
321 void
ipc_thread_init(thread_t thread)322 ipc_thread_init(
323 thread_t thread)
324 {
325 ipc_thread_links_init(thread);
326 ipc_kmsg_queue_init(&thread->ith_messages);
327 thread->ith_mig_reply = MACH_PORT_NULL;
328 thread->ith_rpc_reply = IP_NULL;
329 }
330
331 /*
332 * Routine: ipc_thread_terminate
333 * Purpose:
334 * Clean up and destroy a thread's IPC state.
335 * Conditions:
336 * Nothing locked. The thread must be suspended.
337 * (Or be the current thread.)
338 */
339
340 void
ipc_thread_terminate(thread_t thread)341 ipc_thread_terminate(
342 thread_t thread)
343 {
344 assert(ipc_kmsg_queue_empty(&thread->ith_messages));
345
346 if (thread->ith_rpc_reply != IP_NULL)
347 ipc_port_dealloc_reply(thread->ith_rpc_reply);
348 thread->ith_rpc_reply = IP_NULL;
349 }
350
351 /*
352 * Routine: ipc_thr_act_init
353 * Purpose:
354 * Initialize an thr_act's IPC state.
355 * Conditions:
356 * Nothing locked.
357 */
358
359 void
ipc_thr_act_init(thread_act_t thr_act)360 ipc_thr_act_init(thread_act_t thr_act)
361 {
362 ipc_port_t kport; int i;
363
364 kport = ipc_port_alloc_kernel();
365 if (kport == IP_NULL)
366 panic("ipc_thr_act_init");
367
368 thr_act->ith_self = kport;
369 thr_act->ith_sself = ipc_port_make_send(kport);
370
371 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
372 thr_act->exc_actions[i].port = IP_NULL;
373
374 thr_act->exc_actions[EXC_MACH_SYSCALL].port =
375 ipc_port_make_send(realhost.host_self);
376
377 ipc_kobject_set(kport, (ipc_kobject_t) thr_act, IKOT_ACT);
378 }
379
380 #if 0
381
382 void
383 ipc_thr_act_disable(thread_act_t thr_act)
384 {
385 int i;
386 ipc_port_t kport;
387
388 act_lock(thr_act);
389 kport = thr_act->ith_self;
390
391 if (kport != IP_NULL)
392 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
393 act_unlock(thr_act);
394 }
395
396
397 void
398 ipc_thr_act_disable_act_locked(thread_act_t thr_act)
399 {
400 int i;
401 ipc_port_t kport;
402
403 kport = thr_act->ith_self;
404
405 if (kport != IP_NULL)
406 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
407 }
408 #endif
409
410 void
ipc_thr_act_terminate(thread_act_t thr_act)411 ipc_thr_act_terminate(thread_act_t thr_act)
412 {
413 ipc_port_t kport; int i;
414
415 act_lock(thr_act);
416 kport = thr_act->ith_self;
417
418 if (kport == IP_NULL) {
419 /* the thread is already terminated (can this happen?) */
420 act_unlock(thr_act);
421 return;
422 }
423
424 thr_act->ith_self = IP_NULL;
425 act_unlock(thr_act);
426
427 /* release the naked send rights */
428
429 if (IP_VALID(thr_act->ith_sself))
430 ipc_port_release_send(thr_act->ith_sself);
431 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
432 if (IP_VALID(thr_act->exc_actions[i].port))
433 ipc_port_release_send(thr_act->exc_actions[i].port);
434 }
435
436 /* destroy the kernel port */
437 ipc_port_dealloc_kernel(kport);
438 }
439
440
441 /*
442 * Routine: retrieve_task_self_fast
443 * Purpose:
444 * Optimized version of retrieve_task_self,
445 * that only works for the current task.
446 *
447 * Return a send right (possibly null/dead)
448 * for the task's user-visible self port.
449 * Conditions:
450 * Nothing locked.
451 */
452
453 ipc_port_t
retrieve_task_self_fast(register task_t task)454 retrieve_task_self_fast(
455 register task_t task)
456 {
457 register ipc_port_t port;
458
459 assert(task == current_task());
460
461 itk_lock(task);
462 assert(task->itk_self != IP_NULL);
463
464 if ((port = task->itk_sself) == task->itk_self) {
465 /* no interposing */
466 itk_unlock(task);
467 ip_lock(port);
468 assert(ip_active(port));
469 ip_reference(port);
470 port->ip_srights++;
471 ip_unlock(port);
472 } else {
473 itk_unlock(task);
474 port = ipc_port_copy_send(port);
475 }
476
477 return (port);
478 }
479
480 /*
481 * Routine: retrieve_act_self_fast
482 * Purpose:
483 * Optimized version of retrieve_thread_self,
484 * that only works for the current thread.
485 *
486 * Return a send right (possibly null/dead)
487 * for the thread's user-visible self port.
488 * Conditions:
489 * Nothing locked.
490 */
491
492 ipc_port_t
retrieve_thread_self_fast(thread_t thr_act)493 retrieve_thread_self_fast(thread_t thr_act)
494 {
495 register ipc_port_t port;
496
497 assert(thr_act == current_act());
498 act_lock(thr_act);
499 assert(thr_act->ith_self != IP_NULL);
500
501 if ((port = thr_act->ith_sself) == thr_act->ith_self) {
502 /* no interposing */
503
504 ip_lock(port);
505 assert(ip_active(port));
506 ip_reference(port);
507 port->ip_srights++;
508 ip_unlock(port);
509 } else
510 port = ipc_port_copy_send(port);
511 act_unlock(thr_act);
512
513 return port;
514 }
515
516 /*
517 * Routine: mach_task_self [mach trap]
518 * Purpose:
519 * Give the caller send rights for his own task port.
520 * Conditions:
521 * Nothing locked.
522 * Returns:
523 * MACH_PORT_NULL if there are any resource failures
524 * or other errors.
525 */
526
527 mach_port_name_t
mach_task_self(void)528 mach_task_self(void)
529 {
530 task_t task = current_task();
531 ipc_space_t space = current_space();
532 ipc_port_t sright;
533
534 sright = retrieve_task_self_fast(task);
535 return ipc_port_copyout_send(sright, space);
536 }
537
538 /*
539 * Routine: mach_thread_self [mach trap]
540 * Purpose:
541 * Give the caller send rights for his own thread port.
542 * Conditions:
543 * Nothing locked.
544 * Returns:
545 * MACH_PORT_NULL if there are any resource failures
546 * or other errors.
547 */
548
549 mach_port_name_t
mach_thread_self(void)550 mach_thread_self(void)
551 {
552 thread_t thr_act = current_thread();
553 ipc_space_t space = current_space();
554 ipc_port_t sright;
555
556 sright = retrieve_thread_self_fast(thr_act);
557 return ipc_port_copyout_send(sright, space);
558 }
559
560 /*
561 * Routine: mach_reply_port [mach trap]
562 * Purpose:
563 * Allocate a port for the caller.
564 * Conditions:
565 * Nothing locked.
566 * Returns:
567 * MACH_PORT_NULL if there are any resource failures
568 * or other errors.
569 */
570
571 mach_port_name_t
mach_reply_port(void)572 mach_reply_port(void)
573 {
574 ipc_port_t port;
575 mach_port_name_t name;
576 kern_return_t kr;
577
578 kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
579 if (kr == KERN_SUCCESS)
580 ip_unlock(port);
581 else
582 name = MACH_PORT_NAME_NULL;
583
584 return name;
585 }
586
587 /*
588 * Routine: task_get_special_port [kernel call]
589 * Purpose:
590 * Clones a send right for one of the task's
591 * special ports.
592 * Conditions:
593 * Nothing locked.
594 * Returns:
595 * KERN_SUCCESS Extracted a send right.
596 * KERN_INVALID_ARGUMENT The task is null.
597 * KERN_FAILURE The task/space is dead.
598 * KERN_INVALID_ARGUMENT Invalid special port.
599 */
600
601 kern_return_t
task_get_special_port(task_t task,int which,ipc_port_t * portp)602 task_get_special_port(
603 task_t task,
604 int which,
605 ipc_port_t *portp)
606 {
607 ipc_port_t port;
608
609 if (task == TASK_NULL)
610 return KERN_INVALID_ARGUMENT;
611
612 switch (which) {
613 case TASK_KERNEL_PORT:
614 port = ipc_port_copy_send(task->itk_sself);
615 break;
616
617 case TASK_NAME_PORT:
618 port = ipc_port_make_send(task->itk_nself);
619 break;
620
621 case TASK_HOST_PORT:
622 port = ipc_port_copy_send(task->itk_host);
623 break;
624
625 case TASK_BOOTSTRAP_PORT:
626 port = ipc_port_copy_send(task->itk_bootstrap);
627 break;
628
629 case TASK_SEATBELT_PORT:
630 port = ipc_port_copy_send(task->itk_seatbelt);
631 break;
632
633 case TASK_ACCESS_PORT:
634 port = ipc_port_copy_send(task->itk_task_access);
635 break;
636
637 case TASK_DEBUG_CONTROL_PORT:
638 port = ipc_port_copy_send(task->itk_debug_control);
639 break;
640 default:
641 return KERN_INVALID_ARGUMENT;
642 }
643
644 *portp = port;
645 return KERN_SUCCESS;
646 }
647
648 /*
649 * Routine: task_set_special_port [kernel call]
650 * Purpose:
651 * Changes one of the task's special ports,
652 * setting it to the supplied send right.
653 * Conditions:
654 * Nothing locked. If successful, consumes
655 * the supplied send right.
656 * Returns:
657 * KERN_SUCCESS Changed the special port.
658 * KERN_INVALID_ARGUMENT The task is null.
659 * KERN_FAILURE The task/space is dead.
660 * KERN_INVALID_ARGUMENT Invalid special port.
661 */
662
663 kern_return_t
task_set_special_port(task_t task,int which,ipc_port_t port)664 task_set_special_port(
665 task_t task,
666 int which,
667 ipc_port_t port)
668 {
669 ipc_port_t *whichp;
670 ipc_port_t old;
671
672 #if VERBOSE_DEBUGGING
673 printf("task_set_special_port(task=%p, which=%d, port=%p)\n",task, which, port);
674 #endif
675 /* we only support the current task */
676 if (task == TASK_NULL)
677 return KERN_INVALID_ARGUMENT;
678
679 switch (which) {
680 case TASK_KERNEL_PORT:
681 whichp = &task->itk_sself;
682 break;
683 case TASK_HOST_PORT:
684 whichp = &task->itk_host;
685 break;
686 case TASK_BOOTSTRAP_PORT:
687 whichp = &task->itk_bootstrap;
688 break;
689 case TASK_SEATBELT_PORT:
690 whichp = &task->itk_seatbelt;
691 break;
692 case TASK_ACCESS_PORT:
693 whichp = &task->itk_task_access;
694 break;
695 case TASK_DEBUG_CONTROL_PORT:
696 whichp = &task->itk_debug_control;
697 break;
698 default:
699 return KERN_INVALID_ARGUMENT;
700 }/* switch */
701
702 if ((TASK_SEATBELT_PORT == which || TASK_ACCESS_PORT == which)
703 && IP_VALID(*whichp)) {
704 itk_unlock(task);
705 return KERN_NO_ACCESS;
706 }
707 itk_lock(task);
708 if (task->itk_self == IP_NULL) {
709 itk_unlock(task);
710 return KERN_FAILURE;
711 }
712
713 old = *whichp;
714 *whichp = port;
715 itk_unlock(task);
716
717 if (IP_VALID(old))
718 ipc_port_release_send(old);
719 return KERN_SUCCESS;
720 }
721
722
723 /*
724 * Routine: mach_ports_register [kernel call]
725 * Purpose:
726 * Stash a handful of port send rights in the task.
727 * Child tasks will inherit these rights, but they
728 * must use mach_ports_lookup to acquire them.
729 *
730 * The rights are supplied in a (wired) kalloc'd segment.
731 * Rights which aren't supplied are assumed to be null.
732 * Conditions:
733 * Nothing locked. If successful, consumes
734 * the supplied rights and memory.
735 * Returns:
736 * KERN_SUCCESS Stashed the port rights.
737 * KERN_INVALID_ARGUMENT The task is null.
738 * KERN_INVALID_ARGUMENT The task is dead.
739 * KERN_INVALID_ARGUMENT Too many port rights supplied.
740 */
741
742 kern_return_t
mach_ports_register(task_t task,mach_port_array_t memory,mach_msg_type_number_t portsCnt)743 mach_ports_register(
744 task_t task,
745 mach_port_array_t memory,
746 mach_msg_type_number_t portsCnt)
747 {
748 ipc_port_t ports[TASK_PORT_REGISTER_MAX];
749 int i;
750
751 if ((task == TASK_NULL) ||
752 (portsCnt > TASK_PORT_REGISTER_MAX))
753 return KERN_INVALID_ARGUMENT;
754
755 /*
756 * Pad the port rights with nulls.
757 */
758
759 for (i = 0; i < portsCnt; i++)
760 ports[i] = (ipc_port_t) memory[i];
761 for (; i < TASK_PORT_REGISTER_MAX; i++)
762 ports[i] = IP_NULL;
763
764 itk_lock(task);
765 if (task->itk_self == IP_NULL) {
766 itk_unlock(task);
767 return KERN_INVALID_ARGUMENT;
768 }
769
770 /*
771 * Replace the old send rights with the new.
772 * Release the old rights after unlocking.
773 */
774
775 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
776 ipc_port_t old;
777
778 old = task->itk_registered[i];
779 task->itk_registered[i] = ports[i];
780 ports[i] = old;
781 }
782
783 itk_unlock(task);
784
785 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
786 if (IP_VALID(ports[i]))
787 ipc_port_release_send(ports[i]);
788
789 /*
790 * Now that the operation is known to be successful,
791 * we can free the memory.
792 */
793
794 if (portsCnt != 0)
795 kfree((vm_offset_t) memory,
796 (vm_size_t) (portsCnt * sizeof(mach_port_t)));
797
798 return KERN_SUCCESS;
799 }
800
801 /*
802 * Routine: mach_ports_lookup [kernel call]
803 * Purpose:
804 * Retrieves (clones) the stashed port send rights.
805 * Conditions:
806 * Nothing locked. If successful, the caller gets
807 * rights and memory.
808 * Returns:
809 * KERN_SUCCESS Retrieved the send rights.
810 * KERN_INVALID_ARGUMENT The task is null.
811 * KERN_INVALID_ARGUMENT The task is dead.
812 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
813 */
814
815 kern_return_t
mach_ports_lookup(task_t task,mach_port_array_t * portsp,mach_msg_type_number_t * portsCnt)816 mach_ports_lookup(
817 task_t task,
818 mach_port_array_t *portsp,
819 mach_msg_type_number_t *portsCnt)
820 {
821 vm_offset_t memory;
822 vm_size_t size;
823 ipc_port_t *ports;
824 int i;
825
826 if (task == TASK_NULL)
827 return KERN_INVALID_ARGUMENT;
828
829 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
830
831 memory = KALLOC(size, rt);
832 if (memory == 0)
833 return KERN_RESOURCE_SHORTAGE;
834
835 itk_lock(task);
836 if (task->itk_self == IP_NULL) {
837 itk_unlock(task);
838
839 KFREE(memory, size, rt);
840 return KERN_INVALID_ARGUMENT;
841 }
842
843 ports = (ipc_port_t *) memory;
844
845 /*
846 * Clone port rights. Because kalloc'd memory
847 * is wired, we won't fault while holding the task lock.
848 */
849
850 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
851 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
852
853 itk_unlock(task);
854
855 *portsp = (mach_port_array_t) ports;
856 *portsCnt = TASK_PORT_REGISTER_MAX;
857 return KERN_SUCCESS;
858 }
859
860 /*
861 * Routine: convert_port_to_task
862 * Purpose:
863 * Convert from a port to a task.
864 * Doesn't consume the port ref; produces a task ref,
865 * which may be null.
866 * Conditions:
867 * Nothing locked.
868 */
869
870 task_t
convert_port_to_task(ipc_port_t port)871 convert_port_to_task(
872 ipc_port_t port)
873 {
874 boolean_t r;
875 task_t task = TASK_NULL;
876
877 /* currently only handle current task */
878 return (current_task());
879
880 r = FALSE;
881 while (!r && IP_VALID(port)) {
882 ip_lock(port);
883 r = ref_task_port_locked(port, &task);
884 /* port unlocked */
885 }
886
887 return task;
888 }
889
890 boolean_t
ref_task_port_locked(ipc_port_t port,task_t * ptask)891 ref_task_port_locked( ipc_port_t port, task_t *ptask )
892 {
893 task_t task;
894
895 task = TASK_NULL;
896 if (ip_active(port) &&
897 (ip_kotype(port) == IKOT_TASK)) {
898 task = (task_t) port->ip_kobject;
899 assert(task != TASK_NULL);
900
901 /*
902 * Normal lock ordering puts task_lock() before ip_lock().
903 * Allow out-of-order locking here, inlining
904 * task_reference() to accomodate it.
905 */
906 if (!task_lock_try(task)) {
907 ip_unlock(port);
908 return (FALSE);
909 }
910 task->ref_count++;
911 task_unlock(task);
912 }
913 *ptask = task;
914 ip_unlock(port);
915 return (TRUE);
916 }
917
918 /*
919 * Routine: convert_port_to_space
920 * Purpose:
921 * Convert from a port to a space.
922 * Doesn't consume the port ref; produces a space ref,
923 * which may be null.
924 * Conditions:
925 * Nothing locked.
926 */
927
928 ipc_space_t
convert_port_to_space(ipc_port_t port)929 convert_port_to_space(
930 ipc_port_t port)
931 {
932 boolean_t r;
933 ipc_space_t space = IS_NULL;
934
935 r = FALSE;
936 while (!r && IP_VALID(port)) {
937 ip_lock(port);
938 r = ref_space_port_locked(port, &space);
939 /* port unlocked */
940 }
941 return space;
942 }
943
944 boolean_t
ref_space_port_locked(ipc_port_t port,ipc_space_t * pspace)945 ref_space_port_locked( ipc_port_t port, ipc_space_t *pspace )
946 {
947 ipc_space_t space;
948
949 space = IS_NULL;
950 if (ip_active(port) &&
951 (ip_kotype(port) == IKOT_TASK)) {
952 space = ((task_t) port->ip_kobject)->itk_space;
953
954 /*
955 * Normal lock ordering puts ipc_space lock before
956 * ip_lock(). Allow out-of-order locking here, inlining
957 * is_reference() to accomodate it.
958 */
959 if (!mtx_trylock(&space->is_ref_lock_data)) {
960 ip_unlock(port);
961 return (FALSE);
962 }
963 space->is_references++;
964 mtx_unlock(&space->is_ref_lock_data);
965 }
966 *pspace = space;
967 ip_unlock(port);
968 return (TRUE);
969 }
970
971 /*
972 * Routine: convert_port_to_map
973 * Purpose:
974 * Convert from a port to a map.
975 * Doesn't consume the port ref; produces a map ref,
976 * which may be null.
977 * Conditions:
978 * Nothing locked.
979 */
980
981 vm_map_t
convert_port_to_map(ipc_port_t port)982 convert_port_to_map(
983 ipc_port_t port)
984 {
985 task_t task;
986 vm_map_t map;
987
988 task = convert_port_to_task(port);
989
990 if (task == TASK_NULL)
991 return VM_MAP_NULL;
992
993 map = &task->itk_p->p_vmspace->vm_map;
994 task_deallocate(task);
995 return (map);
996 }
997
998 static boolean_t
ref_act_port_locked(ipc_port_t port,thread_act_t * pthr_act)999 ref_act_port_locked( ipc_port_t port, thread_act_t *pthr_act )
1000 {
1001 thread_act_t thr_act;
1002
1003 thr_act = 0;
1004 if (ip_active(port) &&
1005 (ip_kotype(port) == IKOT_ACT)) {
1006 thr_act = (thread_act_t) port->ip_kobject;
1007 assert(thr_act != THR_ACT_NULL);
1008
1009 /*
1010 * Normal lock ordering is act_lock(), then ip_lock().
1011 * Allow out-of-order locking here, using
1012 * act_reference_act_locked() to accomodate it.
1013 */
1014 if (!act_lock_try(thr_act)) {
1015 ip_unlock(port);
1016 return (FALSE);
1017 }
1018 act_locked_act_reference(thr_act);
1019 act_unlock(thr_act);
1020 }
1021 *pthr_act = thr_act;
1022 ip_unlock(port);
1023 return (TRUE);
1024 }
1025
1026 /*
1027 * Routine: convert_port_to_act
1028 * Purpose:
1029 * Convert from a port to a thr_act.
1030 * Doesn't consume the port ref; produces an thr_act ref,
1031 * which may be null.
1032 * Conditions:
1033 * Nothing locked.
1034 */
1035
1036 thread_act_t
convert_port_to_thread(ipc_port_t port)1037 convert_port_to_thread( ipc_port_t port )
1038 {
1039 boolean_t r;
1040 thread_act_t thr_act = 0;
1041
1042 r = FALSE;
1043 while (!r && IP_VALID(port)) {
1044 ip_lock(port);
1045 r = ref_act_port_locked(port, &thr_act);
1046 /* port unlocked */
1047 }
1048 return (thr_act);
1049 }
1050
1051 /*
1052 * Routine: convert_task_to_port
1053 * Purpose:
1054 * Convert from a task to a port.
1055 * Consumes a task ref; produces a naked send right
1056 * which may be invalid.
1057 * Conditions:
1058 * Nothing locked.
1059 */
1060
1061 ipc_port_t
convert_task_to_port(task_t task)1062 convert_task_to_port(
1063 task_t task)
1064 {
1065 ipc_port_t port;
1066
1067 itk_lock(task);
1068 if (task->itk_self != IP_NULL)
1069 port = ipc_port_make_send(task->itk_self);
1070 else
1071 port = IP_NULL;
1072 itk_unlock(task);
1073
1074 task_deallocate(task);
1075 return port;
1076 }
1077
1078 /*
1079 * Routine: convert_act_to_port
1080 * Purpose:
1081 * Convert from a thr_act to a port.
1082 * Consumes an thr_act ref; produces a naked send right
1083 * which may be invalid.
1084 * Conditions:
1085 * Nothing locked.
1086 */
1087
1088 ipc_port_t
convert_thread_to_port(thread_t thr_act)1089 convert_thread_to_port(thread_t thr_act)
1090 {
1091 ipc_port_t port;
1092
1093 act_lock(thr_act);
1094 if (thr_act->ith_self != IP_NULL)
1095 port = ipc_port_make_send(thr_act->ith_self);
1096 else
1097 port = IP_NULL;
1098 act_unlock(thr_act);
1099
1100 act_deallocate(thr_act);
1101 return port;
1102 }
1103
1104 /*
1105 * Routine: space_deallocate
1106 * Purpose:
1107 * Deallocate a space ref produced by convert_port_to_space.
1108 * Conditions:
1109 * Nothing locked.
1110 */
1111
1112 void
space_deallocate(ipc_space_t space)1113 space_deallocate(
1114 ipc_space_t space)
1115 {
1116 if (space != IS_NULL)
1117 is_release(space);
1118 }
1119
1120 /*
1121 * Routine: host/task_set_exception_ports [kernel call]
1122 * Purpose:
1123 * Sets the host/task exception port, flavor and
1124 * behavior for the exception types specified by the mask.
1125 * There will be one send right per exception per valid
1126 * port.
1127 * Conditions:
1128 * Nothing locked. If successful, consumes
1129 * the supplied send right.
1130 * Returns:
1131 * KERN_SUCCESS Changed the special port.
1132 * KERN_INVALID_ARGUMENT The thread is null,
1133 * Illegal mask bit set.
1134 * Illegal exception behavior
1135 * KERN_FAILURE The thread is dead.
1136 */
1137
1138 kern_return_t
host_set_exception_ports(host_t host,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor)1139 host_set_exception_ports(
1140 host_t host,
1141 exception_mask_t exception_mask,
1142 ipc_port_t new_port,
1143 exception_behavior_t new_behavior,
1144 thread_state_flavor_t new_flavor)
1145 {
1146 register int i;
1147 ipc_port_t old_port[EXC_TYPES_COUNT];
1148
1149 if (!host)
1150 return KERN_INVALID_ARGUMENT;
1151
1152 if (exception_mask & ~EXC_MASK_ALL)
1153 return KERN_INVALID_ARGUMENT;
1154
1155 if (IP_VALID(new_port)) {
1156 switch (new_behavior) {
1157 case EXCEPTION_DEFAULT:
1158 case EXCEPTION_STATE:
1159 case EXCEPTION_STATE_IDENTITY:
1160 break;
1161 default:
1162 return KERN_INVALID_ARGUMENT;
1163 }
1164 }
1165 /* Cannot easily check "flavor", but that just means that the flavor
1166 * in the generated exception message might be garbage. GIGO */
1167
1168 host_lock(host);
1169
1170 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1171 if (exception_mask & (1 << i)) {
1172 old_port[i] = host->exc_actions[i].port;
1173 host->exc_actions[i].port =
1174 ipc_port_copy_send(new_port);
1175 host->exc_actions[i].behavior = new_behavior;
1176 host->exc_actions[i].flavor = new_flavor;
1177 } else
1178 old_port[i] = IP_NULL;
1179 }/* for */
1180 /*
1181 * Consume send rights without any lock held.
1182 */
1183 host_unlock(host);
1184 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1185 if (IP_VALID(old_port[i]))
1186 ipc_port_release_send(old_port[i]);
1187 if (IP_VALID(new_port)) /* consume send right */
1188 ipc_port_release_send(new_port);
1189
1190 return KERN_SUCCESS;
1191 }/* thread_set_exception_port */
1192
1193 kern_return_t
task_set_exception_ports(task_t task,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor)1194 task_set_exception_ports(
1195 task_t task,
1196 exception_mask_t exception_mask,
1197 ipc_port_t new_port,
1198 exception_behavior_t new_behavior,
1199 thread_state_flavor_t new_flavor)
1200 {
1201 register int i;
1202 ipc_port_t old_port[EXC_TYPES_COUNT];
1203
1204 if (task == TASK_NULL) {
1205 return KERN_INVALID_ARGUMENT;
1206 }
1207
1208 if (exception_mask & ~EXC_MASK_ALL) {
1209 return KERN_INVALID_ARGUMENT;
1210 }
1211
1212 if (IP_VALID(new_port)) {
1213 switch (new_behavior) {
1214 case EXCEPTION_DEFAULT:
1215 case EXCEPTION_STATE:
1216 case EXCEPTION_STATE_IDENTITY:
1217 break;
1218 default:
1219 return KERN_INVALID_ARGUMENT;
1220 }
1221 }
1222 /* Cannot easily check "new_flavor", but that just means that
1223 * the flavor in the generated exception message might be garbage:
1224 * GIGO */
1225
1226 itk_lock(task);
1227 if (task->itk_self == IP_NULL) {
1228 itk_unlock(task);
1229 return KERN_FAILURE;
1230 }
1231
1232 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1233 if (exception_mask & (1 << i)) {
1234 old_port[i] = task->exc_actions[i].port;
1235 task->exc_actions[i].port =
1236 ipc_port_copy_send(new_port);
1237 task->exc_actions[i].behavior = new_behavior;
1238 task->exc_actions[i].flavor = new_flavor;
1239 } else
1240 old_port[i] = IP_NULL;
1241 }/* for */
1242
1243 /*
1244 * Consume send rights without any lock held.
1245 */
1246 itk_unlock(task);
1247 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1248 if (IP_VALID(old_port[i]))
1249 ipc_port_release_send(old_port[i]);
1250 if (IP_VALID(new_port)) /* consume send right */
1251 ipc_port_release_send(new_port);
1252
1253 return KERN_SUCCESS;
1254 }/* task_set_exception_port */
1255
1256 /*
1257 * Routine: host/task_swap_exception_ports [kernel call]
1258 * Purpose:
1259 * Sets the thread/task exception port, flavor and
1260 * behavior for the exception types specified by the
1261 * mask.
1262 *
1263 * The old ports, behavior and flavors are returned
1264 * Count specifies the array sizes on input and
1265 * the number of returned ports etc. on output. The
1266 * arrays must be large enough to hold all the returned
1267 * data, MIG returnes an error otherwise. The masks
1268 * array specifies the corresponding exception type(s).
1269 *
1270 * Conditions:
1271 * Nothing locked. If successful, consumes
1272 * the supplied send right.
1273 *
1274 * Returns upto [in} CountCnt elements.
1275 * Returns:
1276 * KERN_SUCCESS Changed the special port.
1277 * KERN_INVALID_ARGUMENT The thread is null,
1278 * Illegal mask bit set.
1279 * Illegal exception behavior
1280 * KERN_FAILURE The thread is dead.
1281 */
1282
1283 kern_return_t
host_swap_exception_ports(host_t host,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1284 host_swap_exception_ports(
1285 host_t host,
1286 exception_mask_t exception_mask,
1287 ipc_port_t new_port,
1288 exception_behavior_t new_behavior,
1289 thread_state_flavor_t new_flavor,
1290 exception_mask_array_t masks,
1291 mach_msg_type_number_t * CountCnt,
1292 exception_port_array_t ports,
1293 exception_behavior_array_t behaviors,
1294 thread_state_flavor_array_t flavors )
1295 {
1296 register int i,
1297 j,
1298 count;
1299 ipc_port_t old_port[EXC_TYPES_COUNT];
1300
1301 if (!host)
1302 return KERN_INVALID_ARGUMENT;
1303
1304 if (exception_mask & ~EXC_MASK_ALL) {
1305 return KERN_INVALID_ARGUMENT;
1306 }
1307
1308 if (IP_VALID(new_port)) {
1309 switch (new_behavior) {
1310 case EXCEPTION_DEFAULT:
1311 case EXCEPTION_STATE:
1312 case EXCEPTION_STATE_IDENTITY:
1313 break;
1314 default:
1315 return KERN_INVALID_ARGUMENT;
1316 }
1317 }
1318 /* Cannot easily check "new_flavor", but that just means that
1319 * the flavor in the generated exception message might be garbage:
1320 * GIGO */
1321
1322 host_lock(host);
1323 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1324 if (exception_mask & (1 << i)) {
1325 for (j = 0; j < count; j++) {
1326 /*
1327 * search for an identical entry, if found
1328 * set corresponding mask for this exception.
1329 */
1330 if (host->exc_actions[i].port == ports[j] &&
1331 host->exc_actions[i].behavior ==behaviors[j]
1332 && host->exc_actions[i].flavor ==flavors[j])
1333 {
1334 masks[j] |= (1 << i);
1335 break;
1336 }
1337 }/* for */
1338 if (j == count) {
1339 masks[j] = (1 << i);
1340 ports[j] =
1341 ipc_port_copy_send(host->exc_actions[i].port);
1342
1343 behaviors[j] = host->exc_actions[i].behavior;
1344 flavors[j] = host->exc_actions[i].flavor;
1345 count++;
1346 }
1347
1348 old_port[i] = host->exc_actions[i].port;
1349 host->exc_actions[i].port =
1350 ipc_port_copy_send(new_port);
1351 host->exc_actions[i].behavior = new_behavior;
1352 host->exc_actions[i].flavor = new_flavor;
1353 if (count > *CountCnt) {
1354 break;
1355 }
1356 } else
1357 old_port[i] = IP_NULL;
1358 }/* for */
1359
1360 /*
1361 * Consume send rights without any lock held.
1362 */
1363 host_unlock(host);
1364 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1365 if (IP_VALID(old_port[i]))
1366 ipc_port_release_send(old_port[i]);
1367 if (IP_VALID(new_port)) /* consume send right */
1368 ipc_port_release_send(new_port);
1369 *CountCnt = count;
1370 return KERN_SUCCESS;
1371 }/* thread_swap_exception_ports */
1372
1373 kern_return_t
task_swap_exception_ports(task_t task,exception_mask_t exception_mask,ipc_port_t new_port,exception_behavior_t new_behavior,thread_state_flavor_t new_flavor,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1374 task_swap_exception_ports(
1375 task_t task,
1376 exception_mask_t exception_mask,
1377 ipc_port_t new_port,
1378 exception_behavior_t new_behavior,
1379 thread_state_flavor_t new_flavor,
1380 exception_mask_array_t masks,
1381 mach_msg_type_number_t * CountCnt,
1382 exception_port_array_t ports,
1383 exception_behavior_array_t behaviors,
1384 thread_state_flavor_array_t flavors )
1385 {
1386 register int i,
1387 j,
1388 count;
1389 ipc_port_t old_port[EXC_TYPES_COUNT];
1390
1391 if (task == TASK_NULL)
1392 return KERN_INVALID_ARGUMENT;
1393
1394 if (exception_mask & ~EXC_MASK_ALL) {
1395 return KERN_INVALID_ARGUMENT;
1396 }
1397
1398 if (IP_VALID(new_port)) {
1399 switch (new_behavior) {
1400 case EXCEPTION_DEFAULT:
1401 case EXCEPTION_STATE:
1402 case EXCEPTION_STATE_IDENTITY:
1403 break;
1404 default:
1405 return KERN_INVALID_ARGUMENT;
1406 }
1407 }
1408 /* Cannot easily check "new_flavor", but that just means that
1409 * the flavor in the generated exception message might be garbage:
1410 * GIGO */
1411
1412 itk_lock(task);
1413 if (task->itk_self == IP_NULL) {
1414 itk_unlock(task);
1415 return KERN_FAILURE;
1416 }
1417
1418 count = 0;
1419
1420 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1421 if (exception_mask & (1 << i)) {
1422 for (j = 0; j < count; j++) {
1423 /*
1424 * search for an identical entry, if found
1425 * set corresponding mask for this exception.
1426 */
1427 if (task->exc_actions[i].port == ports[j] &&
1428 task->exc_actions[i].behavior == behaviors[j]
1429 && task->exc_actions[i].flavor == flavors[j])
1430 {
1431 masks[j] |= (1 << i);
1432 break;
1433 }
1434 }/* for */
1435 if (j == count) {
1436 masks[j] = (1 << i);
1437 ports[j] =
1438 ipc_port_copy_send(task->exc_actions[i].port);
1439 behaviors[j] = task->exc_actions[i].behavior;
1440 flavors[j] = task->exc_actions[i].flavor;
1441 count++;
1442 }
1443 old_port[i] = task->exc_actions[i].port;
1444 task->exc_actions[i].port =
1445 ipc_port_copy_send(new_port);
1446 task->exc_actions[i].behavior = new_behavior;
1447 task->exc_actions[i].flavor = new_flavor;
1448 if (count > *CountCnt) {
1449 break;
1450 }
1451 } else
1452 old_port[i] = IP_NULL;
1453 }/* for */
1454
1455
1456 /*
1457 * Consume send rights without any lock held.
1458 */
1459 itk_unlock(task);
1460 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
1461 if (IP_VALID(old_port[i]))
1462 ipc_port_release_send(old_port[i]);
1463 if (IP_VALID(new_port)) /* consume send right */
1464 ipc_port_release_send(new_port);
1465 *CountCnt = count;
1466
1467 return KERN_SUCCESS;
1468 }/* task_swap_exception_ports */
1469
1470
1471 /*
1472 * Routine: host/task_get_exception_ports [kernel call]
1473 * Purpose:
1474 * Clones a send right for each of the thread/task's exception
1475 * ports specified in the mask and returns the behaviour
1476 * and flavor of said port.
1477 *
1478 * Returns upto [in} CountCnt elements.
1479 *
1480 * Conditions:
1481 * Nothing locked.
1482 * Returns:
1483 * KERN_SUCCESS Extracted a send right.
1484 * KERN_INVALID_ARGUMENT The thread is null,
1485 * Invalid special port,
1486 * Illegal mask bit set.
1487 * KERN_FAILURE The thread is dead.
1488 */
1489
1490 kern_return_t
host_get_exception_ports(host_t host,exception_mask_t exception_mask,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1491 host_get_exception_ports(
1492 host_t host,
1493 exception_mask_t exception_mask,
1494 exception_mask_array_t masks,
1495 mach_msg_type_number_t * CountCnt,
1496 exception_port_array_t ports,
1497 exception_behavior_array_t behaviors,
1498 thread_state_flavor_array_t flavors )
1499 {
1500 register int i,
1501 j,
1502 count;
1503
1504 if (!host)
1505 return KERN_INVALID_ARGUMENT;
1506
1507 if (exception_mask & ~EXC_MASK_ALL) {
1508 return KERN_INVALID_ARGUMENT;
1509 }
1510
1511 host_lock(host);
1512 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1513 if (exception_mask & (1 << i)) {
1514 for (j = 0; j < count; j++) {
1515 /*
1516 * search for an identical entry, if found
1517 * set corresponding mask for this exception.
1518 */
1519 if (host->exc_actions[i].port == ports[j] &&
1520 host->exc_actions[i].behavior ==behaviors[j]
1521 && host->exc_actions[i].flavor == flavors[j])
1522 {
1523 masks[j] |= (1 << i);
1524 break;
1525 }
1526 }/* for */
1527 if (j == count) {
1528 masks[j] = (1 << i);
1529 ports[j] =
1530 ipc_port_copy_send(host->exc_actions[i].port);
1531 behaviors[j] = host->exc_actions[i].behavior;
1532 flavors[j] = host->exc_actions[i].flavor;
1533 count++;
1534 if (count >= *CountCnt) {
1535 break;
1536 }
1537 }
1538 }
1539 }/* for */
1540
1541 host_unlock(host);
1542
1543 *CountCnt = count;
1544 return KERN_SUCCESS;
1545 }/* thread_get_exception_ports */
1546
1547 kern_return_t
task_get_exception_ports(task_t task,exception_mask_t exception_mask,exception_mask_array_t masks,mach_msg_type_number_t * CountCnt,exception_port_array_t ports,exception_behavior_array_t behaviors,thread_state_flavor_array_t flavors)1548 task_get_exception_ports(
1549 task_t task,
1550 exception_mask_t exception_mask,
1551 exception_mask_array_t masks,
1552 mach_msg_type_number_t * CountCnt,
1553 exception_port_array_t ports,
1554 exception_behavior_array_t behaviors,
1555 thread_state_flavor_array_t flavors )
1556 {
1557 register int i,
1558 j,
1559 count;
1560
1561 if (task == TASK_NULL)
1562 return KERN_INVALID_ARGUMENT;
1563
1564 if (exception_mask & ~EXC_MASK_ALL) {
1565 return KERN_INVALID_ARGUMENT;
1566 }
1567
1568 itk_lock(task);
1569 if (task->itk_self == IP_NULL) {
1570 itk_unlock(task);
1571 return KERN_FAILURE;
1572 }
1573
1574 count = 0;
1575
1576 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
1577 if (exception_mask & (1 << i)) {
1578 for (j = 0; j < count; j++) {
1579 /*
1580 * search for an identical entry, if found
1581 * set corresponding mask for this exception.
1582 */
1583 if (task->exc_actions[i].port == ports[j] &&
1584 task->exc_actions[i].behavior == behaviors[j]
1585 && task->exc_actions[i].flavor == flavors[j])
1586 {
1587 masks[j] |= (1 << i);
1588 break;
1589 }
1590 }/* for */
1591 if (j == count) {
1592 masks[j] = (1 << i);
1593 ports[j] =
1594 ipc_port_copy_send(task->exc_actions[i].port);
1595 behaviors[j] = task->exc_actions[i].behavior;
1596 flavors[j] = task->exc_actions[i].flavor;
1597 count++;
1598 if (count > *CountCnt) {
1599 break;
1600 }
1601 }
1602 }
1603 }/* for */
1604
1605 itk_unlock(task);
1606
1607 *CountCnt = count;
1608 return KERN_SUCCESS;
1609 }/* task_get_exception_ports */
1610