1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990 Carnegie Mellon University 34 * All Rights Reserved. 35 * 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. 41 * 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. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 57 */ 58/* 59 * File: ipc/mach_debug.c 60 * Author: Rich Draves 61 * Date: 1989 62 * 63 * Exported IPC debug calls. 64 */ 65#include <mach_ipc_debug.h> 66 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> 74 75#if MACH_IPC_DEBUG 76#include <kern/host.h> 77#include <kern/misc_protos.h> 78#include <vm/vm_map.h> 79#include <vm/vm_kern.h> 80#include <ipc/port.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> 87#endif 88 89/* 90 * Routine: mach_port_get_srights [kernel call] 91 * Purpose: 92 * Retrieve the number of extant send rights 93 * that a receive right has. 94 * Conditions: 95 * Nothing locked. 96 * Returns: 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. 102 */ 103 104#if !MACH_IPC_DEBUG 105kern_return_t 106mach_port_get_srights( 107 __unused ipc_space_t space, 108 __unused mach_port_name_t name, 109 __unused mach_port_rights_t *srightsp) 110{ 111 return KERN_FAILURE; 112} 113#else 114kern_return_t 115mach_port_get_srights( 116 ipc_space_t space, 117 mach_port_name_t name, 118 mach_port_rights_t *srightsp) 119{ 120 ipc_port_t port; 121 kern_return_t kr; 122 mach_port_rights_t srights; 123 124 if (space == IS_NULL) 125 return KERN_INVALID_TASK; 126 127 kr = ipc_port_translate_receive(space, name, &port); 128 if (kr != KERN_SUCCESS) 129 return kr; 130 /* port is locked and active */ 131 132 srights = port->ip_srights; 133 ip_unlock(port); 134 135 *srightsp = srights; 136 return KERN_SUCCESS; 137} 138#endif /* MACH_IPC_DEBUG */ 139 140/* 141 * Routine: host_ipc_hash_info 142 * Purpose: 143 * Return information about the global reverse hash table. 144 * Conditions: 145 * Nothing locked. Obeys CountInOut protocol. 146 * Returns: 147 * KERN_SUCCESS Returned information. 148 * KERN_INVALID_HOST The host is null. 149 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 150 */ 151 152#if !MACH_IPC_DEBUG 153kern_return_t 154host_ipc_hash_info( 155 __unused host_t host, 156 __unused hash_info_bucket_array_t *infop, 157 __unused mach_msg_type_number_t *countp) 158{ 159 return KERN_FAILURE; 160} 161#else 162kern_return_t 163host_ipc_hash_info( 164 host_t host, 165 hash_info_bucket_array_t *infop, 166 mach_msg_type_number_t *countp) 167{ 168 vm_map_copy_t copy; 169 vm_offset_t addr; 170 vm_size_t size; 171 hash_info_bucket_t *info; 172 natural_t count; 173 kern_return_t kr; 174 175 if (host == HOST_NULL) 176 return KERN_INVALID_HOST; 177 178 /* start with in-line data */ 179 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; 185 186 info = (hash_info_bucket_t *) addr; 187 count = ipc_hash_info(info, count); 188 189 if (size > count * sizeof(hash_info_bucket_t)) 190 bzero((char *)&info[count], size - count * sizeof(hash_info_bucket_t)); 191 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); 195 196 *infop = (hash_info_bucket_t *) copy; 197 *countp = count; 198 return KERN_SUCCESS; 199} 200#endif /* MACH_IPC_DEBUG */ 201 202/* 203 * Routine: mach_port_space_info 204 * Purpose: 205 * Returns information about an IPC space. 206 * Conditions: 207 * Nothing locked. Obeys CountInOut protocol. 208 * Returns: 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. 213 */ 214 215#if !MACH_IPC_DEBUG 216kern_return_t 217mach_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) 224{ 225 return KERN_FAILURE; 226} 227#else 228kern_return_t 229mach_port_space_info( 230 ipc_space_t space, 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) 236{ 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; 244 ipc_entry_t table; 245 ipc_entry_num_t tsize; 246 mach_port_index_t index; 247 kern_return_t kr; 248 vm_map_copy_t copy; 249 250 251 if (space == IS_NULL) 252 return KERN_INVALID_TASK; 253 254 /* start with in-line memory */ 255 256 table_size = 0; 257 tree_size = 0; 258 259 for (;;) { 260 is_read_lock(space); 261 if (!space->is_active) { 262 is_read_unlock(space); 263 if (table_size != 0) 264 kmem_free(ipc_kernel_map, 265 table_addr, table_size); 266 if (tree_size != 0) 267 kmem_free(ipc_kernel_map, 268 tree_addr, tree_size); 269 return KERN_INVALID_TASK; 270 } 271 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)); 276 277 if ((table_size_needed == table_size) && 278 (tree_size_needed == tree_size)) 279 break; 280 281 is_read_unlock(space); 282 283 if (table_size != table_size_needed) { 284 if (table_size != 0) 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) { 288 if (tree_size != 0) 289 kmem_free(ipc_kernel_map, tree_addr, tree_size); 290 return KERN_RESOURCE_SHORTAGE; 291 } 292 table_size = table_size_needed; 293 } 294 if (tree_size != tree_size_needed) { 295 if (tree_size != 0) 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) { 299 if (table_size != 0) 300 kmem_free(ipc_kernel_map, table_addr, table_size); 301 return KERN_RESOURCE_SHORTAGE; 302 } 303 tree_size = tree_size_needed; 304 } 305 } 306 /* space is read-locked and active; we have enough wired memory */ 307 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; 315 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; 324 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 = (vm_offset_t) entry->ie_object; 333 iin->iin_next = entry->ie_next; 334 iin->iin_hash = entry->ie_index; 335 } 336 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; 340 tentry != ITE_NULL; 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; 346 347 assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); 348 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 = (vm_offset_t) entry->ie_object; 356 iin->iin_next = entry->ie_next; 357 iin->iin_hash = entry->ie_index; 358 359 if (tentry->ite_lchild == ITE_NULL) 360 iitn->iitn_lchild = MACH_PORT_NULL; 361 else 362 iitn->iitn_lchild = tentry->ite_lchild->ite_name; 363 364 if (tentry->ite_rchild == ITE_NULL) 365 iitn->iitn_rchild = MACH_PORT_NULL; 366 else 367 iitn->iitn_rchild = tentry->ite_rchild->ite_name; 368 369 } 370 ipc_splay_traverse_finish(&space->is_tree); 371 is_read_unlock(space); 372 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)); 378 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; 387 } else { 388 *tablep = (ipc_info_name_t *)0; 389 *tableCntp = 0; 390 } 391 392 /* prepare the tree out-of-line data for return */ 393 if (tree_size > 0) { 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)); 397 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; 406 } else { 407 *treep = (ipc_info_tree_name_t *)0; 408 *treeCntp = 0; 409 } 410 return KERN_SUCCESS; 411} 412#endif /* MACH_IPC_DEBUG */ 413 414/* 415 * Routine: mach_port_dnrequest_info 416 * Purpose: 417 * Returns information about the dead-name requests 418 * registered with the named receive right. 419 * Conditions: 420 * Nothing locked. 421 * Returns: 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. 427 */ 428 429#if !MACH_IPC_DEBUG 430kern_return_t 431mach_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) 436{ 437 return KERN_FAILURE; 438} 439#else 440kern_return_t 441mach_port_dnrequest_info( 442 ipc_space_t space, 443 mach_port_name_t name, 444 unsigned int *totalp, 445 unsigned int *usedp) 446{ 447 unsigned int total, used; 448 ipc_port_t port; 449 kern_return_t kr; 450 451 if (space == IS_NULL) 452 return KERN_INVALID_TASK; 453 454 kr = ipc_port_translate_receive(space, name, &port); 455 if (kr != KERN_SUCCESS) 456 return kr; 457 /* port is locked and active */ 458 459 if (port->ip_dnrequests == IPR_NULL) { 460 total = 0; 461 used = 0; 462 } else { 463 ipc_port_request_t dnrequests = port->ip_dnrequests; 464 ipc_port_request_index_t index; 465 466 total = dnrequests->ipr_size->its_size; 467 468 for (index = 1, used = 0; 469 index < total; index++) { 470 ipc_port_request_t ipr = &dnrequests[index]; 471 472 if (ipr->ipr_name != MACH_PORT_NULL) 473 used++; 474 } 475 } 476 ip_unlock(port); 477 478 *totalp = total; 479 *usedp = used; 480 return KERN_SUCCESS; 481} 482#endif /* MACH_IPC_DEBUG */ 483 484/* 485 * Routine: mach_port_kernel_object [kernel call] 486 * Purpose: 487 * Retrieve the type and address of the kernel object 488 * represented by a send or receive right. 489 * Conditions: 490 * Nothing locked. 491 * Returns: 492 * KERN_SUCCESS Retrieved kernel object info. 493 * KERN_INVALID_TASK The space is null. 494 * KERN_INVALID_TASK The space is dead. 495 * KERN_INVALID_NAME The name doesn't denote a right. 496 * KERN_INVALID_RIGHT Name doesn't denote 497 * send or receive rights. 498 */ 499 500#if !MACH_IPC_DEBUG 501kern_return_t 502mach_port_kernel_object( 503 __unused ipc_space_t space, 504 __unused mach_port_name_t name, 505 __unused unsigned int *typep, 506 __unused vm_offset_t *addrp) 507{ 508 return KERN_FAILURE; 509} 510#else 511kern_return_t 512mach_port_kernel_object( 513 ipc_space_t space, 514 mach_port_name_t name, 515 unsigned int *typep, 516 vm_offset_t *addrp) 517{ 518 ipc_entry_t entry; 519 ipc_port_t port; 520 kern_return_t kr; 521 522 if (space == IS_NULL) 523 return KERN_INVALID_TASK; 524 525 kr = ipc_right_lookup_read(space, name, &entry); 526 if (kr != KERN_SUCCESS) 527 return kr; 528 /* space is read-locked and active */ 529 530 if ((entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) { 531 is_read_unlock(space); 532 return KERN_INVALID_RIGHT; 533 } 534 535 port = (ipc_port_t) entry->ie_object; 536 assert(port != IP_NULL); 537 538 ip_lock(port); 539 is_read_unlock(space); 540 541 if (!ip_active(port)) { 542 ip_unlock(port); 543 return KERN_INVALID_RIGHT; 544 } 545 546 *typep = (unsigned int) ip_kotype(port); 547 *addrp = (vm_offset_t) port->ip_kobject; 548 ip_unlock(port); 549 return KERN_SUCCESS; 550 551} 552#endif /* MACH_IPC_DEBUG */ 553