]> git.saurik.com Git - apple/system_cmds.git/blob - lsmp.tproj/port_details.c
system_cmds-670.1.2.tar.gz
[apple/system_cmds.git] / lsmp.tproj / port_details.c
1 /*
2 * Copyright (c) 2002-20014 Apple 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 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <libproc.h>
27 #include <mach/mach.h>
28 #include <mach/mach_voucher.h>
29 #include "common.h"
30
31 const char * kobject_name(natural_t kotype)
32 {
33 switch (kotype) {
34 case IKOT_NONE: return "message-queue";
35 case IKOT_THREAD: return "THREAD";
36 case IKOT_TASK: return "TASK";
37 case IKOT_HOST: return "HOST";
38 case IKOT_HOST_PRIV: return "HOST-PRIV";
39 case IKOT_PROCESSOR: return "PROCESSOR";
40 case IKOT_PSET: return "PROCESSOR-SET";
41 case IKOT_PSET_NAME: return "PROCESSOR-SET-NAME";
42 case IKOT_TIMER: return "TIMER";
43 case IKOT_PAGING_REQUEST: return "PAGER-REQUEST";
44 case IKOT_MIG: return "MIG";
45 case IKOT_MEMORY_OBJECT: return "MEMORY-OBJECT";
46 case IKOT_XMM_PAGER: return "XMM-PAGER";
47 case IKOT_XMM_KERNEL: return "XMM-KERNEL";
48 case IKOT_XMM_REPLY: return "XMM-REPLY";
49 case IKOT_UND_REPLY: return "UND-REPLY";
50 case IKOT_HOST_NOTIFY: return "message-queue";
51 case IKOT_HOST_SECURITY: return "HOST-SECURITY";
52 case IKOT_LEDGER: return "LEDGER";
53 case IKOT_MASTER_DEVICE: return "MASTER-DEVICE";
54 case IKOT_TASK_NAME: return "TASK-NAME";
55 case IKOT_SUBSYSTEM: return "SUBSYSTEM";
56 case IKOT_IO_DONE_QUEUE: return "IO-QUEUE-DONE";
57 case IKOT_SEMAPHORE: return "SEMAPHORE";
58 case IKOT_LOCK_SET: return "LOCK-SET";
59 case IKOT_CLOCK: return "CLOCK";
60 case IKOT_CLOCK_CTRL: return "CLOCK-CONTROL";
61 case IKOT_IOKIT_SPARE: return "IOKIT-SPARE";
62 case IKOT_NAMED_ENTRY: return "NAMED-MEMORY";
63 case IKOT_IOKIT_CONNECT: return "IOKIT-CONNECT";
64 case IKOT_IOKIT_OBJECT: return "IOKIT-OBJECT";
65 case IKOT_UPL: return "UPL";
66 case IKOT_MEM_OBJ_CONTROL: return "XMM-CONTROL";
67 case IKOT_AU_SESSIONPORT: return "SESSIONPORT";
68 case IKOT_FILEPORT: return "FILEPORT";
69 case IKOT_LABELH: return "MACF-LABEL";
70 case IKOT_TASK_RESUME: return "TASK_RESUME";
71 case IKOT_VOUCHER: return "VOUCHER";
72 case IKOT_VOUCHER_ATTR_CONTROL: return "VOUCHER_ATTR_CONTROL";
73 case IKOT_UNKNOWN:
74 default: return "UNKNOWN";
75 }
76 }
77
78 #define VOUCHER_DETAIL_PREFIX " "
79
80 static const unsigned int voucher_contents_size = 8192;
81 static uint8_t voucher_contents[voucher_contents_size];
82
83
84 void show_recipe_detail(mach_voucher_attr_recipe_t recipe) {
85 printf(VOUCHER_DETAIL_PREFIX "Key: %u, ", recipe->key);
86 printf("Command: %u, ", recipe->command);
87 printf("Previous voucher: 0x%x, ", recipe->previous_voucher);
88 printf("Content size: %u\n", recipe->content_size);
89 switch (recipe->key) {
90 case MACH_VOUCHER_ATTR_KEY_ATM:
91 printf(VOUCHER_DETAIL_PREFIX "ATM ID: %llu\n", *(uint64_t *)(uintptr_t)recipe->content);
92 break;
93 case MACH_VOUCHER_ATTR_KEY_IMPORTANCE:
94 printf(VOUCHER_DETAIL_PREFIX "IMPORTANCE INFO: %s\n", (char *)recipe->content);
95 break;
96 case MACH_VOUCHER_ATTR_KEY_BANK:
97 printf(VOUCHER_DETAIL_PREFIX "RESOURCE ACCOUNTING INFO: %s\n", (char *)recipe->content);
98 break;
99 default:
100 print_hex_data(VOUCHER_DETAIL_PREFIX, "Recipe Contents", (void *)recipe->content, MIN(recipe->content_size, lsmp_config.voucher_detail_length));
101 break;
102 }
103
104 }
105
106 void show_voucher_detail(mach_port_t task, mach_port_name_t voucher) {
107 unsigned int recipe_size = voucher_contents_size;
108 kern_return_t kr = KERN_SUCCESS;
109 bzero((void *)&voucher_contents[0], sizeof(voucher_contents));
110 unsigned v_kobject = 0;
111 unsigned v_kotype = 0;
112 kr = mach_port_kernel_object( task,
113 voucher,
114 &v_kotype, (unsigned *)&v_kobject);
115 if (kr == KERN_SUCCESS && v_kotype == IKOT_VOUCHER ) {
116
117 kr = mach_voucher_debug_info(task, voucher,
118 (mach_voucher_attr_raw_recipe_array_t)&voucher_contents[0],
119 &recipe_size);
120 if (kr != KERN_SUCCESS && kr != KERN_NOT_SUPPORTED) {
121 printf(VOUCHER_DETAIL_PREFIX "Voucher: 0x%x Failed to get contents %s\n", v_kobject, mach_error_string(kr));
122 return;
123 }
124
125 if (recipe_size == 0) {
126 printf(VOUCHER_DETAIL_PREFIX "Voucher: 0x%x has no contents\n", v_kobject);
127 return;
128 }
129 printf(VOUCHER_DETAIL_PREFIX "Voucher: 0x%x\n", v_kobject);
130 unsigned int used_size = 0;
131 mach_voucher_attr_recipe_t recipe = NULL;
132 while (recipe_size > used_size) {
133 recipe = (mach_voucher_attr_recipe_t)&voucher_contents[used_size];
134 if (recipe->key) {
135 show_recipe_detail(recipe);
136 }
137 used_size += sizeof(mach_voucher_attr_recipe_data_t) + recipe->content_size;
138 }
139 } else {
140 printf(VOUCHER_DETAIL_PREFIX "Invalid voucher: 0x%x\n", voucher);
141 }
142 }
143
144 void get_receive_port_context(task_t taskp, mach_port_name_t portname, mach_port_context_t *context) {
145 if (context == NULL) {
146 return;
147 }
148
149 kern_return_t ret;
150 ret = mach_port_get_context(taskp, portname, context);
151 if (ret != KERN_SUCCESS) {
152 fprintf(stderr, "mach_port_get_context(0x%08x) failed: %s\n",
153 portname,
154 mach_error_string(ret));
155 *context = (mach_port_context_t)0;
156 }
157 return;
158 }
159
160 int get_recieve_port_status(task_t taskp, mach_port_name_t portname, mach_port_info_ext_t *info){
161 if (info == NULL) {
162 return -1;
163 }
164 mach_msg_type_number_t statusCnt;
165 kern_return_t ret;
166 statusCnt = MACH_PORT_INFO_EXT_COUNT;
167 ret = mach_port_get_attributes(taskp,
168 portname,
169 MACH_PORT_INFO_EXT,
170 (mach_port_info_t)info,
171 &statusCnt);
172 if (ret != KERN_SUCCESS) {
173 fprintf(stderr, "mach_port_get_attributes(0x%08x) failed: %s\n",
174 portname,
175 mach_error_string(ret));
176 return -1;
177 }
178
179 return 0;
180 }
181
182 void show_task_mach_ports(my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos)
183 {
184 int i, emptycount = 0, portsetcount = 0, sendcount = 0, receivecount = 0, sendoncecount = 0, deadcount = 0, dncount = 0, vouchercount = 0, pid;
185 kern_return_t ret;
186 pid_for_task(taskinfo->task, &pid);
187
188 printf(" name ipc-object rights flags boost reqs recv send sonce oref qlimit msgcount context identifier type\n");
189 printf("--------- ---------- ---------- -------- ----- ---- ----- ----- ----- ---- ------ -------- ------------------ ----------- ------------\n");
190 for (i = 0; i < taskinfo->tableCount; i++) {
191 int j, k;
192 boolean_t send = FALSE;
193 boolean_t sendonce = FALSE;
194 boolean_t dnreq = FALSE;
195 int sendrights = 0;
196 unsigned int kotype = 0;
197 vm_offset_t kobject = (vm_offset_t)0;
198
199 /* skip empty slots in the table */
200 if ((taskinfo->table[i].iin_type & MACH_PORT_TYPE_ALL_RIGHTS) == 0) {
201 emptycount++;
202 continue;
203 }
204
205
206 if (taskinfo->table[i].iin_type == MACH_PORT_TYPE_PORT_SET) {
207 mach_port_name_array_t members;
208 mach_msg_type_number_t membersCnt;
209
210 ret = mach_port_get_set_status(taskinfo->task,
211 taskinfo->table[i].iin_name,
212 &members, &membersCnt);
213 if (ret != KERN_SUCCESS) {
214 fprintf(stderr, "mach_port_get_set_status(0x%08x) failed: %s\n",
215 taskinfo->table[i].iin_name,
216 mach_error_string(ret));
217 continue;
218 }
219 printf("0x%08x 0x%08x port-set -------- --- 1 %d members\n",
220 taskinfo->table[i].iin_name,
221 taskinfo->table[i].iin_object,
222 membersCnt);
223 /* get some info for each portset member */
224 for (j = 0; j < membersCnt; j++) {
225 for (k = 0; k < taskinfo->tableCount; k++) {
226 if (taskinfo->table[k].iin_name == members[j]) {
227 mach_port_info_ext_t info;
228 mach_port_status_t port_status;
229 mach_port_context_t port_context = (mach_port_context_t)0;
230 if (0 != get_recieve_port_status(taskinfo->task, taskinfo->table[k].iin_name, &info)) {
231 bzero((void *)&info, sizeof(info));
232 }
233 port_status = info.mpie_status;
234 get_receive_port_context(taskinfo->task, taskinfo->table[k].iin_name, &port_context);
235 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",
236 taskinfo->table[k].iin_object,
237 (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) ? "recv,send ":"recv ",
238 SHOW_PORT_STATUS_FLAGS(port_status.mps_flags),
239 info.mpie_boost_cnt,
240 (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
241 (port_status.mps_nsrequest) ? "N" : "-",
242 (port_status.mps_pdrequest) ? "P" : "-",
243 1,
244 taskinfo->table[k].iin_urefs,
245 port_status.mps_sorights,
246 (port_status.mps_srights) ? "Y" : "N",
247 port_status.mps_qlimit,
248 port_status.mps_msgcount,
249 (uint64_t)port_context,
250 taskinfo->table[k].iin_name,
251 pid,
252 taskinfo->processName);
253 break;
254 }
255 }
256 }
257
258 ret = vm_deallocate(mach_task_self(), (vm_address_t)members,
259 membersCnt * sizeof(mach_port_name_t));
260 if (ret != KERN_SUCCESS) {
261 fprintf(stderr, "vm_deallocate() failed: %s\n",
262 mach_error_string(ret));
263 exit(1);
264 }
265 portsetcount++;
266 continue;
267 }
268
269 if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_SEND) {
270 send = TRUE;
271 sendrights = taskinfo->table[i].iin_urefs;
272 sendcount++;
273 }
274
275 if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_DNREQUEST) {
276 dnreq = TRUE;
277 dncount++;
278 }
279
280 if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_RECEIVE) {
281 mach_port_status_t status;
282 mach_port_info_ext_t info;
283 mach_port_context_t context = (mach_port_context_t)0;
284 ret = get_recieve_port_status(taskinfo->task, taskinfo->table[i].iin_name, &info);
285 get_receive_port_context(taskinfo->task, taskinfo->table[i].iin_name, &context);
286 /* its ok to fail in fetching attributes */
287 if (ret < 0) {
288 continue;
289 }
290 status = info.mpie_status;
291 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",
292 taskinfo->table[i].iin_name,
293 taskinfo->table[i].iin_object,
294 (send) ? "recv,send ":"recv ",
295 SHOW_PORT_STATUS_FLAGS(status.mps_flags),
296 info.mpie_boost_cnt,
297 (dnreq) ? "D":"-",
298 (status.mps_nsrequest) ? "N":"-",
299 (status.mps_pdrequest) ? "P":"-",
300 1,
301 sendrights,
302 status.mps_sorights,
303 (status.mps_srights) ? "Y":"N",
304 status.mps_qlimit,
305 status.mps_msgcount,
306 (uint64_t)context);
307 receivecount++;
308
309
310 /* show other rights (in this and other tasks) for the port */
311 for (j = 0; j < taskCount; j++) {
312 for (k = 0; k < allTaskInfos[j].tableCount; k++) {
313 if (allTaskInfos[j].valid == FALSE ||
314 &allTaskInfos[j].table[k] == &taskinfo->table[i] ||
315 allTaskInfos[j].table[k].iin_object != taskinfo->table[i].iin_object)
316 continue;
317
318 printf(" + %s -------- %s%s%s %5d <- 0x%08x (%d) %s\n",
319 (allTaskInfos[j].table[k].iin_type & MACH_PORT_TYPE_SEND_ONCE) ?
320 "send-once " : "send ",
321 (allTaskInfos[j].table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
322 "-",
323 "-",
324 allTaskInfos[j].table[k].iin_urefs,
325 allTaskInfos[j].table[k].iin_name,
326 allTaskInfos[j].pid,
327 allTaskInfos[j].processName);
328 }
329 }
330 continue;
331 }
332 else if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_DEAD_NAME)
333 {
334 printf("0x%08x 0x%08x dead-name -------- --- %5d \n",
335 taskinfo->table[i].iin_name,
336 taskinfo->table[i].iin_object,
337 taskinfo->table[i].iin_urefs);
338 deadcount++;
339 continue;
340 }
341
342 if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_SEND_ONCE) {
343 sendonce = TRUE;
344 sendoncecount++;
345 }
346
347 printf("0x%08x 0x%08x %s -------- %s%s%s %5.0d ",
348 taskinfo->table[i].iin_name,
349 taskinfo->table[i].iin_object,
350 (send) ? "send ":"send-once ",
351 (dnreq) ? "D":"-",
352 "-",
353 "-",
354 (send) ? sendrights : 0);
355
356 /* converting to kobjects is not always supported */
357 ret = mach_port_kernel_object(taskinfo->task,
358 taskinfo->table[i].iin_name,
359 &kotype, (unsigned *)&kobject);
360 if (ret == KERN_SUCCESS && kotype != 0) {
361 printf(" 0x%08x %s", (natural_t)kobject, kobject_name(kotype));
362 if ((kotype == IKOT_TASK_RESUME) || (kotype == IKOT_TASK) || (kotype == IKOT_TASK_NAME)) {
363 if (taskinfo->task_kobject == kobject) {
364 /* neat little optimization since in most cases tasks have themselves in their ipc space */
365 printf(" SELF (%d) %s", taskinfo->pid, taskinfo->processName);
366 } else {
367 my_per_task_info_t * _found_task = get_taskinfo_by_kobject((natural_t)kobject);
368 printf(" (%d) %s", _found_task->pid, _found_task->processName);
369 }
370 }
371
372 printf("\n");
373 if (kotype == IKOT_VOUCHER) {
374 vouchercount++;
375 if (lsmp_config.show_voucher_details) {
376 show_voucher_detail(taskinfo->task, taskinfo->table[i].iin_name);
377 }
378 }
379 continue;
380 }
381
382 /* not kobject - find the receive right holder */
383 my_per_task_info_t *recv_holder_taskinfo;
384 mach_port_name_t recv_name = MACH_PORT_NULL;
385 if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(&taskinfo->table[i], &recv_holder_taskinfo, &recv_name)) {
386 mach_port_status_t port_status;
387 mach_port_info_ext_t info;
388 mach_port_context_t port_context = (mach_port_context_t)0;
389 if (0 != get_recieve_port_status(recv_holder_taskinfo->task, recv_name, &info)) {
390 bzero((void *)&port_status, sizeof(port_status));
391 }
392 port_status = info.mpie_status;
393 get_receive_port_context(recv_holder_taskinfo->task, recv_name, &port_context);
394 printf(" -> %6d %8d 0x%016llx 0x%08x (%d) %s\n",
395 port_status.mps_qlimit,
396 port_status.mps_msgcount,
397 (uint64_t)port_context,
398 recv_name,
399 recv_holder_taskinfo->pid,
400 recv_holder_taskinfo->processName);
401
402 } else
403 printf(" 0x00000000 (-) Unknown Process\n");
404
405 }
406 printf("total = %d\n", taskinfo->tableCount + taskinfo->treeCount - emptycount);
407 printf("SEND = %d\n", sendcount);
408 printf("RECEIVE = %d\n", receivecount);
409 printf("SEND_ONCE = %d\n", sendoncecount);
410 printf("PORT_SET = %d\n", portsetcount);
411 printf("DEAD_NAME = %d\n", deadcount);
412 printf("DNREQUEST = %d\n", dncount);
413 printf("VOUCHERS = %d\n", vouchercount);
414
415 }
416
417 void print_hex_data(char *prefix, char *desc, void *addr, int len) {
418 int i;
419 unsigned char buff[17];
420 unsigned char *pc = addr;
421
422 if (desc != NULL)
423 printf ("%s%s:\n", prefix, desc);
424
425 for (i = 0; i < len; i++) {
426
427 if ((i % 16) == 0) {
428 if (i != 0)
429 printf (" %s\n", buff);
430
431 printf ("%s %04x ", prefix, i);
432 }
433
434 printf (" %02x", pc[i]);
435
436 if ((pc[i] < 0x20) || (pc[i] > 0x7e))
437 buff[i % 16] = '.';
438 else
439 buff[i % 16] = pc[i];
440 buff[(i % 16) + 1] = '\0';
441 }
442
443 while ((i % 16) != 0) {
444 printf (" ");
445 i++;
446 }
447
448 printf (" %s\n", buff);
449 }