]> git.cameronkatri.com Git - apple_cmds.git/blob - system_cmds/lsmp.tproj/port_details.c
Merge branch 'apple'
[apple_cmds.git] / system_cmds / lsmp.tproj / port_details.c
1 /*
2 * Copyright (c) 2002-2016 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 <assert.h>
28 typedef char *kobject_description_t[512];
29 #include <mach/mach.h>
30 //#include <mach/mach_port.h.h>
31 #include <mach/mach_voucher.h>
32 #include "common.h"
33 #include "json.h"
34
35 const char * kobject_name(natural_t kotype)
36 {
37 switch (kotype) {
38 case IKOT_NONE: return "message-queue";
39 case IKOT_THREAD_CONTROL: return "THREAD-CONTROL";
40 case IKOT_TASK_CONTROL: return "TASK-CONTROL";
41 case IKOT_HOST: return "HOST";
42 case IKOT_HOST_PRIV: return "HOST-PRIV";
43 case IKOT_PROCESSOR: return "PROCESSOR";
44 case IKOT_PSET: return "PROCESSOR-SET";
45 case IKOT_PSET_NAME: return "PROCESSOR-SET-NAME";
46 case IKOT_TIMER: return "TIMER";
47 case IKOT_PAGING_REQUEST: return "PAGER-REQUEST";
48 case IKOT_MIG: return "MIG";
49 case IKOT_MEMORY_OBJECT: return "MEMORY-OBJECT";
50 case IKOT_XMM_PAGER: return "XMM-PAGER";
51 case IKOT_XMM_KERNEL: return "XMM-KERNEL";
52 case IKOT_XMM_REPLY: return "XMM-REPLY";
53 case IKOT_UND_REPLY: return "UND-REPLY";
54 case IKOT_HOST_NOTIFY: return "message-queue";
55 case IKOT_HOST_SECURITY: return "HOST-SECURITY";
56 case IKOT_LEDGER: return "LEDGER";
57 case IKOT_MASTER_DEVICE: return "MASTER-DEVICE";
58 case IKOT_TASK_NAME: return "TASK-NAME";
59 case IKOT_SUBSYSTEM: return "SUBSYSTEM";
60 case IKOT_IO_DONE_QUEUE: return "IO-QUEUE-DONE";
61 case IKOT_SEMAPHORE: return "SEMAPHORE";
62 case IKOT_LOCK_SET: return "LOCK-SET";
63 case IKOT_CLOCK: return "CLOCK";
64 case IKOT_CLOCK_CTRL: return "CLOCK-CONTROL";
65 case IKOT_IOKIT_IDENT: return "IOKIT-IDENT";
66 case IKOT_NAMED_ENTRY: return "NAMED-MEMORY";
67 case IKOT_IOKIT_CONNECT: return "IOKIT-CONNECT";
68 case IKOT_IOKIT_OBJECT: return "IOKIT-OBJECT";
69 case IKOT_UPL: return "UPL";
70 case IKOT_MEM_OBJ_CONTROL: return "XMM-CONTROL";
71 case IKOT_AU_SESSIONPORT: return "SESSIONPORT";
72 case IKOT_FILEPORT: return "FILEPORT";
73 case IKOT_LABELH: return "MACF-LABEL";
74 case IKOT_TASK_RESUME: return "TASK_RESUME";
75 case IKOT_VOUCHER: return "VOUCHER";
76 case IKOT_VOUCHER_ATTR_CONTROL: return "VOUCHER_ATTR_CONTROL";
77 case IKOT_WORK_INTERVAL: return "WORK_INTERVAL";
78 case IKOT_UX_HANDLER: return "UX_HANDLER";
79 case IKOT_UEXT_OBJECT: return "UEXT_OBJECT";
80 case IKOT_ARCADE_REG: return "ARCADE_REG";
81 case IKOT_EVENTLINK: return "EVENTLINK";
82 case IKOT_TASK_INSPECT: return "TASK-INSPECT";
83 case IKOT_TASK_READ: return "TASK-READ";
84 case IKOT_THREAD_INSPECT: return "THREAD-INSPECT";
85 case IKOT_THREAD_READ: return "THREAD-READ";
86 case IKOT_SUID_CRED: return "SUID_CRED";
87 case IKOT_HYPERVISOR: return "HYPERVISOR";
88 case IKOT_UNKNOWN:
89 default: return "UNKNOWN";
90 }
91 }
92
93 const port_status_flag_info_t port_status_flags[] = {
94 [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_TEMPOWNER)] = {
95 .flag = MACH_PORT_STATUS_FLAG_TEMPOWNER,
96 .compact_name = "T",
97 .name = "tempowner",
98 },
99 [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_GUARDED)] = {
100 .flag = MACH_PORT_STATUS_FLAG_GUARDED,
101 .compact_name = "G",
102 .name = "guarded",
103 },
104 [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_STRICT_GUARD)] = {
105 .flag = MACH_PORT_STATUS_FLAG_STRICT_GUARD,
106 .compact_name = "S",
107 .name = "strict guard",
108 },
109 [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_IMP_DONATION)] = {
110 .flag = MACH_PORT_STATUS_FLAG_IMP_DONATION,
111 .compact_name = "I",
112 .name = "imp donation",
113 },
114 [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_REVIVE)] = {
115 .flag = MACH_PORT_STATUS_FLAG_REVIVE,
116 .compact_name = "R",
117 .name = "revive",
118 },
119 [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_TASKPTR)] = {
120 .flag = MACH_PORT_STATUS_FLAG_TASKPTR,
121 .compact_name = "P",
122 .name = "taskptr",
123 },
124 {0},
125 };
126
127 #define VOUCHER_DETAIL_PREFIX " "
128
129 static const unsigned int voucher_contents_size = 8192;
130 static uint8_t voucher_contents[voucher_contents_size];
131
132 typedef struct {
133 int total;
134 int sendcount;
135 int receivecount;
136 int sendoncecount;
137 int portsetcount;
138 int deadcount;
139 int dncount;
140 int vouchercount;
141 } task_table_entry_counts;
142
143 typedef task_table_entry_counts * task_table_entry_counts_t;
144
145 static void show_task_table_entry(ipc_info_name_t *entry, my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, task_table_entry_counts_t counts, JSON_t json);
146
147 static uint32_t safesize (int len){
148 return (len > 0) ? len : 0;
149 }
150
151 uint32_t show_recipe_detail(mach_voucher_attr_recipe_t recipe, char *voucher_outstr, uint32_t maxlen, JSON_t json) {
152 JSON_OBJECT_BEGIN(json);
153
154 uint32_t len = 0;
155 len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "Key: %u, ", recipe->key);
156 len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Command: %u, ", recipe->command);
157 len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Previous voucher: 0x%x, ", recipe->previous_voucher);
158 len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Content size: %u\n", recipe->content_size);
159
160 JSON_OBJECT_SET(json, key, %u, recipe->key);
161 JSON_OBJECT_SET(json, command, %u, recipe->command);
162 JSON_OBJECT_SET(json, previous_voucher, "0x%x", recipe->previous_voucher);
163 JSON_OBJECT_SET(json, content_size, %u, recipe->content_size);
164
165 switch (recipe->key) {
166 case MACH_VOUCHER_ATTR_KEY_IMPORTANCE:
167 // content may not be valid JSON, exclude
168 // JSON_OBJECT_SET(json, importance_info, "%s", (char *)recipe->content);
169 len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "IMPORTANCE INFO: %s", (char *)recipe->content);
170 break;
171 case MACH_VOUCHER_ATTR_KEY_BANK:
172 // content may not be valid JSON, exclude
173 // JSON_OBJECT_SET(json, resource_accounting_info, "%s", (char *)recipe->content);
174 len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "RESOURCE ACCOUNTING INFO: %s", (char *)recipe->content);
175 break;
176 default:
177 len += print_hex_data(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX, "Recipe Contents", (void *)recipe->content, MIN(recipe->content_size, lsmp_config.voucher_detail_length));
178 break;
179 }
180
181 if (len + 1 < maxlen && voucher_outstr[len - 1] != '\n') {
182 voucher_outstr[len++] = '\n';
183 voucher_outstr[len] = '\0';
184 }
185 JSON_OBJECT_END(json); // recipe
186 return len;
187 }
188
189
190 char * copy_voucher_detail(mach_port_t task, mach_port_name_t voucher, JSON_t json) {
191 unsigned int recipe_size = voucher_contents_size;
192 kern_return_t kr = KERN_SUCCESS;
193 bzero((void *)&voucher_contents[0], sizeof(voucher_contents));
194 unsigned v_kobject = 0;
195 unsigned v_kotype = 0;
196 uint32_t detail_maxlen = VOUCHER_DETAIL_MAXLEN;
197 char * voucher_outstr = (char *)malloc(detail_maxlen);
198 voucher_outstr[0] = '\0';
199 uint32_t plen = 0;
200
201 kr = mach_port_kernel_object( task,
202 voucher,
203 &v_kotype, (unsigned *)&v_kobject);
204 if (kr == KERN_SUCCESS && v_kotype == IKOT_VOUCHER ) {
205
206 kr = mach_voucher_debug_info(task, voucher,
207 (mach_voucher_attr_raw_recipe_array_t)&voucher_contents[0],
208 &recipe_size);
209 if (kr != KERN_SUCCESS && kr != KERN_NOT_SUPPORTED) {
210 plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x Failed to get contents %s\n", v_kobject, mach_error_string(kr));
211 return voucher_outstr;
212 }
213
214 if (recipe_size == 0) {
215 plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x has no contents\n", v_kobject);
216 return voucher_outstr;
217 }
218
219 plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x\n", v_kobject);
220 unsigned int used_size = 0;
221 mach_voucher_attr_recipe_t recipe = NULL;
222 while (recipe_size > used_size) {
223 recipe = (mach_voucher_attr_recipe_t)&voucher_contents[used_size];
224 if (recipe->key) {
225 plen += show_recipe_detail(recipe, &voucher_outstr[plen], safesize(detail_maxlen - plen), json);
226 }
227 used_size += sizeof(mach_voucher_attr_recipe_data_t) + recipe->content_size;
228 }
229 } else {
230 plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Invalid voucher: 0x%x\n", voucher);
231 }
232
233 return voucher_outstr;
234 }
235
236 void get_receive_port_context(task_t taskp, mach_port_name_t portname, mach_port_context_t *context) {
237 if (context == NULL) {
238 return;
239 }
240
241 kern_return_t ret;
242 ret = mach_port_get_context(taskp, portname, context);
243 if (ret != KERN_SUCCESS) {
244 fprintf(stderr, "mach_port_get_context(0x%08x) failed: %s\n",
245 portname,
246 mach_error_string(ret));
247 *context = (mach_port_context_t)0;
248 }
249 return;
250 }
251
252 int get_recieve_port_status(task_t taskp, mach_port_name_t portname, mach_port_info_ext_t *info){
253 if (info == NULL) {
254 return -1;
255 }
256 mach_msg_type_number_t statusCnt;
257 kern_return_t ret;
258 statusCnt = MACH_PORT_INFO_EXT_COUNT;
259 ret = mach_port_get_attributes(taskp,
260 portname,
261 MACH_PORT_INFO_EXT,
262 (mach_port_info_t)info,
263 &statusCnt);
264 if (ret != KERN_SUCCESS) {
265 fprintf(stderr, "mach_port_get_attributes(0x%08x) failed: %s\n",
266 portname,
267 mach_error_string(ret));
268 return -1;
269 }
270
271 return 0;
272 }
273
274 void show_task_mach_ports(my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, JSON_t json)
275 {
276 int i;
277 task_table_entry_counts counts = {0};
278
279 counts.total = taskinfo->tableCount + taskinfo->treeCount;
280
281 JSON_KEY(json, ports)
282 JSON_ARRAY_BEGIN(json);
283
284 printf(" name ipc-object rights flags boost reqs recv send sonce oref qlimit msgcount context identifier type\n");
285 printf("--------- ---------- ---------- -------- ----- ---- ----- ----- ----- ---- ------ -------- ------------------ ----------- ------------\n");
286 for (i = 0; i < taskinfo->tableCount; i++) {
287 show_task_table_entry(&taskinfo->table[i], taskinfo, taskCount, allTaskInfos, &counts, json);
288 }
289
290 JSON_ARRAY_END(json); // ports
291 JSON_OBJECT_SET(json, total, %d, counts.total);
292 JSON_OBJECT_SET(json, send_rights, %d, counts.sendcount);
293 JSON_OBJECT_SET(json, receive_rights, %d, counts.receivecount);
294 JSON_OBJECT_SET(json, send_once_rights, %d, counts.sendoncecount);
295 JSON_OBJECT_SET(json, port_sets, %d, counts.portsetcount);
296 JSON_OBJECT_SET(json, dead_names, %d, counts.deadcount);
297 JSON_OBJECT_SET(json, dead_name requests, %d, counts.dncount);
298 JSON_OBJECT_SET(json, vouchers, %d, counts.vouchercount);
299
300 printf("\n");
301 printf("total = %d\n", counts.total);
302 printf("SEND = %d\n", counts.sendcount);
303 printf("RECEIVE = %d\n", counts.receivecount);
304 printf("SEND_ONCE = %d\n", counts.sendoncecount);
305 printf("PORT_SET = %d\n", counts.portsetcount);
306 printf("DEAD_NAME = %d\n", counts.deadcount);
307 printf("DNREQUEST = %d\n", counts.dncount);
308 printf("VOUCHERS = %d\n", counts.vouchercount);
309 }
310
311 static void show_task_table_entry(ipc_info_name_t *entry, my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, task_table_entry_counts_t counts, JSON_t json) {
312 int j, k, port_status_flag_idx;
313 kern_return_t ret;
314 boolean_t send = FALSE;
315 boolean_t dnreq = FALSE;
316 int sendrights = 0;
317 unsigned int kotype = 0;
318 vm_offset_t kobject = (vm_offset_t)0;
319 kobject_description_t desc;
320 mach_vm_address_t kaddr;
321
322 /* skip empty slots in the table */
323 if ((entry->iin_type & MACH_PORT_TYPE_ALL_RIGHTS) == 0) {
324 counts->total--;
325 return;
326 }
327
328 if (entry->iin_type == MACH_PORT_TYPE_PORT_SET) {
329 mach_port_name_array_t members;
330 mach_msg_type_number_t membersCnt;
331
332 ret = mach_port_get_set_status(taskinfo->task,
333 entry->iin_name,
334 &members, &membersCnt);
335 if (ret != KERN_SUCCESS) {
336 fprintf(stderr, "mach_port_get_set_status(0x%08x) failed: %s\n",
337 entry->iin_name,
338 mach_error_string(ret));
339 return;
340 }
341
342 JSON_OBJECT_BEGIN(json);
343 JSON_OBJECT_SET(json, type, "port set");
344 JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
345 JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
346
347 JSON_KEY(json, members);
348 JSON_ARRAY_BEGIN(json);
349
350 printf("0x%08x 0x%08x port-set -------- --- 1 %d members\n",
351 entry->iin_name,
352 entry->iin_object,
353 membersCnt);
354 /* get some info for each portset member */
355 for (j = 0; j < membersCnt; j++) {
356 for (k = 0; k < taskinfo->tableCount; k++) {
357 if (taskinfo->table[k].iin_name == members[j]) {
358 mach_port_info_ext_t info;
359 mach_port_status_t port_status;
360 mach_port_context_t port_context = (mach_port_context_t)0;
361 if (0 != get_recieve_port_status(taskinfo->task, taskinfo->table[k].iin_name, &info)) {
362 bzero((void *)&info, sizeof(info));
363 }
364 port_status = info.mpie_status;
365 get_receive_port_context(taskinfo->task, taskinfo->table[k].iin_name, &port_context);
366
367 JSON_OBJECT_BEGIN(json);
368 JSON_OBJECT_SET(json, ipc-object, "0x%08x", taskinfo->table[k].iin_object);
369
370 JSON_KEY(json, rights);
371 JSON_ARRAY_BEGIN(json);
372 JSON_ARRAY_APPEND(json, "recv");
373 if (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) {
374 JSON_ARRAY_APPEND(json, "send");
375 }
376 JSON_ARRAY_END(json); // rights
377
378 JSON_KEY(json, port_status_flags);
379 JSON_ARRAY_BEGIN(json);
380 port_status_flag_idx = 0;
381 while (0 != port_status_flags[port_status_flag_idx++].flag) {
382 if (port_status.mps_flags & INDEX_TO_PORT_FLAG(port_status_flag_idx)) {
383 JSON_ARRAY_APPEND(json, "%s", port_status_flags[port_status_flag_idx].name);
384 }
385 }
386 JSON_ARRAY_END(json); // port status flags
387 JSON_OBJECT_SET(json, boosts, %d, info.mpie_boost_cnt);
388
389 JSON_KEY(json, notifications);
390 JSON_ARRAY_BEGIN(json);
391 if (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) {
392 JSON_ARRAY_APPEND(json, "dead name");
393 }
394 if (port_status.mps_nsrequest) {
395 JSON_ARRAY_APPEND(json, "no sender");
396 }
397 if (port_status.mps_nsrequest) {
398 JSON_ARRAY_APPEND(json, "port destroy request");
399 }
400 JSON_ARRAY_END(json); // notifications
401
402 JSON_OBJECT_SET(json, recv_rights, %d, 1);
403 JSON_OBJECT_SET(json, send_rights, %d, taskinfo->table[k].iin_urefs);
404 JSON_OBJECT_SET(json, send_once_rights, %d, port_status.mps_sorights);
405 JSON_OBJECT_SET_BOOL(json, oref, port_status.mps_srights);
406 JSON_OBJECT_SET(json, queue_limit, %d, port_status.mps_qlimit);
407 JSON_OBJECT_SET(json, msg_count, %d, port_status.mps_msgcount);
408 JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)port_context);
409 JSON_OBJECT_SET(json, identifier, "0x%08x", taskinfo->table[k].iin_name);
410 JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
411 JSON_OBJECT_SET(json, process, "%s", taskinfo->processName);
412 JSON_OBJECT_END(json); // member
413
414 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",
415 taskinfo->table[k].iin_object,
416 (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) ? "recv,send ":"recv ",
417 SHOW_PORT_STATUS_FLAGS(port_status.mps_flags),
418 info.mpie_boost_cnt,
419 (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
420 (port_status.mps_nsrequest) ? "N" : "-",
421 (port_status.mps_pdrequest) ? "P" : "-",
422 1,
423 taskinfo->table[k].iin_urefs,
424 port_status.mps_sorights,
425 (port_status.mps_srights) ? "Y" : "N",
426 port_status.mps_qlimit,
427 port_status.mps_msgcount,
428 (uint64_t)port_context,
429 taskinfo->table[k].iin_name,
430 taskinfo->pid,
431 taskinfo->processName);
432 break;
433 }
434 }
435 }
436
437 JSON_ARRAY_END(json); // members
438 JSON_OBJECT_END(json); // port-set
439
440 ret = vm_deallocate(mach_task_self(), (vm_address_t)members,
441 membersCnt * sizeof(mach_port_name_t));
442 if (ret != KERN_SUCCESS) {
443 fprintf(stderr, "vm_deallocate() failed: %s\n",
444 mach_error_string(ret));
445 exit(1);
446 }
447 counts->portsetcount++;
448 return;
449 }
450
451 if (entry->iin_type & MACH_PORT_TYPE_SEND) {
452 send = TRUE;
453 sendrights = entry->iin_urefs;
454 counts->sendcount++;
455 }
456
457 if (entry->iin_type & MACH_PORT_TYPE_DNREQUEST) {
458 dnreq = TRUE;
459 counts->dncount++;
460 }
461
462 if (entry->iin_type & MACH_PORT_TYPE_RECEIVE) {
463 mach_port_status_t status;
464 mach_port_info_ext_t info;
465 mach_port_context_t context = (mach_port_context_t)0;
466 struct k2n_table_node *k2nnode;
467 ret = get_recieve_port_status(taskinfo->task, entry->iin_name, &info);
468 get_receive_port_context(taskinfo->task, entry->iin_name, &context);
469 /* its ok to fail in fetching attributes */
470 if (ret < 0) {
471 return;
472 }
473 status = info.mpie_status;
474
475 JSON_OBJECT_BEGIN(json);
476 JSON_OBJECT_SET(json, type, "port");
477 JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
478 JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
479
480 JSON_KEY(json, rights);
481 JSON_ARRAY_BEGIN(json);
482 JSON_ARRAY_APPEND(json, "recv");
483 if (send) JSON_ARRAY_APPEND(json, "send");
484 JSON_ARRAY_END(json); // rights
485
486 JSON_KEY(json, port_status_flags);
487 JSON_ARRAY_BEGIN(json);
488 port_status_flag_idx = 0;
489 while (0 != port_status_flags[port_status_flag_idx++].flag) {
490 if (status.mps_flags & INDEX_TO_PORT_FLAG(port_status_flag_idx)) {
491 JSON_ARRAY_APPEND(json, "%s", port_status_flags[port_status_flag_idx].name);
492 }
493 }
494 JSON_ARRAY_END(json); // port status flags
495 JSON_OBJECT_SET(json, boosts, %d, info.mpie_boost_cnt);
496
497 JSON_KEY(json, notifications);
498 JSON_ARRAY_BEGIN(json);
499 if (dnreq) {
500 JSON_ARRAY_APPEND(json, "dead name");
501 }
502 if (status.mps_nsrequest) {
503 JSON_ARRAY_APPEND(json, "no sender");
504 }
505 if (status.mps_nsrequest) {
506 JSON_ARRAY_APPEND(json, "port destroy request");
507 }
508 JSON_ARRAY_END(json); // notifications
509
510 JSON_OBJECT_SET(json, recv_rights, %d, 1);
511 JSON_OBJECT_SET(json, send_rights, %d, sendrights);
512 JSON_OBJECT_SET(json, send_once_rights, %d, status.mps_sorights);
513 JSON_OBJECT_SET_BOOL(json, oref, status.mps_srights);
514 JSON_OBJECT_SET(json, queue_limit, %d, status.mps_qlimit);
515 JSON_OBJECT_SET(json, msg_count, %d, status.mps_msgcount);
516 JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)context);
517 JSON_OBJECT_END(json); // port
518
519 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",
520 entry->iin_name,
521 entry->iin_object,
522 (send) ? "recv,send ":"recv ",
523 SHOW_PORT_STATUS_FLAGS(status.mps_flags),
524 info.mpie_boost_cnt,
525 (dnreq) ? "D":"-",
526 (status.mps_nsrequest) ? "N":"-",
527 (status.mps_pdrequest) ? "P":"-",
528 1,
529 sendrights,
530 status.mps_sorights,
531 (status.mps_srights) ? "Y":"N",
532 status.mps_qlimit,
533 status.mps_msgcount,
534 (uint64_t)context);
535 counts->receivecount++;
536
537 /* show other rights (in this and other tasks) for the port */
538 for (j = 0; j < taskCount; j++) {
539 if (allTaskInfos[j].valid == FALSE)
540 continue;
541
542 k2nnode = k2n_table_lookup(allTaskInfos[j].k2ntable, entry->iin_object);
543
544 while (k2nnode) {
545 if (k2nnode->info_name != entry) {
546 assert(k2nnode->info_name->iin_object == entry->iin_object);
547
548 printf(" + %s -------- %s%s%s %5d <- 0x%08x (%d) %s\n",
549 (k2nnode->info_name->iin_type & MACH_PORT_TYPE_SEND_ONCE) ?
550 "send-once " : "send ",
551 (k2nnode->info_name->iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
552 "-",
553 "-",
554 k2nnode->info_name->iin_urefs,
555 k2nnode->info_name->iin_name,
556 allTaskInfos[j].pid,
557 allTaskInfos[j].processName);
558 }
559
560 k2nnode = k2n_table_lookup_next(k2nnode, entry->iin_object);
561 }
562 }
563 return;
564 }
565 else if (entry->iin_type & MACH_PORT_TYPE_DEAD_NAME)
566 {
567 JSON_OBJECT_BEGIN(json);
568 JSON_OBJECT_SET(json, type, "dead name");
569 JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
570 JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
571 JSON_OBJECT_SET(json, send_rights, %d, entry->iin_urefs);
572 JSON_OBJECT_END(json); // dead name
573
574 printf("0x%08x 0x%08x dead-name -------- --- %5d \n",
575 entry->iin_name,
576 entry->iin_object,
577 entry->iin_urefs);
578 counts->deadcount++;
579 return;
580 }
581
582 if (entry->iin_type & MACH_PORT_TYPE_SEND_ONCE) {
583 counts->sendoncecount++;
584 }
585
586 JSON_OBJECT_BEGIN(json);
587 JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
588 JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
589
590 JSON_KEY(json, rights);
591 JSON_ARRAY_BEGIN(json);
592 JSON_ARRAY_APPEND(json, "%s", (send) ? "send":"send once");
593 JSON_ARRAY_END(json); //rights
594
595 JSON_KEY(json, notifications);
596 JSON_ARRAY_BEGIN(json);
597 if (dnreq) JSON_ARRAY_APPEND(json, "dead name");
598 JSON_ARRAY_END(json); // notifications
599
600 JSON_OBJECT_SET(json, send_rights, %d, (send) ? sendrights : 0);
601
602 printf("0x%08x 0x%08x %s -------- %s%s%s %5.0d ",
603 entry->iin_name,
604 entry->iin_object,
605 (send) ? "send ":"send-once ",
606 (dnreq) ? "D":"-",
607 "-",
608 "-",
609 (send) ? sendrights : 0);
610
611 /* converting to kobjects is not always supported */
612
613 #if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 130500
614 desc[0] = '\0';
615 ret = mach_port_kobject_description(taskinfo->task,
616 entry->iin_name,
617 &kotype, &kaddr,
618 desc);
619 if (KERN_SUCCESS == ret) {
620 kobject = (unsigned) kaddr;
621 } else {
622 ret = mach_port_kernel_object(taskinfo->task,
623 entry->iin_name,
624 &kotype, (unsigned *)&kobject);
625 }
626 #else
627 ret = mach_port_kernel_object(taskinfo->task,
628 entry->iin_name,
629 &kotype, (unsigned *)&kobject);
630 #endif
631
632 if (ret == KERN_SUCCESS && kotype != 0) {
633 JSON_OBJECT_SET(json, identifier, "0x%08x", (natural_t)kobject);
634 JSON_OBJECT_SET(json, type, "%s", kobject_name(kotype));
635 if (desc[0]) {
636 JSON_OBJECT_SET(json, description, "%s", desc);
637 printf(" 0x%08x %s %s", (natural_t)kobject, kobject_name(kotype), desc);
638 } else {
639 printf(" 0x%08x %s", (natural_t)kobject, kobject_name(kotype));
640 }
641 if ((kotype == IKOT_TASK_RESUME) || (kotype == IKOT_TASK_CONTROL) || (kotype == IKOT_TASK_NAME)) {
642 if (taskinfo->task_kobject == kobject) {
643 /* neat little optimization since in most cases tasks have themselves in their ipc space */
644 JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
645 JSON_OBJECT_SET(json, process, "%s", taskinfo->processName);
646 printf(" SELF (%d) %s", taskinfo->pid, taskinfo->processName);
647 } else {
648 my_per_task_info_t * _found_task = get_taskinfo_by_kobject((natural_t)kobject);
649 JSON_OBJECT_SET(json, pid, %d, _found_task->pid);
650 JSON_OBJECT_SET(json, process, "%s", _found_task->processName);
651 printf(" (%d) %s", _found_task->pid, _found_task->processName);
652 }
653 }
654
655 if (kotype == IKOT_THREAD_CONTROL) {
656 for (int i = 0; i < taskinfo->threadCount; i++) {
657 if (taskinfo->threadInfos[i].th_kobject == kobject) {
658 printf(" (%#llx)", taskinfo->threadInfos[i].th_id);
659 break;
660 }
661 }
662 }
663
664 printf("\n");
665 if (kotype == IKOT_VOUCHER) {
666 counts->vouchercount++;
667 if (lsmp_config.show_voucher_details) {
668 JSON_KEY(json, recipes);
669 JSON_ARRAY_BEGIN(json);
670 char * detail = copy_voucher_detail(taskinfo->task, entry->iin_name, json);
671 JSON_ARRAY_END(json); // recipes
672 printf("%s\n", detail);
673 free(detail);
674 }
675 }
676 JSON_OBJECT_END(json); // kobject
677 return;
678 }
679
680 /* not kobject - find the receive right holder */
681 my_per_task_info_t *recv_holder_taskinfo;
682 mach_port_name_t recv_name = MACH_PORT_NULL;
683 if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(entry, &recv_holder_taskinfo, &recv_name)) {
684 mach_port_status_t port_status;
685 mach_port_info_ext_t info;
686 mach_port_context_t port_context = (mach_port_context_t)0;
687 if (0 != get_recieve_port_status(recv_holder_taskinfo->task, recv_name, &info)) {
688 bzero((void *)&port_status, sizeof(port_status));
689 }
690 port_status = info.mpie_status;
691 get_receive_port_context(recv_holder_taskinfo->task, recv_name, &port_context);
692
693 JSON_OBJECT_SET(json, queue_limit, %d, port_status.mps_qlimit);
694 JSON_OBJECT_SET(json, msg_count, %d, port_status.mps_msgcount);
695 JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)port_context);
696 JSON_OBJECT_SET(json, identifier, "0x%08x", recv_name);
697 JSON_OBJECT_SET(json, pid, %d, recv_holder_taskinfo->pid);
698 JSON_OBJECT_SET(json, process, "%s", recv_holder_taskinfo->processName);
699
700 printf(" -> %6d %8d 0x%016llx 0x%08x (%d) %s\n",
701 port_status.mps_qlimit,
702 port_status.mps_msgcount,
703 (uint64_t)port_context,
704 recv_name,
705 recv_holder_taskinfo->pid,
706 recv_holder_taskinfo->processName);
707
708 } else {
709 JSON_OBJECT_SET(json, identifier, "0x%08x", 0);
710 JSON_OBJECT_SET(json, pid, %d, -1);
711 JSON_OBJECT_SET(json, process, "unknown");
712 printf(" 0x00000000 (-) Unknown Process\n");
713 }
714
715 JSON_OBJECT_END(json); // non-kobject
716 }
717
718 uint32_t print_hex_data(char *outstr, uint32_t maxlen, char *prefix, char *desc, void *addr, int len) {
719 int i;
720 unsigned char buff[17];
721 unsigned char *pc = addr;
722 uint32_t plen = 0;
723
724 if (desc != NULL)
725 plen += snprintf(&outstr[plen], safesize(maxlen - plen), "%s%s:\n", prefix, desc);
726
727 for (i = 0; i < len; i++) {
728
729 if ((i % 16) == 0) {
730 if (i != 0)
731 plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %s\n", buff);
732
733 plen += snprintf(&outstr[plen], safesize(maxlen - plen), "%s %04x ", prefix, i);
734 }
735
736 plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %02x", pc[i]);
737
738 if ((pc[i] < 0x20) || (pc[i] > 0x7e))
739 buff[i % 16] = '.';
740 else
741 buff[i % 16] = pc[i];
742 buff[(i % 16) + 1] = '\0';
743 }
744
745 while ((i % 16) != 0) {
746 plen += snprintf(&outstr[plen], safesize(maxlen - plen), " ");
747 i++;
748 }
749
750 plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %s\n", buff);
751
752 return plen;
753 }