]> git.saurik.com Git - apple/system_cmds.git/blobdiff - lsmp.tproj/port_details.c
system_cmds-805.200.21.tar.gz
[apple/system_cmds.git] / lsmp.tproj / port_details.c
index 985fb89bf846996a5cf16b57c44963911b17c66a..619bf02484200b8031173b47a227aaf4503ad8f2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-20014 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 #include <unistd.h>
 #include <stdlib.h>
 #include <libproc.h>
+#include <assert.h>
 #include <mach/mach.h>
 #include <mach/mach_voucher.h>
 #include "common.h"
+#include "json.h"
 
 const char * kobject_name(natural_t kotype)
 {
@@ -75,41 +77,108 @@ const char * kobject_name(natural_t kotype)
        }
 }
 
+const port_status_flag_info_t port_status_flags[] = {
+       [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_TEMPOWNER)] = {
+               .flag = MACH_PORT_STATUS_FLAG_TEMPOWNER,
+               .compact_name = "T",
+               .name = "tempowner",
+       },
+       [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_GUARDED)] = {
+               .flag = MACH_PORT_STATUS_FLAG_GUARDED,
+               .compact_name = "G",
+               .name = "guarded",
+       },
+       [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_STRICT_GUARD)] = {
+               .flag = MACH_PORT_STATUS_FLAG_STRICT_GUARD,
+               .compact_name = "S",
+               .name = "strict guard",
+       },
+       [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_IMP_DONATION)] = {
+               .flag = MACH_PORT_STATUS_FLAG_IMP_DONATION,
+               .compact_name = "I",
+               .name = "imp donation",
+       },
+       [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_REVIVE)] = {
+               .flag = MACH_PORT_STATUS_FLAG_REVIVE,
+               .compact_name = "R",
+               .name = "revive",
+       },
+       [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_TASKPTR)] = {
+               .flag = MACH_PORT_STATUS_FLAG_TASKPTR,
+               .compact_name = "P",
+               .name = "taskptr",
+       },
+       {0},
+};
+
 #define VOUCHER_DETAIL_PREFIX "            "
 
 static const unsigned int voucher_contents_size = 8192;
 static uint8_t voucher_contents[voucher_contents_size];
 
+typedef struct {
+    int total;
+    int sendcount;
+    int receivecount;
+    int sendoncecount;
+    int portsetcount;
+    int deadcount;
+    int dncount;
+    int vouchercount;
+} task_table_entry_counts;
+
+typedef task_table_entry_counts * task_table_entry_counts_t;
+
+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);
 
 static uint32_t safesize (int len){
-    return (len > 0)? len : 0;
+    return (len > 0) ? len : 0;
 }
 
-void show_recipe_detail(mach_voucher_attr_recipe_t recipe, char *voucher_outstr, uint32_t maxlen) {
+uint32_t show_recipe_detail(mach_voucher_attr_recipe_t recipe, char *voucher_outstr, uint32_t maxlen, JSON_t json) {
+    JSON_OBJECT_BEGIN(json);
+
     uint32_t len = 0;
-    len += safesize(snprintf(&voucher_outstr[len], maxlen - len, VOUCHER_DETAIL_PREFIX "Key: %u, ", recipe->key));
-    len += safesize(snprintf(&voucher_outstr[len], maxlen - len, "Command: %u, ", recipe->command));
-    len += safesize(snprintf(&voucher_outstr[len], maxlen - len, "Previous voucher: 0x%x, ", recipe->previous_voucher));
-    len += safesize(snprintf(&voucher_outstr[len], maxlen - len, "Content size: %u\n", recipe->content_size));
+    len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "Key: %u, ", recipe->key);
+    len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Command: %u, ", recipe->command);
+    len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Previous voucher: 0x%x, ", recipe->previous_voucher);
+    len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Content size: %u\n", recipe->content_size);
+
+    JSON_OBJECT_SET(json, key, %u, recipe->key);
+    JSON_OBJECT_SET(json, command, %u, recipe->command);
+    JSON_OBJECT_SET(json, previous_voucher, "0x%x", recipe->previous_voucher);
+    JSON_OBJECT_SET(json, content_size, %u, recipe->content_size);
+
     switch (recipe->key) {
         case MACH_VOUCHER_ATTR_KEY_ATM:
-            len += safesize(snprintf(&voucher_outstr[len], maxlen - len, VOUCHER_DETAIL_PREFIX "ATM ID: %llu\n", *(uint64_t *)(uintptr_t)recipe->content));
+            JSON_OBJECT_SET(json, ATM_ID, %llu, *(uint64_t *)(uintptr_t)recipe->content);
+            len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "ATM ID: %llu", *(uint64_t *)(uintptr_t)recipe->content);
             break;
         case MACH_VOUCHER_ATTR_KEY_IMPORTANCE:
-            len += safesize(snprintf(&voucher_outstr[len], maxlen - len, VOUCHER_DETAIL_PREFIX "IMPORTANCE INFO: %s\n", (char *)recipe->content));
+            // content may not be valid JSON, exclude
+            // JSON_OBJECT_SET(json, importance_info, "%s", (char *)recipe->content);
+            len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "IMPORTANCE INFO: %s", (char *)recipe->content);
             break;
         case MACH_VOUCHER_ATTR_KEY_BANK:
