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