2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 * Mach Operating System
28 * Copyright (c) 1991,1990 Carnegie Mellon University
29 * All Rights Reserved.
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
41 * Carnegie Mellon requests users of this software to return to
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
54 * File: ipc/mach_debug.c
58 * Exported IPC debug calls.
60 #include <mach_ipc_debug.h>
62 #include <mach/vm_param.h>
63 #include <mach/kern_return.h>
64 #include <mach/machine/vm_types.h>
65 #include <mach/mach_host_server.h>
66 #include <mach/mach_port_server.h>
67 #include <mach_debug/ipc_info.h>
68 #include <mach_debug/hash_info.h>
71 #include <kern/host.h>
72 #include <kern/misc_protos.h>
73 #include <vm/vm_map.h>
74 #include <vm/vm_kern.h>
76 #include <ipc/ipc_types.h>
77 #include <ipc/ipc_space.h>
78 #include <ipc/ipc_port.h>
79 #include <ipc/ipc_hash.h>
80 #include <ipc/ipc_table.h>
81 #include <ipc/ipc_right.h>
85 * Routine: mach_port_get_srights [kernel call]
87 * Retrieve the number of extant send rights
88 * that a receive right has.
92 * KERN_SUCCESS Retrieved number of send rights.
93 * KERN_INVALID_TASK The space is null.
94 * KERN_INVALID_TASK The space is dead.
95 * KERN_INVALID_NAME The name doesn't denote a right.
96 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
101 mach_port_get_srights(
102 __unused ipc_space_t space
,
103 __unused mach_port_name_t name
,
104 __unused mach_port_rights_t
*srightsp
)
110 mach_port_get_srights(
112 mach_port_name_t name
,
113 mach_port_rights_t
*srightsp
)
117 mach_port_rights_t srights
;
119 if (space
== IS_NULL
)
120 return KERN_INVALID_TASK
;
122 kr
= ipc_port_translate_receive(space
, name
, &port
);
123 if (kr
!= KERN_SUCCESS
)
125 /* port is locked and active */
127 srights
= port
->ip_srights
;
133 #endif /* MACH_IPC_DEBUG */
136 * Routine: host_ipc_hash_info
138 * Return information about the global reverse hash table.
140 * Nothing locked. Obeys CountInOut protocol.
142 * KERN_SUCCESS Returned information.
143 * KERN_INVALID_HOST The host is null.
144 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
150 __unused host_t host
,
151 __unused hash_info_bucket_array_t
*infop
,
152 __unused mach_msg_type_number_t
*countp
)
160 hash_info_bucket_array_t
*infop
,
161 mach_msg_type_number_t
*countp
)
165 hash_info_bucket_t
*info
;
166 unsigned int potential
, actual
;
169 if (host
== HOST_NULL
)
170 return KERN_INVALID_HOST
;
172 /* start with in-line data */
178 actual
= ipc_hash_info(info
, potential
);
179 if (actual
<= potential
)
182 /* allocate more memory */
185 kmem_free(ipc_kernel_map
, addr
, size
);
187 size
= round_page(actual
* sizeof *info
);
188 kr
= kmem_alloc_pageable(ipc_kernel_map
, &addr
, size
);
189 if (kr
!= KERN_SUCCESS
)
190 return KERN_RESOURCE_SHORTAGE
;
192 info
= (hash_info_bucket_t
*) addr
;
193 potential
= size
/sizeof *info
;
196 if (info
== *infop
) {
197 /* data fit in-line; nothing to deallocate */
200 } else if (actual
== 0) {
201 kmem_free(ipc_kernel_map
, addr
, size
);
208 used
= round_page(actual
* sizeof *info
);
211 kmem_free(ipc_kernel_map
, addr
+ used
, size
- used
);
213 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
214 (vm_map_size_t
)used
, TRUE
, ©
);
215 assert(kr
== KERN_SUCCESS
);
217 *infop
= (hash_info_bucket_t
*) copy
;
223 #endif /* MACH_IPC_DEBUG */
226 * Routine: mach_port_space_info
228 * Returns information about an IPC space.
230 * Nothing locked. Obeys CountInOut protocol.
232 * KERN_SUCCESS Returned information.
233 * KERN_INVALID_TASK The space is null.
234 * KERN_INVALID_TASK The space is dead.
235 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
240 mach_port_space_info(
241 __unused ipc_space_t space
,
242 __unused ipc_info_space_t
*infop
,
243 __unused ipc_info_name_array_t
*tablep
,
244 __unused mach_msg_type_number_t
*tableCntp
,
245 __unused ipc_info_tree_name_array_t
*treep
,
246 __unused mach_msg_type_number_t
*treeCntp
)
252 mach_port_space_info(
254 ipc_info_space_t
*infop
,
255 ipc_info_name_array_t
*tablep
,
256 mach_msg_type_number_t
*tableCntp
,
257 ipc_info_tree_name_array_t
*treep
,
258 mach_msg_type_number_t
*treeCntp
)
260 ipc_info_name_t
*table_info
;
261 unsigned int table_potential
, table_actual
;
262 vm_offset_t table_addr
;
263 vm_size_t table_size
;
264 ipc_info_tree_name_t
*tree_info
;
265 unsigned int tree_potential
, tree_actual
;
266 vm_offset_t tree_addr
;
268 ipc_tree_entry_t tentry
;
270 ipc_entry_num_t tsize
;
271 mach_port_index_t index
;
274 if (space
== IS_NULL
)
275 return KERN_INVALID_TASK
;
277 /* start with in-line memory */
280 table_info
= *tablep
;
281 table_potential
= *tableCntp
;
284 tree_potential
= *treeCntp
;
288 if (!space
->is_active
) {
289 is_read_unlock(space
);
290 if (table_info
!= *tablep
)
291 kmem_free(ipc_kernel_map
,
292 table_addr
, table_size
);
293 if (tree_info
!= *treep
)
294 kmem_free(ipc_kernel_map
,
295 tree_addr
, tree_size
);
296 return KERN_INVALID_TASK
;
299 table_actual
= space
->is_table_size
;
300 tree_actual
= space
->is_tree_total
;
302 if ((table_actual
<= table_potential
) &&
303 (tree_actual
<= tree_potential
))
306 is_read_unlock(space
);
308 if (table_actual
> table_potential
) {
309 if (table_info
!= *tablep
)
310 kmem_free(ipc_kernel_map
,
311 table_addr
, table_size
);
313 table_size
= round_page(table_actual
*
315 kr
= kmem_alloc(ipc_kernel_map
,
316 &table_addr
, table_size
);
317 if (kr
!= KERN_SUCCESS
) {
318 if (tree_info
!= *treep
)
319 kmem_free(ipc_kernel_map
,
320 tree_addr
, tree_size
);
322 return KERN_RESOURCE_SHORTAGE
;
325 table_info
= (ipc_info_name_t
*) table_addr
;
326 table_potential
= table_size
/sizeof *table_info
;
329 if (tree_actual
> tree_potential
) {
330 if (tree_info
!= *treep
)
331 kmem_free(ipc_kernel_map
,
332 tree_addr
, tree_size
);
334 tree_size
= round_page(tree_actual
*
336 kr
= kmem_alloc(ipc_kernel_map
,
337 &tree_addr
, tree_size
);
338 if (kr
!= KERN_SUCCESS
) {
339 if (table_info
!= *tablep
)
340 kmem_free(ipc_kernel_map
,
341 table_addr
, table_size
);
343 return KERN_RESOURCE_SHORTAGE
;
346 tree_info
= (ipc_info_tree_name_t
*) tree_addr
;
347 tree_potential
= tree_size
/sizeof *tree_info
;
350 /* space is read-locked and active; we have enough wired memory */
352 infop
->iis_genno_mask
= MACH_PORT_NGEN(MACH_PORT_DEAD
);
353 infop
->iis_table_size
= space
->is_table_size
;
354 infop
->iis_table_next
= space
->is_table_next
->its_size
;
355 infop
->iis_tree_size
= space
->is_tree_total
;
356 infop
->iis_tree_small
= space
->is_tree_small
;
357 infop
->iis_tree_hash
= space
->is_tree_hash
;
359 table
= space
->is_table
;
360 tsize
= space
->is_table_size
;
362 for (index
= 0; index
< tsize
; index
++) {
363 ipc_info_name_t
*iin
= &table_info
[index
];
364 ipc_entry_t entry
= &table
[index
];
365 ipc_entry_bits_t bits
;
367 bits
= entry
->ie_bits
;
368 iin
->iin_name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
369 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
370 iin
->iin_type
= IE_BITS_TYPE(bits
);
371 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
372 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
373 iin
->iin_next
= entry
->ie_next
;
374 iin
->iin_hash
= entry
->ie_index
;
377 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
), index
= 0;
379 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
380 ipc_info_tree_name_t
*iitn
= &tree_info
[index
++];
381 ipc_info_name_t
*iin
= &iitn
->iitn_name
;
382 ipc_entry_t entry
= &tentry
->ite_entry
;
383 ipc_entry_bits_t bits
= entry
->ie_bits
;
385 assert(IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
);
387 iin
->iin_name
= tentry
->ite_name
;
388 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
389 iin
->iin_type
= IE_BITS_TYPE(bits
);
390 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
391 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
392 iin
->iin_next
= entry
->ie_next
;
393 iin
->iin_hash
= entry
->ie_index
;
395 if (tentry
->ite_lchild
== ITE_NULL
)
396 iitn
->iitn_lchild
= MACH_PORT_NULL
;
398 iitn
->iitn_lchild
= tentry
->ite_lchild
->ite_name
;
400 if (tentry
->ite_rchild
== ITE_NULL
)
401 iitn
->iitn_rchild
= MACH_PORT_NULL
;
403 iitn
->iitn_rchild
= tentry
->ite_rchild
->ite_name
;
406 ipc_splay_traverse_finish(&space
->is_tree
);
407 is_read_unlock(space
);
409 if (table_info
== *tablep
) {
410 /* data fit in-line; nothing to deallocate */
412 *tableCntp
= table_actual
;
413 } else if (table_actual
== 0) {
414 kmem_free(ipc_kernel_map
, table_addr
, table_size
);
418 vm_size_t size_used
, rsize_used
;
421 /* kmem_alloc doesn't zero memory */
423 size_used
= table_actual
* sizeof *table_info
;
424 rsize_used
= round_page(size_used
);
426 if (rsize_used
!= table_size
)
427 kmem_free(ipc_kernel_map
,
428 table_addr
+ rsize_used
,
429 table_size
- rsize_used
);
431 if (size_used
!= rsize_used
)
432 bzero((char *) (table_addr
+ size_used
),
433 rsize_used
- size_used
);
435 kr
= vm_map_unwire(ipc_kernel_map
, vm_map_trunc_page(table_addr
),
436 vm_map_round_page(table_addr
+ rsize_used
), FALSE
);
437 assert(kr
== KERN_SUCCESS
);
439 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)table_addr
,
440 (vm_map_size_t
)rsize_used
, TRUE
, ©
);
441 assert(kr
== KERN_SUCCESS
);
443 *tablep
= (ipc_info_name_t
*) copy
;
444 *tableCntp
= table_actual
;
447 if (tree_info
== *treep
) {
448 /* data fit in-line; nothing to deallocate */
450 *treeCntp
= tree_actual
;
451 } else if (tree_actual
== 0) {
452 kmem_free(ipc_kernel_map
, tree_addr
, tree_size
);
456 vm_size_t size_used
, rsize_used
;
459 /* kmem_alloc doesn't zero memory */
461 size_used
= tree_actual
* sizeof *tree_info
;
462 rsize_used
= round_page(size_used
);
464 if (rsize_used
!= tree_size
)
465 kmem_free(ipc_kernel_map
,
466 tree_addr
+ rsize_used
,
467 tree_size
- rsize_used
);
469 if (size_used
!= rsize_used
)
470 bzero((char *) (tree_addr
+ size_used
),
471 rsize_used
- size_used
);
473 kr
= vm_map_unwire(ipc_kernel_map
, vm_map_trunc_page(tree_addr
),
474 vm_map_round_page(tree_addr
+ rsize_used
), FALSE
);
475 assert(kr
== KERN_SUCCESS
);
477 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)tree_addr
,
478 (vm_map_size_t
)rsize_used
, TRUE
, ©
);
479 assert(kr
== KERN_SUCCESS
);
481 *treep
= (ipc_info_tree_name_t
*) copy
;
482 *treeCntp
= tree_actual
;
487 #endif /* MACH_IPC_DEBUG */
490 * Routine: mach_port_dnrequest_info
492 * Returns information about the dead-name requests
493 * registered with the named receive right.
497 * KERN_SUCCESS Retrieved information.
498 * KERN_INVALID_TASK The space is null.
499 * KERN_INVALID_TASK The space is dead.
500 * KERN_INVALID_NAME The name doesn't denote a right.
501 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
506 mach_port_dnrequest_info(
507 __unused ipc_space_t space
,
508 __unused mach_port_name_t name
,
509 __unused
unsigned int *totalp
,
510 __unused
unsigned int *usedp
)
516 mach_port_dnrequest_info(
518 mach_port_name_t name
,
519 unsigned int *totalp
,
522 unsigned int total
, used
;
526 if (space
== IS_NULL
)
527 return KERN_INVALID_TASK
;
529 kr
= ipc_port_translate_receive(space
, name
, &port
);
530 if (kr
!= KERN_SUCCESS
)
532 /* port is locked and active */
534 if (port
->ip_dnrequests
== IPR_NULL
) {
538 ipc_port_request_t dnrequests
= port
->ip_dnrequests
;
539 ipc_port_request_index_t index
;
541 total
= dnrequests
->ipr_size
->its_size
;
543 for (index
= 1, used
= 0;
544 index
< total
; index
++) {
545 ipc_port_request_t ipr
= &dnrequests
[index
];
547 if (ipr
->ipr_name
!= MACH_PORT_NULL
)
557 #endif /* MACH_IPC_DEBUG */
560 * Routine: mach_port_kernel_object [kernel call]
562 * Retrieve the type and address of the kernel object
563 * represented by a send or receive right.
567 * KERN_SUCCESS Retrieved kernel object info.
568 * KERN_INVALID_TASK The space is null.
569 * KERN_INVALID_TASK The space is dead.
570 * KERN_INVALID_NAME The name doesn't denote a right.
571 * KERN_INVALID_RIGHT Name doesn't denote
572 * send or receive rights.
577 mach_port_kernel_object(
578 __unused ipc_space_t space
,
579 __unused mach_port_name_t name
,
580 __unused
unsigned int *typep
,
581 __unused vm_offset_t
*addrp
)
587 mach_port_kernel_object(
589 mach_port_name_t name
,
597 kr
= ipc_right_lookup_read(space
, name
, &entry
);
598 if (kr
!= KERN_SUCCESS
)
600 /* space is read-locked and active */
602 if ((entry
->ie_bits
& MACH_PORT_TYPE_SEND_RECEIVE
) == 0) {
603 is_read_unlock(space
);
604 return KERN_INVALID_RIGHT
;
607 port
= (ipc_port_t
) entry
->ie_object
;
608 assert(port
!= IP_NULL
);
611 is_read_unlock(space
);
613 if (!ip_active(port
)) {
615 return KERN_INVALID_RIGHT
;
618 *typep
= (unsigned int) ip_kotype(port
);
619 *addrp
= (vm_offset_t
) port
->ip_kobject
;
624 #endif /* MACH_IPC_DEBUG */