-            len += safesize(snprintf(&voucher_outstr[len], maxlen - len, VOUCHER_DETAIL_PREFIX "RESOURCE ACCOUNTING INFO: %s\n", (char *)recipe->content));
+            // content may not be valid JSON, exclude
+            // JSON_OBJECT_SET(json, resource_accounting_info, "%s", (char *)recipe->content);
+            len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "RESOURCE ACCOUNTING INFO: %s", (char *)recipe->content);
             break;
         default:
-            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));
+            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));
             break;
     }
 
+    if (len + 1 < maxlen && voucher_outstr[len - 1] != '\n') {
+        voucher_outstr[len++] = '\n';
+        voucher_outstr[len] = '\0';
+    }
+    JSON_OBJECT_END(json); // recipe
+       return len;
 }
 
 
-char * copy_voucher_detail(mach_port_t task, mach_port_name_t voucher) {
+char * copy_voucher_detail(mach_port_t task, mach_port_name_t voucher, JSON_t json) {
     unsigned int recipe_size = voucher_contents_size;
     kern_return_t kr = KERN_SUCCESS;
     bzero((void *)&voucher_contents[0], sizeof(voucher_contents));
@@ -129,29 +198,29 @@ char * copy_voucher_detail(mach_port_t task, mach_port_name_t voucher) {
                                      (mach_voucher_attr_raw_recipe_array_t)&voucher_contents[0],
                                      &recipe_size);
         if (kr != KERN_SUCCESS && kr != KERN_NOT_SUPPORTED) {
-            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)));
+            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));
             return voucher_outstr;
         }
 
         if (recipe_size == 0) {
-            plen += safesize(snprintf(&voucher_outstr[plen], detail_maxlen - plen, VOUCHER_DETAIL_PREFIX "Voucher: 0x%x has no contents\n", v_kobject));
+            plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x has no contents\n", v_kobject);
             return voucher_outstr;
         }
 
-        plen += safesize(snprintf(&voucher_outstr[plen], detail_maxlen - plen, VOUCHER_DETAIL_PREFIX "Voucher: 0x%x\n", v_kobject));
+        plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x\n", v_kobject);
         unsigned int used_size = 0;
         mach_voucher_attr_recipe_t recipe = NULL;
         while (recipe_size > used_size) {
             recipe = (mach_voucher_attr_recipe_t)&voucher_contents[used_size];
             if (recipe->key) {
-                show_recipe_detail(recipe, &voucher_outstr[plen], detail_maxlen - plen);
+                plen += show_recipe_detail(recipe, &voucher_outstr[plen], safesize(detail_maxlen - plen), json);
             }
             used_size += sizeof(mach_voucher_attr_recipe_data_t) + recipe->content_size;
         }
     } else {
-        plen += safesize(snprintf(&voucher_outstr[plen], detail_maxlen - plen, VOUCHER_DETAIL_PREFIX "Invalid voucher: 0x%x\n", voucher));
+        plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Invalid voucher: 0x%x\n", voucher);
     }
-    
+
     return voucher_outstr;
 }
 
@@ -159,7 +228,7 @@ void get_receive_port_context(task_t taskp, mach_port_name_t portname, mach_port
        if (context == NULL) {
                return;
        }
-    
+
        kern_return_t ret;
        ret = mach_port_get_context(taskp, portname, context);
        if (ret != KERN_SUCCESS) {
@@ -189,278 +258,463 @@ int get_recieve_port_status(task_t taskp, mach_port_name_t portname, mach_port_i
                 mach_error_string(ret));
         return -1;
     }
-    
+
     return 0;
 }
 
