2  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_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. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  32  * Mach Operating System 
  33  * Copyright (c) 1991,1990 Carnegie Mellon University 
  34  * All Rights Reserved. 
  36  * Permission to use, copy, modify and distribute this software and its 
  37  * documentation is hereby granted, provided that both the copyright 
  38  * notice and this permission notice appear in all copies of the 
  39  * software, derivative works or modified versions, and any portions 
  40  * thereof, and that both notices appear in supporting documentation. 
  42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
  43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 
  44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 
  46  * Carnegie Mellon requests users of this software to return to 
  48  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU 
  49  *  School of Computer Science 
  50  *  Carnegie Mellon University 
  51  *  Pittsburgh PA 15213-3890 
  53  * any improvements or extensions that they make and grant Carnegie Mellon 
  54  * the rights to redistribute these changes. 
  59  *      File:   ipc/mach_debug.c 
  63  *      Exported IPC debug calls. 
  65 #include <mach_ipc_debug.h> 
  67 #include <mach/vm_param.h> 
  68 #include <mach/kern_return.h> 
  69 #include <mach/machine/vm_types.h> 
  70 #include <mach/mach_host_server.h> 
  71 #include <mach/mach_port_server.h> 
  72 #include <mach_debug/ipc_info.h> 
  73 #include <mach_debug/hash_info.h> 
  76 #include <kern/host.h> 
  77 #include <kern/misc_protos.h> 
  78 #include <vm/vm_map.h> 
  79 #include <vm/vm_kern.h> 
  81 #include <ipc/ipc_types.h> 
  82 #include <ipc/ipc_space.h> 
  83 #include <ipc/ipc_port.h> 
  84 #include <ipc/ipc_hash.h> 
  85 #include <ipc/ipc_table.h> 
  86 #include <ipc/ipc_right.h> 
  90  *      Routine:        mach_port_get_srights [kernel call] 
  92  *              Retrieve the number of extant send rights 
  93  *              that a receive right has. 
  97  *              KERN_SUCCESS            Retrieved number of send rights. 
  98  *              KERN_INVALID_TASK       The space is null. 
  99  *              KERN_INVALID_TASK       The space is dead. 
 100  *              KERN_INVALID_NAME       The name doesn't denote a right. 
 101  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights. 
 106 mach_port_get_srights( 
 107         __unused ipc_space_t            space
, 
 108         __unused mach_port_name_t       name
, 
 109         __unused mach_port_rights_t     
*srightsp
) 
 115 mach_port_get_srights( 
 117         mach_port_name_t        name
, 
 118         mach_port_rights_t      
*srightsp
) 
 122         mach_port_rights_t srights
; 
 124         if (space 
== IS_NULL
) 
 125                 return KERN_INVALID_TASK
; 
 127         kr 
= ipc_port_translate_receive(space
, name
, &port
); 
 128         if (kr 
!= KERN_SUCCESS
) 
 130         /* port is locked and active */ 
 132         srights 
= port
->ip_srights
; 
 138 #endif /* MACH_IPC_DEBUG */ 
 141  *      Routine:        host_ipc_hash_info 
 143  *              Return information about the global reverse hash table. 
 145  *              Nothing locked.  Obeys CountInOut protocol. 
 147  *              KERN_SUCCESS            Returned information. 
 148  *              KERN_INVALID_HOST       The host is null. 
 149  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory. 
 155         __unused host_t                 host
, 
 156         __unused hash_info_bucket_array_t       
*infop
, 
 157         __unused mach_msg_type_number_t         
*countp
) 
 165         hash_info_bucket_array_t                
*infop
, 
 166         mach_msg_type_number_t          
*countp
) 
 171         hash_info_bucket_t 
*info
; 
 175         if (host 
== HOST_NULL
) 
 176                 return KERN_INVALID_HOST
; 
 178         /* start with in-line data */ 
 180         count 
