]> git.saurik.com Git - apple/system_cmds.git/blob - zprint.tproj/zprint.c
104161cea9f78968df7a9c2ceca2880f31e1bd18
[apple/system_cmds.git] / zprint.tproj / zprint.c
1 /*
2 * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
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
68 #include <vm_statistics.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <mach/mach.h>
73 #include <mach_debug/mach_debug.h>
74 #include <mach/mach_error.h>
75 #include <libutil.h>
76 #include <errno.h>
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
88 #define streql(a, b) (strcmp((a), (b)) == 0)
89 #define strneql(a, b, n) (strncmp((a), (b), (n)) == 0)
90 #define PRINTK(fmt, value) \
91 printf(fmt "K", (value) / 1024 ) /* ick */
92
93 static void usage(void);
94 static void printzone(mach_zone_name_t *, task_zone_info_t *);
95 static void colprintzone(mach_zone_name_t *, task_zone_info_t *);
96 static int find_deltas(mach_zone_name_t *, task_zone_info_t *, task_zone_info_t *, char *, int, int);
97 static void colprintzoneheader(void);
98 static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen);
99
100 static int SortName(const void * left, const void * right);
101 static int SortSize(const void * left, const void * right);
102 static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt, int (*func)(const void *, const void *), boolean_t column);
103
104 static char *program;
105
106 static pid_t pid = 0;
107 static task_t task = TASK_NULL;
108 static boolean_t ShowPid = FALSE;
109
110 static boolean_t ShowDeltas = FALSE;
111 static boolean_t ShowWasted = FALSE;
112 static boolean_t ShowTotal = FALSE;
113 static boolean_t ShowLarge = TRUE;
114 static boolean_t SortZones = FALSE;
115 static boolean_t ColFormat = TRUE;
116 static boolean_t PrintHeader = TRUE;
117
118 static unsigned long long totalsize = 0;
119 static unsigned long long totalused = 0;
120 static unsigned long long totalsum = 0;
121 static unsigned long long pidsum = 0;
122
123 static int last_time = 0;
124
125 static char *zname = NULL;
126 static size_t znamelen = 0;
127
128 static void
129 sigintr(__unused int signum)
130 {
131 last_time = 1;
132 }
133
134 static void
135 usage(void)
136 {
137 fprintf(stderr, "usage: %s [-w] [-s] [-c] [-h] [-t] [-d] [-l] [-L] [-p <pid>] [name]\n", program);
138 exit(1);
139 }
140
141 int
142 main(int argc, char **argv)
143 {
144 mach_zone_name_t *name = NULL;
145 unsigned int nameCnt = 0;
146 task_zone_info_t *info = NULL;
147 unsigned int infoCnt = 0;
148 mach_memory_info_t *wiredInfo = NULL;
149 unsigned int wiredInfoCnt = 0;
150 task_zone_info_t *max_info = NULL;
151 char *deltas = NULL;
152
153 kern_return_t kr;
154 int i, j;
155 int first_time = 1;
156 int must_print = 1;
157 int interval = 1;
158
159 signal(SIGINT, sigintr);
160
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++) {
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"))
175 ShowWasted = TRUE;
176 else if (streql(argv[i], "-W"))
177 ShowWasted = FALSE;
178 else if (streql(argv[i], "-l"))
179 ShowLarge = TRUE;
180 else if (streql(argv[i], "-L"))
181 ShowLarge = FALSE;
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;
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], "--")) {
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
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) {
232 fprintf(stderr, "%s: task_for_pid(%d) failed: %s (try running as root)\n",
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));
244 exit(1);
245 }
246 } else {
247 mach_zone_info_t *zinfo = NULL;
248
249 kr = mach_memory_info(mach_host_self(),
250 &name, &nameCnt, &zinfo, &infoCnt,
251 &wiredInfo, &wiredInfoCnt);
252 if (kr != KERN_SUCCESS) {
253 fprintf(stderr, "%s: mach_zone_info: %s\n",
254 program, mach_error_string(kr));
255 exit(1);
256 }
257
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 }
278 }
279
280 if (nameCnt != infoCnt) {
281 fprintf(stderr, "%s: mach/task_zone_info: counts not equal?\n",
282 program);
283 exit(1);
284 }
285
286 if (first_time) {
287 deltas = (char *)malloc(infoCnt);
288 max_info = (task_zone_info_t *)malloc((infoCnt * sizeof *info));
289 }
290
291 if (SortZones) {
292 for (i = 0; i < nameCnt-1; i++)
293 for (j = i+1; j < nameCnt; j++) {
294 unsigned long long wastei, wastej;
295
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));
302
303 if (wastej > wastei) {
304 task_zone_info_t tinfo;
305 mach_zone_name_t tname;
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
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 }
333 }
334
335 if (ShowLarge && first_time) {
336 PrintLarge(wiredInfo, wiredInfoCnt,
337 SortZones ? &SortSize : &SortName, ColFormat);
338 }
339
340 first_time = 0;
341
342 if ((name != NULL) && (nameCnt != 0)) {
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
352 if ((info != NULL) && (infoCnt != 0)) {
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
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
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);
379 }
380
381 if (ShowDeltas == FALSE || last_time)
382 break;
383
384 sleep(interval);
385 }
386 exit(0);
387 }
388
389 static boolean_t
390 substr(const char *a, size_t alen, const char *b, size_t blen)
391 {
392 int i;
393
394 if (alen > blen) return FALSE;
395
396 for (i = 0; i <= blen - alen; i++)
397 if (strneql(a, b+i, alen))
398 return TRUE;
399
400 return FALSE;
401 }
402
403 static void
404 printzone(mach_zone_name_t *name, task_zone_info_t *info)
405 {
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)
428 printf("\tCOLLECTABLE\n");
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 }
438 if (ShowWasted) {
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);
448 }
449 }
450
451 static void
452 colprintzone(mach_zone_name_t *zone_name, task_zone_info_t *info)
453 {
454 char *name = zone_name->mzn_name;
455 int j, namewidth;
456 unsigned long long used, size;
457
458 namewidth = 25;
459 if (ShowWasted || ShowTotal) {
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 }
480 printf(" %6llu", info->tzi_elem_size);
481 PRINTK(" %10llu", info->tzi_cur_size);
482 if (info->tzi_max_size / 1024 > 9999999) {
483 printf(" --------");
484 } else {
485 PRINTK(" %10llu", info->tzi_max_size);
486 }
487 printf(" %10llu", info->tzi_cur_size / info->tzi_elem_size);
488 if (info->tzi_max_size / 1024 >= 999999999) {
489 printf(" ----------");
490 } else {
491 printf(" %11llu", info->tzi_max_size / info->tzi_elem_size);
492 }
493 printf(" %11llu", info->tzi_count);
494 PRINTK(" %5llu", info->tzi_alloc_size);
495 printf(" %6llu", info->tzi_alloc_size / info->tzi_elem_size);
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' : ' '));
505 if (ShowWasted) {
506 PRINTK(" %8llu", size - used);
507 }
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)
513 printf(" %16lluB", info->tzi_sum_size);
514 else
515 PRINTK(" %16llu", info->tzi_sum_size);
516 }
517 printf("\n");
518 }
519
520 static void
521 colprintzoneheader(void)
522 {
523 if (! PrintHeader) {
524 return;
525 }
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)? " " : " " );
533 if (ShowWasted)
534 printf(" wasted");
535 if (ShowPid)
536 printf(" Allocs");
537 if (ShowTotal)
538 printf(" Total Allocs");
539 printf("\n%s-------------------------------------------------------"
540 "-----------------------------------------------",
541 (ShowWasted||ShowTotal)? "" : "-------");
542 if (ShowWasted)
543 printf("----------");
544 if (ShowPid)
545 printf("---------");
546 if (ShowTotal)
547 printf("------------------");
548 printf("\n");
549 }
550
551 int
552 find_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);
574 }
575
576 /*********************************************************************
577 *********************************************************************/
578
579 static char *
580 kern_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;
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;
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
622 static char *
623 kern_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
645 static void
646 MakeLoadTagKeys(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
659 static CSSymbolicatorRef gSym;
660 static CFMutableDictionaryRef gTagDict;
661 static mach_memory_info_t * gSites;
662
663 static char *
664 GetSiteName(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);
696 if (kextInfo)
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
732 static int
733 SortName(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
753 static int
754 SortSize(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
772 static void
773 PrintLarge(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;
784 bool headerPrinted;
785
786 zonetotal = totalsize;
787
788 gSites = wiredInfo;
789
790 gSym = CSSymbolicatorCreateWithMachKernel();
791
792 allKexts = OSKextCopyLoadedKextInfo(NULL, NULL);
793 gTagDict = CFDictionaryCreateMutable(
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],
806 wiredInfoCnt - first,
807 sizeof(sorted[0]),
808 func);
809
810 for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++)
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);
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 }
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
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++)
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);
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 }
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 }