]> git.saurik.com Git - apple/xnu.git/blame_incremental - osfmk/ipc/mach_debug.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_debug.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30/*
31 * @OSF_COPYRIGHT@
32 */
33/*
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58/*
59 */
60/*
61 * File: ipc/mach_debug.c
62 * Author: Rich Draves
63 * Date: 1989
64 *
65 * Exported IPC debug calls.
66 */
67#include <mach_ipc_debug.h>
68
69#include <mach/vm_param.h>
70#include <mach/kern_return.h>
71#include <mach/machine/vm_types.h>
72#include <mach/mach_host_server.h>
73#include <mach/mach_port_server.h>
74#include <mach_debug/ipc_info.h>
75#include <mach_debug/hash_info.h>
76
77#if MACH_IPC_DEBUG
78#include <kern/host.h>
79#include <kern/misc_protos.h>
80#include <vm/vm_map.h>
81#include <vm/vm_kern.h>
82#include <ipc/port.h>
83#include <ipc/ipc_types.h>
84#include <ipc/ipc_space.h>
85#include <ipc/ipc_port.h>
86#include <ipc/ipc_hash.h>
87#include <ipc/ipc_table.h>
88#include <ipc/ipc_right.h>
89#endif
90
91/*
92 * Routine: mach_port_get_srights [kernel call]
93 * Purpose:
94 * Retrieve the number of extant send rights
95 * that a receive right has.
96 * Conditions:
97 * Nothing locked.
98 * Returns:
99 * KERN_SUCCESS Retrieved number of send rights.
100 * KERN_INVALID_TASK The space is null.
101 * KERN_INVALID_TASK The space is dead.
102 * KERN_INVALID_NAME The name doesn't denote a right.
103 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
104 */
105
106#if !MACH_IPC_DEBUG
107kern_return_t
108mach_port_get_srights(
109 __unused ipc_space_t space,
110 __unused mach_port_name_t name,
111 __unused mach_port_rights_t *srightsp)
112{
113 return KERN_FAILURE;
114}
115#else
116kern_return_t
117mach_port_get_srights(
118 ipc_space_t space,
119 mach_port_name_t name,
120 mach_port_rights_t *srightsp)
121{
122 ipc_port_t port;
123 kern_return_t kr;
124 mach_port_rights_t srights;
125
126 if (space == IS_NULL)
127 return KERN_INVALID_TASK;
128
129 kr = ipc_port_translate_receive(space, name, &port);
130 if (kr != KERN_SUCCESS)
131 return kr;
132 /* port is locked and active */
133
134 srights = port->ip_srights;
135 ip_unlock(port);
136
137 *srightsp = srights;
138 return KERN_SUCCESS;
139}
140#endif /* MACH_IPC_DEBUG */
141
142/*
143 * Routine: host_ipc_hash_info
144 * Purpose:
145 * Return information about the global reverse hash table.
146 * Conditions:
147 * Nothing locked. Obeys CountInOut protocol.
148 * Returns:
149 * KERN_SUCCESS Returned information.
150 * KERN_INVALID_HOST The host is null.
151 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
152 */
153
154#if !MACH_IPC_DEBUG
155kern_return_t
156host_ipc_hash_info(
157 __unused host_t host,
158 __unused hash_info_bucket_array_t *infop,
159 __unused mach_msg_type_number_t *countp)
160{
161 return KERN_FAILURE;
162}
163#else
164kern_return_t
165host_ipc_hash_info(
166 host_t host,
167 hash_info_bucket_array_t *infop,
168 mach_msg_type_number_t *countp)
169{
170 vm_offset_t addr;
171 vm_size_t size = 0;
172 hash_info_bucket_t *info;
173 unsigned int potential, actual;
174 kern_return_t kr;
175
176 if (host == HOST_NULL)
177 return KERN_INVALID_HOST;
178
179 /* start with in-line data */
180
181 info = *infop;
182 potential = *countp;
183
184 for (;;) {
185 actual = ipc_hash_info(info, potential);
186 if (actual <= potential)
187 break;
188
189 /* allocate more memory */
190
191 if (info != *infop)
192 kmem_free(ipc_kernel_map, addr, size);
193
194 size = round_page(actual * sizeof *info);
195 kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size);
196 if (kr != KERN_SUCCESS)
197 return KERN_RESOURCE_SHORTAGE;
198
199 info = (hash_info_bucket_t *) addr;
200 potential = size/sizeof *info;
201 }
202
203 if (info == *infop) {
204 /* data fit in-line; nothing to deallocate */
205
206 *countp = actual;
207 } else if (actual == 0) {
208 kmem_free(ipc_kernel_map, addr, size);
209
210 *countp = 0;
211 } else {
212 vm_map_copy_t copy;
213 vm_size_t used;
214
215 used = round_page(actual * sizeof *info);
216
217 if (used != size)
218 kmem_free(ipc_kernel_map, addr + used, size - used);
219
220 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
221 (vm_map_size_t)used, TRUE, &copy);
222 assert(kr == KERN_SUCCESS);
223
224 *infop = (hash_info_bucket_t *) copy;
225 *countp = actual;
226 }
227
228 return KERN_SUCCESS;
229}
230#endif /* MACH_IPC_DEBUG */
231
232/*
233 * Routine: mach_port_space_info
234 * Purpose:
235 * Returns information about an IPC space.
236 * Conditions:
237 * Nothing locked. Obeys CountInOut protocol.
238 * Returns:
239 * KERN_SUCCESS Returned information.
240 * KERN_INVALID_TASK The space is null.
241 * KERN_INVALID_TASK The space is dead.
242 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
243 */
244
245#if !MACH_IPC_DEBUG
246kern_return_t
247mach_port_space_info(
248 __unused ipc_space_t space,
249 __unused ipc_info_space_t *infop,
250 __unused ipc_info_name_array_t *tablep,
251 __unused mach_msg_type_number_t *tableCntp,
252 __unused ipc_info_tree_name_array_t *treep,
253 __unused mach_msg_type_number_t *treeCntp)
254{
255 return KERN_FAILURE;
256}
257#else
258kern_return_t
259mach_port_space_info(
260 ipc_space_t space,
261 ipc_info_space_t *infop,
262 ipc_info_name_array_t *tablep,
263 mach_msg_type_number_t *tableCntp,
264 ipc_info_tree_name_array_t *treep,
265 mach_msg_type_number_t *treeCntp)
266{
267 ipc_info_name_t *table_info;
268 unsigned int table_potential, table_actual;
269 vm_offset_t table_addr;
270 vm_size_t table_size;
271 ipc_info_tree_name_t *tree_info;
272 unsigned int tree_potential, tree_actual;
273 vm_offset_t tree_addr;
274 vm_size_t tree_size;
275 ipc_tree_entry_t tentry;
276 ipc_entry_t table;
277 ipc_entry_num_t tsize;
278 mach_port_index_t index;
279 kern_return_t kr;
280
281 if (space == IS_NULL)
282 return KERN_INVALID_TASK;
283
284 /* start with in-line memory */
285
286 table_size = 0;
287 table_info = *tablep;
288 table_potential = *tableCntp;
289 tree_size = 0;
290 tree_info = *treep;
291 tree_potential = *treeCntp;
292
293 for (;;) {
294 is_read_lock(space);
295 if (!space->is_active) {
296 is_read_unlock(space);
297 if (table_info != *tablep)
298 kmem_free(ipc_kernel_map,
299 table_addr, table_size);
300 if (tree_info != *treep)
301 kmem_free(ipc_kernel_map,
302 tree_addr, tree_size);
303 return KERN_INVALID_TASK;
304 }
305
306 table_actual = space->is_table_size;
307 tree_actual = space->is_tree_total;
308
309 if ((table_actual <= table_potential) &&
310 (tree_actual <= tree_potential))
311 break;
312
313 is_read_unlock(space);
314
315 if (table_actual > table_potential) {
316 if (table_info != *tablep)
317 kmem_free(ipc_kernel_map,
318 table_addr, table_size);
319
320 table_size = round_page(table_actual *
321 sizeof *table_info);
322 kr = kmem_alloc(ipc_kernel_map,
323 &table_addr, table_size);
324 if (kr != KERN_SUCCESS) {
325 if (tree_info != *treep)
326 kmem_free(ipc_kernel_map,
327 tree_addr, tree_size);
328
329 return KERN_RESOURCE_SHORTAGE;
330 }
331
332 table_info = (ipc_info_name_t *) table_addr;
333 table_potential = table_size/sizeof *table_info;
334 }
335
336 if (tree_actual > tree_potential) {
337 if (tree_info != *treep)
338 kmem_free(ipc_kernel_map,
339 tree_addr, tree_size);
340
341 tree_size = round_page(tree_actual *
342 sizeof *tree_info);
343 kr = kmem_alloc(ipc_kernel_map,
344 &tree_addr, tree_size);
345 if (kr != KERN_SUCCESS) {
346 if (table_info != *tablep)
347 kmem_free(ipc_kernel_map,
348 table_addr, table_size);
349
350 return KERN_RESOURCE_SHORTAGE;
351 }
352
353 tree_info = (ipc_info_tree_name_t *) tree_addr;
354 tree_potential = tree_size/sizeof *tree_info;
355 }
356 }
357 /* space is read-locked and active; we have enough wired memory */
358
359 infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
360 infop->iis_table_size = space->is_table_size;
361 infop->iis_table_next = space->is_table_next->its_size;
362 infop->iis_tree_size = space->is_tree_total;
363 infop->iis_tree_small = space->is_tree_small;
364 infop->iis_tree_hash = space->is_tree_hash;
365
366 table = space->is_table;
367 tsize = space->is_table_size;
368
369 for (index = 0; index < tsize; index++) {
370 ipc_info_name_t *iin = &table_info[index];
371 ipc_entry_t entry = &table[index];
372 ipc_entry_bits_t bits;
373
374 bits = entry->ie_bits;
375 iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
376 iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE;
377 iin->iin_type = IE_BITS_TYPE(bits);
378 iin->iin_urefs = IE_BITS_UREFS(bits);
379 iin->iin_object = (vm_offset_t) entry->ie_object;
380 iin->iin_next = entry->ie_next;
381 iin->iin_hash = entry->ie_index;
382 }
383
384 for (tentry = ipc_splay_traverse_start(&space->is_tree), index = 0;
385 tentry != ITE_NULL;
386 tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
387 ipc_info_tree_name_t *iitn = &tree_info[index++];
388 ipc_info_name_t *iin = &iitn->iitn_name;
389 ipc_entry_t entry = &tentry->ite_entry;
390 ipc_entry_bits_t bits = entry->ie_bits;
391
392 assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
393
394 iin->iin_name = tentry->ite_name;
395 iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE;
396 iin->iin_type = IE_BITS_TYPE(bits);
397 iin->iin_urefs = IE_BITS_UREFS(bits);
398 iin->iin_object = (vm_offset_t) entry->ie_object;
399 iin->iin_next = entry->ie_next;
400 iin->iin_hash = entry->ie_index;
401
402 if (tentry->ite_lchild == ITE_NULL)
403 iitn->iitn_lchild = MACH_PORT_NULL;
404 else
405 iitn->iitn_lchild = tentry->ite_lchild->ite_name;
406
407 if (tentry->ite_rchild == ITE_NULL)
408 iitn->iitn_rchild = MACH_PORT_NULL;
409 else
410 iitn->iitn_rchild = tentry->ite_rchild->ite_name;
411
412 }
413 ipc_splay_traverse_finish(&space->is_tree);
414 is_read_unlock(space);
415
416 if (table_info == *tablep) {
417 /* data fit in-line; nothing to deallocate */
418
419 *tableCntp = table_actual;
420 } else if (table_actual == 0) {
421 kmem_free(ipc_kernel_map, table_addr, table_size);
422
423 *tableCntp = 0;
424 } else {
425 vm_size_t size_used, rsize_used;
426 vm_map_copy_t copy;
427
428 /* kmem_alloc doesn't zero memory */
429
430 size_used = table_actual * sizeof *table_info;
431 rsize_used = round_page(size_used);
432
433 if (rsize_used != table_size)
434 kmem_free(ipc_kernel_map,
435 table_addr + rsize_used,
436 table_size - rsize_used);
437
438 if (size_used != rsize_used)
439 bzero((char *) (table_addr + size_used),
440 rsize_used - size_used);
441
442 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(table_addr),
443 vm_map_round_page(table_addr + rsize_used), FALSE);
444 assert(kr == KERN_SUCCESS);
445
446 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)table_addr,
447 (vm_map_size_t)rsize_used, TRUE, &copy);
448 assert(kr == KERN_SUCCESS);
449
450 *tablep = (ipc_info_name_t *) copy;
451 *tableCntp = table_actual;
452 }
453
454 if (tree_info == *treep) {
455 /* data fit in-line; nothing to deallocate */
456
457 *treeCntp = tree_actual;
458 } else if (tree_actual == 0) {
459 kmem_free(ipc_kernel_map, tree_addr, tree_size);
460
461 *treeCntp = 0;
462 } else {
463 vm_size_t size_used, rsize_used;
464 vm_map_copy_t copy;
465
466 /* kmem_alloc doesn't zero memory */
467
468 size_used = tree_actual * sizeof *tree_info;
469 rsize_used = round_page(size_used);
470
471 if (rsize_used != tree_size)
472 kmem_free(ipc_kernel_map,
473 tree_addr + rsize_used,
474 tree_size - rsize_used);
475
476 if (size_used != rsize_used)
477 bzero((char *) (tree_addr + size_used),
478 rsize_used - size_used);
479
480 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(tree_addr),
481 vm_map_round_page(tree_addr + rsize_used), FALSE);
482 assert(kr == KERN_SUCCESS);
483
484 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)tree_addr,
485 (vm_map_size_t)rsize_used, TRUE, &copy);
486 assert(kr == KERN_SUCCESS);
487
488 *treep = (ipc_info_tree_name_t *) copy;
489 *treeCntp = tree_actual;
490 }
491
492 return KERN_SUCCESS;
493}
494#endif /* MACH_IPC_DEBUG */
495
496/*
497 * Routine: mach_port_dnrequest_info
498 * Purpose:
499 * Returns information about the dead-name requests
500 * registered with the named receive right.
501 * Conditions:
502 * Nothing locked.
503 * Returns:
504 * KERN_SUCCESS Retrieved information.
505 * KERN_INVALID_TASK The space is null.
506 * KERN_INVALID_TASK The space is dead.
507 * KERN_INVALID_NAME The name doesn't denote a right.
508 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
509 */
510
511#if !MACH_IPC_DEBUG
512kern_return_t
513mach_port_dnrequest_info(
514 __unused ipc_space_t space,
515 __unused mach_port_name_t name,
516 __unused unsigned int *totalp,
517 __unused unsigned int *usedp)
518{
519 return KERN_FAILURE;
520}
521#else
522kern_return_t
523mach_port_dnrequest_info(
524 ipc_space_t space,
525 mach_port_name_t name,
526 unsigned int *totalp,
527 unsigned int *usedp)
528{
529 unsigned int total, used;
530 ipc_port_t port;
531 kern_return_t kr;
532
533 if (space == IS_NULL)
534 return KERN_INVALID_TASK;
535
536 kr = ipc_port_translate_receive(space, name, &port);
537 if (kr != KERN_SUCCESS)
538 return kr;
539 /* port is locked and active */
540
541 if (port->ip_dnrequests == IPR_NULL) {
542 total = 0;
543 used = 0;
544 } else {
545 ipc_port_request_t dnrequests = port->ip_dnrequests;
546 ipc_port_request_index_t index;
547
548 total = dnrequests->ipr_size->its_size;
549
550 for (index = 1, used = 0;
551 index < total; index++) {
552 ipc_port_request_t ipr = &dnrequests[index];
553
554 if (ipr->ipr_name != MACH_PORT_NULL)
555 used++;
556 }
557 }
558 ip_unlock(port);
559
560 *totalp = total;
561 *usedp = used;
562 return KERN_SUCCESS;
563}
564#endif /* MACH_IPC_DEBUG */
565
566/*
567 * Routine: mach_port_kernel_object [kernel call]
568 * Purpose:
569 * Retrieve the type and address of the kernel object
570 * represented by a send or receive right.
571 * Conditions:
572 * Nothing locked.
573 * Returns:
574 * KERN_SUCCESS Retrieved kernel object info.
575 * KERN_INVALID_TASK The space is null.
576 * KERN_INVALID_TASK The space is dead.
577 * KERN_INVALID_NAME The name doesn't denote a right.
578 * KERN_INVALID_RIGHT Name doesn't denote
579 * send or receive rights.
580 */
581
582#if !MACH_IPC_DEBUG
583kern_return_t
584mach_port_kernel_object(
585 __unused ipc_space_t space,
586 __unused mach_port_name_t name,
587 __unused unsigned int *typep,
588 __unused vm_offset_t *addrp)
589{
590 return KERN_FAILURE;
591}
592#else
593kern_return_t
594mach_port_kernel_object(
595 ipc_space_t space,
596 mach_port_name_t name,
597 unsigned int *typep,
598 vm_offset_t *addrp)
599{
600 ipc_entry_t entry;
601 ipc_port_t port;
602 kern_return_t kr;
603
604 kr = ipc_right_lookup_read(space, name, &entry);
605 if (kr != KERN_SUCCESS)
606 return kr;
607 /* space is read-locked and active */
608
609 if ((entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) {
610 is_read_unlock(space);
611 return KERN_INVALID_RIGHT;
612 }
613
614 port = (ipc_port_t) entry->ie_object;
615 assert(port != IP_NULL);
616
617 ip_lock(port);
618 is_read_unlock(space);
619
620 if (!ip_active(port)) {
621 ip_unlock(port);
622 return KERN_INVALID_RIGHT;
623 }
624
625 *typep = (unsigned int) ip_kotype(port);
626 *addrp = (vm_offset_t) port->ip_kobject;
627 ip_unlock(port);
628 return KERN_SUCCESS;
629
630}
631#endif /* MACH_IPC_DEBUG */