2 * Copyright (c) 2000-2004 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>
75 #include <ipc/ipc_types.h>
76 #include <ipc/ipc_space.h>
77 #include <ipc/ipc_port.h>
78 #include <ipc/ipc_hash.h>
79 #include <ipc/ipc_table.h>
80 #include <ipc/ipc_right.h>
84 * Routine: mach_port_get_srights [kernel call]
86 * Retrieve the number of extant send rights
87 * that a receive right has.
91 * KERN_SUCCESS Retrieved number of send rights.
92 * KERN_INVALID_TASK The space is null.
93 * KERN_INVALID_TASK The space is dead.
94 * KERN_INVALID_NAME The name doesn't denote a right.
95 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
100 mach_port_get_srights(
101 __unused ipc_space_t space
,
102 __unused mach_port_name_t name
,
103 __unused mach_port_rights_t
*srightsp
)
109 mach_port_get_srights(
111 mach_port_name_t name
,
112 mach_port_rights_t
*srightsp
)
116 mach_port_rights_t srights
;
118 if (space
== IS_NULL
)
119 return KERN_INVALID_TASK
;
121 kr
= ipc_port_translate_receive(space
, name
, &port
);
122 if (kr
!= KERN_SUCCESS
)
124 /* port is locked and active */
126 srights
= port
->ip_srights
;
132 #endif /* MACH_IPC_DEBUG */
135 * Routine: host_ipc_hash_info
137 * Return information about the global reverse hash table.
139 * Nothing locked. Obeys CountInOut protocol.
141 * KERN_SUCCESS Returned information.
142 * KERN_INVALID_HOST The host is null.
143 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
149 __unused host_t host
,
150 __unused hash_info_bucket_array_t
*infop
,
151 __unused mach_msg_type_number_t
*countp
)
159 hash_info_bucket_array_t
*infop
,
160 mach_msg_type_number_t
*countp
)
164 hash_info_bucket_t
*info
;
165 unsigned int potential
, actual
;
168 if (host
== HOST_NULL
)
169 return KERN_INVALID_HOST
;
171 /* start with in-line data */
177 actual
= ipc_hash_info(info
, potential
);
178 if (actual
<= potential
)
181 /* allocate more memory */
184 kmem_free(ipc_kernel_map
, addr
, size
);
186 size
= round_page(actual
* sizeof *info
);
187 kr
= kmem_alloc_pageable(ipc_kernel_map
, &addr
, size
);
188 if (kr
!= KERN_SUCCESS
)
189 return KERN_RESOURCE_SHORTAGE
;
191 info
= (hash_info_bucket_t
*) addr
;
192 potential
= size
/sizeof *info
;
195 if (info
== *infop
) {
196 /* data fit in-line; nothing to deallocate */
199 } else if (actual
== 0) {
200 kmem_free(ipc_kernel_map
, addr
, size
);
207 used
= round_page(actual
* sizeof *info
);
210 kmem_free(ipc_kernel_map
, addr
+ used
, size
- used
);
212 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,
213 (vm_map_size_t
)used
, TRUE
, ©
);
214 assert(kr
== KERN_SUCCESS
);
216 *infop
= (hash_info_bucket_t
*) copy
;
222 #endif /* MACH_IPC_DEBUG */
225 * Routine: mach_port_space_info
227 * Returns information about an IPC space.
229 * Nothing locked. Obeys CountInOut protocol.
231 * KERN_SUCCESS Returned information.
232 * KERN_INVALID_TASK The space is null.
233 * KERN_INVALID_TASK The space is dead.
234 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
239 mach_port_space_info(
240 __unused ipc_space_t space
,
241 __unused ipc_info_space_t
*infop
,
242 __unused ipc_info_name_array_t
*tablep
,
243 __unused mach_msg_type_number_t
*tableCntp
,
244 __unused ipc_info_tree_name_array_t
*treep
,
245 __unused mach_msg_type_number_t
*treeCntp
)
251 mach_port_space_info(
253 ipc_info_space_t
*infop
,
254 ipc_info_name_array_t
*tablep
,
255 mach_msg_type_number_t
*tableCntp
,
256 ipc_info_tree_name_array_t
*treep
,
257 mach_msg_type_number_t
*treeCntp
)
259 ipc_info_name_t
*table_info
;
260 unsigned int table_potential
, table_actual
;
261 vm_offset_t table_addr
;
262 vm_size_t table_size
;
263 ipc_info_tree_name_t
*tree_info
;
264 unsigned int tree_potential
, tree_actual
;
265 vm_offset_t tree_addr
;
267 ipc_tree_entry_t tentry
;
269 ipc_entry_num_t tsize
;
270 mach_port_index_t index
;
273 if (space
== IS_NULL
)
274 return KERN_INVALID_TASK
;
276 /* start with in-line memory */
279 table_info
= *tablep
;
280 table_potential
= *tableCntp
;
283 tree_potential
= *treeCntp
;
287 if (!space
->is_active
) {
288 is_read_unlock(space
);
289 if (table_info
!= *tablep
)
290 kmem_free(ipc_kernel_map
,
291 table_addr
, table_size
);
292 if (tree_info
!= *treep
)
293 kmem_free(ipc_kernel_map
,
294 tree_addr
, tree_size
);
295 return KERN_INVALID_TASK
;
298 table_actual
= space
->is_table_size
;
299 tree_actual
= space
->is_tree_total
;
301 if ((table_actual
<= table_potential
) &&
302 (tree_actual
<= tree_potential
))
305 is_read_unlock(space
);
307 if (table_actual
> table_potential
) {
308 if (table_info
!= *tablep
)
309 kmem_free(ipc_kernel_map
,
310 table_addr
, table_size
);
312 table_size
= round_page(table_actual
*
314 kr
= kmem_alloc(ipc_kernel_map
,
315 &table_addr
, table_size
);
316 if (kr
!= KERN_SUCCESS
) {
317 if (tree_info
!= *treep
)
318 kmem_free(ipc_kernel_map
,
319 tree_addr
, tree_size
);
321 return KERN_RESOURCE_SHORTAGE
;
324 table_info
= (ipc_info_name_t
*) table_addr
;
325 table_potential
= table_size
/sizeof *table_info
;
328 if (tree_actual
> tree_potential
) {
329 if (tree_info
!= *treep
)
330 kmem_free(ipc_kernel_map
,
331 tree_addr
, tree_size
);
333 tree_size
= round_page(tree_actual
*
335 kr
= kmem_alloc(ipc_kernel_map
,
336 &tree_addr
, tree_size
);
337 if (kr
!= KERN_SUCCESS
) {
338 if (table_info
!= *tablep
)
339 kmem_free(ipc_kernel_map
,
340 table_addr
, table_size
);
342 return KERN_RESOURCE_SHORTAGE
;
345 tree_info
= (ipc_info_tree_name_t
*) tree_addr
;
346 tree_potential
= tree_size
/sizeof *tree_info
;
349 /* space is read-locked and active; we have enough wired memory */
351 infop
->iis_genno_mask
= MACH_PORT_NGEN(MACH_PORT_DEAD
);
352 infop
->iis_table_size
= space
->is_table_size
;
353 infop
->iis_table_next
= space
->is_table_next
->its_size
;
354 infop
->iis_tree_size
= space
->is_tree_total
;
355 infop
->iis_tree_small
= space
->is_tree_small
;
356 infop
->iis_tree_hash
= space
->is_tree_hash
;
358 table
= space
->is_table
;
359 tsize
= space
->is_table_size
;
361 for (index
= 0; index
< tsize
; index
++) {
362 ipc_info_name_t
*iin
= &table_info
[index
];
363 ipc_entry_t entry
= &table
[index
];
364 ipc_entry_bits_t bits
;
366 bits
= entry
->ie_bits
;
367 iin
->iin_name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
368 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
369 iin
->iin_type
= IE_BITS_TYPE(bits
);
370 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
371 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
372 iin
->iin_next
= entry
->ie_next
;
373 iin
->iin_hash
= entry
->ie_index
;
376 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
), index
= 0;
378 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
379 ipc_info_tree_name_t
*iitn
= &tree_info
[index
++];
380 ipc_info_name_t
*iin
= &iitn
->iitn_name
;
381 ipc_entry_t entry
= &tentry
->ite_entry
;
382 ipc_entry_bits_t bits
= entry
->ie_bits
;
384 assert(IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
);
386 iin
->iin_name
= tentry
->ite_name
;
387 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
388 iin
->iin_type
= IE_BITS_TYPE(bits
);
389 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
390 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
391 iin
->iin_next
= entry
->ie_next
;
392 iin
->iin_hash
= entry
->ie_index
;
394 if (tentry
->ite_lchild
== ITE_NULL
)
395 iitn
->iitn_lchild
= MACH_PORT_NULL
;
397 iitn
->iitn_lchild
= tentry
->ite_lchild
->ite_name
;
399 if (tentry
->ite_rchild
== ITE_NULL
)
400 iitn
->iitn_rchild
= MACH_PORT_NULL
;
402 iitn
->iitn_rchild
= tentry
->ite_rchild
->ite_name
;
405 ipc_splay_traverse_finish(&space
->is_tree
);
406 is_read_unlock(space
);
408 if (table_info
== *tablep
) {
409 /* data fit in-line; nothing to deallocate */
411 *tableCntp
= table_actual
;
412 } else if (table_actual
== 0) {
413 kmem_free(ipc_kernel_map
, table_addr
, table_size
);
417 vm_size_t size_used
, rsize_used
;
420 /* kmem_alloc doesn't zero memory */
422 size_used
= table_actual
* sizeof *table_info
;
423 rsize_used
= round_page(size_used
);
425 if (rsize_used
!= table_size
)
426 kmem_free(ipc_kernel_map
,
427 table_addr
+ rsize_used
,
428 table_size
- rsize_used
);
430 if (size_used
!= rsize_used
)
431 bzero((char *) (table_addr
+ size_used
),
432 rsize_used
- size_used
);
434 kr
= vm_map_unwire(ipc_kernel_map
, vm_map_trunc_page(table_addr
),
435 vm_map_round_page(table_addr
+ rsize_used
), FALSE
);
436 assert(kr
== KERN_SUCCESS
);
438 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)table_addr
,
439 (vm_map_size_t
)rsize_used
, TRUE
, ©
);
440 assert(kr
== KERN_SUCCESS
);
442 *tablep
= (ipc_info_name_t
*) copy
;
443 *tableCntp
= table_actual
;
446 if (tree_info
== *treep
) {
447 /* data fit in-line; nothing to deallocate */
449 *treeCntp
= tree_actual
;
450 } else if (tree_actual
== 0) {
451 kmem_free(ipc_kernel_map
, tree_addr
, tree_size
);
455 vm_size_t size_used
, rsize_used
;
458 /* kmem_alloc doesn't zero memory */
460 size_used
= tree_actual
* sizeof *tree_info
;
461 rsize_used
= round_page(size_used
);
463 if (rsize_used
!= tree_size
)
464 kmem_free(ipc_kernel_map
,
465 tree_addr
+ rsize_used
,
466 tree_size
- rsize_used
);
468 if (size_used
!= rsize_used
)
469 bzero((char *) (tree_addr
+ size_used
),
470 rsize_used
- size_used
);
472 kr
= vm_map_unwire(ipc_kernel_map
, vm_map_trunc_page(tree_addr
),
473 vm_map_round_page(tree_addr
+ rsize_used
), FALSE
);
474 assert(kr
== KERN_SUCCESS
);
476 kr
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)tree_addr
,
477 (vm_map_size_t
)rsize_used
, TRUE
, ©
);
478 assert(kr
== KERN_SUCCESS
);
480 *treep
= (ipc_info_tree_name_t
*) copy
;
481 *treeCntp
= tree_actual
;
486 #endif /* MACH_IPC_DEBUG */
489 * Routine: mach_port_dnrequest_info
491 * Returns information about the dead-name requests
492 * registered with the named receive right.
496 * KERN_SUCCESS Retrieved information.
497 * KERN_INVALID_TASK The space is null.
498 * KERN_INVALID_TASK The space is dead.
499 * KERN_INVALID_NAME The name doesn't denote a right.
500 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
505 mach_port_dnrequest_info(
506 __unused ipc_space_t space
,
507 __unused mach_port_name_t name
,
508 __unused
unsigned int *totalp
,
509 __unused
unsigned int *usedp
)
515 mach_port_dnrequest_info(
517 mach_port_name_t name
,
518 unsigned int *totalp
,
521 unsigned int total
, used
;
525 if (space
== IS_NULL
)
526 return KERN_INVALID_TASK
;
528 kr
= ipc_port_translate_receive(space
, name
, &port
);
529 if (kr
!= KERN_SUCCESS
)
531 /* port is locked and active */
533 if (port
->ip_dnrequests
== IPR_NULL
) {
537 ipc_port_request_t dnrequests
= port
->ip_dnrequests
;
538 ipc_port_request_index_t index
;
540 total
= dnrequests
->ipr_size
->its_size
;
542 for (index
= 1, used
= 0;
543 index
< total
; index
++) {
544 ipc_port_request_t ipr
= &dnrequests
[index
];
546 if (ipr
->ipr_name
!= MACH_PORT_NULL
)
556 #endif /* MACH_IPC_DEBUG */
559 * Routine: mach_port_kernel_object [kernel call]
561 * Retrieve the type and address of the kernel object
562 * represented by a send or receive right.
566 * KERN_SUCCESS Retrieved kernel object info.
567 * KERN_INVALID_TASK The space is null.
568 * KERN_INVALID_TASK The space is dead.
569 * KERN_INVALID_NAME The name doesn't denote a right.
570 * KERN_INVALID_RIGHT Name doesn't denote
571 * send or receive rights.
576 mach_port_kernel_object(
577 __unused ipc_space_t space
,
578 __unused mach_port_name_t name
,
579 __unused
unsigned int *typep
,
580 __unused vm_offset_t
*addrp
)
586 mach_port_kernel_object(
588 mach_port_name_t name
,
596 kr
= ipc_right_lookup_read(space
, name
, &entry
);
597 if (kr
!= KERN_SUCCESS
)
599 /* space is read-locked and active */
601 if ((entry
->ie_bits
& MACH_PORT_TYPE_SEND_RECEIVE
) == 0) {
602 is_read_unlock(space
);
603 return KERN_INVALID_RIGHT
;
606 port
= (ipc_port_t
) entry
->ie_object
;
607 assert(port
!= IP_NULL
);
610 is_read_unlock(space
);
612 if (!ip_active(port
)) {
614 return KERN_INVALID_RIGHT
;
617 *typep
= (unsigned int) ip_kotype(port
);
618 *addrp
= (vm_offset_t
) port
->ip_kobject
;
623 #endif /* MACH_IPC_DEBUG */