= ipc_hash_size(); 
 181         size 
= round_page(count 
* sizeof(hash_info_bucket_t
)); 
 182         kr 
= kmem_alloc_pageable(ipc_kernel_map
, &addr
, size
); 
 183         if (kr 
!= KERN_SUCCESS
) 
 184                 return KERN_RESOURCE_SHORTAGE
; 
 186         info 
= (hash_info_bucket_t 
*) addr
; 
 187         count 
= ipc_hash_info(info
, count
); 
 189         if (size 
> count 
* sizeof(hash_info_bucket_t
)) 
 190                 bzero((char *)&info
[count
], size 
- count 
* sizeof(hash_info_bucket_t
)); 
 192         kr 
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)addr
,  
 193                            (vm_map_size_t
)size
, TRUE
, ©
); 
 194         assert(kr 
== KERN_SUCCESS
); 
 196         *infop 
= (hash_info_bucket_t 
*) copy
; 
 200 #endif /* MACH_IPC_DEBUG */ 
 203  *      Routine:        mach_port_space_info 
 205  *              Returns information about an IPC space. 
 207  *              Nothing locked.  Obeys CountInOut protocol. 
 209  *              KERN_SUCCESS            Returned information. 
 210  *              KERN_INVALID_TASK       The space is null. 
 211  *              KERN_INVALID_TASK       The space is dead. 
 212  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory. 
 217 mach_port_space_info( 
 218         __unused ipc_space_t                    space
, 
 219         __unused ipc_info_space_t               
*infop
, 
 220         __unused ipc_info_name_array_t  
*tablep
, 
 221         __unused mach_msg_type_number_t         
*tableCntp
, 
 222         __unused ipc_info_tree_name_array_t 
*treep
, 
 223         __unused mach_msg_type_number_t         
*treeCntp
) 
 229 mach_port_space_info( 
 231         ipc_info_space_t                
*infop
, 
 232         ipc_info_name_array_t           
*tablep
, 
 233         mach_msg_type_number_t          
*tableCntp
, 
 234         ipc_info_tree_name_array_t      
*treep
, 
 235         mach_msg_type_number_t          
*treeCntp
) 
 237         ipc_info_name_t 
*table_info
; 
 238         vm_offset_t table_addr
; 
 239         vm_size_t table_size
, table_size_needed
; 
 240         ipc_info_tree_name_t 
*tree_info
; 
 241         vm_offset_t tree_addr
; 
 242         vm_size_t tree_size
, tree_size_needed
; 
 243         ipc_tree_entry_t tentry
; 
 245         ipc_entry_num_t tsize
; 
 246         mach_port_index_t index
; 
 251         if (space 
== IS_NULL
) 
 252                 return KERN_INVALID_TASK
