]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/mach_debug.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / osfmk / ipc / mach_debug.c
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
105 kern_return_t
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)
110 {
111 return KERN_FAILURE;
112 }
113 #else
114 kern_return_t
115 mach_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
153 kern_return_t
154 host_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
162 kern_return_t
163 host_ipc_hash_info(
164 host_t host,
165 hash_info_bucket_array_t *infop,
166 mach_msg_type_number_t *countp)
167 {
168 vm_offset_t addr;
169 vm_size_t size = 0;
170 hash_info_bucket_t *info;
171 unsigned int potential, actual;
172 kern_return_t kr;
173
174 if (host == HOST_NULL)
175 return KERN_INVALID_HOST;
176
177 /* start with in-line data */
178
179 info = *infop;
180 potential = *countp;
181
182 for (;;) {
183 actual = ipc_hash_info(info, potential);
184 if (actual <= potential)
185 break;
186
187 /* allocate more memory */
188
189 if (info != *infop)
190 kmem_free(ipc_kernel_map, addr, size);
191
192 size = round_page(actual * sizeof *info);
193 kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size);
194 if (kr != KERN_SUCCESS)
195 return KERN_RESOURCE_SHORTAGE;
196
197 info = (hash_info_bucket_t *) addr;
198 potential = size/sizeof *info;
199 }
200
201 if (info == *infop) {
202 /* data fit in-line; nothing to deallocate */
203
204 *countp = actual;
205 } else if (actual == 0) {
206 kmem_free(ipc_kernel_map, addr, size);
207
208 *countp = 0;
209 } else {
210 vm_map_copy_t copy;
211 vm_size_t used;
212
213 used = round_page(actual * sizeof *info);
214
215 if (used != size)
216 kmem_free(ipc_kernel_map, addr + used, size - used);
217
218 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
219 (vm_map_size_t)used, TRUE, &copy);
220 assert(kr == KERN_SUCCESS);
221
222 *infop = (hash_info_bucket_t *) copy;
223 *countp = actual;
224 }
225
226 return KERN_SUCCESS;
227 }
228 #endif /* MACH_IPC_DEBUG */
229
230 /*
231 * Routine: mach_port_space_info
232 * Purpose:
233 * Returns information about an IPC space.
234 * Conditions:
235 * Nothing locked. Obeys CountInOut protocol.
236 * Returns:
237 * KERN_SUCCESS Returned information.
238 * KERN_INVALID_TASK The space is null.
239 * KERN_INVALID_TASK The space is dead.
240 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
241 */
242
243 #if !MACH_IPC_DEBUG
244 kern_return_t
245 mach_port_space_info(
246 __unused ipc_space_t space,
247 __unused ipc_info_space_t *infop,
248 __unused ipc_info_name_array_t *tablep,
249 __unused mach_msg_type_number_t *tableCntp,
250 __unused ipc_info_tree_name_array_t *treep,
251 __unused mach_msg_type_number_t *treeCntp)
252 {
253 return KERN_FAILURE;
254 }
255 #else
256 kern_return_t
257 mach_port_space_info(
258 ipc_space_t space,
259 ipc_info_space_t *infop,
260 ipc_info_name_array_t *tablep,
261 mach_msg_type_number_t *tableCntp,
262 ipc_info_tree_name_array_t *treep,
263 mach_msg_type_number_t *treeCntp)
264 {
265 ipc_info_name_t *table_info;
266 unsigned int table_potential, table_actual;
267 vm_offset_t table_addr;
268 vm_size_t table_size;
269 ipc_info_tree_name_t *tree_info;
270 unsigned int tree_potential, tree_actual;
271 vm_offset_t tree_addr;
272 vm_size_t tree_size;
273 ipc_tree_entry_t tentry;
274 ipc_entry_t table;
275 ipc_entry_num_t tsize;
276 mach_port_index_t index;
277 kern_return_t kr;
278
279 if (space == IS_NULL)
280 return KERN_INVALID_TASK;
281
282 /* start with in-line memory */
283
284 table_size = 0;
285 table_info = *tablep;
286 table_potential = *tableCntp;
287 tree_size = 0;
288 tree_info = *treep;
289 tree_potential = *treeCntp;
290
291 for (;;) {
292 is_read_lock(space);
293 if (!space->is_active) {
294 is_read_unlock(space);
295 if (table_info != *tablep)
296 kmem_free(ipc_kernel_map,
297 table_addr, table_size);
298 if (tree_info != *treep)
299 kmem_free(ipc_kernel_map,
300 tree_addr, tree_size);
301 return KERN_INVALID_TASK;
302 }
303
304 table_actual = space->is_table_size;
305 tree_actual = space->is_tree_total;
306
307 if ((table_actual <= table_potential) &&
308 (tree_actual <= tree_potential))
309 break;
310
311 is_read_unlock(space);
312
313 if (table_actual > table_potential) {
314 if (table_info != *tablep)
315 kmem_free(ipc_kernel_map,
316 table_addr, table_size);
317
318 table_size = round_page(table_actual *
319 sizeof *table_info);
320 kr = kmem_alloc(ipc_kernel_map,
321 &table_addr, table_size);
322 if (kr != KERN_SUCCESS) {
323 if (tree_info != *treep)
324 kmem_free(ipc_kernel_map,
325 tree_addr, tree_size);
326
327 return KERN_RESOURCE_SHORTAGE;
328 }
329
330 table_info = (ipc_info_name_t *) table_addr;
331 table_potential = table_size/sizeof *table_info;
332 }
333
334 if (tree_actual > tree_potential) {
335 if (tree_info != *treep)
336 kmem_free(ipc_kernel_map,
337 tree_addr, tree_size);
338
339 tree_size = round_page(tree_actual *
340 sizeof *tree_info);
341 kr = kmem_alloc(ipc_kernel_map,
342 &tree_addr, tree_size);
343 if (kr != KERN_SUCCESS) {
344 if (table_info != *tablep)
345 kmem_free(ipc_kernel_map,
346 table_addr, table_size);
347
348 return KERN_RESOURCE_SHORTAGE;
349 }
350
351 tree_info = (ipc_info_tree_name_t *) tree_addr;
352 tree_potential = tree_size/sizeof *tree_info;
353 }
354 }
355 /* space is read-locked and active; we have enough wired memory */
356
357 infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD);
358 infop->iis_table_size = space->is_table_size;
359 infop->iis_table_next = space->is_table_next->its_size;
360 infop->iis_tree_size = space->is_tree_total;
361 infop->iis_tree_small = space->is_tree_small;
362 infop->iis_tree_hash = space->is_tree_hash;
363
364 table = space->is_table;
365 tsize = space->is_table_size;
366
367 for (index = 0; index < tsize; index++) {
368 ipc_info_name_t *iin = &table_info[index];
369 ipc_entry_t entry = &table[index];
370 ipc_entry_bits_t bits;
371
372 bits = entry->ie_bits;
373 iin->iin_name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
374 iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE;
375 iin->iin_type = IE_BITS_TYPE(bits);
376 iin->iin_urefs = IE_BITS_UREFS(bits);
377 iin->iin_object = (vm_offset_t) entry->ie_object;
378 iin->iin_next = entry->ie_next;
379 iin->iin_hash = entry->ie_index;
380 }
381
382 for (tentry = ipc_splay_traverse_start(&space->is_tree), index = 0;
383 tentry != ITE_NULL;
384 tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
385 ipc_info_tree_name_t *iitn = &tree_info[index++];
386 ipc_info_name_t *iin = &iitn->iitn_name;
387 ipc_entry_t entry = &tentry->ite_entry;
388 ipc_entry_bits_t bits = entry->ie_bits;
389
390 assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
391
392 iin->iin_name = tentry->ite_name;
393 iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE;
394 iin->iin_type = IE_BITS_TYPE(bits);
395 iin->iin_urefs = IE_BITS_UREFS(bits);
396 iin->iin_object = (vm_offset_t) entry->ie_object;
397 iin->iin_next = entry->ie_next;
398 iin->iin_hash = entry->ie_index;
399
400 if (tentry->ite_lchild == ITE_NULL)
401 iitn->iitn_lchild = MACH_PORT_NULL;
402 else
403 iitn->iitn_lchild = tentry->ite_lchild->ite_name;
404
405 if (tentry->ite_rchild == ITE_NULL)
406 iitn->iitn_rchild = MACH_PORT_NULL;
407 else
408 iitn->iitn_rchild = tentry->ite_rchild->ite_name;
409
410 }
411 ipc_splay_traverse_finish(&space->is_tree);
412 is_read_unlock(space);
413
414 if (table_info == *tablep) {
415 /* data fit in-line; nothing to deallocate */
416
417 *tableCntp = table_actual;
418 } else if (table_actual == 0) {
419 kmem_free(ipc_kernel_map, table_addr, table_size);
420
421 *tableCntp = 0;
422 } else {
423 vm_size_t size_used, rsize_used;
424 vm_map_copy_t copy;
425
426 /* kmem_alloc doesn't zero memory */
427
428 size_used = table_actual * sizeof *table_info;
429 rsize_used = round_page(size_used);
430
431 if (rsize_used != table_size)
432 kmem_free(ipc_kernel_map,
433 table_addr + rsize_used,
434 table_size - rsize_used);
435
436 if (size_used != rsize_used)
437 bzero((char *) (table_addr + size_used),
438 rsize_used - size_used);
439
440 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(table_addr),
441 vm_map_round_page(table_addr + rsize_used), FALSE);
442 assert(kr == KERN_SUCCESS);
443
444 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)table_addr,
445 (vm_map_size_t)rsize_used, TRUE, &copy);
446 assert(kr == KERN_SUCCESS);
447
448 *tablep = (ipc_info_name_t *) copy;
449 *tableCntp = table_actual;
450 }
451
452 if (tree_info == *treep) {
453 /* data fit in-line; nothing to deallocate */
454
455 *treeCntp = tree_actual;
456 } else if (tree_actual == 0) {
457 kmem_free(ipc_kernel_map, tree_addr, tree_size);
458
459 *treeCntp = 0;
460 } else {
461 vm_size_t size_used, rsize_used;
462 vm_map_copy_t copy;
463
464 /* kmem_alloc doesn't zero memory */
465
466 size_used = tree_actual * sizeof *tree_info;
467 rsize_used = round_page(size_used);
468
469 if (rsize_used != tree_size)
470 kmem_free(ipc_kernel_map,
471 tree_addr + rsize_used,
472 tree_size - rsize_used);
473
474 if (size_used != rsize_used)
475 bzero((char *) (tree_addr + size_used),
476 rsize_used - size_used);
477
478 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(tree_addr),
479 vm_map_round_page(tree_addr + rsize_used), FALSE);
480 assert(kr == KERN_SUCCESS);
481
482 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)tree_addr,
483 (vm_map_size_t)rsize_used, TRUE, &copy);
484 assert(kr == KERN_SUCCESS);
485
486 *treep = (ipc_info_tree_name_t *) copy;
487 *treeCntp = tree_actual;
488 }
489
490 return KERN_SUCCESS;
491 }
492 #endif /* MACH_IPC_DEBUG */
493
494 /*
495 * Routine: mach_port_dnrequest_info
496 * Purpose:
497 * Returns information about the dead-name requests
498 * registered with the named receive right.
499 * Conditions:
500 * Nothing locked.
501 * Returns:
502 * KERN_SUCCESS Retrieved information.
503 * KERN_INVALID_TASK The space is null.
504 * KERN_INVALID_TASK The space is dead.
505 * KERN_INVALID_NAME The name doesn't denote a right.
506 * KERN_INVALID_RIGHT Name doesn't denote receive rights.
507 */
508
509 #if !MACH_IPC_DEBUG
510 kern_return_t
511 mach_port_dnrequest_info(
512 __unused ipc_space_t space,
513 __unused mach_port_name_t name,
514 __unused unsigned int *totalp,
515 __unused unsigned int *usedp)
516 {
517 return KERN_FAILURE;
518 }
519 #else
520 kern_return_t
521 mach_port_dnrequest_info(
522 ipc_space_t space,
523 mach_port_name_t name,
524 unsigned int *totalp,
525 unsigned int *usedp)
526 {
527 unsigned int total, used;
528 ipc_port_t port;
529 kern_return_t kr;
530
531 if (space == IS_NULL)
532 return KERN_INVALID_TASK;
533
534 kr = ipc_port_translate_receive(space, name, &port);
535 if (kr != KERN_SUCCESS)
536 return kr;
537 /* port is locked and active */
538
539 if (port->ip_dnrequests == IPR_NULL) {
540 total = 0;
541 used = 0;
542 } else {
543 ipc_port_request_t dnrequests = port->ip_dnrequests;
544 ipc_port_request_index_t index;
545
546 total = dnrequests->ipr_size->its_size;
547
548 for (index = 1, used = 0;
549 index < total; index++) {
550 ipc_port_request_t ipr = &dnrequests[index];
551
552 if (ipr->ipr_name != MACH_PORT_NULL)
553 used++;
554 }
555 }
556 ip_unlock(port);
557
558 *totalp = total;
559 *usedp = used;
560 return KERN_SUCCESS;
561 }
562 #endif /* MACH_IPC_DEBUG */
563
564 /*
565 * Routine: mach_port_kernel_object [kernel call]
566 * Purpose:
567 * Retrieve the type and address of the kernel object
568 * represented by a send or receive right.
569 * Conditions:
570 * Nothing locked.
571 * Returns:
572 * KERN_SUCCESS Retrieved kernel object info.
573 * KERN_INVALID_TASK The space is null.
574 * KERN_INVALID_TASK The space is dead.
575 * KERN_INVALID_NAME The name doesn't denote a right.
576 * KERN_INVALID_RIGHT Name doesn't denote
577 * send or receive rights.
578 */
579
580 #if !MACH_IPC_DEBUG
581 kern_return_t
582 mach_port_kernel_object(
583 __unused ipc_space_t space,
584 __unused mach_port_name_t name,
585 __unused unsigned int *typep,
586 __unused vm_offset_t *addrp)
587 {
588 return KERN_FAILURE;
589 }
590 #else
591 kern_return_t
592 mach_port_kernel_object(
593 ipc_space_t space,
594 mach_port_name_t name,
595 unsigned int *typep,
596 vm_offset_t *addrp)
597 {
598 ipc_entry_t entry;
599 ipc_port_t port;
600 kern_return_t kr;
601
602 kr = ipc_right_lookup_read(space, name, &entry);
603 if (kr != KERN_SUCCESS)
604 return kr;
605 /* space is read-locked and active */
606
607 if ((entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE) == 0) {
608 is_read_unlock(space);
609 return KERN_INVALID_RIGHT;
610 }
611
612 port = (ipc_port_t) entry->ie_object;
613 assert(port != IP_NULL);
614
615 ip_lock(port);
616 is_read_unlock(space);
617
618 if (!ip_active(port)) {
619 ip_unlock(port);
620 return KERN_INVALID_RIGHT;
621 }
622
623 *typep = (unsigned int) ip_kotype(port);
624 *addrp = (vm_offset_t) port->ip_kobject;
625 ip_unlock(port);
626 return KERN_SUCCESS;
627
628 }
629 #endif /* MACH_IPC_DEBUG */