diff options
Diffstat (limited to 'ipc/mach_debug.c')
-rw-r--r-- | ipc/mach_debug.c | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/ipc/mach_debug.c b/ipc/mach_debug.c new file mode 100644 index 0000000..cd8fad0 --- /dev/null +++ b/ipc/mach_debug.c @@ -0,0 +1,618 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + */ +/* + * File: ipc/mach_debug.c + * Author: Rich Draves + * Date: 1989 + * + * Exported kernel calls. See mach_debug/mach_debug.defs. + */ + +#include <mach_ipc_compat.h> + +#include <mach/kern_return.h> +#include <mach/port.h> +#include <mach/machine/vm_types.h> +#include <mach/vm_param.h> +#include <mach_debug/ipc_info.h> +#include <mach_debug/hash_info.h> +#include <kern/host.h> +#include <vm/vm_map.h> +#include <vm/vm_kern.h> +#include <ipc/ipc_space.h> +#include <ipc/ipc_port.h> +#include <ipc/ipc_hash.h> +#include <ipc/ipc_marequest.h> +#include <ipc/ipc_table.h> +#include <ipc/ipc_right.h> + + + +/* + * Routine: mach_port_get_srights [kernel call] + * Purpose: + * Retrieve the number of extant send rights + * that a receive right has. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Retrieved number of send rights. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_get_srights( + ipc_space_t space, + mach_port_t name, + mach_port_rights_t *srightsp) +{ + ipc_port_t port; + kern_return_t kr; + mach_port_rights_t srights; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + /* port is locked and active */ + + srights = port->ip_srights; + ip_unlock(port); + + *srightsp = srights; + return KERN_SUCCESS; +} + +/* + * Routine: host_ipc_hash_info + * Purpose: + * Return information about the global reverse hash table. + * Conditions: + * Nothing locked. Obeys CountInOut protocol. + * Returns: + * KERN_SUCCESS Returned information. + * KERN_INVALID_HOST The host is null. + * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. + */ + +kern_return_t +host_ipc_hash_info( + host_t host, + hash_info_bucket_array_t *infop, + mach_msg_type_number_t *countp) +{ + vm_offset_t addr; + vm_size_t size; + hash_info_bucket_t *info; + unsigned int potential, actual; + kern_return_t kr; + + if (host == HOST_NULL) + return KERN_INVALID_HOST; + + /* start with in-line data */ + + info = *infop; + potential = *countp; + + for (;;) { + actual = ipc_hash_info(info, potential); + if (actual <= potential) + break; + + /* allocate more memory */ + + if (info != *infop) + kmem_free(ipc_kernel_map, addr, size); + + size = round_page(actual * sizeof *info); + kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size); + if (kr != KERN_SUCCESS) + return KERN_RESOURCE_SHORTAGE; + + info = (hash_info_bucket_t *) addr; + potential = size/sizeof *info; + } + + if (info == *infop) { + /* data fit in-line; nothing to deallocate */ + + *countp = actual; + } else if (actual == 0) { + kmem_free(ipc_kernel_map, addr, size); + + *countp = 0; + } else { + vm_map_copy_t copy; + vm_size_t used; + + used = round_page(actual * sizeof *info); + + if (used != size) + kmem_free(ipc_kernel_map, addr + used, size - used); + + kr = vm_map_copyin(ipc_kernel_map, addr, used, + TRUE, ©); + assert(kr == KERN_SUCCESS); + + *infop = (hash_info_bucket_t *) copy; + *countp = actual; + } + + return KERN_SUCCESS; +} + +/* + * Routine: host_ipc_marequest_info + * Purpose: + * Return information about the marequest hash table. + * Conditions: + * Nothing locked. Obeys CountInOut protocol. + * Returns: + * KERN_SUCCESS Returned information. + * KERN_INVALID_HOST The host is null. + * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. + */ + +kern_return_t +host_ipc_marequest_info(host, maxp, infop, countp) + host_t host; + unsigned int *maxp; + hash_info_bucket_array_t *infop; + unsigned int *countp; +{ + vm_offset_t addr; + vm_size_t size = 0; /* '=0' to shut up lint */ + hash_info_bucket_t *info; + unsigned int potential, actual; + kern_return_t kr; + + if (host == HOST_NULL) + return KERN_INVALID_HOST; + + /* start with in-line data */ + + info = *infop; + potential = *countp; + + for (;;) { + actual = ipc_marequest_info(maxp, info, potential); + if (actual <= potential) + break; + + /* allocate more memory */ + + if (info != *infop) + kmem_free(ipc_kernel_map, addr, size); + + size = round_page(actual * sizeof *info); + kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size); + if (kr != KERN_SUCCESS) + return KERN_RESOURCE_SHORTAGE; + + info = (hash_info_bucket_t *) addr; + potential = size/sizeof *info; + } + + if (info == *infop) { + /* data fit in-line; nothing to deallocate */ + + *countp = actual; + } else if (actual == 0) { + kmem_free(ipc_kernel_map, addr, size); + + *countp = 0; + } else { + vm_map_copy_t copy; + vm_size_t used; + + used = round_page(actual * sizeof *info); + + if (used != size) + kmem_free(ipc_kernel_map, addr + used, size - used); + + kr = vm_map_copyin(ipc_kernel_map, addr, used, + TRUE, ©); + assert(kr == KERN_SUCCESS); + + *infop = (hash_info_bucket_t *) copy; + *countp = actual; + } + + return KERN_SUCCESS; +} + +/* + * Routine: mach_port_space_info + * Purpose: + * Returns information about an IPC space. + * Conditions: + * Nothing locked. Obeys CountInOut protocol. + * Returns: + * KERN_SUCCESS Returned information. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. + */ + +kern_return_t +mach_port_space_info( + ipc_space_t space, + ipc_info_space_t *infop, + ipc_info_name_array_t *tablep, + mach_msg_type_number_t *tableCntp, + ipc_info_tree_name_array_t *treep, + mach_msg_type_number_t *treeCntp) +{ + ipc_info_name_t *table_info; + unsigned int table_potential, table_actual; + vm_offset_t table_addr; + vm_size_t table_size; + ipc_info_tree_name_t *tree_info; + unsigned int tree_potential, tree_actual; + vm_offset_t tree_addr; + vm_size_t tree_size; + ipc_tree_entry_t tentry; + ipc_entry_t table; + ipc_entry_num_t tsize; + mach_port_index_t index; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + /* start with in-line memory */ + + table_info = *tablep; + table_potential = *tableCntp; + tree_info = *treep; + tree_potential = *treeCntp; + + for (;;) { + is_read_lock(space); + if (!space->is_active) { + is_read_unlock(space); + if (table_info != *tablep) + kmem_free(ipc_kernel_map, + table_addr, table_size); + if (tree_info != *treep) + kmem_free(ipc_kernel_map, + tree_addr, tree_size); + return KERN_INVALID_TASK; + } + + table_actual = space->is_table_size; + tree_actual = space->is_tree_total; + + if ((table_actual <= table_potential) && + (tree_actual <= tree_potential)) + break; + + is_read_unlock(space); + + if (table_actual > table_potential) { + if (table_info != *tablep) + kmem_free(ipc_kernel_map, + table_addr, table_size); + + table_size = round_page(table_actual * + sizeof *table_info); + kr = kmem_alloc(ipc_kernel_map, + &table_addr, table_size); + if (kr != KERN_SUCCESS) { + if (tree_info != *treep) + kmem_free(ipc_kernel_map, + tree_addr, tree_size); + + return KERN_RESOURCE_SHORTAGE; + } + + table_info = (ipc_info_name_t *) table_addr; + table_potential = table_size/sizeof *table_info; + } + + if (tree_actual > tree_potential) { + if (tree_info != *treep) + kmem_free(ipc_kernel_map, + tree_addr, tree_size); + + tree_size = round_page(tree_actual * + sizeof *tree_info); + kr = kmem_alloc(ipc_kernel_map, + &tree_addr, tree_size); + if (kr != KERN_SUCCESS) { + if (table_info != *tablep) + kmem_free(ipc_kernel_map, + table_addr, table_size); + + return KERN_RESOURCE_SHORTAGE; + } + + tree_info = (ipc_info_tree_name_t *) tree_addr; + tree_potential = tree_size/sizeof *tree_info; + } + } + /* space is read-locked and active; we have enough wired memory */ + + infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD); + infop->iis_table_size = space->is_table_size; + infop->iis_table_next = space->is_table_next->its_size; + infop->iis_tree_size = space->is_tree_total; + infop->iis_tree_small = space->is_tree_small; + infop->iis_tree_hash = space->is_tree_hash; + + table = space->is_table; + tsize = space->is_table_size; + + for (index = 0; index < tsize; index++) { + ipc_info_name_t *iin = &table_info[index]; + ipc_entry_t entry = &table[index]; + ipc_entry_bits_t bits = entry->ie_bits; + + iin->iin_name = MACH_PORT_MAKEB(index, bits); + iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE; +#if MACH_IPC_COMPAT + iin->iin_compat = (bits & IE_BITS_COMPAT) ? TRUE : FALSE; +#else MACH_IPC_COMPAT + iin->iin_compat = FALSE; +#endif MACH_IPC_COMPAT + iin->iin_marequest = (bits & IE_BITS_MAREQUEST) ? TRUE : FALSE; + iin->iin_type = IE_BITS_TYPE(bits); + iin->iin_urefs = IE_BITS_UREFS(bits); + iin->iin_object = (vm_offset_t) entry->ie_object; + iin->iin_next = entry->ie_next; + iin->iin_hash = entry->ie_index; + } + + for (tentry = ipc_splay_traverse_start(&space->is_tree), index = 0; + tentry != ITE_NULL; + tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { + ipc_info_tree_name_t *iitn = &tree_info[index++]; + ipc_info_name_t *iin = &iitn->iitn_name; + ipc_entry_t entry = &tentry->ite_entry; + ipc_entry_bits_t bits = entry->ie_bits; + + assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); + + iin->iin_name = tentry->ite_name; + iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE; +#if MACH_IPC_COMPAT + iin->iin_compat = (bits & IE_BITS_COMPAT) ? TRUE : FALSE; +#else MACH_IPC_COMPAT + iin->iin_compat = FALSE; +#endif MACH_IPC_COMPAT + iin->iin_marequest = (bits & IE_BITS_MAREQUEST) ? TRUE : FALSE; + iin->iin_type = IE_BITS_TYPE(bits); + iin->iin_urefs = IE_BITS_UREFS(bits); + iin->iin_object = (vm_offset_t) entry->ie_object; + iin->iin_next = entry->ie_next; + iin->iin_hash = entry->ie_index; + + if (tentry->ite_lchild == ITE_NULL) + iitn->iitn_lchild = MACH_PORT_NULL; + else + iitn->iitn_lchild = tentry->ite_lchild->ite_name; + + if (tentry->ite_rchild == ITE_NULL) + iitn->iitn_rchild = MACH_PORT_NULL; + else + iitn->iitn_rchild = tentry->ite_rchild->ite_name; + + } + ipc_splay_traverse_finish(&space->is_tree); + is_read_unlock(space); + + if (table_info == *tablep) { + /* data fit in-line; nothing to deallocate */ + + *tableCntp = table_actual; + } else if (table_actual == 0) { + kmem_free(ipc_kernel_map, table_addr, table_size); + + *tableCntp = 0; + } else { + vm_size_t size_used, rsize_used; + vm_map_copy_t copy; + + /* kmem_alloc doesn't zero memory */ + + size_used = table_actual * sizeof *table_info; + rsize_used = round_page(size_used); + + if (rsize_used != table_size) + kmem_free(ipc_kernel_map, + table_addr + rsize_used, + table_size - rsize_used); + + if (size_used != rsize_used) + bzero((char *) (table_addr + size_used), + rsize_used - size_used); + + kr = vm_map_copyin(ipc_kernel_map, table_addr, rsize_used, + TRUE, ©); + + assert(kr == KERN_SUCCESS); + + *tablep = (ipc_info_name_t *) copy; + *tableCntp = table_actual; + } + + if (tree_info == *treep) { + /* data fit in-line; nothing to deallocate */ + + *treeCntp = tree_actual; + } else if (tree_actual == 0) { + kmem_free(ipc_kernel_map, tree_addr, tree_size); + + *treeCntp = 0; + } else { + vm_size_t size_used, rsize_used; + vm_map_copy_t copy; + + /* kmem_alloc doesn't zero memory */ + + size_used = tree_actual * sizeof *tree_info; + rsize_used = round_page(size_used); + + if (rsize_used != tree_size) + kmem_free(ipc_kernel_map, + tree_addr + rsize_used, + tree_size - rsize_used); + + if (size_used != rsize_used) + bzero((char *) (tree_addr + size_used), + rsize_used - size_used); + + kr = vm_map_copyin(ipc_kernel_map, tree_addr, rsize_used, + TRUE, ©); + + assert(kr == KERN_SUCCESS); + + *treep = (ipc_info_tree_name_t *) copy; + *treeCntp = tree_actual; + } + + return KERN_SUCCESS; +} + +/* + * Routine: mach_port_dnrequest_info + * Purpose: + * Returns information about the dead-name requests + * registered with the named receive right. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Retrieved information. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_dnrequest_info( + ipc_space_t space, + mach_port_t name, + unsigned int *totalp, + unsigned int *usedp) +{ + unsigned int total, used; + ipc_port_t port; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + /* port is locked and active */ + + if (port->ip_dnrequests == IPR_NULL) { + total = 0; + used = 0; + } else { + ipc_port_request_t dnrequests = port->ip_dnrequests; + ipc_port_request_index_t index; + + total = dnrequests->ipr_size->its_size; + + for (index = 1, used = 0; + index < total; index++) { + ipc_port_request_t ipr = &dnrequests[index]; + + if (ipr->ipr_name != MACH_PORT_NULL) + used++; + } + } + ip_unlock(port); + + *totalp = total; + *usedp = used; + return KERN_SUCCESS; +} + +/* + * Routine: mach_port_kernel_object [kernel call] + * Purpose: + * Retrieve the type and address of the kernel object + * represented by a send or receive right. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Retrieved kernel object info. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote + * send or receive rights. + */ + +kern_return_t +mach_port_kernel_object( + ipc_space_t space, + mach_port_t name, + unsigned int *typep, + vm_offset_t *addrp) +{ + ipc_entry_t entry; + ipc_port_t port; + kern_return_t kr; + + kr = ipc_right_lookup_read(space, name, &entry); + if (kr != KERN_SUCCESS) + return kr; + /* space is read-locked and active */ + + if ((entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) { + is_read_unlock(space); + return KERN_INVALID_RIGHT; + } + + port = (ipc_port_t) entry->ie_object; + assert(port != IP_NULL); + + ip_lock(port); + is_read_unlock(space); + + if (!ip_active(port)) { + ip_unlock(port); + return KERN_INVALID_RIGHT; + } + + *typep = (unsigned int) ip_kotype(port); + *addrp = (vm_offset_t) port->ip_kobject; + ip_unlock(port); + return KERN_SUCCESS; +} |