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