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