; 
 254         /* start with in-line memory */ 
 261                 if (!space
->is_active
) { 
 262                         is_read_unlock(space
); 
 264                                 kmem_free(ipc_kernel_map
, 
 265                                           table_addr
, table_size
); 
 267                                 kmem_free(ipc_kernel_map
, 
 268                                           tree_addr
, tree_size
); 
 269                         return KERN_INVALID_TASK
; 
 272                 table_size_needed 
= round_page(space
->is_table_size
 
 273                                                * sizeof(ipc_info_name_t
)); 
 274                 tree_size_needed 
= round_page(space
->is_tree_total
 
 275                                               * sizeof(ipc_info_tree_name_t
)); 
 277                 if ((table_size_needed 
== table_size
) && 
 278                     (tree_size_needed 
== tree_size
)) 
 281                 is_read_unlock(space
); 
 283                 if (table_size 
!= table_size_needed
) { 
 285                                 kmem_free(ipc_kernel_map
, table_addr
, table_size
); 
 286                         kr 
= kmem_alloc(ipc_kernel_map
, &table_addr
, table_size_needed
); 
 287                         if (kr 
!= KERN_SUCCESS
) { 
 289                                         kmem_free(ipc_kernel_map
, tree_addr
, tree_size
); 
 290                                 return KERN_RESOURCE_SHORTAGE
; 
 292                         table_size 
= table_size_needed
; 
 294                 if (tree_size 
!= tree_size_needed
) { 
 296                                 kmem_free(ipc_kernel_map
, tree_addr
, tree_size
); 
 297                         kr 
= kmem_alloc(ipc_kernel_map
, &tree_addr
, tree_size_needed
); 
 298                         if (kr 
!= KERN_SUCCESS
) { 
 300                                         kmem_free(ipc_kernel_map
, table_addr
, table_size
); 
 301                                 return KERN_RESOURCE_SHORTAGE
; 
 303                         tree_size 
= tree_size_needed
; 
 306         /* space is read-locked and active; we have enough wired memory */ 
 308         /* get the overall space info */ 
 309         infop
->iis_genno_mask 
= MACH_PORT_NGEN(MACH_PORT_DEAD
); 
 310         infop
->iis_table_size 
= space
->is_table_size
; 
 311         infop
->iis_table_next 
= space
->is_table_next
->its_size
; 
 312         infop
->iis_tree_size 
= space
->is_tree_total
; 
 313         infop
->iis_tree_small 
= space
->is_tree_small
; 
 314         infop
->iis_tree_hash 
= space
->is_tree_hash
; 
 316         /* walk the table for this space */ 
 317         table 
= space
->is_table
; 
 318         tsize 
= space
->is_table_size
; 
 319         table_info 
= (ipc_info_name_array_t
)table_addr
; 
 320         for (index 
= 0; index 
< tsize
; index
++) { 
 321                 ipc_info_name_t 
*iin 
= &table_info
[index
]; 
 322                 ipc_entry_t entry 
= &table
[index
]; 
 323                 ipc_entry_bits_t bits
; 
 325                 bits 
= entry
->ie_bits
; 
 326                 iin
->iin_name 
= MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)); 
 327                 iin
->iin_collision 
= (bits 
& IE_BITS_COLLISION
) ? TRUE 
: FALSE
; 
 328                 iin
->iin_type 
= IE_BITS_TYPE(bits
); 
 329                 if (entry
->ie_request
) 
 330                         iin
->iin_type 
|= MACH_PORT_TYPE_DNREQUEST
; 
 331                 iin
->iin_urefs 
= IE_BITS_UREFS(bits
); 
 332                 iin
->iin_object 
= (natural_t
)(uintptr_t)entry
->ie_object
; 
 333                 iin
->iin_next 
= entry
->ie_next
; 
 334                 iin
->iin_hash 
= entry
->ie_index
; 
 337         /* walk the splay tree for this space */ 
 338         tree_info 
= (ipc_info_tree_name_array_t
)tree_addr
; 
 339         for (tentry 
= ipc_splay_traverse_start(&space
->is_tree
), index 
= 0; 
 341              tentry 
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) { 
 342                 ipc_info_tree_name_t 
*iitn 
= &tree_info
[index
++]; 
 343                 ipc_info_name_t 
*iin 
= &iitn
->iitn_name
; 
 344                 ipc_entry_t entry 
= &tentry
->ite_entry
; 
 345                 ipc_entry_bits_t bits 
= entry
->ie_bits
; 
 347                 assert(IE_BITS_TYPE(bits
) != MACH_PORT_TYPE_NONE
); 
 349                 iin
->iin_name 
= tentry
->ite_name
; 
 350                 iin
->iin_collision 
= (bits 
& IE_BITS_COLLISION
) ? TRUE 
: FALSE
; 
 351                 iin
->iin_type 
= IE_BITS_TYPE(bits
); 
 352                 if (entry
->ie_request
) 
 353                         iin
->iin_type 
|= MACH_PORT_TYPE_DNREQUEST
; 
 354                 iin
->iin_urefs 
= IE_BITS_UREFS(bits
); 
 355                 iin
->iin_object 
= (natural_t
)(uintptr_t)entry
->ie_object
; 
 356                 iin
->iin_next 
= entry
->ie_next
; 
 357                 iin
->iin_hash 
= entry
->ie_index
; 
 359                 if (tentry
->ite_lchild 
== ITE_NULL
) 
 360                         iitn
->iitn_lchild 
= MACH_PORT_NULL
; 
 362                         iitn
->iitn_lchild 
= tentry
->ite_lchild
->ite_name
; 
 364                 if (tentry
->ite_rchild 
== ITE_NULL
) 
 365                         iitn
->iitn_rchild 
= MACH_PORT_NULL
; 
 367                         iitn
->iitn_rchild 
= tentry
->ite_rchild
->ite_name
; 
 370         ipc_splay_traverse_finish(&space
->is_tree
); 
 371         is_read_unlock(space
); 
 373         /* prepare the table out-of-line data for return */ 
 374         if (table_size 
> 0) { 
 375                 if (table_size 
> infop
->iis_table_size 
* sizeof(ipc_info_name_t
)) 
 376                         bzero((char *)&table_info
[infop
->iis_table_size
], 
 377                               table_size 
- infop
->iis_table_size 
* sizeof(ipc_info_name_t
)); 
 379                 kr 
= vm_map_unwire(ipc_kernel_map
, vm_map_trunc_page(table_addr
), 
 380                                    vm_map_round_page(table_addr 
+ table_size
), FALSE
); 
 381                 assert(kr 
== KERN_SUCCESS
); 
 382                 kr 
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)table_addr
,  
 383                                    (vm_map_size_t
)table_size
, TRUE
, ©
); 
 384                 assert(kr 
== KERN_SUCCESS
); 
 385                 *tablep 
= (ipc_info_name_t 
*)copy
; 
 386                 *tableCntp 
= infop
->iis_table_size
; 
 388                 *tablep 
= (ipc_info_name_t 
*)0; 
 392         /* prepare the tree out-of-line data for return */ 
 394                 if (tree_size 
> infop
->iis_tree_size 
* sizeof(ipc_info_tree_name_t
)) 
 395                         bzero((char *)&tree_info
[infop
->iis_tree_size
], 
 396                               tree_size 
- infop
->iis_tree_size 
* sizeof(ipc_info_tree_name_t
)); 
 398                 kr 
= vm_map_unwire(ipc_kernel_map
, vm_map_trunc_page(tree_addr
), 
 399                                    vm_map_round_page(tree_addr 
+ tree_size
), FALSE
); 
 400                 assert(kr 
== KERN_SUCCESS
); 
 401                 kr 
= vm_map_copyin(ipc_kernel_map
, (vm_map_address_t
)tree_addr
,  
 402                                    (vm_map_size_t
)tree_size
, TRUE
, ©
); 
 403                 assert(kr 
== KERN_SUCCESS
); 
 404                 *treep 
= (ipc_info_tree_name_t 
*)copy
; 
 405                 *treeCntp 
= infop
->iis_tree_size
; 
 407                 *treep 
= (ipc_info_tree_name_t 
*)0; 
 412 #endif /* MACH_IPC_DEBUG */ 
 415  *      Routine:        mach_port_dnrequest_info 
 417  *              Returns information about the dead-name requests 
 418  *              registered with the named receive right. 
 422  *              KERN_SUCCESS            Retrieved information. 
 423  *              KERN_INVALID_TASK       The space is null. 
 424  *              KERN_INVALID_TASK       The space is dead. 
 425  *              KERN_INVALID_NAME       The name doesn't denote a right. 
 426  *              KERN_INVALID_RIGHT      Name doesn't denote receive rights. 
 431 mach_port_dnrequest_info( 
 432         __unused ipc_space_t            space
, 
 433         __unused mach_port_name_t       name
, 
 434         __unused 
unsigned int   *totalp
, 
 435         __unused 
unsigned int   *usedp
) 
 441 mach_port_dnrequest_info( 
 443         mach_port_name_t                name
, 
 444         unsigned int                    *totalp
, 
 447         unsigned int total
, used
; 
 451         if (space 
== IS_NULL
) 
 452                 return KERN_INVALID_TASK
; 
 454         kr 
= ipc_port_translate_receive(space
, name
, &port
); 
 455         if (kr 
!= KERN_SUCCESS
) 
 457         /* port is locked and active */ 
 459         if (port
->ip_dnrequests 
== IPR_NULL
) { 
 463                 ipc_port_request_t dnrequests 
= port
->ip_dnrequests
; 
 464                 ipc_port_request_index_t index
; 
 466                 total 
= dnrequests
->ipr_size
->its_size
; 
 468                 for (index 
= 1, used 
= 0; 
 469                      index 
< total
; index
++) { 
 470                         ipc_port_request_t ipr 
= &dnrequests
[index
]; 
 472                         if (ipr
->ipr_name 
!= MACH_PORT_NULL
) 
 482 #endif /* MACH_IPC_DEBUG */ 
 485  *      Routine:        mach_port_kobject [kernel call] 
 487  *              Retrieve the type and address of the kernel object 
 488  *              represented by a send or receive right. Returns 
 489  *              the kernel address in a mach_vm_address_t to 
 490  *              mask potential differences in kernel address space 
 495  *              KERN_SUCCESS            Retrieved kernel object info. 
 496  *              KERN_INVALID_TASK       The space is null. 
 497  *              KERN_INVALID_TASK       The space is dead. 
 498  *              KERN_INVALID_NAME       The name doesn't denote a right. 
 499  *              KERN_INVALID_RIGHT      Name doesn't denote 
 500  *                                      send or receive rights. 
 506         __unused ipc_space_t            space
, 
 507         __unused mach_port_name_t       name
, 
 508         __unused natural_t              
*typep
, 
 509         __unused mach_vm_address_t      
*addrp
) 
 517         mach_port_name_t                name
, 
 519         mach_vm_address_t               
*addrp
) 
 525         if (space 
== IS_NULL
) 
 526                 return KERN_INVALID_TASK
; 
 528         kr 
= ipc_right_lookup_read(space
, name
, &entry
); 
 529         if (kr 
!= KERN_SUCCESS
) 
 531         /* space is read-locked and active */ 
 533         if ((entry
->ie_bits 
& MACH_PORT_TYPE_SEND_RECEIVE
) == 0) { 
 534                 is_read_unlock(space
); 
 535                 return KERN_INVALID_RIGHT
; 
 538         port 
= (ipc_port_t
) entry
->ie_object
; 
 539         assert(port 
!= IP_NULL
); 
 542         is_read_unlock(space
); 
 544         if (!ip_active(port
)) { 
 546                 return KERN_INVALID_RIGHT
; 
 549         *typep 
= (unsigned int) ip_kotype(port
); 
 550         *addrp 
= (mach_vm_address_t
)port
->ip_kobject
; 
 555 #endif /* MACH_IPC_DEBUG */ 
 557  *      Routine:        mach_port_kernel_object [Legacy kernel call] 
 559  *              Retrieve the type and address of the kernel object 
 560  *              represented by a send or receive right. Hard-coded 
 561  *              to return only the low-order 32-bits of the kernel 
 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 
unsigned int           *addrp
) 
 586 mach_port_kernel_object( 
 588         mach_port_name_t                name
, 
 592         mach_vm_address_t addr 
= 0; 
 595         kr 
= mach_port_kobject(space
, name
, typep
, &addr
); 
 596         *addrp 
= (unsigned int) addr
; 
 599 #endif /* MACH_IPC_DEBUG */