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