-void show_task_mach_ports(my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos)
+void show_task_mach_ports(my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, JSON_t json)
 {
-    int i, emptycount = 0, portsetcount = 0, sendcount = 0, receivecount = 0, sendoncecount = 0, deadcount = 0, dncount = 0, vouchercount = 0, pid;
-    kern_return_t ret;
-    pid_for_task(taskinfo->task, &pid);
-    
+    int i;
+    task_table_entry_counts counts = {0};
+
+    counts.total = taskinfo->tableCount + taskinfo->treeCount;
+
+    JSON_KEY(json, ports)
+    JSON_ARRAY_BEGIN(json);
+
     printf("  name      ipc-object    rights     flags   boost  reqs  recv  send sonce oref  qlimit  msgcount  context            identifier  type\n");
     printf("---------   ----------  ----------  -------- -----  ---- ----- ----- ----- ----  ------  --------  ------------------ ----------- ------------\n");
-       for (i = 0; i < taskinfo->tableCount; i++) {
-               int j, k;
-               boolean_t send = FALSE;
-               boolean_t sendonce = FALSE;
-               boolean_t dnreq = FALSE;
-               int sendrights = 0;
-               unsigned int kotype = 0;
-               vm_offset_t kobject = (vm_offset_t)0;
-        
-        /* skip empty slots in the table */
-        if ((taskinfo->table[i].iin_type & MACH_PORT_TYPE_ALL_RIGHTS) == 0) {
-            emptycount++;
-            continue;
+    for (i = 0; i < taskinfo->tableCount; i++) {
+        show_task_table_entry(&taskinfo->table[i], taskinfo, taskCount, allTaskInfos, &counts, json);
+    }
+
+    JSON_ARRAY_END(json); // ports
+    JSON_OBJECT_SET(json, total, %d, counts.total);
+    JSON_OBJECT_SET(json, send_rights, %d, counts.sendcount);
+    JSON_OBJECT_SET(json, receive_rights, %d, counts.receivecount);
+    JSON_OBJECT_SET(json, send_once_rights, %d, counts.sendoncecount);
+    JSON_OBJECT_SET(json, port_sets, %d, counts.portsetcount);
+    JSON_OBJECT_SET(json, dead_names, %d, counts.deadcount);
+    JSON_OBJECT_SET(json, dead_name requests, %d, counts.dncount);
+    JSON_OBJECT_SET(json, vouchers, %d, counts.vouchercount);
+
+       printf("\n");
+    printf("total     = %d\n", counts.total);
+    printf("SEND      = %d\n", counts.sendcount);
+    printf("RECEIVE   = %d\n", counts.receivecount);
+    printf("SEND_ONCE = %d\n", counts.sendoncecount);
+    printf("PORT_SET  = %d\n", counts.portsetcount);
+    printf("DEAD_NAME = %d\n", counts.deadcount);
+    printf("DNREQUEST = %d\n", counts.dncount);
+    printf("VOUCHERS  = %d\n", counts.vouchercount);
+}
+
+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) {
+    int j, k, port_status_flag_idx;
+    kern_return_t ret;
+    boolean_t send = FALSE;
+    boolean_t dnreq = FALSE;
+    int sendrights = 0;
+    unsigned int kotype = 0;
+    vm_offset_t kobject = (vm_offset_t)0;
+
+    /* skip empty slots in the table */
+    if ((entry->iin_type & MACH_PORT_TYPE_ALL_RIGHTS) == 0) {
+        counts->total--;
+        return;
+    }
+
+    if (entry->iin_type == MACH_PORT_TYPE_PORT_SET) {
+        mach_port_name_array_t members;
+        mach_msg_type_number_t membersCnt;
+
+        ret = mach_port_get_set_status(taskinfo->task,
+                                       entry->iin_name,
+                                       &members, &membersCnt);
+        if (ret != KERN_SUCCESS) {
+            fprintf(stderr, "mach_port_get_set_status(0x%08x) failed: %s\n",
+                    entry->iin_name,
+                    mach_error_string(ret));
+            return;
         }
-        
-        
-               if (taskinfo->table[i].iin_type == MACH_PORT_TYPE_PORT_SET) {
-                       mach_port_name_array_t members;
-                       mach_msg_type_number_t membersCnt;
-                       
-                       ret = mach_port_get_set_status(taskinfo->task,
-                                                                                  taskinfo->table[i].iin_name,
-                                                                                  &members, &membersCnt);
-                       if (ret != KERN_SUCCESS) {
-                               fprintf(stderr, "mach_port_get_set_status(0x%08x) failed: %s\n",
-                                               taskinfo->table[i].iin_name,
-                                               mach_error_string(ret));
-                               continue;
-                       }
-                       printf("0x%08x  0x%08x  port-set    --------        ---      1                                                        %d  members\n",
-                                  taskinfo->table[i].iin_name,
-                                  taskinfo->table[i].iin_object,
-                                  membersCnt);
-                       /* get some info for each portset member */
-                       for (j = 0; j < membersCnt; j++) {
-                               for (k = 0; k < taskinfo->tableCount; k++) {
-                                       if (taskinfo->table[k].iin_name == members[j]) {
-                        mach_port_info_ext_t info;
-                        mach_port_status_t port_status;
-                        mach_port_context_t port_context = (mach_port_context_t)0;
-                        if (0 != get_recieve_port_status(taskinfo->task, taskinfo->table[k].iin_name, &info)) {
-                            bzero((void *)&info, sizeof(info));
+
+        JSON_OBJECT_BEGIN(json);
+        JSON_OBJECT_SET(json, type, "port set");
+        JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+        JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+
+        JSON_KEY(json, members);
+        JSON_ARRAY_BEGIN(json);
+
+        printf("0x%08x  0x%08x  port-set    --------        ---      1                                                        %d  members\n",
+               entry->iin_name,
+               entry->iin_object,
+               membersCnt);
+        /* get some info for each portset member */
+        for (j = 0; j < membersCnt; j++) {
+            for (k = 0; k < taskinfo->tableCount; k++) {
+                if (taskinfo->table[k].iin_name == members[j]) {
+                    mach_port_info_ext_t info;
+                    mach_port_status_t port_status;
+                    mach_port_context_t port_context = (mach_port_context_t)0;
+                    if (0 != get_recieve_port_status(taskinfo->task, taskinfo->table[k].iin_name, &info)) {
+                        bzero((void *)&info, sizeof(info));
+                    }
+                    port_status = info.mpie_status;
+                    get_receive_port_context(taskinfo->task, taskinfo->table[k].iin_name, &port_context);
+
+                    JSON_OBJECT_BEGIN(json);
+                    JSON_OBJECT_SET(json, ipc-object, "0x%08x", taskinfo->table[k].iin_object);
+
+                    JSON_KEY(json, rights);
+                    JSON_ARRAY_BEGIN(json);
+                    JSON_ARRAY_APPEND(json, "recv");
+                    if (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) {
+                        JSON_ARRAY_APPEND(json, "send");
+                    }
+                    JSON_ARRAY_END(json); // rights
+
+                    JSON_KEY(json, port_status_flags);
+                    JSON_ARRAY_BEGIN(json);
+                    port_status_flag_idx = 0;
+                    while (0 != port_status_flags[port_status_flag_idx++].flag) {
+                        if (port_status.mps_flags & INDEX_TO_PORT_FLAG(port_status_flag_idx)) {
+                            JSON_ARRAY_APPEND(json, "%s", port_status_flags[port_status_flag_idx].name);
                         }
-                        port_status = info.mpie_status;
-                        get_receive_port_context(taskinfo->task, taskinfo->table[k].iin_name, &port_context);
-                        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",
-                                                          taskinfo->table[k].iin_object,
-                                                          (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) ? "recv,send ":"recv      ",
-                               SHOW_PORT_STATUS_FLAGS(port_status.mps_flags),
-                               info.mpie_boost_cnt,
-                               (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
-                               (port_status.mps_nsrequest) ? "N" : "-",
-                               (port_status.mps_pdrequest) ? "P" : "-",
-                               1,
-                               taskinfo->table[k].iin_urefs,
-                               port_status.mps_sorights,
-                               (port_status.mps_srights) ? "Y" : "N",
-                               port_status.mps_qlimit,
-                               port_status.mps_msgcount,
-                               (uint64_t)port_context,
-                                                          taskinfo->table[k].iin_name,
-                                                          pid,
-                               taskinfo->processName);
-                                               break;
-                                       }
-                               }
-                       }
-            
-                       ret = vm_deallocate(mach_task_self(), (vm_address_t)members,
-                                                               membersCnt * sizeof(mach_port_name_t));
-                       if (ret != KERN_SUCCESS) {
-                               fprintf(stderr, "vm_deallocate() failed: %s\n",
-                                               mach_error_string(ret));
-                               exit(1);
-                       }
-                       portsetcount++;
-                       continue;
-               }
-        
-               if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_SEND) {
-                       send = TRUE;
-                       sendrights = taskinfo->table[i].iin_urefs;
-                       sendcount++;
-               }
-               
-               if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_DNREQUEST) {
-                       dnreq = TRUE;
-                       dncount++;
-               }
-        
-               if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_RECEIVE) {
-                       mach_port_status_t status;
-                       mach_port_info_ext_t info;
-                       mach_port_context_t context = (mach_port_context_t)0;
-            ret = get_recieve_port_status(taskinfo->task, taskinfo->table[i].iin_name, &info);
-            get_receive_port_context(taskinfo->task, taskinfo->table[i].iin_name, &context);
-            /* its ok to fail in fetching attributes */
-            if (ret < 0) {
-                continue;
+                    }
+                    JSON_ARRAY_END(json); // port status flags
+                    JSON_OBJECT_SET(json, boosts, %d, info.mpie_boost_cnt);
+
+                    JSON_KEY(json, notifications);
+                    JSON_ARRAY_BEGIN(json);
+                    if (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) {
+                        JSON_ARRAY_APPEND(json, "dead name");
+                    }
+                    if (port_status.mps_nsrequest) {
+                        JSON_ARRAY_APPEND(json, "no sender");
+                    }
+                    if (port_status.mps_nsrequest) {
+                        JSON_ARRAY_APPEND(json, "port destroy request");
+                    }
+                    JSON_ARRAY_END(json); // notifications
+
+                    JSON_OBJECT_SET(json, recv_rights, %d, 1);
+                    JSON_OBJECT_SET(json, send_rights, %d, taskinfo->table[k].iin_urefs);
+                    JSON_OBJECT_SET(json, send_once_rights, %d, port_status.mps_sorights);
+                    JSON_OBJECT_SET_BOOL(json, oref, port_status.mps_srights);
+                    JSON_OBJECT_SET(json, queue_limit, %d, port_status.mps_qlimit);
+                    JSON_OBJECT_SET(json, msg_count, %d, port_status.mps_msgcount);
+                    JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)port_context);
+                    JSON_OBJECT_SET(json, identifier, "0x%08x", taskinfo->table[k].iin_name);
+                    JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
+                    JSON_OBJECT_SET(json, process, "%s", taskinfo->processName);
+                    JSON_OBJECT_END(json); // member
+
+                    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",
+                           taskinfo->table[k].iin_object,
+                           (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) ? "recv,send ":"recv      ",
+                           SHOW_PORT_STATUS_FLAGS(port_status.mps_flags),
+                           info.mpie_boost_cnt,
+                           (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
+                           (port_status.mps_nsrequest) ? "N" : "-",
+                           (port_status.mps_pdrequest) ? "P" : "-",
+                           1,
+                           taskinfo->table[k].iin_urefs,
+                           port_status.mps_sorights,
+                           (port_status.mps_srights) ? "Y" : "N",
+                           port_status.mps_qlimit,
+                           port_status.mps_msgcount,
+                           (uint64_t)port_context,
+                           taskinfo->table[k].iin_name,
+                           taskinfo->pid,
+                           taskinfo->processName);
+                    break;
+                }
+            }
+        }
+
+        JSON_ARRAY_END(json); // members
+        JSON_OBJECT_END(json); // port-set
+
+        ret = vm_deallocate(mach_task_self(), (vm_address_t)members,
+                            membersCnt * sizeof(mach_port_name_t));
+        if (ret != KERN_SUCCESS) {
+            fprintf(stderr, "vm_deallocate() failed: %s\n",
+                    mach_error_string(ret));
+            exit(1);
+        }
+        counts->portsetcount++;
+        return;
+    }
+
+    if (entry->iin_type & MACH_PORT_TYPE_SEND) {
+        send = TRUE;
+        sendrights = entry->iin_urefs;
+        counts->sendcount++;
+    }
+
+    if (entry->iin_type & MACH_PORT_TYPE_DNREQUEST) {
+        dnreq = TRUE;
+        counts->dncount++;
+    }
+
+    if (entry->iin_type & MACH_PORT_TYPE_RECEIVE) {
+        mach_port_status_t status;
+        mach_port_info_ext_t info;
+        mach_port_context_t context = (mach_port_context_t)0;
+        struct k2n_table_node *k2nnode;
+        ret = get_recieve_port_status(taskinfo->task, entry->iin_name, &info);
+        get_receive_port_context(taskinfo->task, entry->iin_name, &context);
+        /* its ok to fail in fetching attributes */
+        if (ret < 0) {
+            return;
+        }
+        status = info.mpie_status;
+
+        JSON_OBJECT_BEGIN(json);
+        JSON_OBJECT_SET(json, type, "port");
+        JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+        JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+
+        JSON_KEY(json, rights);
+        JSON_ARRAY_BEGIN(json);
+        JSON_ARRAY_APPEND(json, "recv");
+        if (send) JSON_ARRAY_APPEND(json, "send");
+        JSON_ARRAY_END(json); // rights
+
+        JSON_KEY(json, port_status_flags);
+        JSON_ARRAY_BEGIN(json);
+        port_status_flag_idx = 0;
+        while (0 != port_status_flags[port_status_flag_idx++].flag) {
+            if (status.mps_flags & INDEX_TO_PORT_FLAG(port_status_flag_idx)) {
+                JSON_ARRAY_APPEND(json, "%s", port_status_flags[port_status_flag_idx].name);
             }
-            status = info.mpie_status;
-                       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",
-                                  taskinfo->table[i].iin_name,
-                                  taskinfo->table[i].iin_object,
-                                  (send) ? "recv,send ":"recv      ",
-                                  SHOW_PORT_STATUS_FLAGS(status.mps_flags),
-                                  info.mpie_boost_cnt,
-                                  (dnreq) ? "D":"-",
-                                  (status.mps_nsrequest) ? "N":"-",
-                                  (status.mps_pdrequest) ? "P":"-",
-                   1,
-                                  sendrights,
-                   status.mps_sorights,
-                                  (status.mps_srights) ? "Y":"N",
-                                  status.mps_qlimit,
-                                  status.mps_msgcount,
-                                  (uint64_t)context);
-                       receivecount++;
-            
-            
-                       /* show other rights (in this and other tasks) for the port */
-                       for (j = 0; j < taskCount; j++) {
-                               for (k = 0; k < allTaskInfos[j].tableCount; k++) {
-                                       if (allTaskInfos[j].valid == FALSE ||
-                                               &allTaskInfos[j].table[k] == &taskinfo->table[i] ||
-                                               allTaskInfos[j].table[k].iin_object != taskinfo->table[i].iin_object)
-                                               continue;
-                    
+        }
+        JSON_ARRAY_END(json); // port status flags
+        JSON_OBJECT_SET(json, boosts, %d, info.mpie_boost_cnt);
+
+        JSON_KEY(json, notifications);
+        JSON_ARRAY_BEGIN(json);
+        if (dnreq) {
+            JSON_ARRAY_APPEND(json, "dead name");
+        }
+        if (status.mps_nsrequest) {
+            JSON_ARRAY_APPEND(json, "no sender");
+        }
+        if (status.mps_nsrequest) {
+            JSON_ARRAY_APPEND(json, "port destroy request");
+        }
+        JSON_ARRAY_END(json); // notifications
+
+        JSON_OBJECT_SET(json, recv_rights, %d, 1);
+        JSON_OBJECT_SET(json, send_rights, %d, sendrights);
+        JSON_OBJECT_SET(json, send_once_rights, %d, status.mps_sorights);
+        JSON_OBJECT_SET_BOOL(json, oref, status.mps_srights);
+        JSON_OBJECT_SET(json, queue_limit, %d, status.mps_qlimit);
+        JSON_OBJECT_SET(json, msg_count, %d, status.mps_msgcount);
+        JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)context);
+        JSON_OBJECT_END(json); // port
+
+        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",
+               entry->iin_name,
+               entry->iin_object,
+               (send) ? "recv,send ":"recv      ",
+               SHOW_PORT_STATUS_FLAGS(status.mps_flags),
+               info.mpie_boost_cnt,
+               (dnreq) ? "D":"-",
+               (status.mps_nsrequest) ? "N":"-",
+               (status.mps_pdrequest) ? "P":"-",
+               1,
+               sendrights,
+               status.mps_sorights,
+               (status.mps_srights) ? "Y":"N",
+               status.mps_qlimit,
+               status.mps_msgcount,
+               (uint64_t)context);
+        counts->receivecount++;
+
+        /* show other rights (in this and other tasks) for the port */
+        for (j = 0; j < taskCount; j++) {
+            if (allTaskInfos[j].valid == FALSE)
+                continue;
+
+            k2nnode = k2n_table_lookup(allTaskInfos[j].k2ntable, entry->iin_object);
+
+            while (k2nnode) {
+                if (k2nnode->info_name != entry) {
+                    assert(k2nnode->info_name->iin_object == entry->iin_object);
+
                     printf("                  +     %s  --------        %s%s%s        %5d         <-                                       0x%08x  (%d) %s\n",
-                                                  (allTaskInfos[j].table[k].iin_type & MACH_PORT_TYPE_SEND_ONCE) ?
-                                              "send-once " : "send      ",
-                                                  (allTaskInfos[j].table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
+                           (k2nnode->info_name->iin_type & MACH_PORT_TYPE_SEND_ONCE) ?
+                           "send-once " : "send      ",
+                           (k2nnode->info_name->iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
                            "-",
                            "-",
-                           allTaskInfos[j].table[k].iin_urefs,
-                                                  allTaskInfos[j].table[k].iin_name,
-                                                  allTaskInfos[j].pid,
+                           k2nnode->info_name->iin_urefs,
+                           k2nnode->info_name->iin_name,
+                           allTaskInfos[j].pid,
                            allTaskInfos[j].processName);
-                               }
-                       }
-                       continue;
-               }
-               else if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_DEAD_NAME)
-               {
-                       printf("0x%08x  0x%08x  dead-name   --------        ---        %5d      \n",
-                                  taskinfo->table[i].iin_name,
-                                  taskinfo->table[i].iin_object,
-                                  taskinfo->table[i].iin_urefs);
-                       deadcount++;
-                       continue;
-               }
-        
-               if (taskinfo->table[i].iin_type & MACH_PORT_TYPE_SEND_ONCE) {
-                       sendonce = TRUE;
-                       sendoncecount++;
-               }
-               
-               printf("0x%08x  0x%08x  %s  --------        %s%s%s        %5.0d     ",
-                          taskinfo->table[i].iin_name,
-                          taskinfo->table[i].iin_object,
-                          (send) ? "send      ":"send-once ",
-                          (dnreq) ? "D":"-",
-                          "-",
-                          "-",
-                          (send) ? sendrights : 0);
-               
-               /* converting to kobjects is not always supported */
-               ret = mach_port_kernel_object(taskinfo->task,
-                                                                         taskinfo->table[i].iin_name,
-                                                                         &kotype, (unsigned *)&kobject);
-               if (ret == KERN_SUCCESS && kotype != 0) {
-                       printf("                                             0x%08x  %s", (natural_t)kobject, kobject_name(kotype));
-            if ((kotype == IKOT_TASK_RESUME) || (kotype == IKOT_TASK) || (kotype == IKOT_TASK_NAME)) {
-                if (taskinfo->task_kobject == kobject) {
-                    /* neat little optimization since in most cases tasks have themselves in their ipc space */
-                    printf(" SELF (%d) %s", taskinfo->pid, taskinfo->processName);
-                } else {
-                    my_per_task_info_t * _found_task = get_taskinfo_by_kobject((natural_t)kobject);
-                    printf(" (%d) %s", _found_task->pid, _found_task->processName);
                 }
+
+                k2nnode = k2n_table_lookup_next(k2nnode, entry->iin_object);
             }
-            
-            printf("\n");
-            if (kotype == IKOT_VOUCHER) {
-                vouchercount++;
-                if (lsmp_config.show_voucher_details) {
-                    char * detail = copy_voucher_detail(taskinfo->task, taskinfo->table[i].iin_name);
-                    printf("%s\n", detail);
-                    free(detail);
-                }
+        }
+        return;
+    }
+    else if (entry->iin_type & MACH_PORT_TYPE_DEAD_NAME)
+    {
+        JSON_OBJECT_BEGIN(json);
+        JSON_OBJECT_SET(json, type, "dead name");
+        JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+        JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+        JSON_OBJECT_SET(json, send_rights, %d, entry->iin_urefs);
+        JSON_OBJECT_END(json); // dead name
+
+        printf("0x%08x  0x%08x  dead-name   --------        ---        %5d      \n",
+               entry->iin_name,
+               entry->iin_object,
+               entry->iin_urefs);
+        counts->deadcount++;
+        return;
+    }
+
+    if (entry->iin_type & MACH_PORT_TYPE_SEND_ONCE) {
+        counts->sendoncecount++;
+    }
+
+    JSON_OBJECT_BEGIN(json);
+    JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+    JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+
+    JSON_KEY(json, rights);
+    JSON_ARRAY_BEGIN(json);
+    JSON_ARRAY_APPEND(json, "%s", (send) ? "send":"send once");
+    JSON_ARRAY_END(json); //rights
+
+    JSON_KEY(json, notifications);
+    JSON_ARRAY_BEGIN(json);
+    if (dnreq) JSON_ARRAY_APPEND(json, "dead name");
+    JSON_ARRAY_END(json); // notifications
+
+    JSON_OBJECT_SET(json, send_rights, %d, (send) ? sendrights : 0);
+
+    printf("0x%08x  0x%08x  %s  --------        %s%s%s        %5.0d     ",
+           entry->iin_name,
+           entry->iin_object,
+           (send) ? "send      ":"send-once ",
+           (dnreq) ? "D":"-",
+           "-",
+           "-",
+           (send) ? sendrights : 0);
+
+    /* converting to kobjects is not always supported */
+    ret = mach_port_kernel_object(taskinfo->task,
+                                  entry->iin_name,
+                                  &kotype, (unsigned *)&kobject);
+    if (ret == KERN_SUCCESS && kotype != 0) {
+        JSON_OBJECT_SET(json, identifier, "0x%08x", (natural_t)kobject);
+        JSON_OBJECT_SET(json, type, "%s", kobject_name(kotype));
+        printf("                                             0x%08x  %s", (natural_t)kobject, kobject_name(kotype));
+        if ((kotype == IKOT_TASK_RESUME) || (kotype == IKOT_TASK) || (kotype == IKOT_TASK_NAME)) {
+            if (taskinfo->task_kobject == kobject) {
+                /* neat little optimization since in most cases tasks have themselves in their ipc space */
+                JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
+                JSON_OBJECT_SET(json, process, "%s", taskinfo->processName);
+                printf(" SELF (%d) %s", taskinfo->pid, taskinfo->processName);
+            } else {
+                my_per_task_info_t * _found_task = get_taskinfo_by_kobject((natural_t)kobject);
+                JSON_OBJECT_SET(json, pid, %d, _found_task->pid);
+                JSON_OBJECT_SET(json, process, "%s", _found_task->processName);
+                printf(" (%d) %s", _found_task->pid, _found_task->processName);
             }
-                       continue;
-               }
-        
-        /* not kobject - find the receive right holder */
-        my_per_task_info_t *recv_holder_taskinfo;
-        mach_port_name_t recv_name = MACH_PORT_NULL;
-        if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(&taskinfo->table[i], &recv_holder_taskinfo, &recv_name)) {
-            mach_port_status_t port_status;
-            mach_port_info_ext_t info;
-            mach_port_context_t port_context = (mach_port_context_t)0;
-            if (0 != get_recieve_port_status(recv_holder_taskinfo->task, recv_name, &info)) {
-                bzero((void *)&port_status, sizeof(port_status));
+        }
+
+                       if (kotype == IKOT_THREAD) {
+                               for (int i = 0; i < taskinfo->threadCount; i++) {
+                                       if (taskinfo->threadInfos[i].th_kobject == kobject) {
+                                               printf(" (%#llx)", taskinfo->threadInfos[i].th_id);
+                                               break;
+                                       }
+                               }
+                       }
+
+        printf("\n");
+        if (kotype == IKOT_VOUCHER) {
+            counts->vouchercount++;
+            if (lsmp_config.show_voucher_details) {
+                JSON_KEY(json, recipes);
+                JSON_ARRAY_BEGIN(json);
+                char * detail = copy_voucher_detail(taskinfo->task, entry->iin_name, json);
+                JSON_ARRAY_END(json); // recipes
+                printf("%s\n", detail);
+                free(detail);
             }
-            port_status = info.mpie_status;
-            get_receive_port_context(recv_holder_taskinfo->task, recv_name, &port_context);
-            printf("   ->   %6d  %8d  0x%016llx 0x%08x  (%d) %s\n",
-                   port_status.mps_qlimit,
-                   port_status.mps_msgcount,
-                   (uint64_t)port_context,
-                   recv_name,
-                   recv_holder_taskinfo->pid,
-                   recv_holder_taskinfo->processName);
-
-        } else
-                       printf("                                             0x00000000  (-) Unknown Process\n");
-       }
-       printf("total     = %d\n", taskinfo->tableCount + taskinfo->treeCount - emptycount);
-       printf("SEND      = %d\n", sendcount);
-       printf("RECEIVE   = %d\n", receivecount);
-       printf("SEND_ONCE = %d\n", sendoncecount);
-       printf("PORT_SET  = %d\n", portsetcount);
-       printf("DEAD_NAME = %d\n", deadcount);
-       printf("DNREQUEST = %d\n", dncount);
-    printf("VOUCHERS  = %d\n", vouchercount);
-    
+        }
+        JSON_OBJECT_END(json); // kobject
+        return;
+    }
+
+    /* not kobject - find the receive right holder */
+    my_per_task_info_t *recv_holder_taskinfo;
+    mach_port_name_t recv_name = MACH_PORT_NULL;
+    if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(entry, &recv_holder_taskinfo, &recv_name)) {
+        mach_port_status_t port_status;
+        mach_port_info_ext_t info;
+        mach_port_context_t port_context = (mach_port_context_t)0;
+        if (0 != get_recieve_port_status(recv_holder_taskinfo->task, recv_name, &info)) {
+            bzero((void *)&port_status, sizeof(port_status));
+        }
+        port_status = info.mpie_status;
+        get_receive_port_context(recv_holder_taskinfo->task, recv_name, &port_context);
+
+        JSON_OBJECT_SET(json, queue_limit, %d, port_status.mps_qlimit);
+        JSON_OBJECT_SET(json, msg_count, %d, port_status.mps_msgcount);
+        JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)port_context);
+        JSON_OBJECT_SET(json, identifier, "0x%08x", recv_name);
+        JSON_OBJECT_SET(json, pid, %d, recv_holder_taskinfo->pid);
+        JSON_OBJECT_SET(json, process, "%s", recv_holder_taskinfo->processName);
+
+        printf("   ->   %6d  %8d  0x%016llx 0x%08x  (%d) %s\n",
+               port_status.mps_qlimit,
+               port_status.mps_msgcount,
+               (uint64_t)port_context,
+               recv_name,
+               recv_holder_taskinfo->pid,
+               recv_holder_taskinfo->processName);
+
+    } else {
+        JSON_OBJECT_SET(json, identifier, "0x%08x", 0);
+        JSON_OBJECT_SET(json, pid, %d, -1);
+        JSON_OBJECT_SET(json, process, "unknown");
+        printf("                                             0x00000000  (-) Unknown Process\n");
+    }
+
+    JSON_OBJECT_END(json); // non-kobject
 }
 
