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