]> git.saurik.com Git - apple/system_cmds.git/blame - zprint.tproj/zprint.c
system_cmds-735.50.6.tar.gz
[apple/system_cmds.git] / zprint.tproj / zprint.c
CommitLineData
8459d725 1/*
cf37c299 2 * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
8459d725
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
cf37c299 5 *
8459d725
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
cf37c299 14 *
8459d725
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
cf37c299 17 *
8459d725
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
cf37c299 25 *
8459d725
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
1815bff5
A
28/*
29 * @OSF_COPYRIGHT@
30 */
cf37c299 31/*
1815bff5
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
cf37c299 35 *
1815bff5
A
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
cf37c299
A
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
1815bff5
A
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
cf37c299 45 *
1815bff5 46 * Carnegie Mellon requests users of this software to return to
cf37c299 47 *
1815bff5
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
cf37c299 52 *
1815bff5
A
53 * any improvements or extensions that they make and grant Carnegie the
54 * rights to redistribute these changes.
55 */
56/*
57 * zprint.c
58 *
59 * utility for printing out zone structures
60 *
61 * With no arguments, prints information on all zone structures.
62 * With an argument, prints information only on those zones for
63 * which the given name is a substring of the zone's name.
64 * With a "-w" flag, calculates how much much space is allocated
65 * to zones but not currently in use.
66 */
67
9726c137 68#include <vm_statistics.h>
1815bff5 69#include <stdio.h>
34d340d7 70#include <stdlib.h>
1815bff5
A
71#include <string.h>
72#include <mach/mach.h>
73#include <mach_debug/mach_debug.h>
74#include <mach/mach_error.h>
ef8ad44b
A
75#include <libutil.h>
76#include <errno.h>
9726c137
A
77#include <sysexits.h>
78#include <getopt.h>
79#include <malloc/malloc.h>
80#include <Kernel/IOKit/IOKitDebug.h>
81#include <Kernel/libkern/OSKextLibPrivate.h>
82#include <IOKit/IOKitLib.h>
83#include <IOKit/IOKitKeys.h>
84#include <IOKit/kext/OSKext.h>
85#include <CoreFoundation/CoreFoundation.h>
86#include <CoreSymbolication/CoreSymbolication.h>
87
1815bff5
A
88#define streql(a, b) (strcmp((a), (b)) == 0)
89#define strneql(a, b, n) (strncmp((a), (b), (n)) == 0)
9726c137
A
90#define PRINTK(fmt, value) \
91 printf(fmt "K", (value) / 1024 ) /* ick */
1815bff5 92
8459d725
A
93static void usage(void);
94static void printzone(mach_zone_name_t *, task_zone_info_t *);
95static void colprintzone(mach_zone_name_t *, task_zone_info_t *);
96static int find_deltas(mach_zone_name_t *, task_zone_info_t *, task_zone_info_t *, char *, int, int);
97static void colprintzoneheader(void);
9726c137
A
98static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen);
99
100static int SortName(const void * left, const void * right);
101static int SortSize(const void * left, const void * right);
102static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, int (*func)(const void *, const void *), boolean_t column);
1815bff5
A
103
104static char *program;
105
8459d725
A
106static pid_t pid = 0;
107static task_t task = TASK_NULL;
108static boolean_t ShowPid = FALSE;
109
110static boolean_t ShowDeltas = FALSE;
1815bff5 111static boolean_t ShowWasted = FALSE;
8459d725 112static boolean_t ShowTotal = FALSE;
9726c137 113static boolean_t ShowLarge = TRUE;
1815bff5
A
114static boolean_t SortZones = FALSE;
115static boolean_t ColFormat = TRUE;
116static boolean_t PrintHeader = TRUE;
117
8459d725
A
118static unsigned long long totalsize = 0;
119static unsigned long long totalused = 0;
120static unsigned long long totalsum = 0;
121static unsigned long long pidsum = 0;
122
123static int last_time = 0;
124
125static char *zname = NULL;
9726c137 126static size_t znamelen = 0;
8459d725
A
127
128static void
129sigintr(__unused int signum)
130{
131 last_time = 1;
132}
1815bff5
A
133
134static void
8459d725 135usage(void)
1815bff5 136{
cf37c299 137 fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p <pid>] [name]\n", program);
1815bff5
A
138 exit(1);
139}
140
34d340d7 141int
8459d725 142main(int argc, char **argv)
1815bff5 143{
8459d725
A
144 mach_zone_name_t *name = NULL;
145 unsigned int nameCnt = 0;
146 task_zone_info_t *info = NULL;
147 unsigned int infoCnt = 0;
9726c137
A
148 mach_memory_info_t *wiredInfo = NULL;
149 unsigned int wiredInfoCnt = 0;
8459d725
A
150 task_zone_info_t *max_info = NULL;
151 char *deltas = NULL;
1815bff5
A
152
153 kern_return_t kr;
154 int i, j;
8459d725
A
155 int first_time = 1;
156 int must_print = 1;
157 int interval = 1;
1815bff5 158
8459d725 159 signal(SIGINT, sigintr);
ef8ad44b 160
1815bff5
A
161 program = strrchr(argv[0], '/');
162 if (program == NULL)
163 program = argv[0];
164 else
165 program++;
166
167 for (i = 1; i < argc; i++) {
8459d725
A
168 if (streql(argv[i], "-d"))
169 ShowDeltas = TRUE;
170 else if (streql(argv[i], "-t"))
171 ShowTotal = TRUE;
172 else if (streql(argv[i], "-T"))
173 ShowTotal = FALSE;
174 else if (streql(argv[i], "-w"))
1815bff5
A
175 ShowWasted = TRUE;
176 else if (streql(argv[i], "-W"))
177 ShowWasted = FALSE;
9726c137
A
178 else if (streql(argv[i], "-l"))
179 ShowLarge = TRUE;
180 else if (streql(argv[i], "-L"))
181 ShowLarge = FALSE;
1815bff5
A
182 else if (streql(argv[i], "-s"))
183 SortZones = TRUE;
184 else if (streql(argv[i], "-S"))
185 SortZones = FALSE;
186 else if (streql(argv[i], "-c"))
187 ColFormat = TRUE;
188 else if (streql(argv[i], "-C"))
189 ColFormat = FALSE;
190 else if (streql(argv[i], "-H"))
191 PrintHeader = FALSE;
8459d725
A
192 else if (streql(argv[i], "-p")) {
193 ShowPid = TRUE;
194 if (i < argc - 1) {
195 pid = atoi(argv[i+1]);
196 i++;
197 } else
198 usage();
199 } else if (streql(argv[i], "--")) {
1815bff5
A
200 i++;
201 break;
202 } else if (argv[i][0] == '-')
203 usage();
204 else
205 break;
206 }
207
208 switch (argc - i) {
209 case 0:
210 zname = "";
211 znamelen = 0;
212 break;
213
214 case 1:
215 zname = argv[i];
216 znamelen = strlen(zname);
217 break;
218
219 default:
220 usage();
221 }
222
8459d725
A
223 if (ShowDeltas) {
224 SortZones = FALSE;
225 ColFormat = TRUE;
226 PrintHeader = TRUE;
227 }
228
229 if (ShowPid) {
230 kr = task_for_pid(mach_task_self(), pid, &task);
231 if (kr != KERN_SUCCESS) {
cf37c299 232 fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n",
8459d725
A
233 program, pid, mach_error_string(kr));
234 exit(1);
235 }
236 }
237
238 for (;;) {
239 if (ShowPid) {
240 kr = task_zone_info(task, &name, &nameCnt, &info, &infoCnt);
241 if (kr != KERN_SUCCESS) {
242 fprintf(stderr, "%s: task_zone_info: %s\n",
243 program, mach_error_string(kr));
1815bff5 244 exit(1);
8459d725
A
245 }
246 } else {
247 mach_zone_info_t *zinfo = NULL;
248
9726c137
A
249 kr = mach_memory_info(mach_host_self(),
250 &name, &nameCnt, &zinfo, &infoCnt,
251 &wiredInfo, &wiredInfoCnt);
8459d725
A
252 if (kr != KERN_SUCCESS) {
253 fprintf(stderr, "%s: mach_zone_info: %s\n",
254 program, mach_error_string(kr));
255 exit(1);
256 }
9726c137 257
8459d725
A
258 kr = vm_allocate(mach_task_self(), (vm_address_t *)&info,
259 infoCnt * sizeof *info, VM_FLAGS_ANYWHERE);
260 if (kr != KERN_SUCCESS) {
261 fprintf(stderr, "%s vm_allocate: %s\n",
262 program, mach_error_string(kr));
263 exit(1);
264 }
265 for (i = 0; i < infoCnt; i++) {
266 *(mach_zone_info_t *)(info + i) = zinfo[i];
267 info[i].tzi_caller_acct = 0;
268 info[i].tzi_task_alloc = 0;
269 info[i].tzi_task_free = 0;
270 }
271 kr = vm_deallocate(mach_task_self(), (vm_address_t) zinfo,
272 (vm_size_t) (infoCnt * sizeof *zinfo));
273 if (kr != KERN_SUCCESS) {
274 fprintf(stderr, "%s: vm_deallocate: %s\n",
275 program, mach_error_string(kr));
276 exit(1);
277 }
1815bff5 278 }
8459d725
A
279
280 if (nameCnt != infoCnt) {
281 fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n",
1815bff5
A
282 program);
283 exit(1);
284 }
285
8459d725
A
286 if (first_time) {
287 deltas = (char *)malloc(infoCnt);
288 max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info));
289 }
290
1815bff5
A
291 if (SortZones) {
292 for (i = 0; i < nameCnt-1; i++)
293 for (j = i+1; j < nameCnt; j++) {
9726c137 294 unsigned long long wastei, wastej;
1815bff5 295
8459d725
A
296 wastei = (info[i].tzi_cur_size -
297 (info[i].tzi_elem_size *
298 info[i].tzi_count));
299 wastej = (info[j].tzi_cur_size -
300 (info[j].tzi_elem_size *
301 info[j].tzi_count));
1815bff5
A
302
303 if (wastej > wastei) {
8459d725
A
304 task_zone_info_t tinfo;
305 mach_zone_name_t tname;
1815bff5
A
306
307 tinfo = info[i];
308 info[i] = info[j];
309 info[j] = tinfo;
310
311 tname = name[i];
312 name[i] = name[j];
313 name[j] = tname;
314 }
315 }
316 }
317
8459d725
A
318 must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
319 if (must_print) {
320 if (ColFormat) {
321 if (!first_time)
322 printf("\n");
323 colprintzoneheader();
324 }
325 for (i = 0; i < nameCnt; i++) {
326 if (deltas[i]) {
327 if (ColFormat)
328 colprintzone(&name[i], &info[i]);
329 else
330 printzone(&name[i], &info[i]);
331 }
332 }
cf37c299 333 }
9726c137 334
cf37c299
A
335 if (ShowLarge && first_time) {
336 PrintLarge(wiredInfo, wiredInfoCnt,
337 SortZones ? &SortSize : &SortName, ColFormat);
1815bff5 338 }
8459d725
A
339
340 first_time = 0;
341
342 if ((name != NULL) && (nameCnt != 0)) {
1815bff5
A
343 kr = vm_deallocate(mach_task_self(), (vm_address_t) name,
344 (vm_size_t) (nameCnt * sizeof *name));
345 if (kr != KERN_SUCCESS) {
346 fprintf(stderr, "%s: vm_deallocate: %s\n",
347 program, mach_error_string(kr));
348 exit(1);
349 }
350 }
351
8459d725 352 if ((info != NULL) && (infoCnt != 0)) {
1815bff5
A
353 kr = vm_deallocate(mach_task_self(), (vm_address_t) info,
354 (vm_size_t) (infoCnt * sizeof *info));
355 if (kr != KERN_SUCCESS) {
356 fprintf(stderr, "%s: vm_deallocate: %s\n",
357 program, mach_error_string(kr));
358 exit(1);
359 }
360 }
361
9726c137
A
362 if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) {
363 kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo,
364 (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo));
365 if (kr != KERN_SUCCESS) {
366 fprintf(stderr, "%s: vm_deallocate: %s\n",
367 program, mach_error_string(kr));
368 exit(1);
369 }
370 }
371
8459d725
A
372 if ((ShowWasted||ShowTotal) && PrintHeader && !ShowDeltas) {
373 printf("TOTAL SIZE = %llu\n", totalsize);
374 printf("TOTAL USED = %llu\n", totalused);
375 if (ShowWasted)
376 printf("TOTAL WASTED = %llu\n", totalsize - totalused);
377 if (ShowTotal)
378 printf("TOTAL ALLOCS = %llu\n", totalsum);
1815bff5
A
379 }
380
8459d725
A
381 if (ShowDeltas == FALSE || last_time)
382 break;
1815bff5 383
8459d725
A
384 sleep(interval);
385 }
386 exit(0);
1815bff5
A
387}
388
389static boolean_t
9726c137 390substr(const char *a, size_t alen, const char *b, size_t blen)
1815bff5
A
391{
392 int i;
393
cf37c299
A
394 if (alen > blen) return FALSE;
395
1815bff5
A
396 for (i = 0; i <= blen - alen; i++)
397 if (strneql(a, b+i, alen))
398 return TRUE;
399
400 return FALSE;
401}
402
403static void
8459d725 404printzone(mach_zone_name_t *name, task_zone_info_t *info)
1815bff5 405{
8459d725
A
406 unsigned long long used, size;
407
408 printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name);
409 printf("\tcur_size: %lluK bytes (%llu elements)\n",
410 info->tzi_cur_size/1024,
411 (info->tzi_elem_size == 0) ? 0 :
412 info->tzi_cur_size/info->tzi_elem_size);
413 printf("\tmax_size: %lluK bytes (%llu elements)\n",
414 info->tzi_max_size/1024,
415 (info->tzi_elem_size == 0) ? 0 :
416 info->tzi_max_size/info->tzi_elem_size);
417 printf("\telem_size: %llu bytes\n",
418 info->tzi_elem_size);
419 printf("\t# of elems: %llu\n",
420 info->tzi_count);
421 printf("\talloc_size: %lluK bytes (%llu elements)\n",
422 info->tzi_alloc_size/1024,
423 (info->tzi_elem_size == 0) ? 0 :
424 info->tzi_alloc_size/info->tzi_elem_size);
425 if (info->tzi_exhaustible)
426 printf("\tEXHAUSTIBLE\n");
427 if (info->tzi_collectable)
1815bff5 428 printf("\tCOLLECTABLE\n");
8459d725
A
429 if (ShowPid && info->tzi_caller_acct)
430 printf("\tCALLER ACCOUNTED\n");
431 if (ShowPid) {
432 pidsum += info->tzi_task_alloc - info->tzi_task_free;
433 printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n",
434 (int)((info->tzi_task_alloc - info->tzi_task_free)/1024),
435 (info->tzi_elem_size == 0) ? 0 :
436 (info->tzi_task_alloc - info->tzi_task_free)/info->tzi_elem_size);
437 }
1815bff5 438 if (ShowWasted) {
8459d725
A
439 totalused += used = info->tzi_elem_size * info->tzi_count;
440 totalsize += size = info->tzi_cur_size;
441 printf("\t\t\t\t\tWASTED: %llu\n", size - used);
442 }
443 if (ShowTotal) {
444 totalsum += info->tzi_sum_size;
445 printf("\t\t\t\t\tTOTAL: %llu\n", totalsum);
446 if (ShowPid)
447 printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum);
1815bff5
A
448 }
449}
450
1815bff5 451static void
8459d725 452colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info)
1815bff5 453{
8459d725 454 char *name = zone_name->mzn_name;
34d340d7 455 int j, namewidth;
8459d725 456 unsigned long long used, size;
1815bff5
A
457
458 namewidth = 25;
8459d725 459 if (ShowWasted || ShowTotal) {
1815bff5
A
460 namewidth -= 7;
461 }
462 for (j = 0; j < namewidth - 1 && name[j]; j++) {
463 if (name[j] == ' ') {
464 putchar('.');
465 } else {
466 putchar(name[j]);
467 }
468 }
469 if (j == namewidth - 1) {
470 if (name[j]) {
471 putchar('$');
472 } else {
473 putchar(' ');
474 }
475 } else {
476 for (; j < namewidth; j++) {
477 putchar(' ');
478 }
479 }
aaff5f01
A
480 printf(" %6llu", info->tzi_elem_size);
481 PRINTK(" %10llu", info->tzi_cur_size);
8459d725 482 if (info->tzi_max_size / 1024 > 9999999) {
aaff5f01 483 printf(" --------");
1815bff5 484 } else {
aaff5f01 485 PRINTK(" %10llu", info->tzi_max_size);
1815bff5 486 }
aaff5f01 487 printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size);
8459d725 488 if (info->tzi_max_size / 1024 >= 999999999) {
aaff5f01 489 printf(" ----------");
1815bff5 490 } else {
aaff5f01 491 printf(" %11llu", info->tzi_max_size / info->tzi_elem_size);
1815bff5 492 }
aaff5f01
A
493 printf(" %11llu", info->tzi_count);
494 PRINTK(" %5llu", info->tzi_alloc_size);
495 printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size);
8459d725
A
496
497 totalused += used = info->tzi_elem_size * info->tzi_count;
498 totalsize += size = info->tzi_cur_size;
499 totalsum += info->tzi_sum_size;
500
501 printf(" %c%c%c",
502 (info->tzi_exhaustible ? 'X' : ' '),
503 (info->tzi_caller_acct ? 'A' : ' '),
504 (info->tzi_collectable ? 'C' : ' '));
1815bff5 505 if (ShowWasted) {
aaff5f01 506 PRINTK(" %8llu", size - used);
1815bff5 507 }
8459d725
A
508 if (ShowPid) {
509 printf("%8dK", (int)((info->tzi_task_alloc - info->tzi_task_free)/1024));
510 }
511 if (ShowTotal) {
512 if (info->tzi_sum_size < 1024)
aaff5f01 513 printf(" %16lluB", info->tzi_sum_size);
8459d725 514 else
aaff5f01 515 PRINTK(" %16llu", info->tzi_sum_size);
8459d725
A
516 }
517 printf("\n");
1815bff5
A
518}
519
520static void
8459d725 521colprintzoneheader(void)
1815bff5
A
522{
523 if (! PrintHeader) {
524 return;
525 }
aaff5f01
A
526 printf("%s elem cur max cur max"
527 " cur alloc alloc %s%s\n",
528 (ShowWasted||ShowTotal)? "" : " ",
529 (ShowWasted)? " ":"",
530 (ShowPid) ? " PID" : "" );
531 printf("zone name%s size size size #elts #elts"
532 " inuse size count ", (ShowWasted||ShowTotal)? " " : " " );
8459d725 533 if (ShowWasted)
aaff5f01 534 printf(" wasted");
8459d725 535 if (ShowPid)
aaff5f01 536 printf(" Allocs");
8459d725 537 if (ShowTotal)
aaff5f01
A
538 printf(" Total Allocs");
539 printf("\n%s-------------------------------------------------------"
540 "-----------------------------------------------",
8459d725
A
541 (ShowWasted||ShowTotal)? "" : "-------");
542 if (ShowWasted)
8459d725 543 printf("----------");
aaff5f01
A
544 if (ShowPid)
545 printf("---------");
8459d725 546 if (ShowTotal)
aaff5f01 547 printf("------------------");
8459d725
A
548 printf("\n");
549}
550
551int
552find_deltas(mach_zone_name_t *name, task_zone_info_t *info, task_zone_info_t *max_info,
553 char *deltas, int cnt, int first_time)
554{
555 int i;
556 int found_one = 0;
557
558 for (i = 0; i < cnt; i++) {
559 deltas[i] = 0;
560 if (substr(zname, znamelen, name[i].mzn_name,
561 strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) {
562 if (first_time || info->tzi_cur_size > max_info->tzi_cur_size ||
563 (ShowTotal && ((info->tzi_sum_size >> 1) > max_info->tzi_sum_size))) {
564 max_info->tzi_cur_size = info->tzi_cur_size;
565 max_info->tzi_sum_size = info->tzi_sum_size;
566 deltas[i] = 1;
567 found_one = 1;
568 }
569 }
570 info++;
571 max_info++;
572 }
573 return(found_one);
1815bff5 574}
9726c137
A
575
576/*********************************************************************
577*********************************************************************/
578
579static char *
580kern_vm_tag_name(uint64_t tag)
581{
582 char * result;
583 const char * name;
584 switch (tag)
585 {
586 case (VM_KERN_MEMORY_NONE): name = "VM_KERN_MEMORY_NONE"; break;
587 case (VM_KERN_MEMORY_OSFMK): name = "VM_KERN_MEMORY_OSFMK"; break;
588 case (VM_KERN_MEMORY_BSD): name = "VM_KERN_MEMORY_BSD"; break;
589 case (VM_KERN_MEMORY_IOKIT): name = "VM_KERN_MEMORY_IOKIT"; break;
590 case (VM_KERN_MEMORY_LIBKERN): name = "VM_KERN_MEMORY_LIBKERN"; break;
591 case (VM_KERN_MEMORY_OSKEXT): name = "VM_KERN_MEMORY_OSKEXT"; break;
592 case (VM_KERN_MEMORY_KEXT): name = "VM_KERN_MEMORY_KEXT"; break;
593 case (VM_KERN_MEMORY_IPC): name = "VM_KERN_MEMORY_IPC"; break;
594 case (VM_KERN_MEMORY_STACK): name = "VM_KERN_MEMORY_STACK"; break;
595 case (VM_KERN_MEMORY_CPU): name = "VM_KERN_MEMORY_CPU"; break;
596 case (VM_KERN_MEMORY_PMAP): name = "VM_KERN_MEMORY_PMAP"; break;
597 case (VM_KERN_MEMORY_PTE): name = "VM_KERN_MEMORY_PTE"; break;
598 case (VM_KERN_MEMORY_ZONE): name = "VM_KERN_MEMORY_ZONE"; break;
599 case (VM_KERN_MEMORY_KALLOC): name = "VM_KERN_MEMORY_KALLOC"; break;
600 case (VM_KERN_MEMORY_COMPRESSOR): name = "VM_KERN_MEMORY_COMPRESSOR"; break;
601 case (VM_KERN_MEMORY_COMPRESSED_DATA): name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break;
602 case (VM_KERN_MEMORY_PHANTOM_CACHE): name = "VM_KERN_MEMORY_PHANTOM_CACHE"; break;
603 case (VM_KERN_MEMORY_WAITQ): name = "VM_KERN_MEMORY_WAITQ"; break;
604 case (VM_KERN_MEMORY_DIAG): name = "VM_KERN_MEMORY_DIAG"; break;
605 case (VM_KERN_MEMORY_LOG): name = "VM_KERN_MEMORY_LOG"; break;
606 case (VM_KERN_MEMORY_FILE): name = "VM_KERN_MEMORY_FILE"; break;
607 case (VM_KERN_MEMORY_MBUF): name = "VM_KERN_MEMORY_MBUF"; break;
608 case (VM_KERN_MEMORY_UBC): name = "VM_KERN_MEMORY_UBC"; break;
609 case (VM_KERN_MEMORY_SECURITY): name = "VM_KERN_MEMORY_SECURITY"; break;
610 case (VM_KERN_MEMORY_MLOCK): name = "VM_KERN_MEMORY_MLOCK"; break;
cf37c299
A
611 case (VM_KERN_MEMORY_REASON): name = "VM_KERN_MEMORY_REASON"; break;
612 case (VM_KERN_MEMORY_SKYWALK): name = "VM_KERN_MEMORY_SKYWALK"; break;
613 case (VM_KERN_MEMORY_LTABLE): name = "VM_KERN_MEMORY_LTABLE"; break;
9726c137
A
614 case (VM_KERN_MEMORY_ANY): name = "VM_KERN_MEMORY_ANY"; break;
615 default: name = NULL; break;
616 }
617 if (name) asprintf(&result, "%s", name);
618 else asprintf(&result, "VM_KERN_MEMORY_%lld", tag);
619 return (result);
620 }
621
cf37c299 622static char *
9726c137
A
623kern_vm_counter_name(uint64_t tag)
624{
625 char * result;
626 const char * name;
627 switch (tag)
628 {
629 case (VM_KERN_COUNT_MANAGED): name = "VM_KERN_COUNT_MANAGED"; break;
630 case (VM_KERN_COUNT_RESERVED): name = "VM_KERN_COUNT_RESERVED"; break;
631 case (VM_KERN_COUNT_WIRED): name = "VM_KERN_COUNT_WIRED"; break;
632 case (VM_KERN_COUNT_WIRED_MANAGED): name = "VM_KERN_COUNT_WIRED_MANAGED"; break;
633 case (VM_KERN_COUNT_STOLEN): name = "VM_KERN_COUNT_STOLEN"; break;
634 case (VM_KERN_COUNT_LOPAGE): name = "VM_KERN_COUNT_LOPAGE"; break;
635 case (VM_KERN_COUNT_MAP_KERNEL): name = "VM_KERN_COUNT_MAP_KERNEL"; break;
636 case (VM_KERN_COUNT_MAP_ZONE): name = "VM_KERN_COUNT_MAP_ZONE"; break;
637 case (VM_KERN_COUNT_MAP_KALLOC): name = "VM_KERN_COUNT_MAP_KALLOC"; break;
638 default: name = NULL; break;
639 }
640 if (name) asprintf(&result, "%s", name);
641 else asprintf(&result, "VM_KERN_COUNT_%lld", tag);
642 return (result);
643}
644
645static void
646MakeLoadTagKeys(const void * key, const void * value, void * context)
647{
648 CFMutableDictionaryRef newDict = context;
649 CFDictionaryRef kextInfo = value;
650 CFNumberRef loadTag;
651 uint32_t loadTagValue;
652
653 loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey));
654 CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue);
655 key = (const void *)(uintptr_t) loadTagValue;
656 CFDictionarySetValue(newDict, key, value);
657}
658
cf37c299 659static CSSymbolicatorRef gSym;
9726c137
A
660static CFMutableDictionaryRef gTagDict;
661static mach_memory_info_t * gSites;
662
cf37c299 663static char *
9726c137
A
664GetSiteName(int siteIdx)
665{
666 const char * name;
667 char * result;
668 mach_vm_address_t addr;
669 CFDictionaryRef kextInfo;
670 CFStringRef bundleID;
671 uint32_t type;
672
673 const mach_memory_info_t * site;
674 const char * fileName;
675 CSSymbolRef symbol;
676 const char * symbolName;
677 CSSourceInfoRef sourceInfo;
678
679 name = NULL;
680 result = NULL;
681 site = &gSites[siteIdx];
682 addr = site->site;
683 type = (VM_KERN_SITE_TYPE & site->flags);
684 switch (type)
685 {
686 case VM_KERN_SITE_TAG:
687 result = kern_vm_tag_name(addr);
688 break;
689
690 case VM_KERN_SITE_COUNTER:
691 result = kern_vm_counter_name(addr);
692 break;
693
694 case VM_KERN_SITE_KMOD:
695 kextInfo = CFDictionaryGetValue(gTagDict, (const void *)(uintptr_t) addr);
cf37c299 696 if (kextInfo)
9726c137
A
697 {
698 bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey);
699 name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8);
700 // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
701 }
702 asprintf(&result, "%-64s%3lld", name ? name : "(unknown kmod)", addr);
703 break;
704
705 case VM_KERN_SITE_KERNEL:
706 symbolName = NULL;
707 if (addr)
708 {
709 symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow);
710 symbolName = CSSymbolGetName(symbol);
711 }
712 if (symbolName)
713 {
714 asprintf(&result, "%s", symbolName);
715 sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow);
716 fileName = CSSourceInfoGetPath(sourceInfo);
717 if (fileName) printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo));
718 }
719 else
720 {
721 asprintf(&result, "site 0x%qx", addr);
722 }
723 break;
724 default:
725 asprintf(&result, "");
726 break;
727 }
728
729 return (result);
730}
731
cf37c299 732static int
9726c137
A
733SortName(const void * left, const void * right)
734{
735 const int * idxL;
736 const int * idxR;
737 char * l;
738 char * r;
739 int result;
740
741 idxL = (typeof(idxL)) left;
742 idxR = (typeof(idxR)) right;
743 l = GetSiteName(*idxL);
744 r = GetSiteName(*idxR);
745
746 result = strcmp(l, r);
747 free(l);
748 free(r);
749
750 return (result);
751}
752
cf37c299 753static int
9726c137
A
754SortSize(const void * left, const void * right)
755{
756 const mach_memory_info_t * siteL;
757 const mach_memory_info_t * siteR;
758 const int * idxL;
759 const int * idxR;
760
761 idxL = (typeof(idxL)) left;
762 idxR = (typeof(idxR)) right;
763 siteL = &gSites[*idxL];
764 siteR = &gSites[*idxR];
765
766 if (siteL->size > siteR->size) return (-1);
767 else if (siteL->size < siteR->size) return (1);
768 return (0);
769}
770
771
772static void
773PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
774 int (*func)(const void *, const void *), boolean_t column)
775{
776 uint64_t zonetotal;
777 uint64_t top_wired;
778
779 CFDictionaryRef allKexts;
780 unsigned int idx, site, first;
781 int sorted[wiredInfoCnt];
782 char totalstr[40];
783 char * name;
cf37c299 784 bool headerPrinted;
9726c137
A
785
786 zonetotal = totalsize;
787
788 gSites = wiredInfo;
789
790 gSym = CSSymbolicatorCreateWithMachKernel();
cf37c299 791
9726c137 792 allKexts = OSKextCopyLoadedKextInfo(NULL, NULL);
cf37c299 793 gTagDict = CFDictionaryCreateMutable(
9726c137
A
794 kCFAllocatorDefault, (CFIndex) 0,
795 (CFDictionaryKeyCallBacks *) 0,
796 &kCFTypeDictionaryValueCallBacks);
797
798 CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict);
799 CFRelease(allKexts);
800
801 top_wired = 0;
802
803 for (idx = 0; idx < wiredInfoCnt; idx++) sorted[idx] = idx;
804 first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
805 qsort(&sorted[first],
cf37c299
A
806 wiredInfoCnt - first,
807 sizeof(sorted[0]),
9726c137
A
808 func);
809
cf37c299 810 for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
9726c137
A
811 {
812 site = sorted[idx];
813 if (!gSites[site].size) continue;
814 if (VM_KERN_COUNT_WIRED == gSites[site].site) top_wired = gSites[site].size;
815 if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
816 if (!(VM_KERN_SITE_WIRED & gSites[site].flags)) continue;
817
818 name = GetSiteName(site);
cf37c299
A
819 if (!substr(zname, znamelen, name, strlen(name))) continue;
820 if (!headerPrinted)
821 {
822 printf("-------------------------------------------------------------------------------------------------------------\n");
823 printf(" kmod vm cur\n");
824 printf("wired memory id tag size\n");
825 printf("-------------------------------------------------------------------------------------------------------------\n");
826 headerPrinted = true;
827 }
9726c137
A
828 printf("%-67s", name);
829 free(name);
830 printf("%12d", site);
831
832 printf(" %11s", "");
833 PRINTK(" %12llu", gSites[site].size);
834 totalsize += gSites[site].size;
835
836 printf("\n");
837 }
838
cf37c299
A
839 if (!znamelen)
840 {
841 printf("%-67s", "zones");
842 printf("%12s", "");
843 printf(" %11s", "");
844 PRINTK(" %12llu", zonetotal);
845 printf("\n");
846 }
847 if (headerPrinted)
848 {
849 snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0);
850 printf("total%100s\n", totalstr);
851 }
852 for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
9726c137
A
853 {
854 site = sorted[idx];
855 if (!gSites[site].size) continue;
856 if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
857 if (VM_KERN_SITE_WIRED & gSites[site].flags) continue;
858
859 name = GetSiteName(site);
cf37c299
A
860 if (!substr(zname, znamelen, name, strlen(name))) continue;
861 if (!headerPrinted)
862 {
863 printf("-------------------------------------------------------------------------------------------------------------\n");
864 printf(" largest\n");
865 printf("maps free free size\n");
866 printf("-------------------------------------------------------------------------------------------------------------\n");
867 headerPrinted = true;
868 }
9726c137
A
869 printf("%-67s", name);
870 free(name);
871
872 PRINTK(" %10llu", gSites[site].free);
873 PRINTK(" %10llu", gSites[site].largest);
874 PRINTK(" %12llu", gSites[site].size);
875
876 printf("\n");
877 }
878}