]> git.saurik.com Git - apple/system_cmds.git/blame - zprint.tproj/zprint.c
system_cmds-790.30.1.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
887d5eed
A
100static int SortName(void * thunk, const void * left, const void * right);
101static int SortSize(void * thunk, const void * left, const void * right);
102static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
103 task_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames,
104 unsigned int zoneCnt, uint64_t zoneElements,
105 int (*func)(void *, const void *, const void *), boolean_t column);
1815bff5
A
106
107static char *program;
108
8459d725
A
109static pid_t pid = 0;
110static task_t task = TASK_NULL;
111static boolean_t ShowPid = FALSE;
112
113static boolean_t ShowDeltas = FALSE;
1815bff5 114static boolean_t ShowWasted = FALSE;
8459d725 115static boolean_t ShowTotal = FALSE;
9726c137 116static boolean_t ShowLarge = TRUE;
1815bff5
A
117static boolean_t SortZones = FALSE;
118static boolean_t ColFormat = TRUE;
119static boolean_t PrintHeader = TRUE;
120
8459d725
A
121static unsigned long long totalsize = 0;
122static unsigned long long totalused = 0;
123static unsigned long long totalsum = 0;
124static unsigned long long pidsum = 0;
125
126static int last_time = 0;
127
128static char *zname = NULL;
9726c137 129static size_t znamelen = 0;
8459d725
A
130
131static void
132sigintr(__unused int signum)
133{
134 last_time = 1;
135}
1815bff5
A
136
137static void
8459d725 138usage(void)
1815bff5 139{
cf37c299 140 fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p <pid>] [name]\n", program);
1815bff5
A
141 exit(1);
142}
143
34d340d7 144int
8459d725 145main(int argc, char **argv)
1815bff5 146{
8459d725
A
147 mach_zone_name_t *name = NULL;
148 unsigned int nameCnt = 0;
149 task_zone_info_t *info = NULL;
150 unsigned int infoCnt = 0;
9726c137
A
151 mach_memory_info_t *wiredInfo = NULL;
152 unsigned int wiredInfoCnt = 0;
8459d725
A
153 task_zone_info_t *max_info = NULL;
154 char *deltas = NULL;
887d5eed 155 uint64_t zoneElements;
1815bff5
A
156
157 kern_return_t kr;
158 int i, j;
8459d725
A
159 int first_time = 1;
160 int must_print = 1;
161 int interval = 1;
1815bff5 162
8459d725 163 signal(SIGINT, sigintr);
ef8ad44b 164
1815bff5
A
165 program = strrchr(argv[0], '/');
166 if (program == NULL)
167 program = argv[0];
168 else
169 program++;
170
171 for (i = 1; i < argc; i++) {
8459d725
A
172 if (streql(argv[i], "-d"))
173 ShowDeltas = TRUE;
174 else if (streql(argv[i], "-t"))
175 ShowTotal = TRUE;
176 else if (streql(argv[i], "-T"))
177 ShowTotal = FALSE;
178 else if (streql(argv[i], "-w"))
1815bff5
A
179 ShowWasted = TRUE;
180 else if (streql(argv[i], "-W"))
181 ShowWasted = FALSE;
9726c137
A
182 else if (streql(argv[i], "-l"))
183 ShowLarge = TRUE;
184 else if (streql(argv[i], "-L"))
185 ShowLarge = FALSE;
1815bff5
A
186 else if (streql(argv[i], "-s"))
187 SortZones = TRUE;
188 else if (streql(argv[i], "-S"))
189 SortZones = FALSE;
190 else if (streql(argv[i], "-c"))
191 ColFormat = TRUE;
192 else if (streql(argv[i], "-C"))
193 ColFormat = FALSE;
194 else if (streql(argv[i], "-H"))
195 PrintHeader = FALSE;
8459d725
A
196 else if (streql(argv[i], "-p")) {
197 ShowPid = TRUE;
198 if (i < argc - 1) {
199 pid = atoi(argv[i+1]);
200 i++;
201 } else
202 usage();
203 } else if (streql(argv[i], "--")) {
1815bff5
A
204 i++;
205 break;
206 } else if (argv[i][0] == '-')
207 usage();
208 else
209 break;
210 }
211
212 switch (argc - i) {
213 case 0:
214 zname = "";
215 znamelen = 0;
216 break;
217
218 case 1:
219 zname = argv[i];
220 znamelen = strlen(zname);
221 break;
222
223 default:
224 usage();
225 }
226
8459d725
A
227 if (ShowDeltas) {
228 SortZones = FALSE;
229 ColFormat = TRUE;
230 PrintHeader = TRUE;
231 }
232
233 if (ShowPid) {
234 kr = task_for_pid(mach_task_self(), pid, &task);
235 if (kr != KERN_SUCCESS) {
cf37c299 236 fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n",
8459d725
A
237 program, pid, mach_error_string(kr));
238 exit(1);
239 }
240 }
241
242 for (;;) {
243 if (ShowPid) {
244 kr = task_zone_info(task, &name, &nameCnt, &info, &infoCnt);
245 if (kr != KERN_SUCCESS) {
246 fprintf(stderr, "%s: task_zone_info: %s\n",
247 program, mach_error_string(kr));
1815bff5 248 exit(1);
8459d725
A
249 }
250 } else {
251 mach_zone_info_t *zinfo = NULL;
252
9726c137
A
253 kr = mach_memory_info(mach_host_self(),
254 &name, &nameCnt, &zinfo, &infoCnt,
255 &wiredInfo, &wiredInfoCnt);
8459d725
A
256 if (kr != KERN_SUCCESS) {
257 fprintf(stderr, "%s: mach_zone_info: %s\n",
258 program, mach_error_string(kr));
259 exit(1);
260 }
9726c137 261
8459d725
A
262 kr = vm_allocate(mach_task_self(), (vm_address_t *)&info,
263 infoCnt * sizeof *info, VM_FLAGS_ANYWHERE);
264 if (kr != KERN_SUCCESS) {
265 fprintf(stderr, "%s vm_allocate: %s\n",
266 program, mach_error_string(kr));
267 exit(1);
268 }
269 for (i = 0; i < infoCnt; i++) {
270 *(mach_zone_info_t *)(info + i) = zinfo[i];
271 info[i].tzi_caller_acct = 0;
272 info[i].tzi_task_alloc = 0;
273 info[i].tzi_task_free = 0;
274 }
275 kr = vm_deallocate(mach_task_self(), (vm_address_t) zinfo,
276 (vm_size_t) (infoCnt * sizeof *zinfo));
277 if (kr != KERN_SUCCESS) {
278 fprintf(stderr, "%s: vm_deallocate: %s\n",
279 program, mach_error_string(kr));
280 exit(1);
281 }
1815bff5 282 }
8459d725
A
283
284 if (nameCnt != infoCnt) {
285 fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n",
1815bff5
A
286 program);
287 exit(1);
288 }
289
8459d725
A
290 if (first_time) {
291 deltas = (char *)malloc(infoCnt);
292 max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info));
293 }
294
1815bff5
A
295 if (SortZones) {
296 for (i = 0; i < nameCnt-1; i++)
297 for (j = i+1; j < nameCnt; j++) {
9726c137 298 unsigned long long wastei, wastej;
1815bff5 299
8459d725
A
300 wastei = (info[i].tzi_cur_size -
301 (info[i].tzi_elem_size *
302 info[i].tzi_count));
303 wastej = (info[j].tzi_cur_size -
304 (info[j].tzi_elem_size *
305 info[j].tzi_count));
1815bff5
A
306
307 if (wastej > wastei) {
8459d725
A
308 task_zone_info_t tinfo;
309 mach_zone_name_t tname;
1815bff5
A
310
311 tinfo = info[i];
312 info[i] = info[j];
313 info[j] = tinfo;
314
315 tname = name[i];
316 name[i] = name[j];
317 name[j] = tname;
318 }
319 }
320 }
321
8459d725 322 must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
887d5eed 323 zoneElements = 0;
8459d725
A
324 if (must_print) {
325 if (ColFormat) {
326 if (!first_time)
327 printf("\n");
328 colprintzoneheader();
329 }
330 for (i = 0; i < nameCnt; i++) {
331 if (deltas[i]) {
332 if (ColFormat)
333 colprintzone(&name[i], &info[i]);
334 else
335 printzone(&name[i], &info[i]);
887d5eed 336 zoneElements += info[i].tzi_count;
8459d725
A
337 }
338 }
cf37c299 339 }
9726c137 340
cf37c299 341 if (ShowLarge && first_time) {
887d5eed
A
342 PrintLarge(wiredInfo, wiredInfoCnt, &info[0], &name[0],
343 nameCnt, zoneElements,
cf37c299 344 SortZones ? &SortSize : &SortName, ColFormat);
1815bff5 345 }
8459d725
A
346
347 first_time = 0;
348
349 if ((name != NULL) && (nameCnt != 0)) {
1815bff5
A
350 kr = vm_deallocate(mach_task_self(), (vm_address_t) name,
351 (vm_size_t) (nameCnt * sizeof *name));
352 if (kr != KERN_SUCCESS) {
353 fprintf(stderr, "%s: vm_deallocate: %s\n",
354 program, mach_error_string(kr));
355 exit(1);
356 }
357 }
358
8459d725 359 if ((info != NULL) && (infoCnt != 0)) {
1815bff5
A
360 kr = vm_deallocate(mach_task_self(), (vm_address_t) info,
361 (vm_size_t) (infoCnt * sizeof *info));
362 if (kr != KERN_SUCCESS) {
363 fprintf(stderr, "%s: vm_deallocate: %s\n",
364 program, mach_error_string(kr));
365 exit(1);
366 }
367 }
368
9726c137
A
369 if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) {
370 kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo,
371 (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo));
372 if (kr != KERN_SUCCESS) {
373 fprintf(stderr, "%s: vm_deallocate: %s\n",
374 program, mach_error_string(kr));
375 exit(1);
376 }
377 }
378
8459d725
A
379 if ((ShowWasted||ShowTotal) && PrintHeader && !ShowDeltas) {
380 printf("TOTAL SIZE = %llu\n", totalsize);
381 printf("TOTAL USED = %llu\n", totalused);
382 if (ShowWasted)
383 printf("TOTAL WASTED = %llu\n", totalsize - totalused);
384 if (ShowTotal)
385 printf("TOTAL ALLOCS = %llu\n", totalsum);
1815bff5
A
386 }
387
8459d725
A
388 if (ShowDeltas == FALSE || last_time)
389 break;
1815bff5 390
8459d725
A
391 sleep(interval);
392 }
393 exit(0);
1815bff5
A
394}
395
396static boolean_t
9726c137 397substr(const char *a, size_t alen, const char *b, size_t blen)
1815bff5
A
398{
399 int i;
400
cf37c299
A
401 if (alen > blen) return FALSE;
402
1815bff5
A
403 for (i = 0; i <= blen - alen; i++)
404 if (strneql(a, b+i, alen))
405 return TRUE;
406
407 return FALSE;
408}
409
410static void
8459d725 411printzone(mach_zone_name_t *name, task_zone_info_t *info)
1815bff5 412{
8459d725
A
413 unsigned long long used, size;
414
415 printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name);
416 printf("\tcur_size: %lluK bytes (%llu elements)\n",
417 info->tzi_cur_size/1024,
418 (info->tzi_elem_size == 0) ? 0 :
419 info->tzi_cur_size/info->tzi_elem_size);
420 printf("\tmax_size: %lluK bytes (%llu elements)\n",
421 info->tzi_max_size/1024,
422 (info->tzi_elem_size == 0) ? 0 :
423 info->tzi_max_size/info->tzi_elem_size);
424 printf("\telem_size: %llu bytes\n",
425 info->tzi_elem_size);
426 printf("\t# of elems: %llu\n",
427 info->tzi_count);
428 printf("\talloc_size: %lluK bytes (%llu elements)\n",
429 info->tzi_alloc_size/1024,
430 (info->tzi_elem_size == 0) ? 0 :
431 info->tzi_alloc_size/info->tzi_elem_size);
432 if (info->tzi_exhaustible)
433 printf("\tEXHAUSTIBLE\n");
434 if (info->tzi_collectable)
1815bff5 435 printf("\tCOLLECTABLE\n");
8459d725
A
436 if (ShowPid && info->tzi_caller_acct)
437 printf("\tCALLER ACCOUNTED\n");
438 if (ShowPid) {
439 pidsum += info->tzi_task_alloc - info->tzi_task_free;
440 printf("\tproc_alloc_size: %8dK bytes (%llu elements)\n",
441 (int)((info->tzi_task_alloc - info->tzi_task_free)/1024),
442 (info->tzi_elem_size == 0) ? 0 :
443 (info->tzi_task_alloc - info->tzi_task_free)/info->tzi_elem_size);
444 }
1815bff5 445 if (ShowWasted) {
8459d725
A
446 totalused += used = info->tzi_elem_size * info->tzi_count;
447 totalsize += size = info->tzi_cur_size;
448 printf("\t\t\t\t\tWASTED: %llu\n", size - used);
449 }
450 if (ShowTotal) {
451 totalsum += info->tzi_sum_size;
452 printf("\t\t\t\t\tTOTAL: %llu\n", totalsum);
453 if (ShowPid)
454 printf("\t\t\t\t\tPID TOTAL: %llu\n", pidsum);
1815bff5
A
455 }
456}
457
1815bff5 458static void
8459d725 459colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info)
1815bff5 460{
8459d725 461 char *name = zone_name->mzn_name;
34d340d7 462 int j, namewidth;
8459d725 463 unsigned long long used, size;
1815bff5
A
464
465 namewidth = 25;
8459d725 466 if (ShowWasted || ShowTotal) {
1815bff5
A
467 namewidth -= 7;
468 }
469 for (j = 0; j < namewidth - 1 && name[j]; j++) {
470 if (name[j] == ' ') {
471 putchar('.');
472 } else {
473 putchar(name[j]);
474 }
475 }
476 if (j == namewidth - 1) {
477 if (name[j]) {
478 putchar('$');
479 } else {
480 putchar(' ');
481 }
482 } else {
483 for (; j < namewidth; j++) {
484 putchar(' ');
485 }
486 }
aaff5f01
A
487 printf(" %6llu", info->tzi_elem_size);
488 PRINTK(" %10llu", info->tzi_cur_size);
8459d725 489 if (info->tzi_max_size / 1024 > 9999999) {
aaff5f01 490 printf(" --------");
1815bff5 491 } else {
aaff5f01 492 PRINTK(" %10llu", info->tzi_max_size);
1815bff5 493 }
aaff5f01 494 printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size);
8459d725 495 if (info->tzi_max_size / 1024 >= 999999999) {
aaff5f01 496 printf(" ----------");
1815bff5 497 } else {
aaff5f01 498 printf(" %11llu", info->tzi_max_size / info->tzi_elem_size);
1815bff5 499 }
aaff5f01
A
500 printf(" %11llu", info->tzi_count);
501 PRINTK(" %5llu", info->tzi_alloc_size);
502 printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size);
8459d725
A
503
504 totalused += used = info->tzi_elem_size * info->tzi_count;
505 totalsize += size = info->tzi_cur_size;
506 totalsum += info->tzi_sum_size;
507
508 printf(" %c%c%c",
509 (info->tzi_exhaustible ? 'X' : ' '),
510 (info->tzi_caller_acct ? 'A' : ' '),
511 (info->tzi_collectable ? 'C' : ' '));
1815bff5 512 if (ShowWasted) {
aaff5f01 513 PRINTK(" %8llu", size - used);
1815bff5 514 }
8459d725
A
515 if (ShowPid) {
516 printf("%8dK", (int)((info->tzi_task_alloc - info->tzi_task_free)/1024));
517 }
518 if (ShowTotal) {
519 if (info->tzi_sum_size < 1024)
aaff5f01 520 printf(" %16lluB", info->tzi_sum_size);
8459d725 521 else
aaff5f01 522 PRINTK(" %16llu", info->tzi_sum_size);
8459d725
A
523 }
524 printf("\n");
1815bff5
A
525}
526
527static void
8459d725 528colprintzoneheader(void)
1815bff5
A
529{
530 if (! PrintHeader) {
531 return;
532 }
aaff5f01
A
533 printf("%s elem cur max cur max"
534 " cur alloc alloc %s%s\n",
535 (ShowWasted||ShowTotal)? "" : " ",
536 (ShowWasted)? " ":"",
537 (ShowPid) ? " PID" : "" );
538 printf("zone name%s size size size #elts #elts"
539 " inuse size count ", (ShowWasted||ShowTotal)? " " : " " );
8459d725 540 if (ShowWasted)
aaff5f01 541 printf(" wasted");
8459d725 542 if (ShowPid)
aaff5f01 543 printf(" Allocs");
8459d725 544 if (ShowTotal)
aaff5f01
A
545 printf(" Total Allocs");
546 printf("\n%s-------------------------------------------------------"
547 "-----------------------------------------------",
8459d725
A
548 (ShowWasted||ShowTotal)? "" : "-------");
549 if (ShowWasted)
8459d725 550 printf("----------");
aaff5f01
A
551 if (ShowPid)
552 printf("---------");
8459d725 553 if (ShowTotal)
aaff5f01 554 printf("------------------");
8459d725
A
555 printf("\n");
556}
557
558int
559find_deltas(mach_zone_name_t *name, task_zone_info_t *info, task_zone_info_t *max_info,
560 char *deltas, int cnt, int first_time)
561{
562 int i;
563 int found_one = 0;
564
565 for (i = 0; i < cnt; i++) {
566 deltas[i] = 0;
567 if (substr(zname, znamelen, name[i].mzn_name,
568 strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) {
569 if (first_time || info->tzi_cur_size > max_info->tzi_cur_size ||
570 (ShowTotal && ((info->tzi_sum_size >> 1) > max_info->tzi_sum_size))) {
571 max_info->tzi_cur_size = info->tzi_cur_size;
572 max_info->tzi_sum_size = info->tzi_sum_size;
573 deltas[i] = 1;
574 found_one = 1;
575 }
576 }
577 info++;
578 max_info++;
579 }
580 return(found_one);
1815bff5 581}
9726c137
A
582
583/*********************************************************************
584*********************************************************************/
585
586static char *
587kern_vm_tag_name(uint64_t tag)
588{
589 char * result;
590 const char * name;
591 switch (tag)
592 {
593 case (VM_KERN_MEMORY_NONE): name = "VM_KERN_MEMORY_NONE"; break;
594 case (VM_KERN_MEMORY_OSFMK): name = "VM_KERN_MEMORY_OSFMK"; break;
595 case (VM_KERN_MEMORY_BSD): name = "VM_KERN_MEMORY_BSD"; break;
596 case (VM_KERN_MEMORY_IOKIT): name = "VM_KERN_MEMORY_IOKIT"; break;
597 case (VM_KERN_MEMORY_LIBKERN): name = "VM_KERN_MEMORY_LIBKERN"; break;
598 case (VM_KERN_MEMORY_OSKEXT): name = "VM_KERN_MEMORY_OSKEXT"; break;
599 case (VM_KERN_MEMORY_KEXT): name = "VM_KERN_MEMORY_KEXT"; break;
600 case (VM_KERN_MEMORY_IPC): name = "VM_KERN_MEMORY_IPC"; break;
601 case (VM_KERN_MEMORY_STACK): name = "VM_KERN_MEMORY_STACK"; break;
602 case (VM_KERN_MEMORY_CPU): name = "VM_KERN_MEMORY_CPU"; break;
603 case (VM_KERN_MEMORY_PMAP): name = "VM_KERN_MEMORY_PMAP"; break;
604 case (VM_KERN_MEMORY_PTE): name = "VM_KERN_MEMORY_PTE"; break;
605 case (VM_KERN_MEMORY_ZONE): name = "VM_KERN_MEMORY_ZONE"; break;
606 case (VM_KERN_MEMORY_KALLOC): name = "VM_KERN_MEMORY_KALLOC"; break;
607 case (VM_KERN_MEMORY_COMPRESSOR): name = "VM_KERN_MEMORY_COMPRESSOR"; break;
608 case (VM_KERN_MEMORY_COMPRESSED_DATA): name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break;
609 case (VM_KERN_MEMORY_PHANTOM_CACHE): name = "VM_KERN_MEMORY_PHANTOM_CACHE"; break;
610 case (VM_KERN_MEMORY_WAITQ): name = "VM_KERN_MEMORY_WAITQ"; break;
611 case (VM_KERN_MEMORY_DIAG): name = "VM_KERN_MEMORY_DIAG"; break;
612 case (VM_KERN_MEMORY_LOG): name = "VM_KERN_MEMORY_LOG"; break;
613 case (VM_KERN_MEMORY_FILE): name = "VM_KERN_MEMORY_FILE"; break;
614 case (VM_KERN_MEMORY_MBUF): name = "VM_KERN_MEMORY_MBUF"; break;
615 case (VM_KERN_MEMORY_UBC): name = "VM_KERN_MEMORY_UBC"; break;
616 case (VM_KERN_MEMORY_SECURITY): name = "VM_KERN_MEMORY_SECURITY"; break;
617 case (VM_KERN_MEMORY_MLOCK): name = "VM_KERN_MEMORY_MLOCK"; break;
cf37c299
A
618 case (VM_KERN_MEMORY_REASON): name = "VM_KERN_MEMORY_REASON"; break;
619 case (VM_KERN_MEMORY_SKYWALK): name = "VM_KERN_MEMORY_SKYWALK"; break;
620 case (VM_KERN_MEMORY_LTABLE): name = "VM_KERN_MEMORY_LTABLE"; break;
9726c137
A
621 case (VM_KERN_MEMORY_ANY): name = "VM_KERN_MEMORY_ANY"; break;
622 default: name = NULL; break;
623 }
624 if (name) asprintf(&result, "%s", name);
625 else asprintf(&result, "VM_KERN_MEMORY_%lld", tag);
626 return (result);
627 }
628
cf37c299 629static char *
9726c137
A
630kern_vm_counter_name(uint64_t tag)
631{
632 char * result;
633 const char * name;
634 switch (tag)
635 {
636 case (VM_KERN_COUNT_MANAGED): name = "VM_KERN_COUNT_MANAGED"; break;
637 case (VM_KERN_COUNT_RESERVED): name = "VM_KERN_COUNT_RESERVED"; break;
638 case (VM_KERN_COUNT_WIRED): name = "VM_KERN_COUNT_WIRED"; break;
887d5eed 639 case (VM_KERN_COUNT_WIRED_BOOT): name = "VM_KERN_COUNT_WIRED_BOOT"; break;
9726c137
A
640 case (VM_KERN_COUNT_WIRED_MANAGED): name = "VM_KERN_COUNT_WIRED_MANAGED"; break;
641 case (VM_KERN_COUNT_STOLEN): name = "VM_KERN_COUNT_STOLEN"; break;
887d5eed 642 case (VM_KERN_COUNT_BOOT_STOLEN): name = "VM_KERN_COUNT_BOOT_STOLEN"; break;
9726c137
A
643 case (VM_KERN_COUNT_LOPAGE): name = "VM_KERN_COUNT_LOPAGE"; break;
644 case (VM_KERN_COUNT_MAP_KERNEL): name = "VM_KERN_COUNT_MAP_KERNEL"; break;
645 case (VM_KERN_COUNT_MAP_ZONE): name = "VM_KERN_COUNT_MAP_ZONE"; break;
646 case (VM_KERN_COUNT_MAP_KALLOC): name = "VM_KERN_COUNT_MAP_KALLOC"; break;
647 default: name = NULL; break;
648 }
649 if (name) asprintf(&result, "%s", name);
650 else asprintf(&result, "VM_KERN_COUNT_%lld", tag);
651 return (result);
652}
653
654static void
655MakeLoadTagKeys(const void * key, const void * value, void * context)
656{
657 CFMutableDictionaryRef newDict = context;
658 CFDictionaryRef kextInfo = value;
659 CFNumberRef loadTag;
660 uint32_t loadTagValue;
661
662 loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey));
663 CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue);
664 key = (const void *)(uintptr_t) loadTagValue;
665 CFDictionarySetValue(newDict, key, value);
666}
667
cf37c299 668static CSSymbolicatorRef gSym;
9726c137
A
669static CFMutableDictionaryRef gTagDict;
670static mach_memory_info_t * gSites;
671
cf37c299 672static char *
887d5eed 673GetSiteName(int siteIdx, mach_zone_name_t * zoneNames, unsigned int zoneNamesCnt)
9726c137
A
674{
675 const char * name;
887d5eed 676 uintptr_t kmodid;
9726c137 677 char * result;
887d5eed 678 char * append;
9726c137
A
679 mach_vm_address_t addr;
680 CFDictionaryRef kextInfo;
681 CFStringRef bundleID;
682 uint32_t type;
683
684 const mach_memory_info_t * site;
685 const char * fileName;
686 CSSymbolRef symbol;
687 const char * symbolName;
688 CSSourceInfoRef sourceInfo;
689
690 name = NULL;
691 result = NULL;
692 site = &gSites[siteIdx];
693 addr = site->site;
694 type = (VM_KERN_SITE_TYPE & site->flags);
887d5eed
A
695 kmodid = 0;
696
697 if (VM_KERN_SITE_NAMED & site->flags)
698 {
699 asprintf(&result, "%s", &site->name[0]);
700 }
701 else switch (type)
9726c137
A
702 {
703 case VM_KERN_SITE_TAG:
704 result = kern_vm_tag_name(addr);
705 break;
706
707 case VM_KERN_SITE_COUNTER:
708 result = kern_vm_counter_name(addr);
709 break;
710
711 case VM_KERN_SITE_KMOD:
887d5eed
A
712
713 kmodid = (uintptr_t) addr;
714 kextInfo = CFDictionaryGetValue(gTagDict, (const void *)kmodid);
cf37c299 715 if (kextInfo)
9726c137
A
716 {
717 bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey);
718 name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8);
719 // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
720 }
887d5eed
A
721
722 if (name) asprintf(&result, "%s", name);
723 else asprintf(&result, "(unloaded kmod)");
9726c137
A
724 break;
725
726 case VM_KERN_SITE_KERNEL:
727 symbolName = NULL;
728 if (addr)
729 {
730 symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow);
731 symbolName = CSSymbolGetName(symbol);
732 }
733 if (symbolName)
734 {
735 asprintf(&result, "%s", symbolName);
736 sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow);
737 fileName = CSSourceInfoGetPath(sourceInfo);
738 if (fileName) printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo));
739 }
740 else
741 {
742 asprintf(&result, "site 0x%qx", addr);
743 }
744 break;
745 default:
746 asprintf(&result, "");
747 break;
748 }
749
887d5eed
A
750 if (result
751 && (VM_KERN_SITE_ZONE & site->flags)
752 && zoneNames
753 && (site->zone < zoneNamesCnt))
754 {
755 size_t namelen, zonelen;
756 namelen = strlen(result);
757 zonelen = strnlen(zoneNames[site->zone].mzn_name, sizeof(zoneNames[site->zone].mzn_name));
758 if (((namelen + zonelen) > 61) && (zonelen < 61)) namelen = (61 - zonelen);
759 asprintf(&append, "%.*s[%.*s]",
760 (int)namelen,
761 result,
762 (int)zonelen,
763 zoneNames[site->zone].mzn_name);
764 free(result);
765 result = append;
766 }
767 if (result && kmodid)
768 {
769 asprintf(&append, "%-64s%3ld", result, kmodid);
770 free(result);
771 result = append;
772 }
773
774 return (result);
9726c137
A
775}
776
887d5eed
A
777struct CompareThunk
778{
779 mach_zone_name_t *zoneNames;
780 unsigned int zoneNamesCnt;
781};
782
cf37c299 783static int
887d5eed 784SortName(void * thunk, const void * left, const void * right)
9726c137 785{
887d5eed 786 const struct CompareThunk * t = (typeof(t)) thunk;
9726c137
A
787 const int * idxL;
788 const int * idxR;
789 char * l;
790 char * r;
887d5eed
A
791 CFStringRef lcf;
792 CFStringRef rcf;
9726c137
A
793 int result;
794
795 idxL = (typeof(idxL)) left;
796 idxR = (typeof(idxR)) right;
887d5eed
A
797 l = GetSiteName(*idxL, t->zoneNames, t->zoneNamesCnt);
798 r = GetSiteName(*idxR, t->zoneNames, t->zoneNamesCnt);
799
800 lcf = CFStringCreateWithCString(kCFAllocatorDefault, l, kCFStringEncodingUTF8);
801 rcf = CFStringCreateWithCString(kCFAllocatorDefault, r, kCFStringEncodingUTF8);
802
803 result = (int) CFStringCompareWithOptionsAndLocale(lcf, rcf, CFRangeMake(0, CFStringGetLength(lcf)), kCFCompareNumerically, NULL);
9726c137 804
887d5eed
A
805 CFRelease(lcf);
806 CFRelease(rcf);
9726c137
A
807 free(l);
808 free(r);
809
810 return (result);
811}
812
cf37c299 813static int
887d5eed 814SortSize(void * thunk, const void * left, const void * right)
9726c137
A
815{
816 const mach_memory_info_t * siteL;
817 const mach_memory_info_t * siteR;
818 const int * idxL;
819 const int * idxR;
820
821 idxL = (typeof(idxL)) left;
822 idxR = (typeof(idxR)) right;
823 siteL = &gSites[*idxL];
824 siteR = &gSites[*idxR];
825
826 if (siteL->size > siteR->size) return (-1);
827 else if (siteL->size < siteR->size) return (1);
828 return (0);
829}
830
831
832static void
833PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
887d5eed
A
834 task_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames,
835 unsigned int zoneCnt, uint64_t zoneElements,
836 int (*func)(void *, const void *, const void *), boolean_t column)
9726c137
A
837{
838 uint64_t zonetotal;
839 uint64_t top_wired;
887d5eed
A
840 uint64_t size;
841 uint64_t elemsTagged;
9726c137
A
842
843 CFDictionaryRef allKexts;
844 unsigned int idx, site, first;
845 int sorted[wiredInfoCnt];
846 char totalstr[40];
847 char * name;
cf37c299 848 bool headerPrinted;
9726c137
A
849
850 zonetotal = totalsize;
851
852 gSites = wiredInfo;
853
854 gSym = CSSymbolicatorCreateWithMachKernel();
cf37c299 855
9726c137 856 allKexts = OSKextCopyLoadedKextInfo(NULL, NULL);
cf37c299 857 gTagDict = CFDictionaryCreateMutable(
9726c137
A
858 kCFAllocatorDefault, (CFIndex) 0,
859 (CFDictionaryKeyCallBacks *) 0,
860 &kCFTypeDictionaryValueCallBacks);
861
862 CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict);
863 CFRelease(allKexts);
864
865 top_wired = 0;
866
867 for (idx = 0; idx < wiredInfoCnt; idx++) sorted[idx] = idx;
868 first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
887d5eed
A
869 struct CompareThunk thunk;
870 thunk.zoneNames = zoneNames;
871 thunk.zoneNamesCnt = zoneCnt;
872 qsort_r(&sorted[first],
cf37c299
A
873 wiredInfoCnt - first,
874 sizeof(sorted[0]),
887d5eed 875 &thunk,
9726c137
A
876 func);
877
887d5eed 878 elemsTagged = 0;
cf37c299 879 for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
9726c137
A
880 {
881 site = sorted[idx];
887d5eed
A
882 if ((VM_KERN_SITE_COUNTER & gSites[site].flags)
883 && (VM_KERN_COUNT_WIRED == gSites[site].site)) top_wired = gSites[site].size;
9726c137 884 if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
887d5eed
A
885 if (!((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) continue;
886
887 if ((VM_KERN_SITE_ZONE & gSites[site].flags)
888 && gSites[site].zone < zoneCnt)
889 {
890 elemsTagged += gSites[site].size / zoneInfo[gSites[site].zone].tzi_elem_size;
891 }
892
893 if ((gSites[site].size < 1024) && (gSites[site].peak < 1024)) continue;
9726c137 894
887d5eed 895 name = GetSiteName(site, zoneNames, zoneCnt);
cf37c299
A
896 if (!substr(zname, znamelen, name, strlen(name))) continue;
897 if (!headerPrinted)
898 {
899 printf("-------------------------------------------------------------------------------------------------------------\n");
887d5eed
A
900 printf(" kmod vm peak cur\n");
901 printf("wired memory id tag size waste size\n");
cf37c299
A
902 printf("-------------------------------------------------------------------------------------------------------------\n");
903 headerPrinted = true;
904 }
9726c137
A
905 printf("%-67s", name);
906 free(name);
887d5eed 907 printf("%12d", gSites[site].tag);
9726c137 908
887d5eed
A
909 if (gSites[site].peak) PRINTK(" %10llu", gSites[site].peak);
910 else printf(" %11s", "");
911
912 if (gSites[site].collectable_bytes) PRINTK(" %5llu", gSites[site].collectable_bytes);
913 else printf(" %6s", "");
914
915 PRINTK(" %9llu", gSites[site].size);
916
917 if (!(VM_KERN_SITE_ZONE & gSites[site].flags)) totalsize += gSites[site].size;
9726c137
A
918
919 printf("\n");
920 }
921
cf37c299
A
922 if (!znamelen)
923 {
924 printf("%-67s", "zones");
925 printf("%12s", "");
926 printf(" %11s", "");
887d5eed
A
927 printf(" %6s", "");
928 PRINTK(" %9llu", zonetotal);
cf37c299
A
929 printf("\n");
930 }
931 if (headerPrinted)
932 {
887d5eed
A
933 if (elemsTagged)
934 {
935 snprintf(totalstr, sizeof(totalstr), "%lld of %lld", elemsTagged, zoneElements);
936 printf("zone tags%100s\n", totalstr);
937 }
cf37c299 938 snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0);
887d5eed 939 printf("total%104s\n", totalstr);
cf37c299
A
940 }
941 for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
9726c137
A
942 {
943 site = sorted[idx];
887d5eed
A
944 size = gSites[site].mapped;
945 if (!size) continue;
9726c137 946 if (VM_KERN_SITE_HIDE & gSites[site].flags) continue;
887d5eed
A
947 if ((size == gSites[site].size)
948 && ((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) continue;
9726c137 949
887d5eed 950 name = GetSiteName(site, NULL, 0);
cf37c299
A
951 if (!substr(zname, znamelen, name, strlen(name))) continue;
952 if (!headerPrinted)
953 {
954 printf("-------------------------------------------------------------------------------------------------------------\n");
887d5eed
A
955 printf(" largest peak cur\n");
956 printf("maps free free size size\n");
cf37c299
A
957 printf("-------------------------------------------------------------------------------------------------------------\n");
958 headerPrinted = true;
959 }
887d5eed 960 printf("%-55s", name);
9726c137
A
961 free(name);
962
887d5eed
A
963 if (gSites[site].free) PRINTK(" %10llu", gSites[site].free);
964 else printf(" %11s", "");
965 if (gSites[site].largest) PRINTK(" %10llu", gSites[site].largest);
966 else printf(" %11s", "");
967 if (gSites[site].peak) PRINTK(" %10llu", gSites[site].peak);
968 else printf(" %11s", "");
969 PRINTK(" %16llu", size);
9726c137
A
970
971 printf("\n");
972 }
973}