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