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