1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <unistd.h> 32*0Sstevel@tonic-gate #include <ctype.h> 33*0Sstevel@tonic-gate #include <fcntl.h> 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <dirent.h> 36*0Sstevel@tonic-gate #include <limits.h> 37*0Sstevel@tonic-gate #include <link.h> 38*0Sstevel@tonic-gate #include <libelf.h> 39*0Sstevel@tonic-gate #include <sys/types.h> 40*0Sstevel@tonic-gate #include <sys/stat.h> 41*0Sstevel@tonic-gate #include <sys/mkdev.h> 42*0Sstevel@tonic-gate #include <libproc.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate struct totals { 45*0Sstevel@tonic-gate ulong_t total_size; 46*0Sstevel@tonic-gate ulong_t total_swap; 47*0Sstevel@tonic-gate ulong_t total_rss; 48*0Sstevel@tonic-gate ulong_t total_anon; 49*0Sstevel@tonic-gate ulong_t total_locked; 50*0Sstevel@tonic-gate }; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int); 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate static int xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *, 55*0Sstevel@tonic-gate int); 56*0Sstevel@tonic-gate static int rmapping_iter(struct ps_prochandle *, proc_map_f *, void *); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate static int look_map(void *, const prmap_t *, const char *); 59*0Sstevel@tonic-gate static int look_smap(void *, const prxmap_t *, const char *, int, int); 60*0Sstevel@tonic-gate static int look_xmap(void *, const prxmap_t *, const char *, int, int); 61*0Sstevel@tonic-gate static int look_xmap_nopgsz(void *, const prxmap_t *, const char *, 62*0Sstevel@tonic-gate int, int); 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate static int gather_map(void *, const prmap_t *, const char *); 65*0Sstevel@tonic-gate static int gather_xmap(void *, const prxmap_t *, const char *, int, int); 66*0Sstevel@tonic-gate static int iter_map(proc_map_f *, void *); 67*0Sstevel@tonic-gate static int iter_xmap(proc_xmap_f *, void *); 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate static int perr(char *); 70*0Sstevel@tonic-gate static void printK(long, int); 71*0Sstevel@tonic-gate static char *mflags(uint_t); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static int lflag = 0; 74*0Sstevel@tonic-gate static int aflag = 0; 75*0Sstevel@tonic-gate static int addr_width, size_width; 76*0Sstevel@tonic-gate static char *command; 77*0Sstevel@tonic-gate static char *procname; 78*0Sstevel@tonic-gate static struct ps_prochandle *Pr; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate typedef struct lwpstack { 81*0Sstevel@tonic-gate lwpid_t lwps_lwpid; 82*0Sstevel@tonic-gate stack_t lwps_stack; 83*0Sstevel@tonic-gate } lwpstack_t; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate typedef struct { 86*0Sstevel@tonic-gate prxmap_t md_xmap; 87*0Sstevel@tonic-gate prmap_t md_map; 88*0Sstevel@tonic-gate char *md_objname; 89*0Sstevel@tonic-gate int md_last; 90*0Sstevel@tonic-gate int md_doswap; 91*0Sstevel@tonic-gate } mapdata_t; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate static mapdata_t *maps; 94*0Sstevel@tonic-gate static int map_count; 95*0Sstevel@tonic-gate static int map_alloc; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate static lwpstack_t *stacks = NULL; 98*0Sstevel@tonic-gate static uint_t nstacks = 0; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate #define MAX_TRIES 5 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate static int 103*0Sstevel@tonic-gate getstack(void *data, const lwpstatus_t *lsp) 104*0Sstevel@tonic-gate { 105*0Sstevel@tonic-gate int *np = (int *)data; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 108*0Sstevel@tonic-gate stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 109*0Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 110*0Sstevel@tonic-gate (*np)++; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 114*0Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 115*0Sstevel@tonic-gate (*np)++; 116*0Sstevel@tonic-gate } 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate return (0); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * We compare the high memory addresses since stacks are faulted in from 123*0Sstevel@tonic-gate * high memory addresses to low memory addresses, and our prmap_t 124*0Sstevel@tonic-gate * structures identify only the range of addresses that have been faulted 125*0Sstevel@tonic-gate * in so far. 126*0Sstevel@tonic-gate */ 127*0Sstevel@tonic-gate static int 128*0Sstevel@tonic-gate cmpstacks(const void *ap, const void *bp) 129*0Sstevel@tonic-gate { 130*0Sstevel@tonic-gate const lwpstack_t *as = ap; 131*0Sstevel@tonic-gate const lwpstack_t *bs = bp; 132*0Sstevel@tonic-gate uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 133*0Sstevel@tonic-gate uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate if (a < b) 136*0Sstevel@tonic-gate return (1); 137*0Sstevel@tonic-gate if (a > b) 138*0Sstevel@tonic-gate return (-1); 139*0Sstevel@tonic-gate return (0); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate int 144*0Sstevel@tonic-gate main(int argc, char **argv) 145*0Sstevel@tonic-gate { 146*0Sstevel@tonic-gate int rflag = 0, sflag = 0, xflag = 0; 147*0Sstevel@tonic-gate int errflg = 0, Sflag = 0; 148*0Sstevel@tonic-gate int rc = 0; 149*0Sstevel@tonic-gate int opt; 150*0Sstevel@tonic-gate const char *bar8 = "-------"; 151*0Sstevel@tonic-gate const char *bar16 = "----------"; 152*0Sstevel@tonic-gate const char *bar; 153*0Sstevel@tonic-gate struct rlimit rlim; 154*0Sstevel@tonic-gate struct stat64 statbuf; 155*0Sstevel@tonic-gate char buf[128]; 156*0Sstevel@tonic-gate int mapfd; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 159*0Sstevel@tonic-gate command++; 160*0Sstevel@tonic-gate else 161*0Sstevel@tonic-gate command = argv[0]; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate while ((opt = getopt(argc, argv, "arsxSlF")) != EOF) { 164*0Sstevel@tonic-gate switch (opt) { 165*0Sstevel@tonic-gate case 'a': /* include shared mappings in -[xS] */ 166*0Sstevel@tonic-gate aflag = 1; 167*0Sstevel@tonic-gate break; 168*0Sstevel@tonic-gate case 'r': /* show reserved mappings */ 169*0Sstevel@tonic-gate rflag = 1; 170*0Sstevel@tonic-gate break; 171*0Sstevel@tonic-gate case 's': /* show hardware page sizes */ 172*0Sstevel@tonic-gate sflag = 1; 173*0Sstevel@tonic-gate break; 174*0Sstevel@tonic-gate case 'S': /* show swap reservations */ 175*0Sstevel@tonic-gate Sflag = 1; 176*0Sstevel@tonic-gate break; 177*0Sstevel@tonic-gate case 'x': /* show extended mappings */ 178*0Sstevel@tonic-gate xflag = 1; 179*0Sstevel@tonic-gate break; 180*0Sstevel@tonic-gate case 'l': /* show unresolved link map names */ 181*0Sstevel@tonic-gate lflag = 1; 182*0Sstevel@tonic-gate break; 183*0Sstevel@tonic-gate case 'F': 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * Since we grab the process readonly now, the -F flag 186*0Sstevel@tonic-gate * is meaningless. Consume it anyway it for backwards 187*0Sstevel@tonic-gate * compatbility. 188*0Sstevel@tonic-gate */ 189*0Sstevel@tonic-gate break; 190*0Sstevel@tonic-gate default: 191*0Sstevel@tonic-gate errflg = 1; 192*0Sstevel@tonic-gate break; 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate argc -= optind; 197*0Sstevel@tonic-gate argv += optind; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || 200*0Sstevel@tonic-gate (aflag && (!xflag && !Sflag))) { 201*0Sstevel@tonic-gate errflg = 1; 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate if (errflg || argc <= 0) { 205*0Sstevel@tonic-gate (void) fprintf(stderr, 206*0Sstevel@tonic-gate "usage:\t%s [-rslF] { pid | core } ...\n", command); 207*0Sstevel@tonic-gate (void) fprintf(stderr, 208*0Sstevel@tonic-gate "\t\t(report process address maps)\n"); 209*0Sstevel@tonic-gate (void) fprintf(stderr, 210*0Sstevel@tonic-gate "\t%s -x [-aslF] pid ...\n", command); 211*0Sstevel@tonic-gate (void) fprintf(stderr, 212*0Sstevel@tonic-gate "\t\t(show resident/anon/locked mapping details)\n"); 213*0Sstevel@tonic-gate (void) fprintf(stderr, 214*0Sstevel@tonic-gate "\t%s -S [-alF] { pid | core } ...\n", command); 215*0Sstevel@tonic-gate (void) fprintf(stderr, 216*0Sstevel@tonic-gate "\t\t(show swap reservations)\n\n"); 217*0Sstevel@tonic-gate (void) fprintf(stderr, 218*0Sstevel@tonic-gate "\t-a: include shared mappings in -[xS] summary\n"); 219*0Sstevel@tonic-gate (void) fprintf(stderr, 220*0Sstevel@tonic-gate "\t-r: show reserved address maps\n"); 221*0Sstevel@tonic-gate (void) fprintf(stderr, 222*0Sstevel@tonic-gate "\t-s: show hardware page sizes\n"); 223*0Sstevel@tonic-gate (void) fprintf(stderr, 224*0Sstevel@tonic-gate "\t-l: show unresolved dynamic linker map names\n"); 225*0Sstevel@tonic-gate (void) fprintf(stderr, 226*0Sstevel@tonic-gate "\t-F: force grabbing of the target process\n"); 227*0Sstevel@tonic-gate return (2); 228*0Sstevel@tonic-gate } 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate /* 231*0Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 232*0Sstevel@tonic-gate * that has many many mappings. 233*0Sstevel@tonic-gate */ 234*0Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 235*0Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 236*0Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate while (argc-- > 0) { 240*0Sstevel@tonic-gate char *arg; 241*0Sstevel@tonic-gate int gcode; 242*0Sstevel@tonic-gate psinfo_t psinfo; 243*0Sstevel@tonic-gate int tries = 0; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, 246*0Sstevel@tonic-gate PGRAB_RDONLY, &gcode)) == NULL) { 247*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 248*0Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 249*0Sstevel@tonic-gate rc++; 250*0Sstevel@tonic-gate continue; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate procname = arg; /* for perr() */ 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 256*0Sstevel@tonic-gate size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 257*0Sstevel@tonic-gate bar = addr_width == 8 ? bar8 : bar16; 258*0Sstevel@tonic-gate (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 259*0Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 262*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 263*0Sstevel@tonic-gate "/proc/%d/map", (int)psinfo.pr_pid); 264*0Sstevel@tonic-gate if ((mapfd = open(buf, O_RDONLY)) < 0) { 265*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 266*0Sstevel@tonic-gate "examine %s: lost control of " 267*0Sstevel@tonic-gate "process\n", command, arg); 268*0Sstevel@tonic-gate rc++; 269*0Sstevel@tonic-gate Prelease(Pr, 0); 270*0Sstevel@tonic-gate continue; 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate } else { 273*0Sstevel@tonic-gate mapfd = -1; 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate again: 277*0Sstevel@tonic-gate map_count = 0; 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 280*0Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 281*0Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if (rflag || sflag || xflag || Sflag) { 284*0Sstevel@tonic-gate (void) printf(" -%c option is not compatible " 285*0Sstevel@tonic-gate "with core files\n", xflag ? 'x' : 286*0Sstevel@tonic-gate sflag ? 's' : rflag ? 'r' : 'S'); 287*0Sstevel@tonic-gate Prelease(Pr, 0); 288*0Sstevel@tonic-gate rc++; 289*0Sstevel@tonic-gate continue; 290*0Sstevel@tonic-gate } 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate } else { 293*0Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 294*0Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 298*0Sstevel@tonic-gate struct totals t; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Since we're grabbing the process readonly, we need 302*0Sstevel@tonic-gate * to make sure the address space doesn't change during 303*0Sstevel@tonic-gate * execution. 304*0Sstevel@tonic-gate */ 305*0Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 306*0Sstevel@tonic-gate if (tries++ == MAX_TRIES) { 307*0Sstevel@tonic-gate Prelease(Pr, 0); 308*0Sstevel@tonic-gate (void) close(mapfd); 309*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 310*0Sstevel@tonic-gate "examine %s: address space is " 311*0Sstevel@tonic-gate "changing\n", command, arg); 312*0Sstevel@tonic-gate continue; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate if (fstat64(mapfd, &statbuf) != 0) { 316*0Sstevel@tonic-gate Prelease(Pr, 0); 317*0Sstevel@tonic-gate (void) close(mapfd); 318*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 319*0Sstevel@tonic-gate "examine %s: lost control of " 320*0Sstevel@tonic-gate "process\n", command, arg); 321*0Sstevel@tonic-gate continue; 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate nstacks = psinfo.pr_nlwp * 2; 326*0Sstevel@tonic-gate stacks = calloc(nstacks, sizeof (stacks[0])); 327*0Sstevel@tonic-gate if (stacks != NULL) { 328*0Sstevel@tonic-gate int n = 0; 329*0Sstevel@tonic-gate (void) Plwp_iter(Pr, getstack, &n); 330*0Sstevel@tonic-gate qsort(stacks, nstacks, sizeof (stacks[0]), 331*0Sstevel@tonic-gate cmpstacks); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate (void) memset(&t, 0, sizeof (t)); 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && 337*0Sstevel@tonic-gate Prd_agent(Pr) == NULL) { 338*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: " 339*0Sstevel@tonic-gate "librtld_db failed to initialize; " 340*0Sstevel@tonic-gate "shared library information will not be " 341*0Sstevel@tonic-gate "available\n", command); 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * Gather data 346*0Sstevel@tonic-gate */ 347*0Sstevel@tonic-gate if (xflag) 348*0Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 0); 349*0Sstevel@tonic-gate else if (Sflag) 350*0Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 1); 351*0Sstevel@tonic-gate else { 352*0Sstevel@tonic-gate if (rflag) 353*0Sstevel@tonic-gate rc += rmapping_iter(Pr, gather_map, 354*0Sstevel@tonic-gate NULL); 355*0Sstevel@tonic-gate else if (sflag) 356*0Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, 357*0Sstevel@tonic-gate NULL, 0); 358*0Sstevel@tonic-gate else 359*0Sstevel@tonic-gate rc += Pmapping_iter(Pr, gather_map, 360*0Sstevel@tonic-gate NULL); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * Ensure mappings are consistent. 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 367*0Sstevel@tonic-gate struct stat64 newbuf; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate if (fstat64(mapfd, &newbuf) != 0 || 370*0Sstevel@tonic-gate memcmp(&newbuf.st_mtim, &statbuf.st_mtim, 371*0Sstevel@tonic-gate sizeof (newbuf.st_mtim)) != 0) { 372*0Sstevel@tonic-gate if (stacks != NULL) { 373*0Sstevel@tonic-gate free(stacks); 374*0Sstevel@tonic-gate stacks = NULL; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate goto again; 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate /* 381*0Sstevel@tonic-gate * Display data. 382*0Sstevel@tonic-gate */ 383*0Sstevel@tonic-gate if (xflag) { 384*0Sstevel@tonic-gate (void) printf("%*s%*s%*s%*s%*s " 385*0Sstevel@tonic-gate "%sMode Mapped File\n", 386*0Sstevel@tonic-gate addr_width, "Address", 387*0Sstevel@tonic-gate size_width, "Kbytes", 388*0Sstevel@tonic-gate size_width, "RSS", 389*0Sstevel@tonic-gate size_width, "Anon", 390*0Sstevel@tonic-gate size_width, "Locked", 391*0Sstevel@tonic-gate sflag ? "Pgsz " : ""); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate rc += iter_xmap(sflag ? look_xmap : 394*0Sstevel@tonic-gate look_xmap_nopgsz, &t); 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate (void) printf("%s%s %s %s %s %s\n", 397*0Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 398*0Sstevel@tonic-gate bar, bar, bar, bar, bar); 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 401*0Sstevel@tonic-gate " " : ""); 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate printK(t.total_size, size_width); 404*0Sstevel@tonic-gate printK(t.total_rss, size_width); 405*0Sstevel@tonic-gate printK(t.total_anon, size_width); 406*0Sstevel@tonic-gate printK(t.total_locked, size_width); 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate (void) printf("\n"); 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate } else if (Sflag) { 411*0Sstevel@tonic-gate (void) printf("%*s%*s%*s Mode Mapped File\n", 412*0Sstevel@tonic-gate addr_width, "Address", 413*0Sstevel@tonic-gate size_width, "Kbytes", 414*0Sstevel@tonic-gate size_width, "Swap"); 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate rc += iter_xmap(look_xmap_nopgsz, &t); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate (void) printf("%s%s %s %s\n", 419*0Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 420*0Sstevel@tonic-gate bar, bar, bar); 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 423*0Sstevel@tonic-gate " " : ""); 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate printK(t.total_size, size_width); 426*0Sstevel@tonic-gate printK(t.total_swap, size_width); 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate (void) printf("\n"); 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate } else { 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate if (rflag) { 433*0Sstevel@tonic-gate rc += iter_map(look_map, &t); 434*0Sstevel@tonic-gate } else if (sflag) { 435*0Sstevel@tonic-gate (void) printf("%*s %*s %4s %-6s %s\n", 436*0Sstevel@tonic-gate addr_width, "Address", size_width, 437*0Sstevel@tonic-gate "Bytes", "Pgsz", "Mode ", 438*0Sstevel@tonic-gate "Mapped File"); 439*0Sstevel@tonic-gate rc += iter_xmap(look_smap, &t); 440*0Sstevel@tonic-gate } else { 441*0Sstevel@tonic-gate rc += iter_map(look_map, &t); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate (void) printf(" %stotal %*luK\n", 445*0Sstevel@tonic-gate addr_width == 16 ? 446*0Sstevel@tonic-gate " " : "", 447*0Sstevel@tonic-gate size_width, t.total_size); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate if (stacks != NULL) { 451*0Sstevel@tonic-gate free(stacks); 452*0Sstevel@tonic-gate stacks = NULL; 453*0Sstevel@tonic-gate } 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate Prelease(Pr, 0); 458*0Sstevel@tonic-gate if (mapfd != -1) 459*0Sstevel@tonic-gate (void) close(mapfd); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate return (rc); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate static char * 466*0Sstevel@tonic-gate make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 467*0Sstevel@tonic-gate char *buf, size_t bufsz) 468*0Sstevel@tonic-gate { 469*0Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 470*0Sstevel@tonic-gate char fname[100]; 471*0Sstevel@tonic-gate struct stat statb; 472*0Sstevel@tonic-gate int len; 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate if (!lflag && strcmp(mapname, "a.out") == 0 && 475*0Sstevel@tonic-gate Pexecname(Pr, buf, bufsz) != NULL) 476*0Sstevel@tonic-gate return (buf); 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate if (Pobjname(Pr, addr, buf, bufsz) != NULL) { 479*0Sstevel@tonic-gate if (lflag) 480*0Sstevel@tonic-gate return (buf); 481*0Sstevel@tonic-gate if ((len = resolvepath(buf, buf, bufsz)) > 0) { 482*0Sstevel@tonic-gate buf[len] = '\0'; 483*0Sstevel@tonic-gate return (buf); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate } 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD && *mapname != '\0') { 488*0Sstevel@tonic-gate (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s", 489*0Sstevel@tonic-gate (int)Psp->pr_pid, mapname); 490*0Sstevel@tonic-gate if (stat(fname, &statb) == 0) { 491*0Sstevel@tonic-gate dev_t dev = statb.st_dev; 492*0Sstevel@tonic-gate ino_t ino = statb.st_ino; 493*0Sstevel@tonic-gate (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", 494*0Sstevel@tonic-gate (ulong_t)major(dev), (ulong_t)minor(dev), ino); 495*0Sstevel@tonic-gate return (buf); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate return (NULL); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate 502*0Sstevel@tonic-gate static char * 503*0Sstevel@tonic-gate anon_name(char *name, const pstatus_t *Psp, 504*0Sstevel@tonic-gate uintptr_t vaddr, size_t size, int mflags, int shmid) 505*0Sstevel@tonic-gate { 506*0Sstevel@tonic-gate if (mflags & MA_ISM) { 507*0Sstevel@tonic-gate if (shmid == -1) 508*0Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 509*0Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism"); 510*0Sstevel@tonic-gate else 511*0Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 512*0Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 513*0Sstevel@tonic-gate } else if (mflags & MA_SHM) { 514*0Sstevel@tonic-gate if (shmid == -1) 515*0Sstevel@tonic-gate (void) sprintf(name, " [ shmid=null ]"); 516*0Sstevel@tonic-gate else 517*0Sstevel@tonic-gate (void) sprintf(name, " [ shmid=0x%x ]", shmid); 518*0Sstevel@tonic-gate } else if (vaddr + size > Psp->pr_stkbase && 519*0Sstevel@tonic-gate vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 520*0Sstevel@tonic-gate (void) strcpy(name, " [ stack ]"); 521*0Sstevel@tonic-gate } else if ((mflags & MA_ANON) && 522*0Sstevel@tonic-gate vaddr + size > Psp->pr_brkbase && 523*0Sstevel@tonic-gate vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 524*0Sstevel@tonic-gate (void) strcpy(name, " [ heap ]"); 525*0Sstevel@tonic-gate } else { 526*0Sstevel@tonic-gate lwpstack_t key, *stk; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate key.lwps_stack.ss_sp = (void *)vaddr; 529*0Sstevel@tonic-gate key.lwps_stack.ss_size = size; 530*0Sstevel@tonic-gate if (nstacks > 0 && 531*0Sstevel@tonic-gate (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 532*0Sstevel@tonic-gate cmpstacks)) != NULL) { 533*0Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 534*0Sstevel@tonic-gate (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 535*0Sstevel@tonic-gate "altstack" : "stack", 536*0Sstevel@tonic-gate stk->lwps_lwpid); 537*0Sstevel@tonic-gate } else if (Pstate(Pr) != PS_DEAD) { 538*0Sstevel@tonic-gate (void) strcpy(name, " [ anon ]"); 539*0Sstevel@tonic-gate } else { 540*0Sstevel@tonic-gate return (NULL); 541*0Sstevel@tonic-gate } 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate return (name); 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate static int 548*0Sstevel@tonic-gate rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd) 549*0Sstevel@tonic-gate { 550*0Sstevel@tonic-gate char mapname[PATH_MAX]; 551*0Sstevel@tonic-gate int mapfd, nmap, i, rc; 552*0Sstevel@tonic-gate struct stat st; 553*0Sstevel@tonic-gate prmap_t *prmapp, *pmp; 554*0Sstevel@tonic-gate ssize_t n; 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 557*0Sstevel@tonic-gate "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid); 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 560*0Sstevel@tonic-gate if (mapfd >= 0) 561*0Sstevel@tonic-gate (void) close(mapfd); 562*0Sstevel@tonic-gate return (perr(mapname)); 563*0Sstevel@tonic-gate } 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate nmap = st.st_size / sizeof (prmap_t); 566*0Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prmap_t)); 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) { 569*0Sstevel@tonic-gate (void) close(mapfd); 570*0Sstevel@tonic-gate free(prmapp); 571*0Sstevel@tonic-gate return (perr("read rmap")); 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate (void) close(mapfd); 575*0Sstevel@tonic-gate nmap = n / sizeof (prmap_t); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 578*0Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL)) != 0) { 579*0Sstevel@tonic-gate free(prmapp); 580*0Sstevel@tonic-gate return (rc); 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate free(prmapp); 585*0Sstevel@tonic-gate return (0); 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate static int 589*0Sstevel@tonic-gate xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap) 590*0Sstevel@tonic-gate { 591*0Sstevel@tonic-gate char mapname[PATH_MAX]; 592*0Sstevel@tonic-gate int mapfd, nmap, i, rc; 593*0Sstevel@tonic-gate struct stat st; 594*0Sstevel@tonic-gate prxmap_t *prmapp, *pmp; 595*0Sstevel@tonic-gate ssize_t n; 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 598*0Sstevel@tonic-gate "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid); 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 601*0Sstevel@tonic-gate if (mapfd >= 0) 602*0Sstevel@tonic-gate (void) close(mapfd); 603*0Sstevel@tonic-gate return (perr(mapname)); 604*0Sstevel@tonic-gate } 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate nmap = st.st_size / sizeof (prxmap_t); 607*0Sstevel@tonic-gate nmap *= 2; 608*0Sstevel@tonic-gate again: 609*0Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prxmap_t)); 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) { 612*0Sstevel@tonic-gate (void) close(mapfd); 613*0Sstevel@tonic-gate free(prmapp); 614*0Sstevel@tonic-gate return (perr("read xmap")); 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate if (nmap < n / sizeof (prxmap_t)) { 618*0Sstevel@tonic-gate free(prmapp); 619*0Sstevel@tonic-gate nmap *= 2; 620*0Sstevel@tonic-gate goto again; 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate (void) close(mapfd); 624*0Sstevel@tonic-gate nmap = n / sizeof (prxmap_t); 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 627*0Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) { 628*0Sstevel@tonic-gate free(prmapp); 629*0Sstevel@tonic-gate return (rc); 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate free(prmapp); 634*0Sstevel@tonic-gate return (0); 635*0Sstevel@tonic-gate } 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate /*ARGSUSED*/ 638*0Sstevel@tonic-gate static int 639*0Sstevel@tonic-gate look_map(void *data, const prmap_t *pmp, const char *object_name) 640*0Sstevel@tonic-gate { 641*0Sstevel@tonic-gate struct totals *t = data; 642*0Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 643*0Sstevel@tonic-gate size_t size = (pmp->pr_size + 1023) / 1024; 644*0Sstevel@tonic-gate char mname[PATH_MAX]; 645*0Sstevel@tonic-gate char *lname = NULL; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate /* 648*0Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 649*0Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 652*0Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 653*0Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 654*0Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 655*0Sstevel@tonic-gate mname, sizeof (mname)); 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate if (lname == NULL && 659*0Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 660*0Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 661*0Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate (void) printf(lname ? "%.*lX %*luK %-6s %s\n" : "%.*lX %*luK %s\n", 665*0Sstevel@tonic-gate addr_width, (uintptr_t)pmp->pr_vaddr, 666*0Sstevel@tonic-gate size_width - 1, size, mflags(pmp->pr_mflags), lname); 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate t->total_size += size; 669*0Sstevel@tonic-gate return (0); 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate static void 673*0Sstevel@tonic-gate printK(long value, int width) 674*0Sstevel@tonic-gate { 675*0Sstevel@tonic-gate if (value == 0) 676*0Sstevel@tonic-gate (void) printf(width == 8 ? " -" : " -"); 677*0Sstevel@tonic-gate else 678*0Sstevel@tonic-gate (void) printf(" %*lu", width - 1, value); 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate static const char * 682*0Sstevel@tonic-gate pagesize(const prxmap_t *pmp) 683*0Sstevel@tonic-gate { 684*0Sstevel@tonic-gate int pagesize = pmp->pr_hatpagesize; 685*0Sstevel@tonic-gate static char buf[32]; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate if (pagesize == 0) { 688*0Sstevel@tonic-gate return ("-"); /* no underlying HAT mapping */ 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate if (pagesize >= 1024 && (pagesize % 1024) == 0) { 692*0Sstevel@tonic-gate if ((pagesize % (1024 * 1024 * 1024)) == 0) 693*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dG", 694*0Sstevel@tonic-gate pagesize / (1024 * 1024 * 1024)); 695*0Sstevel@tonic-gate else if ((pagesize % (1024 * 1024)) == 0) 696*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dM", 697*0Sstevel@tonic-gate pagesize / (1024 * 1024)); 698*0Sstevel@tonic-gate else 699*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dK", 700*0Sstevel@tonic-gate pagesize / 1024); 701*0Sstevel@tonic-gate } else 702*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%db", pagesize); 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate return (buf); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate /*ARGSUSED*/ 708*0Sstevel@tonic-gate static int 709*0Sstevel@tonic-gate look_smap(void *data, 710*0Sstevel@tonic-gate const prxmap_t *pmp, 711*0Sstevel@tonic-gate const char *object_name, 712*0Sstevel@tonic-gate int last, int doswap) 713*0Sstevel@tonic-gate { 714*0Sstevel@tonic-gate struct totals *t = data; 715*0Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 716*0Sstevel@tonic-gate size_t size = (pmp->pr_size + 1023) / 1024; 717*0Sstevel@tonic-gate char mname[PATH_MAX]; 718*0Sstevel@tonic-gate char *lname = NULL; 719*0Sstevel@tonic-gate const char *format; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate /* 722*0Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 723*0Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 724*0Sstevel@tonic-gate */ 725*0Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 726*0Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 727*0Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 728*0Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 729*0Sstevel@tonic-gate mname, sizeof (mname)); 730*0Sstevel@tonic-gate } 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate if (lname == NULL && 733*0Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 734*0Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 735*0Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate if (lname != NULL) 739*0Sstevel@tonic-gate format = "%.*lX %*luK %4s %-6s %s\n"; 740*0Sstevel@tonic-gate else 741*0Sstevel@tonic-gate format = "%.*lX %*luK %4s %s\n"; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate (void) printf(format, addr_width, (uintptr_t)pmp->pr_vaddr, 744*0Sstevel@tonic-gate size_width - 1, size, 745*0Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate t->total_size += size; 748*0Sstevel@tonic-gate return (0); 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate #define ANON(x) ((aflag || (((x)->pr_mflags & MA_SHARED) == 0)) ? \ 752*0Sstevel@tonic-gate ((x)->pr_anon) : 0) 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate /*ARGSUSED*/ 755*0Sstevel@tonic-gate static int 756*0Sstevel@tonic-gate look_xmap(void *data, 757*0Sstevel@tonic-gate const prxmap_t *pmp, 758*0Sstevel@tonic-gate const char *object_name, 759*0Sstevel@tonic-gate int last, int doswap) 760*0Sstevel@tonic-gate { 761*0Sstevel@tonic-gate struct totals *t = data; 762*0Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 763*0Sstevel@tonic-gate char mname[PATH_MAX]; 764*0Sstevel@tonic-gate char *lname = NULL; 765*0Sstevel@tonic-gate char *ln; 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate /* 768*0Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 769*0Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 772*0Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 773*0Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 774*0Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 775*0Sstevel@tonic-gate mname, sizeof (mname)); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate if (lname != NULL) { 779*0Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 780*0Sstevel@tonic-gate lname = ln + 1; 781*0Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 782*0Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 783*0Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate printK((pmp->pr_size + 1023) / 1024, size_width); 789*0Sstevel@tonic-gate printK(pmp->pr_rss * (pmp->pr_pagesize / 1024), size_width); 790*0Sstevel@tonic-gate printK(ANON(pmp) * (pmp->pr_pagesize / 1024), size_width); 791*0Sstevel@tonic-gate printK(pmp->pr_locked * (pmp->pr_pagesize / 1024), size_width); 792*0Sstevel@tonic-gate (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n", 793*0Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate t->total_size += (pmp->pr_size + 1023) / 1024; 796*0Sstevel@tonic-gate t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / 1024); 797*0Sstevel@tonic-gate t->total_anon += ANON(pmp) * (pmp->pr_pagesize / 1024); 798*0Sstevel@tonic-gate t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / 1024)); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate return (0); 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate /*ARGSUSED*/ 804*0Sstevel@tonic-gate static int 805*0Sstevel@tonic-gate look_xmap_nopgsz(void *data, 806*0Sstevel@tonic-gate const prxmap_t *pmp, 807*0Sstevel@tonic-gate const char *object_name, 808*0Sstevel@tonic-gate int last, int doswap) 809*0Sstevel@tonic-gate { 810*0Sstevel@tonic-gate struct totals *t = data; 811*0Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 812*0Sstevel@tonic-gate char mname[PATH_MAX]; 813*0Sstevel@tonic-gate char *lname = NULL; 814*0Sstevel@tonic-gate char *ln; 815*0Sstevel@tonic-gate static uintptr_t prev_vaddr; 816*0Sstevel@tonic-gate static size_t prev_size; 817*0Sstevel@tonic-gate static offset_t prev_offset; 818*0Sstevel@tonic-gate static int prev_mflags; 819*0Sstevel@tonic-gate static char *prev_lname; 820*0Sstevel@tonic-gate static char prev_mname[PATH_MAX]; 821*0Sstevel@tonic-gate static ulong_t prev_rss; 822*0Sstevel@tonic-gate static ulong_t prev_anon; 823*0Sstevel@tonic-gate static ulong_t prev_locked; 824*0Sstevel@tonic-gate static ulong_t prev_swap; 825*0Sstevel@tonic-gate int merged = 0; 826*0Sstevel@tonic-gate static int first = 1; 827*0Sstevel@tonic-gate ulong_t swap = 0; 828*0Sstevel@tonic-gate int kperpage; 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate /* 831*0Sstevel@tonic-gate * Calculate swap reservations 832*0Sstevel@tonic-gate */ 833*0Sstevel@tonic-gate if (pmp->pr_mflags & MA_SHARED) { 834*0Sstevel@tonic-gate if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) { 835*0Sstevel@tonic-gate /* Swap reserved for entire non-ism SHM */ 836*0Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_NORESERVE) { 839*0Sstevel@tonic-gate /* Swap reserved on fault for each anon page */ 840*0Sstevel@tonic-gate swap = pmp->pr_anon; 841*0Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_WRITE) { 842*0Sstevel@tonic-gate /* Swap reserve for entire writable segment */ 843*0Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 844*0Sstevel@tonic-gate } 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate /* 847*0Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 848*0Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 849*0Sstevel@tonic-gate */ 850*0Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 851*0Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 852*0Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 853*0Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 854*0Sstevel@tonic-gate mname, sizeof (mname)); 855*0Sstevel@tonic-gate } 856*0Sstevel@tonic-gate 857*0Sstevel@tonic-gate if (lname != NULL) { 858*0Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 859*0Sstevel@tonic-gate lname = ln + 1; 860*0Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 861*0Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 862*0Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate kperpage = pmp->pr_pagesize / 1024; 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate t->total_size += (pmp->pr_size + 1023) / 1024; 868*0Sstevel@tonic-gate t->total_rss += pmp->pr_rss * kperpage; 869*0Sstevel@tonic-gate t->total_anon += ANON(pmp) * kperpage; 870*0Sstevel@tonic-gate t->total_locked += pmp->pr_locked * kperpage; 871*0Sstevel@tonic-gate t->total_swap += swap * kperpage; 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate if (first == 1) { 874*0Sstevel@tonic-gate first = 0; 875*0Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 876*0Sstevel@tonic-gate prev_size = pmp->pr_size; 877*0Sstevel@tonic-gate prev_offset = pmp->pr_offset; 878*0Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 879*0Sstevel@tonic-gate if (lname == NULL) { 880*0Sstevel@tonic-gate prev_lname = NULL; 881*0Sstevel@tonic-gate } else { 882*0Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 883*0Sstevel@tonic-gate prev_lname = prev_mname; 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 886*0Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 887*0Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 888*0Sstevel@tonic-gate prev_swap = swap * kperpage; 889*0Sstevel@tonic-gate if (last == 0) { 890*0Sstevel@tonic-gate return (0); 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate merged = 1; 893*0Sstevel@tonic-gate } else if (prev_vaddr + prev_size == pmp->pr_vaddr && 894*0Sstevel@tonic-gate prev_mflags == pmp->pr_mflags && 895*0Sstevel@tonic-gate ((prev_mflags & MA_ISM) || 896*0Sstevel@tonic-gate prev_offset + prev_size == pmp->pr_offset) && 897*0Sstevel@tonic-gate ((lname == NULL && prev_lname == NULL) || 898*0Sstevel@tonic-gate (lname != NULL && prev_lname != NULL && 899*0Sstevel@tonic-gate strcmp(lname, prev_lname) == 0))) { 900*0Sstevel@tonic-gate prev_size += pmp->pr_size; 901*0Sstevel@tonic-gate prev_rss += pmp->pr_rss * kperpage; 902*0Sstevel@tonic-gate prev_anon += ANON(pmp) * kperpage; 903*0Sstevel@tonic-gate prev_locked += pmp->pr_locked * kperpage; 904*0Sstevel@tonic-gate prev_swap += swap * kperpage; 905*0Sstevel@tonic-gate if (last == 0) { 906*0Sstevel@tonic-gate return (0); 907*0Sstevel@tonic-gate } 908*0Sstevel@tonic-gate merged = 1; 909*0Sstevel@tonic-gate } 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr); 912*0Sstevel@tonic-gate printK((prev_size + 1023) / 1024, size_width); 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate if (doswap) 915*0Sstevel@tonic-gate printK(prev_swap, size_width); 916*0Sstevel@tonic-gate else { 917*0Sstevel@tonic-gate printK(prev_rss, size_width); 918*0Sstevel@tonic-gate printK(prev_anon, size_width); 919*0Sstevel@tonic-gate printK(prev_locked, size_width); 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate (void) printf(prev_lname ? " %-6s %s\n" : " %s\n", 922*0Sstevel@tonic-gate mflags(prev_mflags), prev_lname); 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate if (last == 0) { 925*0Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 926*0Sstevel@tonic-gate prev_size = pmp->pr_size; 927*0Sstevel@tonic-gate prev_offset = pmp->pr_offset; 928*0Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 929*0Sstevel@tonic-gate if (lname == NULL) { 930*0Sstevel@tonic-gate prev_lname = NULL; 931*0Sstevel@tonic-gate } else { 932*0Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 933*0Sstevel@tonic-gate prev_lname = prev_mname; 934*0Sstevel@tonic-gate } 935*0Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 936*0Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 937*0Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 938*0Sstevel@tonic-gate prev_swap = swap * kperpage; 939*0Sstevel@tonic-gate } else if (merged == 0) { 940*0Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 941*0Sstevel@tonic-gate printK((pmp->pr_size + 1023) / 1024, size_width); 942*0Sstevel@tonic-gate if (doswap) 943*0Sstevel@tonic-gate printK(swap * kperpage, size_width); 944*0Sstevel@tonic-gate else { 945*0Sstevel@tonic-gate printK(pmp->pr_rss * kperpage, size_width); 946*0Sstevel@tonic-gate printK(ANON(pmp) * kperpage, size_width); 947*0Sstevel@tonic-gate printK(pmp->pr_locked * kperpage, size_width); 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate (void) printf(lname ? " %-6s %s\n" : " %s\n", 950*0Sstevel@tonic-gate mflags(pmp->pr_mflags), lname); 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate if (last != 0) 954*0Sstevel@tonic-gate first = 1; 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate return (0); 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate static int 960*0Sstevel@tonic-gate perr(char *s) 961*0Sstevel@tonic-gate { 962*0Sstevel@tonic-gate if (s) 963*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 964*0Sstevel@tonic-gate else 965*0Sstevel@tonic-gate s = procname; 966*0Sstevel@tonic-gate perror(s); 967*0Sstevel@tonic-gate return (1); 968*0Sstevel@tonic-gate } 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate static char * 971*0Sstevel@tonic-gate mflags(uint_t arg) 972*0Sstevel@tonic-gate { 973*0Sstevel@tonic-gate static char code_buf[80]; 974*0Sstevel@tonic-gate char *str = code_buf; 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate /* 977*0Sstevel@tonic-gate * rwxsR 978*0Sstevel@tonic-gate * 979*0Sstevel@tonic-gate * r - segment is readable 980*0Sstevel@tonic-gate * w - segment is writable 981*0Sstevel@tonic-gate * x - segment is executable 982*0Sstevel@tonic-gate * s - segment is shared 983*0Sstevel@tonic-gate * R - segment is mapped MAP_NORESERVE 984*0Sstevel@tonic-gate * 985*0Sstevel@tonic-gate */ 986*0Sstevel@tonic-gate (void) sprintf(str, "%c%c%c%c%c%c", 987*0Sstevel@tonic-gate arg & MA_READ ? 'r' : '-', 988*0Sstevel@tonic-gate arg & MA_WRITE ? 'w' : '-', 989*0Sstevel@tonic-gate arg & MA_EXEC ? 'x' : '-', 990*0Sstevel@tonic-gate arg & MA_SHARED ? 's' : '-', 991*0Sstevel@tonic-gate arg & MA_NORESERVE ? 'R' : '-', 992*0Sstevel@tonic-gate arg & MA_RESERVED1 ? '*' : ' '); 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate return (str); 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate static mapdata_t * 998*0Sstevel@tonic-gate nextmap(void) 999*0Sstevel@tonic-gate { 1000*0Sstevel@tonic-gate mapdata_t *newmaps; 1001*0Sstevel@tonic-gate int next; 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate if (map_count == map_alloc) { 1004*0Sstevel@tonic-gate if (map_alloc == 0) 1005*0Sstevel@tonic-gate next = 16; 1006*0Sstevel@tonic-gate else 1007*0Sstevel@tonic-gate next = map_alloc * 2; 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate newmaps = realloc(maps, next * sizeof (mapdata_t)); 1010*0Sstevel@tonic-gate if (newmaps == NULL) { 1011*0Sstevel@tonic-gate (void) perr("failed to allocate maps"); 1012*0Sstevel@tonic-gate exit(1); 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate (void) memset(newmaps + map_alloc, '\0', 1015*0Sstevel@tonic-gate (next - map_alloc) * sizeof (mapdata_t)); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate map_alloc = next; 1018*0Sstevel@tonic-gate maps = newmaps; 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate return (&maps[map_count++]); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate /*ARGSUSED*/ 1025*0Sstevel@tonic-gate static int 1026*0Sstevel@tonic-gate gather_map(void *ignored, const prmap_t *map, const char *objname) 1027*0Sstevel@tonic-gate { 1028*0Sstevel@tonic-gate mapdata_t *data = nextmap(); 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate data->md_map = *map; 1031*0Sstevel@tonic-gate if (data->md_objname != NULL) 1032*0Sstevel@tonic-gate free(data->md_objname); 1033*0Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate return (0); 1036*0Sstevel@tonic-gate } 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate /*ARGSUSED*/ 1039*0Sstevel@tonic-gate static int 1040*0Sstevel@tonic-gate gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname, 1041*0Sstevel@tonic-gate int last, int doswap) 1042*0Sstevel@tonic-gate { 1043*0Sstevel@tonic-gate mapdata_t *data = nextmap(); 1044*0Sstevel@tonic-gate 1045*0Sstevel@tonic-gate data->md_xmap = *xmap; 1046*0Sstevel@tonic-gate if (data->md_objname != NULL) 1047*0Sstevel@tonic-gate free(data->md_objname); 1048*0Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 1049*0Sstevel@tonic-gate data->md_last = last; 1050*0Sstevel@tonic-gate data->md_doswap = doswap; 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate return (0); 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate static int 1056*0Sstevel@tonic-gate iter_map(proc_map_f *func, void *data) 1057*0Sstevel@tonic-gate { 1058*0Sstevel@tonic-gate int i; 1059*0Sstevel@tonic-gate int ret; 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1062*0Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_map, 1063*0Sstevel@tonic-gate maps[i].md_objname)) != 0) 1064*0Sstevel@tonic-gate return (ret); 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate return (0); 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate static int 1071*0Sstevel@tonic-gate iter_xmap(proc_xmap_f *func, void *data) 1072*0Sstevel@tonic-gate { 1073*0Sstevel@tonic-gate int i; 1074*0Sstevel@tonic-gate int ret; 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1077*0Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname, 1078*0Sstevel@tonic-gate maps[i].md_last, maps[i].md_doswap)) != 0) 1079*0Sstevel@tonic-gate return (ret); 1080*0Sstevel@tonic-gate } 1081*0Sstevel@tonic-gate 1082*0Sstevel@tonic-gate return (0); 1083*0Sstevel@tonic-gate } 1084