2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * File: ipc/mach_debug.c
57 * Exported IPC debug calls.
59 #include <mach_ipc_debug.h>
61 #include <mach/vm_param.h>
62 #include <mach/kern_return.h>
63 #include <mach/machine/vm_types.h>
64 #include <mach/mach_host_server.h>
65 #include <mach/mach_port_server.h>
66 #include <mach_debug/ipc_info.h>
67 #include <mach_debug/hash_info.h>
70 #include <kern/host.h>
71 #include <kern/misc_protos.h>
72 #include <vm/vm_map.h>
73 #include <vm/vm_kern.h>
74 #include <ipc/ipc_space.h>
75 #include <ipc/ipc_port.h>
76 #include <ipc/ipc_hash.h>
77 #include <ipc/ipc_table.h>
78 #include <ipc/ipc_right.h>
82 * Routine: mach_port_get_srights [kernel call]
84 * Retrieve the number of extant send rights
85 * that a receive right has.
89 * KERN_SUCCESS Retrieved number of send rights.
90 * KERN_INVALID_TASK The space is null.
91 * KERN_INVALID_TASK The space is dead.
92 * KERN_INVALID_NAME The name doesn't denote a right.
93 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
97 mach_port_get_srights(
99 mach_port_name_t name
,
100 mach_port_rights_t
*srightsp
)
107 mach_port_rights_t srights
;
109 if (space
== IS_NULL
)
110 return KERN_INVALID_TASK
;
112 kr
= ipc_port_translate_receive(space
, name
, &port
);
113 if (kr
!= KERN_SUCCESS
)
115 /* port is locked and active */
117 srights
= port
->ip_srights
;
122 #endif /* MACH_IPC_DEBUG */
126 * Routine: host_ipc_hash_info
128 * Return information about the global reverse hash table.
130 * Nothing locked. Obeys CountInOut protocol.
132 * KERN_SUCCESS Returned information.
133 * KERN_INVALID_HOST The host is null.
134 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
140 hash_info_bucket_array_t
*infop
,
141 mach_msg_type_number_t
*countp
)
148 hash_info_bucket_t
*info
;
149 unsigned int potential
, actual
;
152 if (host
== HOST_NULL
)
153 return KERN_INVALID_HOST
;
155 /* start with in-line data */
161 actual
= ipc_hash_info(info
, potential
);
162 if (actual
<= potential
)
165 /* allocate more memory */
168 kmem_free(ipc_kernel_map
, addr
, size
);
170 size
= round_page(actual
* sizeof *info
);
171 kr
= kmem_alloc_pageable(ipc_kernel_map
, &addr
, size
);
172 if (kr
!= KERN_SUCCESS
)
173 return KERN_RESOURCE_SHORTAGE
;
175 info
= (hash_info_bucket_t
*) addr
;
176 potential
= size
/sizeof *info
;
179 if (info
== *infop
) {
180 /* data fit in-line; nothing to deallocate */
183 } else if (actual
== 0) {
184 kmem_free(ipc_kernel_map
, addr
, size
);
191 used
= round_page(actual
* sizeof *info
);
194 kmem_free(ipc_kernel_map
, addr
+ used
, size
- used
);
196 kr
= vm_map_copyin(ipc_kernel_map
, addr
, used
,
198 assert(kr
== KERN_SUCCESS
);
200 *infop
= (hash_info_bucket_t
*) copy
;
205 #endif /* MACH_IPC_DEBUG */
209 * Routine: mach_port_space_info
211 * Returns information about an IPC space.
213 * Nothing locked. Obeys CountInOut protocol.
215 * KERN_SUCCESS Returned information.
216 * KERN_INVALID_TASK The space is null.
217 * KERN_INVALID_TASK The space is dead.
218 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
222 mach_port_space_info(
224 ipc_info_space_t
*infop
,
225 ipc_info_name_array_t
*tablep
,
226 mach_msg_type_number_t
*tableCntp
,
227 ipc_info_tree_name_array_t
*treep
,
228 mach_msg_type_number_t
*treeCntp
)
233 ipc_info_name_t
*table_info
;
234 unsigned int table_potential
, table_actual
;
235 vm_offset_t table_addr
;
236 vm_size_t table_size
;
237 ipc_info_tree_name_t
*tree_info
;
238 unsigned int tree_potential
, tree_actual
;
239 vm_offset_t tree_addr
;
241 ipc_tree_entry_t tentry
;
243 ipc_entry_num_t tsize
;
244 mach_port_index_t index
;
246 ipc_entry_bits_t
*capability
;
248 if (space
== IS_NULL
)
249 return KERN_INVALID_TASK
;
251 /* start with in-line memory */
253 table_info
= *tablep
;
254 table_potential
= *tableCntp
;
256 tree_potential
= *treeCntp
;
260 if (!space
->is_active
) {
261 is_read_unlock(space
);
262 if (table_info
!= *tablep
)
263 kmem_free(ipc_kernel_map
,
264 table_addr
, table_size
);
265 if (tree_info
!= *treep
)
266 kmem_free(ipc_kernel_map
,
267 tree_addr
, tree_size
);
268 return KERN_INVALID_TASK
;
271 table_actual
= space
->is_table_size
;
272 tree_actual
= space
->is_tree_total
;
274 if ((table_actual
<= table_potential
) &&
275 (tree_actual
<= tree_potential
))
278 is_read_unlock(space
);
280 if (table_actual
> table_potential
) {
281 if (table_info
!= *tablep
)
282 kmem_free(ipc_kernel_map
,
283 table_addr
, table_size
);
285 table_size
= round_page(table_actual
*
287 kr
= kmem_alloc(ipc_kernel_map
,
288 &table_addr
, table_size
);
289 if (kr
!= KERN_SUCCESS
) {
290 if (tree_info
!= *treep
)
291 kmem_free(ipc_kernel_map
,
292 tree_addr
, tree_size
);
294 return KERN_RESOURCE_SHORTAGE
;
297 table_info
= (ipc_info_name_t
*) table_addr
;
298 table_potential
= table_size
/sizeof *table_info
;
301 if (tree_actual
> tree_potential
) {
302 if (tree_info
!= *treep
)
303 kmem_free(ipc_kernel_map
,
304 tree_addr
, tree_size
);
306 tree_size
= round_page(tree_actual
*
308 kr
= kmem_alloc(ipc_kernel_map
,
309 &tree_addr
, tree_size
);
310 if (kr
!= KERN_SUCCESS
) {
311 if (table_info
!= *tablep
)
312 kmem_free(ipc_kernel_map
,
313 table_addr
, table_size
);
315 return KERN_RESOURCE_SHORTAGE
;
318 tree_info
= (ipc_info_tree_name_t
*) tree_addr
;
319 tree_potential
= tree_size
/sizeof *tree_info
;
322 /* space is read-locked and active; we have enough wired memory */
324 infop
->iis_genno_mask
= MACH_PORT_NGEN(MACH_PORT_DEAD
);
325 infop
->iis_table_size
= space
->is_table_size
;
326 infop
->iis_table_next
= space
->is_table_next
->its_size
;
327 infop
->iis_tree_size
= space
->is_tree_total
;
328 infop
->iis_tree_small
= space
->is_tree_small
;
329 infop
->iis_tree_hash
= space
->is_tree_hash
;
331 table
= space
->is_table
;
332 tsize
= space
->is_table_size
;
334 for (index
= 0; index
< tsize
; index
++) {
335 ipc_info_name_t
*iin
= &table_info
[index
];
336 ipc_entry_t entry
= &table
[index
];
337 ipc_entry_bits_t bits
;
339 bits
= entry
->ie_bits
;
340 iin
->iin_name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
341 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
342 iin
->iin_type
= IE_BITS_TYPE(bits
);
343 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
344 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
345 iin
->iin_next
= entry
->ie_next
;
346 iin
->iin_hash
= entry
->ie_index
;
349 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
), index
= 0;
351 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
352 ipc_info_tree_name_t
*iitn
= &tree_info
[index
++];
353 ipc_info_name_t
*iin
= &iitn
->iitn_name
;
354 ipc_entry_t entry
= &tentry
->ite_entry
;
355 ipc_entry_bits_t bits
= entry
->ie_bits
;
357 assert(IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
);
359 iin
->iin_name
= tentry
->ite_name
;
360 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
361 iin
->iin_type
= IE_BITS_TYPE(bits
);
362 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
363 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
364 iin
->iin_next
= entry
->ie_next
;
365 iin
->iin_hash
= entry
->ie_index
;
367 if (tentry
->ite_lchild
== ITE_NULL
)
368 iitn
->iitn_lchild
= MACH_PORT_NULL
;
370 iitn
->iitn_lchild
= tentry
->ite_lchild
->ite_name
;
372 if (tentry
->ite_rchild
== ITE_NULL
)
373 iitn
->iitn_rchild
= MACH_PORT_NULL
;
375 iitn
->iitn_rchild
= tentry
->ite_rchild
->ite_name
;
378 ipc_splay_traverse_finish(&space
->is_tree
);
379 is_read_unlock(space
);
381 if (table_info
== *tablep
) {
382 /* data fit in-line; nothing to deallocate */
384 *tableCntp
= table_actual
;
385 } else if (table_actual
== 0) {
386 kmem_free(ipc_kernel_map
, table_addr
, table_size
);
390 vm_size_t size_used
, rsize_used
;
393 /* kmem_alloc doesn't zero memory */
395 size_used
= table_actual
* sizeof *table_info
;
396 rsize_used
= round_page(size_used
);
398 if (rsize_used
!= table_size
)
399 kmem_free(ipc_kernel_map
,
400 table_addr
+ rsize_used
,
401 table_size
- rsize_used
);
403 if (size_used
!= rsize_used
)
404 bzero((char *) (table_addr
+ size_used
),
405 rsize_used
- size_used
);
407 kr
= vm_map_unwire(ipc_kernel_map
, table_addr
,
408 table_addr
+ rsize_used
, FALSE
);
409 assert(kr
== KERN_SUCCESS
);
411 kr
= vm_map_copyin(ipc_kernel_map
, table_addr
, rsize_used
,
413 assert(kr
== KERN_SUCCESS
);
415 *tablep
= (ipc_info_name_t
*) copy
;
416 *tableCntp
= table_actual
;
419 if (tree_info
== *treep
) {
420 /* data fit in-line; nothing to deallocate */
422 *treeCntp
= tree_actual
;
423 } else if (tree_actual
== 0) {
424 kmem_free(ipc_kernel_map
, tree_addr
, tree_size
);
428 vm_size_t size_used
, rsize_used
;
431 /* kmem_alloc doesn't zero memory */
433 size_used
= tree_actual
* sizeof *tree_info
;
434 rsize_used
= round_page(size_used
);
436 if (rsize_used
!= tree_size
)
437 kmem_free(ipc_kernel_map
,
438 tree_addr
+ rsize_used
,
439 tree_size
- rsize_used
);
441 if (size_used
!= rsize_used
)
442 bzero((char *) (tree_addr
+ size_used
),
443 rsize_used
- size_used
);
445 kr
= vm_map_unwire(ipc_kernel_map
, tree_addr
,
446 tree_addr
+ rsize_used
, FALSE
);
447 assert(kr
== KERN_SUCCESS
);
449 kr
= vm_map_copyin(ipc_kernel_map
, tree_addr
, rsize_used
,
451 assert(kr
== KERN_SUCCESS
);
453 *treep
= (ipc_info_tree_name_t
*) copy
;
454 *treeCntp
= tree_actual
;
458 #endif /* MACH_IPC_DEBUG */
462 * Routine: mach_port_dnrequest_info
464 * Returns information about the dead-name requests
465 * registered with the named receive right.
469 * KERN_SUCCESS Retrieved information.
470 * KERN_INVALID_TASK The space is null.
471 * KERN_INVALID_TASK The space is dead.
472 * KERN_INVALID_NAME The name doesn't denote a right.
473 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
477 mach_port_dnrequest_info(
479 mach_port_name_t name
,
480 unsigned int *totalp
,
486 unsigned int total
, used
;
490 if (space
== IS_NULL
)
491 return KERN_INVALID_TASK
;
493 kr
= ipc_port_translate_receive(space
, name
, &port
);
494 if (kr
!= KERN_SUCCESS
)
496 /* port is locked and active */
498 if (port
->ip_dnrequests
== IPR_NULL
) {
502 ipc_port_request_t dnrequests
= port
->ip_dnrequests
;
503 ipc_port_request_index_t index
;
505 total
= dnrequests
->ipr_size
->its_size
;
507 for (index
= 1, used
= 0;
508 index
< total
; index
++) {
509 ipc_port_request_t ipr
= &dnrequests
[index
];
511 if (ipr
->ipr_name
!= MACH_PORT_NULL
)
520 #endif /* MACH_IPC_DEBUG */
524 * Routine: mach_port_kernel_object [kernel call]
526 * Retrieve the type and address of the kernel object
527 * represented by a send or receive right.
531 * KERN_SUCCESS Retrieved kernel object info.
532 * KERN_INVALID_TASK The space is null.
533 * KERN_INVALID_TASK The space is dead.
534 * KERN_INVALID_NAME The name doesn't denote a right.
535 * KERN_INVALID_RIGHT Name doesn't denote
536 * send or receive rights.
540 mach_port_kernel_object(
542 mach_port_name_t name
,
553 kr
= ipc_right_lookup_read(space
, name
, &entry
);
554 if (kr
!= KERN_SUCCESS
)
556 /* space is read-locked and active */
558 if ((entry
->ie_bits
& MACH_PORT_TYPE_SEND_RECEIVE
) == 0) {
559 is_read_unlock(space
);
560 return KERN_INVALID_RIGHT
;
563 port
= (ipc_port_t
) entry
->ie_object
;
564 assert(port
!= IP_NULL
);
567 is_read_unlock(space
);
569 if (!ip_active(port
)) {
571 return KERN_INVALID_RIGHT
;
574 *typep
= (unsigned int) ip_kotype(port
);
575 *addrp
= (vm_offset_t
) port
->ip_kobject
;
579 #endif /* MACH_IPC_DEBUG */