]> git.saurik.com Git - apple/system_cmds.git/blobdiff - zprint.tproj/zprint.c
system_cmds-735.50.6.tar.gz
[apple/system_cmds.git] / zprint.tproj / zprint.c
index 1d030ae11f3236bffb1215b807e059df77b09021..104161cea9f78968df7a9c2ceca2880f31e1bd18 100644 (file)
@@ -1,28 +1,55 @@
+/*
+ * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
 /*
  * @OSF_COPYRIGHT@
  */
-/* 
+/*
  * Mach Operating System
  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
  * All Rights Reserved.
- * 
+ *
  * Permission to use, copy, modify and distribute this software and its
  * documentation is hereby granted, provided that both the copyright
  * notice and this permission notice appear in all copies of the
  * software, derivative works or modified versions, and any portions
  * thereof, and that both notices appear in supporting documentation.
- * 
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- * 
+ *
  * Carnegie Mellon requests users of this software to return to
- * 
+ *
  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  *  School of Computer Science
  *  Carnegie Mellon University
  *  Pittsburgh PA 15213-3890
- * 
+ *
  * any improvements or extensions that they make and grant Carnegie the
  * rights to redistribute these changes.
  */
  *     to zones but not currently in use.
  */
 
+#include <vm_statistics.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <mach/mach.h>
 #include <mach_debug/mach_debug.h>
 #include <mach/mach_error.h>
+#include <libutil.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <getopt.h>
+#include <malloc/malloc.h>
+#include <Kernel/IOKit/IOKitDebug.h>
+#include <Kernel/libkern/OSKextLibPrivate.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/kext/OSKext.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreSymbolication/CoreSymbolication.h>
 
 #define streql(a, b)           (strcmp((a), (b)) == 0)
 #define strneql(a, b, n)       (strncmp((a), (b), (n)) == 0)
+#define        PRINTK(fmt, value)      \
+       printf(fmt "K", (value) / 1024 )        /* ick */
 
-static void printzone();
-static void colprintzone();
-static void colprintzoneheader();
-static void printk();
-static int strnlen();
-static boolean_t substr();
+static void usage(void);
+static void printzone(mach_zone_name_t *, task_zone_info_t *);
+static void colprintzone(mach_zone_name_t *, task_zone_info_t *);
+static int  find_deltas(mach_zone_name_t *, task_zone_info_t *, task_zone_info_t *, char *, int, int);
+static void colprintzoneheader(void);
+static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen);
+
+static int  SortName(const void * left, const void * right);
+static int  SortSize(const void * left, const void * right);
+static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, int (*func)(const void *, const void *), boolean_t column);
 
 static char *program;
 
+static pid_t pid = 0;
+static task_t task = TASK_NULL;
+static boolean_t ShowPid = FALSE;
+
+static boolean_t ShowDeltas = FALSE;
 static boolean_t ShowWasted = FALSE;
+static boolean_t ShowTotal = FALSE;
+static boolean_t ShowLarge = TRUE;
 static boolean_t SortZones = FALSE;
 static boolean_t ColFormat = TRUE;
 static boolean_t PrintHeader = TRUE;
 
-static unsigned int totalsize = 0;
-static unsigned int totalused = 0;
+static unsigned long long totalsize = 0;
+static unsigned long long totalused = 0;
+static unsigned long long totalsum = 0;
+static unsigned long long pidsum = 0;
+
+static int last_time = 0;
+
+static char    *zname = NULL;
+static size_t  znamelen = 0;
 
 static void
-usage()
+sigintr(__unused int signum)
 {
-       fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [name]\n", program);
-       exit(1);
+       last_time = 1;
 }
 
-main(argc, argv)
-       int     argc;
-       char    *argv[];
+static void
+usage(void)
 {
-       zone_name_t name_buf[1024];
-       zone_name_t *name = name_buf;
-       unsigned int nameCnt = sizeof name_buf/sizeof name_buf[0];
-       zone_info_t info_buf[1024];
-       zone_info_t *info = info_buf;
-       unsigned int infoCnt = sizeof info_buf/sizeof info_buf[0];
+       fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p <pid>] [name]\n", program);
+       exit(1);
+}
 