-void print_hex_data(char *outstr, size_t maxlen, char *prefix, char *desc, void *addr, int len) {
+uint32_t print_hex_data(char *outstr, uint32_t maxlen, char *prefix, char *desc, void *addr, int len) {
     int i;
     unsigned char buff[17];
     unsigned char *pc = addr;
     uint32_t plen = 0;
-    
+
     if (desc != NULL)
-        plen += safesize(snprintf(&outstr[len], maxlen - plen, "%s%s:\n", prefix, desc));
-    
+        plen += snprintf(&outstr[plen], safesize(maxlen - plen), "%s%s:\n", prefix, desc);
+
     for (i = 0; i < len; i++) {
-        
+
         if ((i % 16) == 0) {
             if (i != 0)
-                plen += safesize(snprintf(&outstr[len], maxlen - plen, "  %s\n", buff));
-            
-            plen += safesize(snprintf(&outstr[len], maxlen - plen, "%s  %04x ", prefix, i));
+                plen += snprintf(&outstr[plen], safesize(maxlen - plen), "  %s\n", buff);
+
+            plen += snprintf(&outstr[plen], safesize(maxlen - plen), "%s  %04x ", prefix, i);
         }
-        
-        plen += safesize(snprintf(&outstr[len], maxlen - plen, " %02x", pc[i]));
-        
+
+        plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %02x", pc[i]);
+
         if ((pc[i] < 0x20) || (pc[i] > 0x7e))
             buff[i % 16] = '.';
         else
             buff[i % 16] = pc[i];
         buff[(i % 16) + 1] = '\0';
     }
-    
+
     while ((i % 16) != 0) {
-        plen += safesize(snprintf(&outstr[len], maxlen - plen, "   "));
+        plen += snprintf(&outstr[plen], safesize(maxlen - plen), "   ");
         i++;
     }
-    
-    plen += safesize(snprintf(&outstr[len], maxlen - plen, "  %s\n", buff));
+
+    plen += snprintf(&outstr[plen], safesize(maxlen - plen), "  %s\n", buff);
+
+    return plen;
 }