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