-       char            *zname = NULL;
-       int             znamelen;
+int
+main(int argc, char **argv)
+{
+       mach_zone_name_t *name = NULL;
+       unsigned int nameCnt = 0;
+       task_zone_info_t *info = NULL;
+       unsigned int infoCnt = 0;
+       mach_memory_info_t *wiredInfo = NULL;
+       unsigned int wiredInfoCnt = 0;
+       task_zone_info_t *max_info = NULL;
+       char            *deltas = NULL;
 
        kern_return_t   kr;
        int             i, j;
+       int             first_time = 1;
+       int             must_print = 1;
+       int             interval = 1;
+
+       signal(SIGINT, sigintr);
 
        program = strrchr(argv[0], '/');
        if (program == NULL)
@@ -95,10 +165,20 @@ main(argc, argv)
                program++;
 
        for (i = 1; i < argc; i++) {
-               if (streql(argv[i], "-w"))
+               if (streql(argv[i], "-d"))
+                       ShowDeltas = TRUE;
+               else if (streql(argv[i], "-t"))
+                       ShowTotal = TRUE;
+               else if (streql(argv[i], "-T"))
+                       ShowTotal = FALSE;
+               else if (streql(argv[i], "-w"))
                        ShowWasted = TRUE;
                else if (streql(argv[i], "-W"))
                        ShowWasted = FALSE;
+               else if (streql(argv[i], "-l"))
+                       ShowLarge = TRUE;
+               else if (streql(argv[i], "-L"))
+                       ShowLarge = FALSE;
                else if (streql(argv[i], "-s"))
                        SortZones = TRUE;
                else if (streql(argv[i], "-S"))
@@ -109,7 +189,14 @@ main(argc, argv)
                        ColFormat = FALSE;
                else if (streql(argv[i], "-H"))
                        PrintHeader = FALSE;
-               else if (streql(argv[i], "--")) {
+               else if (streql(argv[i], "-p")) {
+                       ShowPid = TRUE;
+                       if (i < argc - 1) {
+                               pid = atoi(argv[i+1]);
+                               i++;
+                       } else
+                               usage();
+               } else if (streql(argv[i], "--")) {
                        i++;
                        break;
                } else if (argv[i][0] == '-')
@@ -133,34 +220,89 @@ main(argc, argv)
                usage();
        }
 
-       kr = host_zone_info(mach_host_self(),
-                           &name, &nameCnt, &info, &infoCnt);
-       if (kr != KERN_SUCCESS) {
-               fprintf(stderr, "%s: host_zone_info: %s\n",
-                    program, mach_error_string(kr));
+       if (ShowDeltas) {
+               SortZones = FALSE;
+               ColFormat = TRUE;
+               PrintHeader = TRUE;
+       }
+
+       if (ShowPid) {
+               kr = task_for_pid(mach_task_self(), pid, &task);
+               if (kr != KERN_SUCCESS) {
+                       fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n",
+                               program, pid, mach_error_string(kr));
+                       exit(1);
+               }
+       }
+
+    for (;;) {
+        if (ShowPid) {
+           kr = task_zone_info(task, &name, &nameCnt, &info, &infoCnt);
+           if (kr != KERN_SUCCESS) {
+               fprintf(stderr, "%s: task_zone_info: %s\n",
+                       program, mach_error_string(kr));
+               exit(1);
+           }
+       } else {
+           mach_zone_info_t *zinfo = NULL;
+
+           kr = mach_memory_info(mach_host_self(),
+                               &name, &nameCnt, &zinfo, &infoCnt,
+                               &wiredInfo, &wiredInfoCnt);
+           if (kr != KERN_SUCCESS) {
+               fprintf(stderr, "%s: mach_zone_info: %s\n",
+                       program, mach_error_string(kr));
                exit(1);
+           }
+
+           kr = vm_allocate(mach_task_self(), (vm_address_t *)&info,
+                            infoCnt * sizeof *info, VM_FLAGS_ANYWHERE);
+           if (kr != KERN_SUCCESS) {
+                   fprintf(stderr, "%s vm_allocate: %s\n",
+                           program, mach_error_string(kr));
+                   exit(1);
+           }
+           for (i = 0; i < infoCnt; i++) {
+                   *(mach_zone_info_t *)(info + i) = zinfo[i];
+                   info[i].tzi_caller_acct = 0;
+                   info[i].tzi_task_alloc = 0;
+                   info[i].tzi_task_free = 0;
+           }
+           kr = vm_deallocate(mach_task_self(), (vm_address_t) zinfo,
+                              (vm_size_t) (infoCnt * sizeof *zinfo));
+           if (kr != KERN_SUCCESS) {
+                   fprintf(stderr, "%s: vm_deallocate: %s\n",
+                           program, mach_error_string(kr));
+                   exit(1);
+           }
        }
-       else if (nameCnt != infoCnt) {
-               fprintf(stderr, "%s: host_zone_info: counts not equal?\n",
+
+       if (nameCnt != infoCnt) {
+               fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n",
                        program);
                exit(1);
        }
 
+       if (first_time) {
+               deltas = (char *)malloc(infoCnt);
+               max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info));
+       }
+
        if (SortZones) {
                for (i = 0; i < nameCnt-1; i++)
                        for (j = i+1; j < nameCnt; j++) {
-                               int wastei, wastej;
+                               unsigned long long wastei, wastej;
 
-                               wastei = (info[i].zi_cur_size -
-                                         (info[i].zi_elem_size *
-                                          info[i].zi_count));
-                               wastej = (info[j].zi_cur_size -
-                                         (info[j].zi_elem_size *
-                                          info[j].zi_count));
+                               wastei = (info[i].tzi_cur_size -
+                                         (info[i].tzi_elem_size *
+                                          info[i].tzi_count));
+                               wastej = (info[j].tzi_cur_size -
+                                         (info[j].tzi_elem_size *
+                                          info[j].tzi_count));
 
                                if (wastej > wastei) {
-                                       zone_info_t tinfo;
-                                       zone_name_t tname;
+                                       task_zone_info_t tinfo;
+                                       mach_zone_name_t tname;
 
                                        tinfo = info[i];
                                        info[i] = info[j];
@@ -173,18 +315,31 @@ main(argc, argv)
                        }
        }
 
-       if (ColFormat) {
-               colprintzoneheader();
+       must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
+       if (must_print) {
+               if (ColFormat) {
+                       if (!first_time)
+                               printf("\n");
+                       colprintzoneheader();
+               }
+               for (i = 0; i < nameCnt; i++) {
+                       if (deltas[i]) {
+                               if (ColFormat)
+                                       colprintzone(&name[i], &info[i]);
+                               else
+                                       printzone(&name[i], &info[i]);
+                       }
+               }
        }
-       for (i = 0; i < nameCnt; i++)
-               if (substr(zname, znamelen, name[i].zn_name,
-                          strnlen(name[i].zn_name, sizeof name[i].zn_name)))
-                       if (ColFormat)
-                               colprintzone(&name[i], &info[i]);
-                       else
-                               printzone(&name[i], &info[i]);
-
-       if ((name != name_buf) && (nameCnt != 0)) {
+
+       if (ShowLarge && first_time) {
+               PrintLarge(wiredInfo, wiredInfoCnt,
+                          SortZones ? &SortSize : &SortName, ColFormat);
+       }
+
+       first_time = 0;
+
+       if ((name != NULL) && (nameCnt != 0)) {
                kr = vm_deallocate(mach_task_self(), (vm_address_t) name,
                                   (vm_size_t) (nameCnt * sizeof *name));
                if (kr != KERN_SUCCESS) {
@@ -194,7 +349,7 @@ main(argc, argv)
                }
        }
 
-       if ((info != info_buf) && (infoCnt != 0)) {
+       if ((info != NULL) && (infoCnt != 0)) {
                kr = vm_deallocate(mach_task_self(), (vm_address_t) info,
                                   (vm_size_t) (infoCnt * sizeof *info));
                if (kr != KERN_SUCCESS) {
@@ -204,37 +359,40 @@ main(argc, argv)
                }
        }
 
-       if (ShowWasted && PrintHeader) {
-               printf("TOTAL SIZE   = %u\n", totalsize);
-               printf("TOTAL USED   = %u\n", totalused);
-               printf("TOTAL WASTED = %d\n", totalsize - totalused);
+       if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) {
+               kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo,
+                                  (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo));
+               if (kr != KERN_SUCCESS) {
+                       fprintf(stderr, "%s: vm_deallocate: %s\n",
+                            program, mach_error_string(kr));
+                       exit(1);
+               }
        }
 
-       exit(0);
-}
-
-static int
-strnlen(s, n)
-       char *s;
-       int n;
-{
-       int len = 0;
+       if ((ShowWasted||ShowTotal) && PrintHeader && !ShowDeltas) {
+               printf("TOTAL SIZE   = %llu\n", totalsize);
+               printf("TOTAL USED   = %llu\n", totalused);
+               if (ShowWasted)
+                       printf("TOTAL WASTED = %llu\n", totalsize - totalused);
+               if (ShowTotal)
+                       printf("TOTAL ALLOCS = %llu\n", totalsum);
+       }
 
-       while ((len < n) && (*s++ != '\0'))
-               len++;
+       if (ShowDeltas == FALSE || last_time)
+               break;
 
-       return len;
+       sleep(interval);
+    }
+    exit(0);
 }
 
 static boolean_t
-substr(a, alen, b, blen)
-       char *a;
-       int alen;
-       char *b;
-       int blen;
+substr(const char *a, size_t alen, const char *b, size_t blen)
 {
        int i;
 
+       if (alen > blen) return FALSE;
+
        for (i = 0; i <= blen - alen; i++)
                if (strneql(a, b+i, alen))
                        return TRUE;
@@ -243,58 +401,62 @@ substr(a, alen, b, blen)
 }
 
 static void
-printzone(name, info)
-       zone_name_t *name;
-       zone_info_t *info;
+printzone(mach_zone_name_t *name, task_zone_info_t *info)
 {
-       unsigned int used, size;
-
-       printf("%.*s zone:\n", sizeof name->zn_name, name->zn_name);
-       printf("\tcur_size:    %dK bytes (%d elements)\n",
-              info->zi_cur_size/1024,
-              info->zi_cur_size/info->zi_elem_size);
-       printf("\tmax_size:    %dK bytes (%d elements)\n",
-              info->zi_max_size/1024,
-              info->zi_max_size/info->zi_elem_size);
-       printf("\telem_size:   %d bytes\n",
-              info->zi_elem_size);
-       printf("\t# of elems:  %d\n",
-              info->zi_count);
-       printf("\talloc_size:  %dK bytes (%d elements)\n",
-              info->zi_alloc_size/1024,
-              info->zi_alloc_size/info->zi_elem_size);
-       if (info->zi_pageable)
-               printf("\tPAGEABLE\n");
-       if (info->zi_collectable)
+       unsigned long long used, size;
+
+       printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name);
+       printf("\tcur_size:    %lluK bytes (%llu elements)\n",
+              info->tzi_cur_size/1024,
+              (info->tzi_elem_size == 0) ? 0 :
+              info->tzi_cur_size/info->tzi_elem_size);
+       printf("\tmax_size:    %lluK bytes (%llu elements)\n",
+              info->tzi_max_size/1024,
+              (info->tzi_elem_size == 0) ? 0 :
+              info->tzi_max_size/info->tzi_elem_size);
+       printf("\telem_size:   %llu bytes\n",
+              info->tzi_elem_size);
+       printf("\t# of elems:  %llu\n",
+              info->tzi_count);
+       printf("\talloc_size:  %lluK bytes (%llu elements)\n",
+              info->tzi_alloc_size/1024,
+              (info->tzi_elem_size == 0) ? 0 :
+              info->tzi_alloc_size/info->tzi_elem_size);
+       if (info->tzi_exhaustible)
+               printf("\tEXHAUSTIBLE\n");
+       if (info->tzi_collectable)
                printf("\tCOLLECTABLE\n");
-
+       if (ShowPid && info->tzi_caller_acct)
+               printf("\tCALLER ACCOUNTED\n");
+       if (ShowPid) {
+               pidsum += info->tzi_task_alloc - info->tzi_task_free;
+               printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n",
+                      (int)((info->tzi_task_alloc - info->tzi_task_free)/1024),
+                      (info->tzi_elem_size == 0) ? 0 :
+                      (info->tzi_task_alloc - info->tzi_task_free)/info->tzi_elem_size);
+       }
        if (ShowWasted) {
-               totalused += used = info->zi_elem_size * info->zi_count;
-               totalsize += size = info->zi_cur_size;
-               printf("\t\t\t\t\tWASTED: %d\n", size - used);
+               totalused += used = info->tzi_elem_size * info->tzi_count;
+               totalsize += size = info->tzi_cur_size;
+               printf("\t\t\t\t\tWASTED: %llu\n", size - used);
+       }
+       if (ShowTotal) {
+               totalsum += info->tzi_sum_size;
+               printf("\t\t\t\t\tTOTAL: %llu\n", totalsum);
+               if (ShowPid)
+                       printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum);
        }
 }
 
 static void
