2 * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
28 #include <mach/mach.h>
29 #include <mach/mach_voucher.h>
32 const char * kobject_name(natural_t kotype
)
35 case IKOT_NONE
: return "message-queue";
36 case IKOT_THREAD
: return "THREAD";
37 case IKOT_TASK
: return "TASK";
38 case IKOT_HOST
: return "HOST";
39 case IKOT_HOST_PRIV
: return "HOST-PRIV";
40 case IKOT_PROCESSOR
: return "PROCESSOR";
41 case IKOT_PSET
: return "PROCESSOR-SET";
42 case IKOT_PSET_NAME
: return "PROCESSOR-SET-NAME";
43 case IKOT_TIMER
: return "TIMER";
44 case IKOT_PAGING_REQUEST
: return "PAGER-REQUEST";
45 case IKOT_MIG
: return "MIG";
46 case IKOT_MEMORY_OBJECT
: return "MEMORY-OBJECT";
47 case IKOT_XMM_PAGER
: return "XMM-PAGER";
48 case IKOT_XMM_KERNEL
: return "XMM-KERNEL";
49 case IKOT_XMM_REPLY
: return "XMM-REPLY";
50 case IKOT_UND_REPLY
: return "UND-REPLY";
51 case IKOT_HOST_NOTIFY
: return "message-queue";
52 case IKOT_HOST_SECURITY
: return "HOST-SECURITY";
53 case IKOT_LEDGER
: return "LEDGER";
54 case IKOT_MASTER_DEVICE
: return "MASTER-DEVICE";
55 case IKOT_TASK_NAME
: return "TASK-NAME";
56 case IKOT_SUBSYSTEM
: return "SUBSYSTEM";
57 case IKOT_IO_DONE_QUEUE
: return "IO-QUEUE-DONE";
58 case IKOT_SEMAPHORE
: return "SEMAPHORE";
59 case IKOT_LOCK_SET
: return "LOCK-SET";
60 case IKOT_CLOCK
: return "CLOCK";
61 case IKOT_CLOCK_CTRL
: return "CLOCK-CONTROL";
62 case IKOT_IOKIT_SPARE
: return "IOKIT-SPARE";
63 case IKOT_NAMED_ENTRY
: return "NAMED-MEMORY";
64 case IKOT_IOKIT_CONNECT
: return "IOKIT-CONNECT";
65 case IKOT_IOKIT_OBJECT
: return "IOKIT-OBJECT";
66 case IKOT_UPL
: return "UPL";
67 case IKOT_MEM_OBJ_CONTROL
: return "XMM-CONTROL";
68 case IKOT_AU_SESSIONPORT
: return "SESSIONPORT";
69 case IKOT_FILEPORT
: return "FILEPORT";
70 case IKOT_LABELH
: return "MACF-LABEL";
71 case IKOT_TASK_RESUME
: return "TASK_RESUME";
72 case IKOT_VOUCHER
: return "VOUCHER";
73 case IKOT_VOUCHER_ATTR_CONTROL
: return "VOUCHER_ATTR_CONTROL";
75 default: return "UNKNOWN";
79 #define VOUCHER_DETAIL_PREFIX " "
81 static const unsigned int voucher_contents_size
= 8192;
82 static uint8_t voucher_contents
[voucher_contents_size
];
85 static uint32_t safesize (int len
){
86 return (len
> 0) ? len
: 0;
89 uint32_t show_recipe_detail(mach_voucher_attr_recipe_t recipe
, char *voucher_outstr
, uint32_t maxlen
) {
91 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, VOUCHER_DETAIL_PREFIX
"Key: %u, ", recipe
->key
));
92 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, "Command: %u, ", recipe
->command
));
93 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, "Previous voucher: 0x%x, ", recipe
->previous_voucher
));
94 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, "Content size: %u\n", recipe
->content_size
));
96 switch (recipe
->key
) {
97 case MACH_VOUCHER_ATTR_KEY_ATM
:
98 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, VOUCHER_DETAIL_PREFIX
"ATM ID: %llu\n", *(uint64_t *)(uintptr_t)recipe
->content
));
100 case MACH_VOUCHER_ATTR_KEY_IMPORTANCE
:
101 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, VOUCHER_DETAIL_PREFIX
"IMPORTANCE INFO: %s\n", (char *)recipe
->content
));
103 case MACH_VOUCHER_ATTR_KEY_BANK
:
104 len
+= safesize(snprintf(&voucher_outstr
[len
], maxlen
- len
, VOUCHER_DETAIL_PREFIX
"RESOURCE ACCOUNTING INFO: %s\n", (char *)recipe
->content
));
107 len
+= print_hex_data(&voucher_outstr
[len
], maxlen
- len
, VOUCHER_DETAIL_PREFIX
, "Recipe Contents", (void *)recipe
->content
, MIN(recipe
->content_size
, lsmp_config
.voucher_detail_length
));
115 char * copy_voucher_detail(mach_port_t task
, mach_port_name_t voucher
) {
116 unsigned int recipe_size
= voucher_contents_size
;
117 kern_return_t kr
= KERN_SUCCESS
;
118 bzero((void *)&voucher_contents
[0], sizeof(voucher_contents
));
119 unsigned v_kobject
= 0;
120 unsigned v_kotype
= 0;
121 uint32_t detail_maxlen
= VOUCHER_DETAIL_MAXLEN
;
122 char * voucher_outstr
= (char *)malloc(detail_maxlen
);
123 voucher_outstr
[0] = '\0';
126 kr
= mach_port_kernel_object( task
,
128 &v_kotype
, (unsigned *)&v_kobject
);
129 if (kr
== KERN_SUCCESS
&& v_kotype
== IKOT_VOUCHER
) {
131 kr
= mach_voucher_debug_info(task
, voucher
,
132 (mach_voucher_attr_raw_recipe_array_t
)&voucher_contents
[0],
134 if (kr
!= KERN_SUCCESS
&& kr
!= KERN_NOT_SUPPORTED
) {
135 plen
+= safesize(snprintf(&voucher_outstr
[plen
], detail_maxlen
- plen
, VOUCHER_DETAIL_PREFIX
"Voucher: 0x%x Failed to get contents %s\n", v_kobject
, mach_error_string(kr
)));
136 return voucher_outstr
;
139 if (recipe_size
== 0) {
140 plen
+= safesize(snprintf(&voucher_outstr
[plen
], detail_maxlen
- plen
, VOUCHER_DETAIL_PREFIX
"Voucher: 0x%x has no contents\n", v_kobject
));
141 return voucher_outstr
;
144 plen
+= safesize(snprintf(&voucher_outstr
[plen
], detail_maxlen
- plen
, VOUCHER_DETAIL_PREFIX
"Voucher: 0x%x\n", v_kobject
));
145 unsigned int used_size
= 0;
146 mach_voucher_attr_recipe_t recipe
= NULL
;
147 while (recipe_size
> used_size
) {
148 recipe
= (mach_voucher_attr_recipe_t
)&voucher_contents
[used_size
];
150 plen
+= show_recipe_detail(recipe
, &voucher_outstr
[plen
], detail_maxlen
- plen
);
152 used_size
+= sizeof(mach_voucher_attr_recipe_data_t
) + recipe
->content_size
;
155 plen
+= safesize(snprintf(&voucher_outstr
[plen
], detail_maxlen
- plen
, VOUCHER_DETAIL_PREFIX
"Invalid voucher: 0x%x\n", voucher
));
158 return voucher_outstr
;
161 void get_receive_port_context(task_t taskp
, mach_port_name_t portname
, mach_port_context_t
*context
) {
162 if (context
== NULL
) {
167 ret
= mach_port_get_context(taskp
, portname
, context
);
168 if (ret
!= KERN_SUCCESS
) {
169 fprintf(stderr
, "mach_port_get_context(0x%08x) failed: %s\n",
171 mach_error_string(ret
));
172 *context
= (mach_port_context_t
)0;
177 int get_recieve_port_status(task_t taskp
, mach_port_name_t portname
, mach_port_info_ext_t
*info
){
181 mach_msg_type_number_t statusCnt
;
183 statusCnt
= MACH_PORT_INFO_EXT_COUNT
;
184 ret
= mach_port_get_attributes(taskp
,
187 (mach_port_info_t
)info
,
189 if (ret
!= KERN_SUCCESS
) {
190 fprintf(stderr
, "mach_port_get_attributes(0x%08x) failed: %s\n",
192 mach_error_string(ret
));
199 void show_task_mach_ports(my_per_task_info_t
*taskinfo
, uint32_t taskCount
, my_per_task_info_t
*allTaskInfos
)
201 int i
, emptycount
= 0, portsetcount
= 0, sendcount
= 0, receivecount
= 0, sendoncecount
= 0, deadcount
= 0, dncount
= 0, vouchercount
= 0, pid
;
203 pid_for_task(taskinfo
->task
, &pid
);
205 printf(" name ipc-object rights flags boost reqs recv send sonce oref qlimit msgcount context identifier type\n");
206 printf("--------- ---------- ---------- -------- ----- ---- ----- ----- ----- ---- ------ -------- ------------------ ----------- ------------\n");
207 for (i
= 0; i
< taskinfo
->tableCount
; i
++) {
209 boolean_t send
= FALSE
;
210 boolean_t sendonce
= FALSE
;
211 boolean_t dnreq
= FALSE
;
213 unsigned int kotype
= 0;
214 vm_offset_t kobject
= (vm_offset_t
)0;
216 /* skip empty slots in the table */
217 if ((taskinfo
->table
[i
].iin_type
& MACH_PORT_TYPE_ALL_RIGHTS
) == 0) {
222 if (taskinfo
->table
[i
].iin_type
== MACH_PORT_TYPE_PORT_SET
) {
223 mach_port_name_array_t members
;
224 mach_msg_type_number_t membersCnt
;
226 ret
= mach_port_get_set_status(taskinfo
->task
,
227 taskinfo
->table
[i
].iin_name
,
228 &members
, &membersCnt
);
229 if (ret
!= KERN_SUCCESS
) {
230 fprintf(stderr
, "mach_port_get_set_status(0x%08x) failed: %s\n",
231 taskinfo
->table
[i
].iin_name
,
232 mach_error_string(ret
));
235 printf("0x%08x 0x%08x port-set -------- --- 1 %d members\n",
236 taskinfo
->table
[i
].iin_name
,
237 taskinfo
->table
[i
].iin_object
,
239 /* get some info for each portset member */
240 for (j
= 0; j
< membersCnt
; j
++) {
241 for (k
= 0; k
< taskinfo
->tableCount
; k
++) {
242 if (taskinfo
->table
[k
].iin_name
== members
[j
]) {
243 mach_port_info_ext_t info
;
244 mach_port_status_t port_status
;
245 mach_port_context_t port_context
= (mach_port_context_t
)0;
246 if (0 != get_recieve_port_status(taskinfo
->task
, taskinfo
->table
[k
].iin_name
, &info
)) {
247 bzero((void *)&info
, sizeof(info
));
249 port_status
= info
.mpie_status
;
250 get_receive_port_context(taskinfo
->task
, taskinfo
->table
[k
].iin_name
, &port_context
);
251 printf(" - 0x%08x %s --%s%s%s%s%s%s %5d %s%s%s %5d %5.0d %5.0d %s %6d %8d 0x%016llx 0x%08x (%d) %s\n",
252 taskinfo
->table
[k
].iin_object
,
253 (taskinfo
->table
[k
].iin_type
& MACH_PORT_TYPE_SEND
) ? "recv,send ":"recv ",
254 SHOW_PORT_STATUS_FLAGS(port_status
.mps_flags
),
256 (taskinfo
->table
[k
].iin_type
& MACH_PORT_TYPE_DNREQUEST
) ? "D" : "-",
257 (port_status
.mps_nsrequest
) ? "N" : "-",
258 (port_status
.mps_pdrequest
) ? "P" : "-",
260 taskinfo
->table
[k
].iin_urefs
,
261 port_status
.mps_sorights
,
262 (port_status
.mps_srights
) ? "Y" : "N",
263 port_status
.mps_qlimit
,
264 port_status
.mps_msgcount
,
265 (uint64_t)port_context
,
266 taskinfo
->table
[k
].iin_name
,
268 taskinfo
->processName
);
274 ret
= vm_deallocate(mach_task_self(), (vm_address_t
)members
,
275 membersCnt
* sizeof(mach_port_name_t
));
276 if (ret
!= KERN_SUCCESS
) {
277 fprintf(stderr
, "vm_deallocate() failed: %s\n",
278 mach_error_string(ret
));
285 if (taskinfo
->table
[i
].iin_type
& MACH_PORT_TYPE_SEND
) {
287 sendrights
= taskinfo
->table
[i
].iin_urefs
;
291 if (taskinfo
->table
[i
].iin_type
& MACH_PORT_TYPE_DNREQUEST
) {
296 if (taskinfo
->table
[i
].iin_type
& MACH_PORT_TYPE_RECEIVE
) {
297 mach_port_status_t status
;
298 mach_port_info_ext_t info
;
299 mach_port_context_t context
= (mach_port_context_t
)0;
300 struct k2n_table_node
*k2nnode
;
301 ret
= get_recieve_port_status(taskinfo
->task
, taskinfo
->table
[i
].iin_name
, &info
);
302 get_receive_port_context(taskinfo
->task
, taskinfo
->table
[i
].iin_name
, &context
);
303 /* its ok to fail in fetching attributes */
307 status
= info
.mpie_status
;
308 printf("0x%08x 0x%08x %s --%s%s%s%s%s%s %5d %s%s%s %5d %5.0d %5.0d %s %6d %8d 0x%016llx \n",
309 taskinfo
->table
[i
].iin_name
,
310 taskinfo
->table
[i
].iin_object
,
311 (send
) ? "recv,send ":"recv ",
312 SHOW_PORT_STATUS_FLAGS(status
.mps_flags
),
315 (status
.mps_nsrequest
) ? "N":"-",
316 (status
.mps_pdrequest
) ? "P":"-",
320 (status
.mps_srights
) ? "Y":"N",
326 /* show other rights (in this and other tasks) for the port */
327 for (j
= 0; j
< taskCount
; j
++) {
328 if (allTaskInfos
[j
].valid
== FALSE
)
331 k2nnode
= k2n_table_lookup(allTaskInfos
[j
].k2ntable
, taskinfo
->table
[i
].iin_object
);
334 if (k2nnode
->info_name
!= &taskinfo
->table
[i
]) {
335 assert(k2nnode
->info_name
->iin_object
== taskinfo
->table
[i
].iin_object
);
337 printf(" + %s -------- %s%s%s %5d <- 0x%08x (%d) %s\n",
338 (k2nnode
->info_name
->iin_type
& MACH_PORT_TYPE_SEND_ONCE
) ?
339 "send-once " : "send ",
340 (k2nnode
->info_name
->iin_type
& MACH_PORT_TYPE_DNREQUEST
) ? "D" : "-",
343 k2nnode
->info_name
->iin_urefs
,
344 k2nnode
->info_name
->iin_name
,
346 allTaskInfos
[j
].processName
);
349 k2nnode
= k2n_table_lookup_next(k2nnode
, k2nnode
->info_name
->iin_name
);
354 else if (taskinfo
->table
[i
].iin_type
& MACH_PORT_TYPE_DEAD_NAME
)
356 printf("0x%08x 0x%08x dead-name -------- --- %5d \n",
357 taskinfo
->table
[i
].iin_name
,
358 taskinfo
->table
[i
].iin_object
,
359 taskinfo
->table
[i
].iin_urefs
);
364 if (taskinfo
->table
[i
].iin_type
& MACH_PORT_TYPE_SEND_ONCE
) {
369 printf("0x%08x 0x%08x %s -------- %s%s%s %5.0d ",
370 taskinfo
->table
[i
].iin_name
,
371 taskinfo
->table
[i
].iin_object
,
372 (send
) ? "send ":"send-once ",
376 (send
) ? sendrights
: 0);
378 /* converting to kobjects is not always supported */
379 ret
= mach_port_kernel_object(taskinfo
->task
,
380 taskinfo
->table
[i
].iin_name
,
381 &kotype
, (unsigned *)&kobject
);
382 if (ret
== KERN_SUCCESS
&& kotype
!= 0) {
383 printf(" 0x%08x %s", (natural_t
)kobject
, kobject_name(kotype
));
384 if ((kotype
== IKOT_TASK_RESUME
) || (kotype
== IKOT_TASK
) || (kotype
== IKOT_TASK_NAME
)) {
385 if (taskinfo
->task_kobject
== kobject
) {
386 /* neat little optimization since in most cases tasks have themselves in their ipc space */
387 printf(" SELF (%d) %s", taskinfo
->pid
, taskinfo
->processName
);
389 my_per_task_info_t
* _found_task
= get_taskinfo_by_kobject((natural_t
)kobject
);
390 printf(" (%d) %s", _found_task
->pid
, _found_task
->processName
);
395 if (kotype
== IKOT_VOUCHER
) {
397 if (lsmp_config
.show_voucher_details
) {
398 char * detail
= copy_voucher_detail(taskinfo
->task
, taskinfo
->table
[i
].iin_name
);
399 printf("%s\n", detail
);
406 /* not kobject - find the receive right holder */
407 my_per_task_info_t
*recv_holder_taskinfo
;
408 mach_port_name_t recv_name
= MACH_PORT_NULL
;
409 if (KERN_SUCCESS
== get_taskinfo_of_receiver_by_send_right(&taskinfo
->table
[i
], &recv_holder_taskinfo
, &recv_name
)) {
410 mach_port_status_t port_status
;
411 mach_port_info_ext_t info
;
412 mach_port_context_t port_context
= (mach_port_context_t
)0;
413 if (0 != get_recieve_port_status(recv_holder_taskinfo
->task
, recv_name
, &info
)) {
414 bzero((void *)&port_status
, sizeof(port_status
));
416 port_status
= info
.mpie_status
;
417 get_receive_port_context(recv_holder_taskinfo
->task
, recv_name
, &port_context
);
418 printf(" -> %6d %8d 0x%016llx 0x%08x (%d) %s\n",
419 port_status
.mps_qlimit
,
420 port_status
.mps_msgcount
,
421 (uint64_t)port_context
,
423 recv_holder_taskinfo
->pid
,
424 recv_holder_taskinfo
->processName
);
427 printf(" 0x00000000 (-) Unknown Process\n");
430 printf("total = %d\n", taskinfo
->tableCount
+ taskinfo
->treeCount
- emptycount
);
431 printf("SEND = %d\n", sendcount
);
432 printf("RECEIVE = %d\n", receivecount
);
433 printf("SEND_ONCE = %d\n", sendoncecount
);
434 printf("PORT_SET = %d\n", portsetcount
);
435 printf("DEAD_NAME = %d\n", deadcount
);
436 printf("DNREQUEST = %d\n", dncount
);
437 printf("VOUCHERS = %d\n", vouchercount
);
441 uint32_t print_hex_data(char *outstr
, size_t maxlen
, char *prefix
, char *desc
, void *addr
, int len
) {
443 unsigned char buff
[17];
444 unsigned char *pc
= addr
;
448 plen
+= safesize(snprintf(&outstr
[len
], maxlen
- plen
, "%s%s:\n", prefix
, desc
));
450 for (i
= 0; i
< len
; i
++) {
454 plen
+= safesize(snprintf(&outstr
[len
], maxlen
- plen
, " %s\n", buff
));
456 plen
+= safesize(snprintf(&outstr
[len
], maxlen
- plen
, "%s %04x ", prefix
, i
));
459 plen
+= safesize(snprintf(&outstr
[len
], maxlen
- plen
, " %02x", pc
[i
]));
461 if ((pc
[i
] < 0x20) || (pc
[i
] > 0x7e))
464 buff
[i
% 16] = pc
[i
];
465 buff
[(i
% 16) + 1] = '\0';
468 while ((i
% 16) != 0) {
469 plen
+= safesize(snprintf(&outstr
[len
], maxlen
- plen
, " "));
473 plen
+= safesize(snprintf(&outstr
[len
], maxlen
- plen
, " %s\n", buff
));