2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
56 * File: ipc/mach_debug.c
60 * Exported IPC debug calls.
62 #include <mach_ipc_debug.h>
64 #include <mach/vm_param.h>
65 #include <mach/kern_return.h>
66 #include <mach/machine/vm_types.h>
67 #include <mach/mach_host_server.h>
68 #include <mach/mach_port_server.h>
69 #include <mach_debug/ipc_info.h>
70 #include <mach_debug/hash_info.h>
73 #include <kern/host.h>
74 #include <kern/misc_protos.h>
75 #include <vm/vm_map.h>
76 #include <vm/vm_kern.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.
100 mach_port_get_srights(
102 mach_port_name_t name
,
103 mach_port_rights_t
*srightsp
)
110 mach_port_rights_t srights
;
112 if (space
== IS_NULL
)
113 return KERN_INVALID_TASK
;
115 kr
= ipc_port_translate_receive(space
, name
, &port
);
116 if (kr
!= KERN_SUCCESS
)
118 /* port is locked and active */
120 srights
= port
->ip_srights
;
125 #endif /* MACH_IPC_DEBUG */
129 * Routine: host_ipc_hash_info
131 * Return information about the global reverse hash table.
133 * Nothing locked. Obeys CountInOut protocol.
135 * KERN_SUCCESS Returned information.
136 * KERN_INVALID_HOST The host is null.
137 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
143 hash_info_bucket_array_t
*infop
,
144 mach_msg_type_number_t
*countp
)
151 hash_info_bucket_t
*info
;
152 unsigned int potential
, actual
;
155 if (host
== HOST_NULL
)
156 return KERN_INVALID_HOST
;
158 /* start with in-line data */
164 actual
= ipc_hash_info(info
, potential
);
165 if (actual
<= potential
)
168 /* allocate more memory */
171 kmem_free(ipc_kernel_map
, addr
, size
);
173 size
= round_page_32(actual
* sizeof *info
);
174 kr
= kmem_alloc_pageable(ipc_kernel_map
, &addr
, size
);
175 if (kr
!= KERN_SUCCESS
)
176 return KERN_RESOURCE_SHORTAGE
;
178 info
= (hash_info_bucket_t
*) addr
;
179 potential
= size
/sizeof *info
;
182 if (info
== *infop
) {
183 /* data fit in-line; nothing to deallocate */
186 } else if (actual
== 0) {
187 kmem_free(ipc_kernel_map
, addr
, size
);
194 used
= round_page_32(actual
* sizeof *info
);
197 kmem_free(ipc_kernel_map
, addr
+ used
, size
- used
);
199 kr
= vm_map_copyin(ipc_kernel_map
, addr
, used
,
201 assert(kr
== KERN_SUCCESS
);
203 *infop
= (hash_info_bucket_t
*) copy
;
208 #endif /* MACH_IPC_DEBUG */
212 * Routine: mach_port_space_info
214 * Returns information about an IPC space.
216 * Nothing locked. Obeys CountInOut protocol.
218 * KERN_SUCCESS Returned information.
219 * KERN_INVALID_TASK The space is null.
220 * KERN_INVALID_TASK The space is dead.
221 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
225 mach_port_space_info(
227 ipc_info_space_t
*infop
,
228 ipc_info_name_array_t
*tablep
,
229 mach_msg_type_number_t
*tableCntp
,
230 ipc_info_tree_name_array_t
*treep
,
231 mach_msg_type_number_t
*treeCntp
)
236 ipc_info_name_t
*table_info
;
237 unsigned int table_potential
, table_actual
;
238 vm_offset_t table_addr
;
239 vm_size_t table_size
;
240 ipc_info_tree_name_t
*tree_info
;
241 unsigned int tree_potential
, tree_actual
;
242 vm_offset_t tree_addr
;
244 ipc_tree_entry_t tentry
;
246 ipc_entry_num_t tsize
;
247 mach_port_index_t index
;
249 ipc_entry_bits_t
*capability
;
251 if (space
== IS_NULL
)
252 return KERN_INVALID_TASK
;
254 /* start with in-line memory */
256 table_info
= *tablep
;
257 table_potential
= *tableCntp
;
259 tree_potential
= *treeCntp
;
263 if (!space
->is_active
) {
264 is_read_unlock(space
);
265 if (table_info
!= *tablep
)
266 kmem_free(ipc_kernel_map
,
267 table_addr
, table_size
);
268 if (tree_info
!= *treep
)
269 kmem_free(ipc_kernel_map
,
270 tree_addr
, tree_size
);
271 return KERN_INVALID_TASK
;
274 table_actual
= space
->is_table_size
;
275 tree_actual
= space
->is_tree_total
;
277 if ((table_actual
<= table_potential
) &&
278 (tree_actual
<= tree_potential
))
281 is_read_unlock(space
);
283 if (table_actual
> table_potential
) {
284 if (table_info
!= *tablep
)
285 kmem_free(ipc_kernel_map
,
286 table_addr
, table_size
);
288 table_size
= round_page_32(table_actual
*
290 kr
= kmem_alloc(ipc_kernel_map
,
291 &table_addr
, table_size
);
292 if (kr
!= KERN_SUCCESS
) {
293 if (tree_info
!= *treep
)
294 kmem_free(ipc_kernel_map
,
295 tree_addr
, tree_size
);
297 return KERN_RESOURCE_SHORTAGE
;
300 table_info
= (ipc_info_name_t
*) table_addr
;
301 table_potential
= table_size
/sizeof *table_info
;
304 if (tree_actual
> tree_potential
) {
305 if (tree_info
!= *treep
)
306 kmem_free(ipc_kernel_map
,
307 tree_addr
, tree_size
);
309 tree_size
= round_page_32(tree_actual
*
311 kr
= kmem_alloc(ipc_kernel_map
,
312 &tree_addr
, tree_size
);
313 if (kr
!= KERN_SUCCESS
) {
314 if (table_info
!= *tablep
)
315 kmem_free(ipc_kernel_map
,
316 table_addr
, table_size
);
318 return KERN_RESOURCE_SHORTAGE
;
321 tree_info
= (ipc_info_tree_name_t
*) tree_addr
;
322 tree_potential
= tree_size
/sizeof *tree_info
;
325 /* space is read-locked and active; we have enough wired memory */
327 infop
->iis_genno_mask
= MACH_PORT_NGEN(MACH_PORT_DEAD
);
328 infop
->iis_table_size
= space
->is_table_size
;
329 infop
->iis_table_next
= space
->is_table_next
->its_size
;
330 infop
->iis_tree_size
= space
->is_tree_total
;
331 infop
->iis_tree_small
= space
->is_tree_small
;
332 infop
->iis_tree_hash
= space
->is_tree_hash
;
334 table
= space
->is_table
;
335 tsize
= space
->is_table_size
;
337 for (index
= 0; index
< tsize
; index
++) {
338 ipc_info_name_t
*iin
= &table_info
[index
];
339 ipc_entry_t entry
= &table
[index
];
340 ipc_entry_bits_t bits
;
342 bits
= entry
->ie_bits
;
343 iin
->iin_name
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
));
344 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
345 iin
->iin_type
= IE_BITS_TYPE(bits
);
346 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
347 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
348 iin
->iin_next
= entry
->ie_next
;
349 iin
->iin_hash
= entry
->ie_index
;
352 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
), index
= 0;
354 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
355 ipc_info_tree_name_t
*iitn
= &tree_info
[index
++];
356 ipc_info_name_t
*iin
= &iitn
->iitn_name
;
357 ipc_entry_t entry
= &tentry
->ite_entry
;
358 ipc_entry_bits_t bits
= entry
->ie_bits
;
360 assert(IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
);
362 iin
->iin_name
= tentry
->ite_name
;
363 iin
->iin_collision
= (bits
& IE_BITS_COLLISION
) ? TRUE
: FALSE
;
364 iin
->iin_type
= IE_BITS_TYPE(bits
);
365 iin
->iin_urefs
= IE_BITS_UREFS(bits
);
366 iin
->iin_object
= (vm_offset_t
) entry
->ie_object
;
367 iin
->iin_next
= entry
->ie_next
;
368 iin
->iin_hash
= entry
->ie_index
;
370 if (tentry
->ite_lchild
== ITE_NULL
)
371 iitn
->iitn_lchild
= MACH_PORT_NULL
;
373 iitn
->iitn_lchild
= tentry
->ite_lchild
->ite_name
;
375 if (tentry
->ite_rchild
== ITE_NULL
)
376 iitn
->iitn_rchild
= MACH_PORT_NULL
;
378 iitn
->iitn_rchild
= tentry
->ite_rchild
->ite_name
;
381 ipc_splay_traverse_finish(&space
->is_tree
);
382 is_read_unlock(space
);
384 if (table_info
== *tablep
) {
385 /* data fit in-line; nothing to deallocate */
387 *tableCntp
= table_actual
;
388 } else if (table_actual
== 0) {
389 kmem_free(ipc_kernel_map
, table_addr
, table_size
);
393 vm_size_t size_used
, rsize_used
;
396 /* kmem_alloc doesn't zero memory */
398 size_used
= table_actual
* sizeof *table_info
;
399 rsize_used
= round_page_32(size_used
);
401 if (rsize_used
!= table_size
)
402 kmem_free(ipc_kernel_map
,
403 table_addr
+ rsize_used
,
404 table_size
- rsize_used
);
406 if (size_used
!= rsize_used
)
407 bzero((char *) (table_addr
+ size_used
),
408 rsize_used
- size_used
);
410 kr
= vm_map_unwire(ipc_kernel_map
, table_addr
,
411 table_addr
+ rsize_used
, FALSE
);
412 assert(kr
== KERN_SUCCESS
);
414 kr
= vm_map_copyin(ipc_kernel_map
, table_addr
, rsize_used
,
416 assert(kr
== KERN_SUCCESS
);
418 *tablep
= (ipc_info_name_t
*) copy
;
419 *tableCntp
= table_actual
;
422 if (tree_info
== *treep
) {
423 /* data fit in-line; nothing to deallocate */
425 *treeCntp
= tree_actual
;
426 } else if (tree_actual
== 0) {
427 kmem_free(ipc_kernel_map
, tree_addr
, tree_size
);
431 vm_size_t size_used
, rsize_used
;
434 /* kmem_alloc doesn't zero memory */
436 size_used
= tree_actual
* sizeof *tree_info
;
437 rsize_used
= round_page_32(size_used
);
439 if (rsize_used
!= tree_size
)
440 kmem_free(ipc_kernel_map
,
441 tree_addr
+ rsize_used
,
442 tree_size
- rsize_used
);
444 if (size_used
!= rsize_used
)
445 bzero((char *) (tree_addr
+ size_used
),
446 rsize_used
- size_used
);
448 kr
= vm_map_unwire(ipc_kernel_map
, tree_addr
,
449 tree_addr
+ rsize_used
, FALSE
);
450 assert(kr
== KERN_SUCCESS
);
452 kr
= vm_map_copyin(ipc_kernel_map
, tree_addr
, rsize_used
,
454 assert(kr
== KERN_SUCCESS
);
456 *treep
= (ipc_info_tree_name_t
*) copy
;
457 *treeCntp
= tree_actual
;
461 #endif /* MACH_IPC_DEBUG */
465 * Routine: mach_port_dnrequest_info
467 * Returns information about the dead-name requests
468 * registered with the named receive right.
472 * KERN_SUCCESS Retrieved information.
473 * KERN_INVALID_TASK The space is null.
474 * KERN_INVALID_TASK The space is dead.
475 * KERN_INVALID_NAME The name doesn't denote a right.
476 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
480 mach_port_dnrequest_info(
482 mach_port_name_t name
,
483 unsigned int *totalp
,
489 unsigned int total
, used
;
493 if (space
== IS_NULL
)
494 return KERN_INVALID_TASK
;
496 kr
= ipc_port_translate_receive(space
, name
, &port
);
497 if (kr
!= KERN_SUCCESS
)
499 /* port is locked and active */
501 if (port
->ip_dnrequests
== IPR_NULL
) {
505 ipc_port_request_t dnrequests
= port
->ip_dnrequests
;
506 ipc_port_request_index_t index
;
508 total
= dnrequests
->ipr_size
->its_size
;
510 for (index
= 1, used
= 0;
511 index
< total
; index
++) {
512 ipc_port_request_t ipr
= &dnrequests
[index
];
514 if (ipr
->ipr_name
!= MACH_PORT_NULL
)
523 #endif /* MACH_IPC_DEBUG */
527 * Routine: mach_port_kernel_object [kernel call]
529 * Retrieve the type and address of the kernel object
530 * represented by a send or receive right.
534 * KERN_SUCCESS Retrieved kernel object info.
535 * KERN_INVALID_TASK The space is null.
536 * KERN_INVALID_TASK The space is dead.
537 * KERN_INVALID_NAME The name doesn't denote a right.
538 * KERN_INVALID_RIGHT Name doesn't denote
539 * send or receive rights.
543 mach_port_kernel_object(
545 mach_port_name_t name
,
556 kr
= ipc_right_lookup_read(space
, name
, &entry
);
557 if (kr
!= KERN_SUCCESS
)
559 /* space is read-locked and active */
561 if ((entry
->ie_bits
& MACH_PORT_TYPE_SEND_RECEIVE
) == 0) {
562 is_read_unlock(space
);
563 return KERN_INVALID_RIGHT
;
566 port
= (ipc_port_t
) entry
->ie_object
;
567 assert(port
!= IP_NULL
);
570 is_read_unlock(space
);
572 if (!ip_active(port
)) {
574 return KERN_INVALID_RIGHT
;
577 *typep
= (unsigned int) ip_kotype(port
);
578 *addrp
= (vm_offset_t
) port
->ip_kobject
;
582 #endif /* MACH_IPC_DEBUG */