-printk(fmt, i)
-       char *fmt;
-       int i;
-{
-       printf(fmt, i / 1024);
-       putchar('K');
-}
-
-static void
-colprintzone(zone_name, info)
-       zone_name_t *zone_name;
-       zone_info_t *info;
+colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info)
 {
-       char *name = zone_name->zn_name;
-       int j, namewidth, retval;
-       unsigned int used, size;
+       char *name = zone_name->mzn_name;
+       int j, namewidth;
+       unsigned long long used, size;
 
        namewidth = 25;
-       if (ShowWasted) {
+       if (ShowWasted || ShowTotal) {
                namewidth -= 7;
        }
        for (j = 0; j < namewidth - 1 && name[j]; j++) {
@@ -315,51 +477,402 @@ colprintzone(zone_name, info)
                        putchar(' ');
                }
        }
-       printf("%5d", info->zi_elem_size);
-       printk("%6d", info->zi_cur_size);
-       if (info->zi_max_size >= 99999 * 1024) {
-               printf("   ----");
+       printf(" %6llu", info->tzi_elem_size);
+       PRINTK(" %10llu", info->tzi_cur_size);
+       if (info->tzi_max_size / 1024 > 9999999) {
+               printf("    --------");
        } else {
-               printk("%6d", info->zi_max_size);
+               PRINTK(" %10llu", info->tzi_max_size);
        }
-       printf("%7d", info->zi_cur_size / info->zi_elem_size);
-       if (info->zi_max_size >= 99999 * 1024) {
-               printf("   ----");
+       printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size);
+       if (info->tzi_max_size / 1024 >= 999999999) {
+               printf("  ----------");
        } else {
-               printf("%7d", info->zi_max_size / info->zi_elem_size);
+               printf(" %11llu", info->tzi_max_size / info->tzi_elem_size);
        }
-       printf("%6d", info->zi_count);
-       printk("%5d", info->zi_alloc_size);
-       printf("%6d", info->zi_alloc_size / info->zi_elem_size);
-
-       totalused += used = info->zi_elem_size * info->zi_count;
-       totalsize += size = info->zi_cur_size;
+       printf(" %11llu", info->tzi_count);
+       PRINTK(" %5llu", info->tzi_alloc_size);
+       printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size);
+
+       totalused += used = info->tzi_elem_size * info->tzi_count;
+       totalsize += size = info->tzi_cur_size;
+       totalsum += info->tzi_sum_size;
+
+       printf(" %c%c%c",
+              (info->tzi_exhaustible ? 'X' : ' '),
+              (info->tzi_caller_acct ? 'A' : ' '),
+              (info->tzi_collectable ? 'C' : ' '));
        if (ShowWasted) {
-               printf("%7d", size - used);
+               PRINTK(" %8llu", size - used);
        }
-
-       printf("%c%c\n",
-              (info->zi_pageable ? 'P' : ' '),
-              (info->zi_collectable ? 'C' : ' '));
+       if (ShowPid) {
+               printf("%8dK", (int)((info->tzi_task_alloc - info->tzi_task_free)/1024));
+       }
+       if (ShowTotal) {
+               if (info->tzi_sum_size < 1024)
+                       printf(" %16lluB", info->tzi_sum_size);
+               else
+                       PRINTK(" %16llu", info->tzi_sum_size);
+       }
+       printf("\n");
 }
 
 static void
