10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1914Scasper * Common Development and Distribution License (the "License"). 6*1914Scasper * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1914Scasper * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <stdio.h> 29*1914Scasper #include <stdio_ext.h> 300Sstevel@tonic-gate #include <stdlib.h> 310Sstevel@tonic-gate #include <unistd.h> 320Sstevel@tonic-gate #include <ctype.h> 330Sstevel@tonic-gate #include <fcntl.h> 340Sstevel@tonic-gate #include <string.h> 350Sstevel@tonic-gate #include <dirent.h> 360Sstevel@tonic-gate #include <limits.h> 370Sstevel@tonic-gate #include <link.h> 380Sstevel@tonic-gate #include <libelf.h> 390Sstevel@tonic-gate #include <sys/types.h> 400Sstevel@tonic-gate #include <sys/stat.h> 410Sstevel@tonic-gate #include <sys/mkdev.h> 420Sstevel@tonic-gate #include <libproc.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate struct totals { 450Sstevel@tonic-gate ulong_t total_size; 460Sstevel@tonic-gate ulong_t total_swap; 470Sstevel@tonic-gate ulong_t total_rss; 480Sstevel@tonic-gate ulong_t total_anon; 490Sstevel@tonic-gate ulong_t total_locked; 500Sstevel@tonic-gate }; 510Sstevel@tonic-gate 520Sstevel@tonic-gate typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int); 530Sstevel@tonic-gate 540Sstevel@tonic-gate static int xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *, 550Sstevel@tonic-gate int); 560Sstevel@tonic-gate static int rmapping_iter(struct ps_prochandle *, proc_map_f *, void *); 570Sstevel@tonic-gate 580Sstevel@tonic-gate static int look_map(void *, const prmap_t *, const char *); 590Sstevel@tonic-gate static int look_smap(void *, const prxmap_t *, const char *, int, int); 600Sstevel@tonic-gate static int look_xmap(void *, const prxmap_t *, const char *, int, int); 610Sstevel@tonic-gate static int look_xmap_nopgsz(void *, const prxmap_t *, const char *, 620Sstevel@tonic-gate int, int); 630Sstevel@tonic-gate 640Sstevel@tonic-gate static int gather_map(void *, const prmap_t *, const char *); 650Sstevel@tonic-gate static int gather_xmap(void *, const prxmap_t *, const char *, int, int); 660Sstevel@tonic-gate static int iter_map(proc_map_f *, void *); 670Sstevel@tonic-gate static int iter_xmap(proc_xmap_f *, void *); 680Sstevel@tonic-gate 690Sstevel@tonic-gate static int perr(char *); 700Sstevel@tonic-gate static void printK(long, int); 710Sstevel@tonic-gate static char *mflags(uint_t); 720Sstevel@tonic-gate 730Sstevel@tonic-gate static int lflag = 0; 740Sstevel@tonic-gate static int aflag = 0; 750Sstevel@tonic-gate static int addr_width, size_width; 760Sstevel@tonic-gate static char *command; 770Sstevel@tonic-gate static char *procname; 780Sstevel@tonic-gate static struct ps_prochandle *Pr; 790Sstevel@tonic-gate 800Sstevel@tonic-gate typedef struct lwpstack { 810Sstevel@tonic-gate lwpid_t lwps_lwpid; 820Sstevel@tonic-gate stack_t lwps_stack; 830Sstevel@tonic-gate } lwpstack_t; 840Sstevel@tonic-gate 850Sstevel@tonic-gate typedef struct { 860Sstevel@tonic-gate prxmap_t md_xmap; 870Sstevel@tonic-gate prmap_t md_map; 880Sstevel@tonic-gate char *md_objname; 890Sstevel@tonic-gate int md_last; 900Sstevel@tonic-gate int md_doswap; 910Sstevel@tonic-gate } mapdata_t; 920Sstevel@tonic-gate 930Sstevel@tonic-gate static mapdata_t *maps; 940Sstevel@tonic-gate static int map_count; 950Sstevel@tonic-gate static int map_alloc; 960Sstevel@tonic-gate 970Sstevel@tonic-gate static lwpstack_t *stacks = NULL; 980Sstevel@tonic-gate static uint_t nstacks = 0; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate #define MAX_TRIES 5 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate static int 1030Sstevel@tonic-gate getstack(void *data, const lwpstatus_t *lsp) 1040Sstevel@tonic-gate { 1050Sstevel@tonic-gate int *np = (int *)data; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1080Sstevel@tonic-gate stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 1090Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1100Sstevel@tonic-gate (*np)++; 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1140Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1150Sstevel@tonic-gate (*np)++; 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate return (0); 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * We compare the high memory addresses since stacks are faulted in from 1230Sstevel@tonic-gate * high memory addresses to low memory addresses, and our prmap_t 1240Sstevel@tonic-gate * structures identify only the range of addresses that have been faulted 1250Sstevel@tonic-gate * in so far. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate static int 1280Sstevel@tonic-gate cmpstacks(const void *ap, const void *bp) 1290Sstevel@tonic-gate { 1300Sstevel@tonic-gate const lwpstack_t *as = ap; 1310Sstevel@tonic-gate const lwpstack_t *bs = bp; 1320Sstevel@tonic-gate uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 1330Sstevel@tonic-gate uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate if (a < b) 1360Sstevel@tonic-gate return (1); 1370Sstevel@tonic-gate if (a > b) 1380Sstevel@tonic-gate return (-1); 1390Sstevel@tonic-gate return (0); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate int 1440Sstevel@tonic-gate main(int argc, char **argv) 1450Sstevel@tonic-gate { 1460Sstevel@tonic-gate int rflag = 0, sflag = 0, xflag = 0; 1470Sstevel@tonic-gate int errflg = 0, Sflag = 0; 1480Sstevel@tonic-gate int rc = 0; 1490Sstevel@tonic-gate int opt; 1500Sstevel@tonic-gate const char *bar8 = "-------"; 1510Sstevel@tonic-gate const char *bar16 = "----------"; 1520Sstevel@tonic-gate const char *bar; 1530Sstevel@tonic-gate struct rlimit rlim; 1540Sstevel@tonic-gate struct stat64 statbuf; 1550Sstevel@tonic-gate char buf[128]; 1560Sstevel@tonic-gate int mapfd; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 1590Sstevel@tonic-gate command++; 1600Sstevel@tonic-gate else 1610Sstevel@tonic-gate command = argv[0]; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate while ((opt = getopt(argc, argv, "arsxSlF")) != EOF) { 1640Sstevel@tonic-gate switch (opt) { 1650Sstevel@tonic-gate case 'a': /* include shared mappings in -[xS] */ 1660Sstevel@tonic-gate aflag = 1; 1670Sstevel@tonic-gate break; 1680Sstevel@tonic-gate case 'r': /* show reserved mappings */ 1690Sstevel@tonic-gate rflag = 1; 1700Sstevel@tonic-gate break; 1710Sstevel@tonic-gate case 's': /* show hardware page sizes */ 1720Sstevel@tonic-gate sflag = 1; 1730Sstevel@tonic-gate break; 1740Sstevel@tonic-gate case 'S': /* show swap reservations */ 1750Sstevel@tonic-gate Sflag = 1; 1760Sstevel@tonic-gate break; 1770Sstevel@tonic-gate case 'x': /* show extended mappings */ 1780Sstevel@tonic-gate xflag = 1; 1790Sstevel@tonic-gate break; 1800Sstevel@tonic-gate case 'l': /* show unresolved link map names */ 1810Sstevel@tonic-gate lflag = 1; 1820Sstevel@tonic-gate break; 1830Sstevel@tonic-gate case 'F': 1840Sstevel@tonic-gate /* 1850Sstevel@tonic-gate * Since we grab the process readonly now, the -F flag 1860Sstevel@tonic-gate * is meaningless. Consume it anyway it for backwards 1870Sstevel@tonic-gate * compatbility. 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate break; 1900Sstevel@tonic-gate default: 1910Sstevel@tonic-gate errflg = 1; 1920Sstevel@tonic-gate break; 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate argc -= optind; 1970Sstevel@tonic-gate argv += optind; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || 2000Sstevel@tonic-gate (aflag && (!xflag && !Sflag))) { 2010Sstevel@tonic-gate errflg = 1; 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (errflg || argc <= 0) { 2050Sstevel@tonic-gate (void) fprintf(stderr, 2060Sstevel@tonic-gate "usage:\t%s [-rslF] { pid | core } ...\n", command); 2070Sstevel@tonic-gate (void) fprintf(stderr, 2080Sstevel@tonic-gate "\t\t(report process address maps)\n"); 2090Sstevel@tonic-gate (void) fprintf(stderr, 2100Sstevel@tonic-gate "\t%s -x [-aslF] pid ...\n", command); 2110Sstevel@tonic-gate (void) fprintf(stderr, 2120Sstevel@tonic-gate "\t\t(show resident/anon/locked mapping details)\n"); 2130Sstevel@tonic-gate (void) fprintf(stderr, 2140Sstevel@tonic-gate "\t%s -S [-alF] { pid | core } ...\n", command); 2150Sstevel@tonic-gate (void) fprintf(stderr, 2160Sstevel@tonic-gate "\t\t(show swap reservations)\n\n"); 2170Sstevel@tonic-gate (void) fprintf(stderr, 2180Sstevel@tonic-gate "\t-a: include shared mappings in -[xS] summary\n"); 2190Sstevel@tonic-gate (void) fprintf(stderr, 2200Sstevel@tonic-gate "\t-r: show reserved address maps\n"); 2210Sstevel@tonic-gate (void) fprintf(stderr, 2220Sstevel@tonic-gate "\t-s: show hardware page sizes\n"); 2230Sstevel@tonic-gate (void) fprintf(stderr, 2240Sstevel@tonic-gate "\t-l: show unresolved dynamic linker map names\n"); 2250Sstevel@tonic-gate (void) fprintf(stderr, 2260Sstevel@tonic-gate "\t-F: force grabbing of the target process\n"); 2270Sstevel@tonic-gate return (2); 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 2320Sstevel@tonic-gate * that has many many mappings. 2330Sstevel@tonic-gate */ 2340Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 2350Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 2360Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 237*1914Scasper (void) enable_extended_FILE_stdio(-1, -1); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate while (argc-- > 0) { 2410Sstevel@tonic-gate char *arg; 2420Sstevel@tonic-gate int gcode; 2430Sstevel@tonic-gate psinfo_t psinfo; 2440Sstevel@tonic-gate int tries = 0; 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, 2470Sstevel@tonic-gate PGRAB_RDONLY, &gcode)) == NULL) { 2480Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 2490Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 2500Sstevel@tonic-gate rc++; 2510Sstevel@tonic-gate continue; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate procname = arg; /* for perr() */ 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 2570Sstevel@tonic-gate size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 2580Sstevel@tonic-gate bar = addr_width == 8 ? bar8 : bar16; 2590Sstevel@tonic-gate (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 2600Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 2630Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2640Sstevel@tonic-gate "/proc/%d/map", (int)psinfo.pr_pid); 2650Sstevel@tonic-gate if ((mapfd = open(buf, O_RDONLY)) < 0) { 2660Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 2670Sstevel@tonic-gate "examine %s: lost control of " 2680Sstevel@tonic-gate "process\n", command, arg); 2690Sstevel@tonic-gate rc++; 2700Sstevel@tonic-gate Prelease(Pr, 0); 2710Sstevel@tonic-gate continue; 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate } else { 2740Sstevel@tonic-gate mapfd = -1; 2750Sstevel@tonic-gate } 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate again: 2780Sstevel@tonic-gate map_count = 0; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 2810Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 2820Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate if (rflag || sflag || xflag || Sflag) { 2850Sstevel@tonic-gate (void) printf(" -%c option is not compatible " 2860Sstevel@tonic-gate "with core files\n", xflag ? 'x' : 2870Sstevel@tonic-gate sflag ? 's' : rflag ? 'r' : 'S'); 2880Sstevel@tonic-gate Prelease(Pr, 0); 2890Sstevel@tonic-gate rc++; 2900Sstevel@tonic-gate continue; 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate } else { 2940Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 2950Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 2990Sstevel@tonic-gate struct totals t; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /* 3020Sstevel@tonic-gate * Since we're grabbing the process readonly, we need 3030Sstevel@tonic-gate * to make sure the address space doesn't change during 3040Sstevel@tonic-gate * execution. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 3070Sstevel@tonic-gate if (tries++ == MAX_TRIES) { 3080Sstevel@tonic-gate Prelease(Pr, 0); 3090Sstevel@tonic-gate (void) close(mapfd); 3100Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 3110Sstevel@tonic-gate "examine %s: address space is " 3120Sstevel@tonic-gate "changing\n", command, arg); 3130Sstevel@tonic-gate continue; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate if (fstat64(mapfd, &statbuf) != 0) { 3170Sstevel@tonic-gate Prelease(Pr, 0); 3180Sstevel@tonic-gate (void) close(mapfd); 3190Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 3200Sstevel@tonic-gate "examine %s: lost control of " 3210Sstevel@tonic-gate "process\n", command, arg); 3220Sstevel@tonic-gate continue; 3230Sstevel@tonic-gate } 3240Sstevel@tonic-gate } 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate nstacks = psinfo.pr_nlwp * 2; 3270Sstevel@tonic-gate stacks = calloc(nstacks, sizeof (stacks[0])); 3280Sstevel@tonic-gate if (stacks != NULL) { 3290Sstevel@tonic-gate int n = 0; 3300Sstevel@tonic-gate (void) Plwp_iter(Pr, getstack, &n); 3310Sstevel@tonic-gate qsort(stacks, nstacks, sizeof (stacks[0]), 3320Sstevel@tonic-gate cmpstacks); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate (void) memset(&t, 0, sizeof (t)); 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && 3380Sstevel@tonic-gate Prd_agent(Pr) == NULL) { 3390Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: " 3400Sstevel@tonic-gate "librtld_db failed to initialize; " 3410Sstevel@tonic-gate "shared library information will not be " 3420Sstevel@tonic-gate "available\n", command); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * Gather data 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate if (xflag) 3490Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 0); 3500Sstevel@tonic-gate else if (Sflag) 3510Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 1); 3520Sstevel@tonic-gate else { 3530Sstevel@tonic-gate if (rflag) 3540Sstevel@tonic-gate rc += rmapping_iter(Pr, gather_map, 3550Sstevel@tonic-gate NULL); 3560Sstevel@tonic-gate else if (sflag) 3570Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, 3580Sstevel@tonic-gate NULL, 0); 3590Sstevel@tonic-gate else 3600Sstevel@tonic-gate rc += Pmapping_iter(Pr, gather_map, 3610Sstevel@tonic-gate NULL); 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Ensure mappings are consistent. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 3680Sstevel@tonic-gate struct stat64 newbuf; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate if (fstat64(mapfd, &newbuf) != 0 || 3710Sstevel@tonic-gate memcmp(&newbuf.st_mtim, &statbuf.st_mtim, 3720Sstevel@tonic-gate sizeof (newbuf.st_mtim)) != 0) { 3730Sstevel@tonic-gate if (stacks != NULL) { 3740Sstevel@tonic-gate free(stacks); 3750Sstevel@tonic-gate stacks = NULL; 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate goto again; 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Display data. 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate if (xflag) { 3850Sstevel@tonic-gate (void) printf("%*s%*s%*s%*s%*s " 3860Sstevel@tonic-gate "%sMode Mapped File\n", 3870Sstevel@tonic-gate addr_width, "Address", 3880Sstevel@tonic-gate size_width, "Kbytes", 3890Sstevel@tonic-gate size_width, "RSS", 3900Sstevel@tonic-gate size_width, "Anon", 3910Sstevel@tonic-gate size_width, "Locked", 3920Sstevel@tonic-gate sflag ? "Pgsz " : ""); 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate rc += iter_xmap(sflag ? look_xmap : 3950Sstevel@tonic-gate look_xmap_nopgsz, &t); 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate (void) printf("%s%s %s %s %s %s\n", 3980Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 3990Sstevel@tonic-gate bar, bar, bar, bar, bar); 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 4020Sstevel@tonic-gate " " : ""); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate printK(t.total_size, size_width); 4050Sstevel@tonic-gate printK(t.total_rss, size_width); 4060Sstevel@tonic-gate printK(t.total_anon, size_width); 4070Sstevel@tonic-gate printK(t.total_locked, size_width); 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate (void) printf("\n"); 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate } else if (Sflag) { 4120Sstevel@tonic-gate (void) printf("%*s%*s%*s Mode Mapped File\n", 4130Sstevel@tonic-gate addr_width, "Address", 4140Sstevel@tonic-gate size_width, "Kbytes", 4150Sstevel@tonic-gate size_width, "Swap"); 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate rc += iter_xmap(look_xmap_nopgsz, &t); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate (void) printf("%s%s %s %s\n", 4200Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 4210Sstevel@tonic-gate bar, bar, bar); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 4240Sstevel@tonic-gate " " : ""); 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate printK(t.total_size, size_width); 4270Sstevel@tonic-gate printK(t.total_swap, size_width); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate (void) printf("\n"); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate } else { 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if (rflag) { 4340Sstevel@tonic-gate rc += iter_map(look_map, &t); 4350Sstevel@tonic-gate } else if (sflag) { 4360Sstevel@tonic-gate (void) printf("%*s %*s %4s %-6s %s\n", 4370Sstevel@tonic-gate addr_width, "Address", size_width, 4380Sstevel@tonic-gate "Bytes", "Pgsz", "Mode ", 4390Sstevel@tonic-gate "Mapped File"); 4400Sstevel@tonic-gate rc += iter_xmap(look_smap, &t); 4410Sstevel@tonic-gate } else { 4420Sstevel@tonic-gate rc += iter_map(look_map, &t); 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate (void) printf(" %stotal %*luK\n", 4460Sstevel@tonic-gate addr_width == 16 ? 4470Sstevel@tonic-gate " " : "", 4480Sstevel@tonic-gate size_width, t.total_size); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate if (stacks != NULL) { 4520Sstevel@tonic-gate free(stacks); 4530Sstevel@tonic-gate stacks = NULL; 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate } 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate Prelease(Pr, 0); 4590Sstevel@tonic-gate if (mapfd != -1) 4600Sstevel@tonic-gate (void) close(mapfd); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate return (rc); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate static char * 4670Sstevel@tonic-gate make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 4680Sstevel@tonic-gate char *buf, size_t bufsz) 4690Sstevel@tonic-gate { 4700Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 4710Sstevel@tonic-gate char fname[100]; 4720Sstevel@tonic-gate struct stat statb; 4730Sstevel@tonic-gate int len; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if (!lflag && strcmp(mapname, "a.out") == 0 && 4760Sstevel@tonic-gate Pexecname(Pr, buf, bufsz) != NULL) 4770Sstevel@tonic-gate return (buf); 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate if (Pobjname(Pr, addr, buf, bufsz) != NULL) { 4800Sstevel@tonic-gate if (lflag) 4810Sstevel@tonic-gate return (buf); 4820Sstevel@tonic-gate if ((len = resolvepath(buf, buf, bufsz)) > 0) { 4830Sstevel@tonic-gate buf[len] = '\0'; 4840Sstevel@tonic-gate return (buf); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD && *mapname != '\0') { 4890Sstevel@tonic-gate (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s", 4900Sstevel@tonic-gate (int)Psp->pr_pid, mapname); 4910Sstevel@tonic-gate if (stat(fname, &statb) == 0) { 4920Sstevel@tonic-gate dev_t dev = statb.st_dev; 4930Sstevel@tonic-gate ino_t ino = statb.st_ino; 4940Sstevel@tonic-gate (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", 4950Sstevel@tonic-gate (ulong_t)major(dev), (ulong_t)minor(dev), ino); 4960Sstevel@tonic-gate return (buf); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate } 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate return (NULL); 5010Sstevel@tonic-gate } 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate static char * 5040Sstevel@tonic-gate anon_name(char *name, const pstatus_t *Psp, 5050Sstevel@tonic-gate uintptr_t vaddr, size_t size, int mflags, int shmid) 5060Sstevel@tonic-gate { 5070Sstevel@tonic-gate if (mflags & MA_ISM) { 5080Sstevel@tonic-gate if (shmid == -1) 5090Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 5100Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism"); 5110Sstevel@tonic-gate else 5120Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 5130Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 5140Sstevel@tonic-gate } else if (mflags & MA_SHM) { 5150Sstevel@tonic-gate if (shmid == -1) 5160Sstevel@tonic-gate (void) sprintf(name, " [ shmid=null ]"); 5170Sstevel@tonic-gate else 5180Sstevel@tonic-gate (void) sprintf(name, " [ shmid=0x%x ]", shmid); 5190Sstevel@tonic-gate } else if (vaddr + size > Psp->pr_stkbase && 5200Sstevel@tonic-gate vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 5210Sstevel@tonic-gate (void) strcpy(name, " [ stack ]"); 5220Sstevel@tonic-gate } else if ((mflags & MA_ANON) && 5230Sstevel@tonic-gate vaddr + size > Psp->pr_brkbase && 5240Sstevel@tonic-gate vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 5250Sstevel@tonic-gate (void) strcpy(name, " [ heap ]"); 5260Sstevel@tonic-gate } else { 5270Sstevel@tonic-gate lwpstack_t key, *stk; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate key.lwps_stack.ss_sp = (void *)vaddr; 5300Sstevel@tonic-gate key.lwps_stack.ss_size = size; 5310Sstevel@tonic-gate if (nstacks > 0 && 5320Sstevel@tonic-gate (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 5330Sstevel@tonic-gate cmpstacks)) != NULL) { 5340Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 5350Sstevel@tonic-gate (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 5360Sstevel@tonic-gate "altstack" : "stack", 5370Sstevel@tonic-gate stk->lwps_lwpid); 5380Sstevel@tonic-gate } else if (Pstate(Pr) != PS_DEAD) { 5390Sstevel@tonic-gate (void) strcpy(name, " [ anon ]"); 5400Sstevel@tonic-gate } else { 5410Sstevel@tonic-gate return (NULL); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate return (name); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate static int 5490Sstevel@tonic-gate rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd) 5500Sstevel@tonic-gate { 5510Sstevel@tonic-gate char mapname[PATH_MAX]; 5520Sstevel@tonic-gate int mapfd, nmap, i, rc; 5530Sstevel@tonic-gate struct stat st; 5540Sstevel@tonic-gate prmap_t *prmapp, *pmp; 5550Sstevel@tonic-gate ssize_t n; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 5580Sstevel@tonic-gate "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid); 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 5610Sstevel@tonic-gate if (mapfd >= 0) 5620Sstevel@tonic-gate (void) close(mapfd); 5630Sstevel@tonic-gate return (perr(mapname)); 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate nmap = st.st_size / sizeof (prmap_t); 5670Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prmap_t)); 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) { 5700Sstevel@tonic-gate (void) close(mapfd); 5710Sstevel@tonic-gate free(prmapp); 5720Sstevel@tonic-gate return (perr("read rmap")); 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate (void) close(mapfd); 5760Sstevel@tonic-gate nmap = n / sizeof (prmap_t); 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 5790Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL)) != 0) { 5800Sstevel@tonic-gate free(prmapp); 5810Sstevel@tonic-gate return (rc); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate free(prmapp); 5860Sstevel@tonic-gate return (0); 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate static int 5900Sstevel@tonic-gate xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap) 5910Sstevel@tonic-gate { 5920Sstevel@tonic-gate char mapname[PATH_MAX]; 5930Sstevel@tonic-gate int mapfd, nmap, i, rc; 5940Sstevel@tonic-gate struct stat st; 5950Sstevel@tonic-gate prxmap_t *prmapp, *pmp; 5960Sstevel@tonic-gate ssize_t n; 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 5990Sstevel@tonic-gate "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid); 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 6020Sstevel@tonic-gate if (mapfd >= 0) 6030Sstevel@tonic-gate (void) close(mapfd); 6040Sstevel@tonic-gate return (perr(mapname)); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate nmap = st.st_size / sizeof (prxmap_t); 6080Sstevel@tonic-gate nmap *= 2; 6090Sstevel@tonic-gate again: 6100Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prxmap_t)); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) { 6130Sstevel@tonic-gate (void) close(mapfd); 6140Sstevel@tonic-gate free(prmapp); 6150Sstevel@tonic-gate return (perr("read xmap")); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (nmap < n / sizeof (prxmap_t)) { 6190Sstevel@tonic-gate free(prmapp); 6200Sstevel@tonic-gate nmap *= 2; 6210Sstevel@tonic-gate goto again; 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate (void) close(mapfd); 6250Sstevel@tonic-gate nmap = n / sizeof (prxmap_t); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 6280Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) { 6290Sstevel@tonic-gate free(prmapp); 6300Sstevel@tonic-gate return (rc); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate free(prmapp); 6350Sstevel@tonic-gate return (0); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /*ARGSUSED*/ 6390Sstevel@tonic-gate static int 6400Sstevel@tonic-gate look_map(void *data, const prmap_t *pmp, const char *object_name) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate struct totals *t = data; 6430Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 6440Sstevel@tonic-gate size_t size = (pmp->pr_size + 1023) / 1024; 6450Sstevel@tonic-gate char mname[PATH_MAX]; 6460Sstevel@tonic-gate char *lname = NULL; 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate /* 6490Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 6500Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 6530Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 6540Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 6550Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 6560Sstevel@tonic-gate mname, sizeof (mname)); 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate if (lname == NULL && 6600Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 6610Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 6620Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate (void) printf(lname ? "%.*lX %*luK %-6s %s\n" : "%.*lX %*luK %s\n", 6660Sstevel@tonic-gate addr_width, (uintptr_t)pmp->pr_vaddr, 6670Sstevel@tonic-gate size_width - 1, size, mflags(pmp->pr_mflags), lname); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate t->total_size += size; 6700Sstevel@tonic-gate return (0); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate static void 6740Sstevel@tonic-gate printK(long value, int width) 6750Sstevel@tonic-gate { 6760Sstevel@tonic-gate if (value == 0) 6770Sstevel@tonic-gate (void) printf(width == 8 ? " -" : " -"); 6780Sstevel@tonic-gate else 6790Sstevel@tonic-gate (void) printf(" %*lu", width - 1, value); 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate static const char * 6830Sstevel@tonic-gate pagesize(const prxmap_t *pmp) 6840Sstevel@tonic-gate { 6850Sstevel@tonic-gate int pagesize = pmp->pr_hatpagesize; 6860Sstevel@tonic-gate static char buf[32]; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate if (pagesize == 0) { 6890Sstevel@tonic-gate return ("-"); /* no underlying HAT mapping */ 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate if (pagesize >= 1024 && (pagesize % 1024) == 0) { 6930Sstevel@tonic-gate if ((pagesize % (1024 * 1024 * 1024)) == 0) 6940Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dG", 6950Sstevel@tonic-gate pagesize / (1024 * 1024 * 1024)); 6960Sstevel@tonic-gate else if ((pagesize % (1024 * 1024)) == 0) 6970Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dM", 6980Sstevel@tonic-gate pagesize / (1024 * 1024)); 6990Sstevel@tonic-gate else 7000Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dK", 7010Sstevel@tonic-gate pagesize / 1024); 7020Sstevel@tonic-gate } else 7030Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%db", pagesize); 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate return (buf); 7060Sstevel@tonic-gate } 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /*ARGSUSED*/ 7090Sstevel@tonic-gate static int 7100Sstevel@tonic-gate look_smap(void *data, 7110Sstevel@tonic-gate const prxmap_t *pmp, 7120Sstevel@tonic-gate const char *object_name, 7130Sstevel@tonic-gate int last, int doswap) 7140Sstevel@tonic-gate { 7150Sstevel@tonic-gate struct totals *t = data; 7160Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 7170Sstevel@tonic-gate size_t size = (pmp->pr_size + 1023) / 1024; 7180Sstevel@tonic-gate char mname[PATH_MAX]; 7190Sstevel@tonic-gate char *lname = NULL; 7200Sstevel@tonic-gate const char *format; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 7240Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 7250Sstevel@tonic-gate */ 7260Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 7270Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 7280Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 7290Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 7300Sstevel@tonic-gate mname, sizeof (mname)); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate if (lname == NULL && 7340Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 7350Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 7360Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate if (lname != NULL) 7400Sstevel@tonic-gate format = "%.*lX %*luK %4s %-6s %s\n"; 7410Sstevel@tonic-gate else 7420Sstevel@tonic-gate format = "%.*lX %*luK %4s %s\n"; 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate (void) printf(format, addr_width, (uintptr_t)pmp->pr_vaddr, 7450Sstevel@tonic-gate size_width - 1, size, 7460Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate t->total_size += size; 7490Sstevel@tonic-gate return (0); 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate #define ANON(x) ((aflag || (((x)->pr_mflags & MA_SHARED) == 0)) ? \ 7530Sstevel@tonic-gate ((x)->pr_anon) : 0) 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate /*ARGSUSED*/ 7560Sstevel@tonic-gate static int 7570Sstevel@tonic-gate look_xmap(void *data, 7580Sstevel@tonic-gate const prxmap_t *pmp, 7590Sstevel@tonic-gate const char *object_name, 7600Sstevel@tonic-gate int last, int doswap) 7610Sstevel@tonic-gate { 7620Sstevel@tonic-gate struct totals *t = data; 7630Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 7640Sstevel@tonic-gate char mname[PATH_MAX]; 7650Sstevel@tonic-gate char *lname = NULL; 7660Sstevel@tonic-gate char *ln; 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate /* 7690Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 7700Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 7710Sstevel@tonic-gate */ 7720Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 7730Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 7740Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 7750Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 7760Sstevel@tonic-gate mname, sizeof (mname)); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate if (lname != NULL) { 7800Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 7810Sstevel@tonic-gate lname = ln + 1; 7820Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 7830Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 7840Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate printK((pmp->pr_size + 1023) / 1024, size_width); 7900Sstevel@tonic-gate printK(pmp->pr_rss * (pmp->pr_pagesize / 1024), size_width); 7910Sstevel@tonic-gate printK(ANON(pmp) * (pmp->pr_pagesize / 1024), size_width); 7920Sstevel@tonic-gate printK(pmp->pr_locked * (pmp->pr_pagesize / 1024), size_width); 7930Sstevel@tonic-gate (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n", 7940Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate t->total_size += (pmp->pr_size + 1023) / 1024; 7970Sstevel@tonic-gate t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / 1024); 7980Sstevel@tonic-gate t->total_anon += ANON(pmp) * (pmp->pr_pagesize / 1024); 7990Sstevel@tonic-gate t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / 1024)); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate return (0); 8020Sstevel@tonic-gate } 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate /*ARGSUSED*/ 8050Sstevel@tonic-gate static int 8060Sstevel@tonic-gate look_xmap_nopgsz(void *data, 8070Sstevel@tonic-gate const prxmap_t *pmp, 8080Sstevel@tonic-gate const char *object_name, 8090Sstevel@tonic-gate int last, int doswap) 8100Sstevel@tonic-gate { 8110Sstevel@tonic-gate struct totals *t = data; 8120Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 8130Sstevel@tonic-gate char mname[PATH_MAX]; 8140Sstevel@tonic-gate char *lname = NULL; 8150Sstevel@tonic-gate char *ln; 8160Sstevel@tonic-gate static uintptr_t prev_vaddr; 8170Sstevel@tonic-gate static size_t prev_size; 8180Sstevel@tonic-gate static offset_t prev_offset; 8190Sstevel@tonic-gate static int prev_mflags; 8200Sstevel@tonic-gate static char *prev_lname; 8210Sstevel@tonic-gate static char prev_mname[PATH_MAX]; 8220Sstevel@tonic-gate static ulong_t prev_rss; 8230Sstevel@tonic-gate static ulong_t prev_anon; 8240Sstevel@tonic-gate static ulong_t prev_locked; 8250Sstevel@tonic-gate static ulong_t prev_swap; 8260Sstevel@tonic-gate int merged = 0; 8270Sstevel@tonic-gate static int first = 1; 8280Sstevel@tonic-gate ulong_t swap = 0; 8290Sstevel@tonic-gate int kperpage; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* 8320Sstevel@tonic-gate * Calculate swap reservations 8330Sstevel@tonic-gate */ 8340Sstevel@tonic-gate if (pmp->pr_mflags & MA_SHARED) { 8350Sstevel@tonic-gate if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) { 8360Sstevel@tonic-gate /* Swap reserved for entire non-ism SHM */ 8370Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_NORESERVE) { 8400Sstevel@tonic-gate /* Swap reserved on fault for each anon page */ 8410Sstevel@tonic-gate swap = pmp->pr_anon; 8420Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_WRITE) { 8430Sstevel@tonic-gate /* Swap reserve for entire writable segment */ 8440Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate /* 8480Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 8490Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 8520Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 8530Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 8540Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 8550Sstevel@tonic-gate mname, sizeof (mname)); 8560Sstevel@tonic-gate } 8570Sstevel@tonic-gate 8580Sstevel@tonic-gate if (lname != NULL) { 8590Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 8600Sstevel@tonic-gate lname = ln + 1; 8610Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 8620Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 8630Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 8640Sstevel@tonic-gate } 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate kperpage = pmp->pr_pagesize / 1024; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate t->total_size += (pmp->pr_size + 1023) / 1024; 8690Sstevel@tonic-gate t->total_rss += pmp->pr_rss * kperpage; 8700Sstevel@tonic-gate t->total_anon += ANON(pmp) * kperpage; 8710Sstevel@tonic-gate t->total_locked += pmp->pr_locked * kperpage; 8720Sstevel@tonic-gate t->total_swap += swap * kperpage; 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate if (first == 1) { 8750Sstevel@tonic-gate first = 0; 8760Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 8770Sstevel@tonic-gate prev_size = pmp->pr_size; 8780Sstevel@tonic-gate prev_offset = pmp->pr_offset; 8790Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 8800Sstevel@tonic-gate if (lname == NULL) { 8810Sstevel@tonic-gate prev_lname = NULL; 8820Sstevel@tonic-gate } else { 8830Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 8840Sstevel@tonic-gate prev_lname = prev_mname; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 8870Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 8880Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 8890Sstevel@tonic-gate prev_swap = swap * kperpage; 8900Sstevel@tonic-gate if (last == 0) { 8910Sstevel@tonic-gate return (0); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate merged = 1; 8940Sstevel@tonic-gate } else if (prev_vaddr + prev_size == pmp->pr_vaddr && 8950Sstevel@tonic-gate prev_mflags == pmp->pr_mflags && 8960Sstevel@tonic-gate ((prev_mflags & MA_ISM) || 8970Sstevel@tonic-gate prev_offset + prev_size == pmp->pr_offset) && 8980Sstevel@tonic-gate ((lname == NULL && prev_lname == NULL) || 8990Sstevel@tonic-gate (lname != NULL && prev_lname != NULL && 9000Sstevel@tonic-gate strcmp(lname, prev_lname) == 0))) { 9010Sstevel@tonic-gate prev_size += pmp->pr_size; 9020Sstevel@tonic-gate prev_rss += pmp->pr_rss * kperpage; 9030Sstevel@tonic-gate prev_anon += ANON(pmp) * kperpage; 9040Sstevel@tonic-gate prev_locked += pmp->pr_locked * kperpage; 9050Sstevel@tonic-gate prev_swap += swap * kperpage; 9060Sstevel@tonic-gate if (last == 0) { 9070Sstevel@tonic-gate return (0); 9080Sstevel@tonic-gate } 9090Sstevel@tonic-gate merged = 1; 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr); 9130Sstevel@tonic-gate printK((prev_size + 1023) / 1024, size_width); 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate if (doswap) 9160Sstevel@tonic-gate printK(prev_swap, size_width); 9170Sstevel@tonic-gate else { 9180Sstevel@tonic-gate printK(prev_rss, size_width); 9190Sstevel@tonic-gate printK(prev_anon, size_width); 9200Sstevel@tonic-gate printK(prev_locked, size_width); 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate (void) printf(prev_lname ? " %-6s %s\n" : " %s\n", 9230Sstevel@tonic-gate mflags(prev_mflags), prev_lname); 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate if (last == 0) { 9260Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 9270Sstevel@tonic-gate prev_size = pmp->pr_size; 9280Sstevel@tonic-gate prev_offset = pmp->pr_offset; 9290Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 9300Sstevel@tonic-gate if (lname == NULL) { 9310Sstevel@tonic-gate prev_lname = NULL; 9320Sstevel@tonic-gate } else { 9330Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 9340Sstevel@tonic-gate prev_lname = prev_mname; 9350Sstevel@tonic-gate } 9360Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 9370Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 9380Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 9390Sstevel@tonic-gate prev_swap = swap * kperpage; 9400Sstevel@tonic-gate } else if (merged == 0) { 9410Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 9420Sstevel@tonic-gate printK((pmp->pr_size + 1023) / 1024, size_width); 9430Sstevel@tonic-gate if (doswap) 9440Sstevel@tonic-gate printK(swap * kperpage, size_width); 9450Sstevel@tonic-gate else { 9460Sstevel@tonic-gate printK(pmp->pr_rss * kperpage, size_width); 9470Sstevel@tonic-gate printK(ANON(pmp) * kperpage, size_width); 9480Sstevel@tonic-gate printK(pmp->pr_locked * kperpage, size_width); 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate (void) printf(lname ? " %-6s %s\n" : " %s\n", 9510Sstevel@tonic-gate mflags(pmp->pr_mflags), lname); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate if (last != 0) 9550Sstevel@tonic-gate first = 1; 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate return (0); 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate static int 9610Sstevel@tonic-gate perr(char *s) 9620Sstevel@tonic-gate { 9630Sstevel@tonic-gate if (s) 9640Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 9650Sstevel@tonic-gate else 9660Sstevel@tonic-gate s = procname; 9670Sstevel@tonic-gate perror(s); 9680Sstevel@tonic-gate return (1); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate static char * 9720Sstevel@tonic-gate mflags(uint_t arg) 9730Sstevel@tonic-gate { 9740Sstevel@tonic-gate static char code_buf[80]; 9750Sstevel@tonic-gate char *str = code_buf; 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * rwxsR 9790Sstevel@tonic-gate * 9800Sstevel@tonic-gate * r - segment is readable 9810Sstevel@tonic-gate * w - segment is writable 9820Sstevel@tonic-gate * x - segment is executable 9830Sstevel@tonic-gate * s - segment is shared 9840Sstevel@tonic-gate * R - segment is mapped MAP_NORESERVE 9850Sstevel@tonic-gate * 9860Sstevel@tonic-gate */ 9870Sstevel@tonic-gate (void) sprintf(str, "%c%c%c%c%c%c", 9880Sstevel@tonic-gate arg & MA_READ ? 'r' : '-', 9890Sstevel@tonic-gate arg & MA_WRITE ? 'w' : '-', 9900Sstevel@tonic-gate arg & MA_EXEC ? 'x' : '-', 9910Sstevel@tonic-gate arg & MA_SHARED ? 's' : '-', 9920Sstevel@tonic-gate arg & MA_NORESERVE ? 'R' : '-', 9930Sstevel@tonic-gate arg & MA_RESERVED1 ? '*' : ' '); 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate return (str); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate static mapdata_t * 9990Sstevel@tonic-gate nextmap(void) 10000Sstevel@tonic-gate { 10010Sstevel@tonic-gate mapdata_t *newmaps; 10020Sstevel@tonic-gate int next; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate if (map_count == map_alloc) { 10050Sstevel@tonic-gate if (map_alloc == 0) 10060Sstevel@tonic-gate next = 16; 10070Sstevel@tonic-gate else 10080Sstevel@tonic-gate next = map_alloc * 2; 10090Sstevel@tonic-gate 10100Sstevel@tonic-gate newmaps = realloc(maps, next * sizeof (mapdata_t)); 10110Sstevel@tonic-gate if (newmaps == NULL) { 10120Sstevel@tonic-gate (void) perr("failed to allocate maps"); 10130Sstevel@tonic-gate exit(1); 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate (void) memset(newmaps + map_alloc, '\0', 10160Sstevel@tonic-gate (next - map_alloc) * sizeof (mapdata_t)); 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate map_alloc = next; 10190Sstevel@tonic-gate maps = newmaps; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate return (&maps[map_count++]); 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate /*ARGSUSED*/ 10260Sstevel@tonic-gate static int 10270Sstevel@tonic-gate gather_map(void *ignored, const prmap_t *map, const char *objname) 10280Sstevel@tonic-gate { 10290Sstevel@tonic-gate mapdata_t *data = nextmap(); 10300Sstevel@tonic-gate 10310Sstevel@tonic-gate data->md_map = *map; 10320Sstevel@tonic-gate if (data->md_objname != NULL) 10330Sstevel@tonic-gate free(data->md_objname); 10340Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate return (0); 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate /*ARGSUSED*/ 10400Sstevel@tonic-gate static int 10410Sstevel@tonic-gate gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname, 10420Sstevel@tonic-gate int last, int doswap) 10430Sstevel@tonic-gate { 10440Sstevel@tonic-gate mapdata_t *data = nextmap(); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate data->md_xmap = *xmap; 10470Sstevel@tonic-gate if (data->md_objname != NULL) 10480Sstevel@tonic-gate free(data->md_objname); 10490Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 10500Sstevel@tonic-gate data->md_last = last; 10510Sstevel@tonic-gate data->md_doswap = doswap; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate return (0); 10540Sstevel@tonic-gate } 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate static int 10570Sstevel@tonic-gate iter_map(proc_map_f *func, void *data) 10580Sstevel@tonic-gate { 10590Sstevel@tonic-gate int i; 10600Sstevel@tonic-gate int ret; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 10630Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_map, 10640Sstevel@tonic-gate maps[i].md_objname)) != 0) 10650Sstevel@tonic-gate return (ret); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate return (0); 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate static int 10720Sstevel@tonic-gate iter_xmap(proc_xmap_f *func, void *data) 10730Sstevel@tonic-gate { 10740Sstevel@tonic-gate int i; 10750Sstevel@tonic-gate int ret; 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 10780Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname, 10790Sstevel@tonic-gate maps[i].md_last, maps[i].md_doswap)) != 0) 10800Sstevel@tonic-gate return (ret); 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate return (0); 10840Sstevel@tonic-gate } 1085