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