-colprintzoneheader()
+colprintzoneheader(void)
 {
        if (! PrintHeader) {
                return;
        }
-       if (ShowWasted) {
-               printf("                   elem    cur    max    cur    max%s",
-                      "   cur alloc alloc\n");
-               printf("zone name          size   size   size  #elts  #elts%s",
-                      " inuse  size count wasted\n");
-       } else {
-               printf("                          elem    cur    max    cur%s",
-                      "    max   cur alloc alloc\n");
-               printf("zone name                 size   size   size  #elts%s",
-                      "  #elts inuse  size count\n");
-       }
-       printf("-----------------------------------------------%s",
-              "--------------------------------\n");
+       printf("%s                     elem         cur         max        cur         max"
+              "         cur  alloc  alloc    %s%s\n", 
+              (ShowWasted||ShowTotal)? "" : "       ",
+              (ShowWasted)? "          ":"",
+              (ShowPid) ? "      PID" : "" );
+       printf("zone name%s           size        size        size      #elts       #elts"
+              "       inuse   size  count    ", (ShowWasted||ShowTotal)? " " : "        " );
+       if (ShowWasted)
+               printf("    wasted");
+       if (ShowPid)
+               printf("   Allocs");
+       if (ShowTotal)
+               printf("      Total Allocs");
+       printf("\n%s-------------------------------------------------------"
+              "-----------------------------------------------",
+              (ShowWasted||ShowTotal)? "" : "-------");
+       if (ShowWasted)
+               printf("----------");
+       if (ShowPid)
+               printf("---------");
+       if (ShowTotal)
+               printf("------------------");
+       printf("\n");
+}
+
+int
+find_deltas(mach_zone_name_t *name, task_zone_info_t *info, task_zone_info_t *max_info,
+           char *deltas, int cnt, int first_time)
+{
+       int i;
+       int  found_one = 0;
+
+       for (i = 0; i < cnt; i++) {
+              deltas[i] = 0;
+              if (substr(zname, znamelen, name[i].mzn_name,
+                         strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) {
+                      if (first_time || info->tzi_cur_size > max_info->tzi_cur_size ||
+                          (ShowTotal && ((info->tzi_sum_size >> 1) > max_info->tzi_sum_size))) {
+                              max_info->tzi_cur_size = info->tzi_cur_size;
+                              max_info->tzi_sum_size = info->tzi_sum_size;
+                              deltas[i] = 1;
+                              found_one = 1;
+                      }
+              }
+              info++;
+              max_info++;
+       }
+       return(found_one);
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static char *
+kern_vm_tag_name(uint64_t tag)
+{
+    char * result;
+    const char * name;
+    switch (tag)
+    {
+       case (VM_KERN_MEMORY_NONE):             name = "VM_KERN_MEMORY_NONE"; break;
+       case (VM_KERN_MEMORY_OSFMK):            name = "VM_KERN_MEMORY_OSFMK"; break;
+       case (VM_KERN_MEMORY_BSD):              name = "VM_KERN_MEMORY_BSD"; break;
+       case (VM_KERN_MEMORY_IOKIT):            name = "VM_KERN_MEMORY_IOKIT"; break;
+       case (VM_KERN_MEMORY_LIBKERN):          name = "VM_KERN_MEMORY_LIBKERN"; break;
+       case (VM_KERN_MEMORY_OSKEXT):           name = "VM_KERN_MEMORY_OSKEXT"; break;
+       case (VM_KERN_MEMORY_KEXT):             name = "VM_KERN_MEMORY_KEXT"; break;
+       case (VM_KERN_MEMORY_IPC):              name = "VM_KERN_MEMORY_IPC"; break;
+       case (VM_KERN_MEMORY_STACK):            name = "VM_KERN_MEMORY_STACK"; break;
+       case (VM_KERN_MEMORY_CPU):              name = "VM_KERN_MEMORY_CPU"; break;
+       case (VM_KERN_MEMORY_PMAP):             name = "VM_KERN_MEMORY_PMAP"; break;
+       case (VM_KERN_MEMORY_PTE):              name = "VM_KERN_MEMORY_PTE"; break;
+       case (VM_KERN_MEMORY_ZONE):             name = "VM_KERN_MEMORY_ZONE"; break;
+       case (VM_KERN_MEMORY_KALLOC):           name = "VM_KERN_MEMORY_KALLOC"; break;
+       case (VM_KERN_MEMORY_COMPRESSOR):       name = "VM_KERN_MEMORY_COMPRESSOR";      break;
+       case (VM_KERN_MEMORY_COMPRESSED_DATA):  name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break;
+       case (VM_KERN_MEMORY_PHANTOM_CACHE):    name = "VM_KERN_MEMORY_PHANTOM_CACHE";   break;
+       case (VM_KERN_MEMORY_WAITQ):            name = "VM_KERN_MEMORY_WAITQ"; break;
+       case (VM_KERN_MEMORY_DIAG):             name = "VM_KERN_MEMORY_DIAG"; break;
+       case (VM_KERN_MEMORY_LOG):              name = "VM_KERN_MEMORY_LOG"; break;
+       case (VM_KERN_MEMORY_FILE):             name = "VM_KERN_MEMORY_FILE"; break;
+       case (VM_KERN_MEMORY_MBUF):             name = "VM_KERN_MEMORY_MBUF"; break;
+       case (VM_KERN_MEMORY_UBC):              name = "VM_KERN_MEMORY_UBC"; break;
+       case (VM_KERN_MEMORY_SECURITY):         name = "VM_KERN_MEMORY_SECURITY"; break;
+       case (VM_KERN_MEMORY_MLOCK):            name = "VM_KERN_MEMORY_MLOCK"; break;
+       case (VM_KERN_MEMORY_REASON):           name = "VM_KERN_MEMORY_REASON"; break;
+       case (VM_KERN_MEMORY_SKYWALK):          name = "VM_KERN_MEMORY_SKYWALK"; break;
+       case (VM_KERN_MEMORY_LTABLE):           name = "VM_KERN_MEMORY_LTABLE"; break;
+       case (VM_KERN_MEMORY_ANY):              name = "VM_KERN_MEMORY_ANY"; break;
+       default:                                name = NULL; break;
+    }
+    if (name) asprintf(&result, "%s", name);
+    else      asprintf(&result, "VM_KERN_MEMORY_%lld", tag);
+    return (result);
+ }
+
+static char *
+kern_vm_counter_name(uint64_t tag)
+{
+    char * result;
+    const char * name;
+    switch (tag)
+    {
+       case (VM_KERN_COUNT_MANAGED):           name = "VM_KERN_COUNT_MANAGED"; break;
+       case (VM_KERN_COUNT_RESERVED):          name = "VM_KERN_COUNT_RESERVED"; break;
+       case (VM_KERN_COUNT_WIRED):             name = "VM_KERN_COUNT_WIRED"; break;
+       case (VM_KERN_COUNT_WIRED_MANAGED):     name = "VM_KERN_COUNT_WIRED_MANAGED"; break;
+       case (VM_KERN_COUNT_STOLEN):            name = "VM_KERN_COUNT_STOLEN"; break;
+       case (VM_KERN_COUNT_LOPAGE):            name = "VM_KERN_COUNT_LOPAGE"; break;
+       case (VM_KERN_COUNT_MAP_KERNEL):        name = "VM_KERN_COUNT_MAP_KERNEL"; break;
+       case (VM_KERN_COUNT_MAP_ZONE):          name = "VM_KERN_COUNT_MAP_ZONE"; break;
+       case (VM_KERN_COUNT_MAP_KALLOC):        name = "VM_KERN_COUNT_MAP_KALLOC"; break;
+       default:                                name = NULL; break;
+    }
+    if (name) asprintf(&result, "%s", name);
+    else      asprintf(&result, "VM_KERN_COUNT_%lld", tag);
+    return (result);
+}
+
+static void
+MakeLoadTagKeys(const void * key, const void * value, void * context)
+{
+    CFMutableDictionaryRef newDict  = context;
+    CFDictionaryRef        kextInfo = value;
+    CFNumberRef            loadTag;
+    uint32_t               loadTagValue;
+
+    loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey));
+    CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue);
+    key = (const void *)(uintptr_t) loadTagValue;
+    CFDictionarySetValue(newDict, key, value);
+}
+
+static CSSymbolicatorRef        gSym;
+static CFMutableDictionaryRef    gTagDict;
+static mach_memory_info_t *  gSites;
+
+static char *
+GetSiteName(int siteIdx)
+{
+    const char      * name;
+    char            * result;
+    mach_vm_address_t addr;
+    CFDictionaryRef   kextInfo;
+    CFStringRef       bundleID;
+    uint32_t          type;
+
+    const mach_memory_info_t * site;
+    const char                   * fileName;
+    CSSymbolRef                    symbol;
+    const char                   * symbolName;
+    CSSourceInfoRef                sourceInfo;
+
+    name = NULL;
+    result = NULL;
+    site = &gSites[siteIdx];
+    addr = site->site;
+    type = (VM_KERN_SITE_TYPE & site->flags);
+    switch (type)
+    {
+       case VM_KERN_SITE_TAG:
+           result = kern_vm_tag_name(addr);
+           break;
+
+       case VM_KERN_SITE_COUNTER:
+           result = kern_vm_counter_name(addr);
+           break;
+
+       case VM_KERN_SITE_KMOD:
+           kextInfo = CFDictionaryGetValue(gTagDict, (const void *)(uintptr_t) addr);
+           if (kextInfo)
+           {
+               bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo,  kCFBundleIdentifierKey);
+               name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8);
+           //    wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
+           }
+           asprintf(&result,  "%-64s%3lld", name ?  name : "(unknown kmod)", addr);
+           break;
+
+       case VM_KERN_SITE_KERNEL:
+           symbolName = NULL;
+           if (addr)
+           {
+               symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow);
+               symbolName = CSSymbolGetName(symbol);
+           }
+           if (symbolName)
+           {
+               asprintf(&result, "%s", symbolName);
+               sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow);
+               fileName = CSSourceInfoGetPath(sourceInfo);
+               if (fileName) printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo));
+           }
+           else
+           {
+               asprintf(&result, "site 0x%qx", addr);
+           }
+           break;
+       default:
+           asprintf(&result, "");
+           break;
+    }
+
+     return (result);
+}
+
+static int
+SortName(const void * left, const void * right)
+{
+    const int * idxL;
+    const int * idxR;
+    char * l;
+    char * r;
+    int result;
+
+    idxL = (typeof(idxL)) left;
+    idxR = (typeof(idxR)) right;
+    l = GetSiteName(*idxL);
+    r = GetSiteName(*idxR);
+
+    result = strcmp(l, r);
+    free(l);
+    free(r);
+
+    return (result);
+}
+
+static int
+SortSize(const void * left, const void * right)
+{
+    const mach_memory_info_t * siteL;
+    const mach_memory_info_t * siteR;
+    const int * idxL;
+    const int * idxR;
+
+    idxL = (typeof(idxL)) left;
+    idxR = (typeof(idxR)) right;
+    siteL = &gSites[*idxL];
+    siteR = &gSites[*idxR];
+
+    if (siteL->size > siteR->size) return (-1);
+    else if (siteL->size < siteR->size) return (1);
+    return (0);
+}
+
+
+static void
+PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
+               int (*func)(const void *, const void *), boolean_t column)
+{
+    uint64_t zonetotal;
+    uint64_t top_wired;
+
+    CFDictionaryRef allKexts;
+    unsigned int idx, site, first;
+    int sorted[wiredInfoCnt];
+    char totalstr[40];
+    char * name;
+    bool   headerPrinted;
+
+    zonetotal = totalsize;
+
+    gSites = wiredInfo;
+
+    gSym = CSSymbolicatorCreateWithMachKernel();
+
+    allKexts = OSKextCopyLoadedKextInfo(NULL, NULL);
+    gTagDict = CFDictionaryCreateMutable(
+                           kCFAllocatorDefault, (CFIndex) 0,
+                           (CFDictionaryKeyCallBacks *) 0,
+                           &kCFTypeDictionaryValueCallBacks);
+
+    CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict);
+    CFRelease(allKexts);
+
+    top_wired = 0;
+
+    for (idx = 0; idx < wiredInfoCnt; idx++) sorted[idx] = idx;
+    first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
+    qsort(&sorted[first],
+           wiredInfoCnt - first,
+           sizeof(sorted[0]),
+           func);
+
+    for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
+    {
+        site = sorted[idx];
+       if (!gSites[site].size) continue;
+       if (VM_KERN_COUNT_WIRED == gSites[site].site) top_wired = gSites[site].size;
+       if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
+       if (!(VM_KERN_SITE_WIRED & gSites[site].flags)) continue;
+
+       name = GetSiteName(site);
+        if (!substr(zname, znamelen, name, strlen(name))) continue;
+        if (!headerPrinted)
+        {
+            printf("-------------------------------------------------------------------------------------------------------------\n");
+            printf("                                                               kmod          vm                       cur\n");
+            printf("wired memory                                                     id         tag                      size\n");
+            printf("-------------------------------------------------------------------------------------------------------------\n");
+            headerPrinted = true;
+        }
+       printf("%-67s", name);
+       free(name);
+       printf("%12d", site);
+
+       printf(" %11s", "");
+       PRINTK(" %12llu", gSites[site].size);
+       totalsize += gSites[site].size;
+
+       printf("\n");
+    }
+
+    if (!znamelen)
+    {
+        printf("%-67s", "zones");
+        printf("%12s", "");
+        printf(" %11s", "");
+        PRINTK(" %12llu", zonetotal);
+        printf("\n");
+    }
+    if (headerPrinted)
+    {
+        snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0);
+        printf("total%100s\n", totalstr);
+    }
+    for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
+    {
+        site = sorted[idx];
+       if (!gSites[site].size) continue;
+       if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
+       if (VM_KERN_SITE_WIRED & gSites[site].flags) continue;
+
+       name = GetSiteName(site);
+        if (!substr(zname, znamelen, name, strlen(name))) continue;
+        if (!headerPrinted)
+        {
+            printf("-------------------------------------------------------------------------------------------------------------\n");
+            printf("                                                                                    largest\n");
+            printf("maps                                                                       free        free          size\n");
+            printf("-------------------------------------------------------------------------------------------------------------\n");
+            headerPrinted = true;
+        }
+       printf("%-67s", name);
+       free(name);
+
+       PRINTK(" %10llu", gSites[site].free);
+       PRINTK(" %10llu", gSites[site].largest);
+       PRINTK(" %12llu", gSites[site].size);
+
+       printf("\n");
+    }
 }