summaryrefslogtreecommitdiff
path: root/ipc/mach_debug.c
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
committerThomas Bushnell <thomas@gnu.org>1997-02-25 21:28:37 +0000
commitf07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch)
tree12b07c7e578fc1a5f53dbfde2632408491ff2a70 /ipc/mach_debug.c
Initial source
Diffstat (limited to 'ipc/mach_debug.c')
-rw-r--r--ipc/mach_debug.c618
1 files changed, 618 insertions, 0 deletions
diff --git a/ipc/mach_debug.c b/ipc/mach_debug.c
new file mode 100644
index 00000000..cd8fad04
--- /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, &copy);
+ 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, &copy);
+ 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, &copy);
+
+ 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, &copy);
+
+ 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;
+}