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 /* 23 * Copyright 2008 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 <stdio_ext.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <ctype.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <dirent.h> 37 #include <limits.h> 38 #include <link.h> 39 #include <libelf.h> 40 #include <sys/types.h> 41 #include <signal.h> 42 #include <sys/stat.h> 43 #include <sys/mkdev.h> 44 #include <sys/mman.h> 45 #include <sys/lgrp_user.h> 46 #include <libproc.h> 47 #include <libzonecfg.h> 48 49 #define KILOBYTE 1024 50 #define MEGABYTE (KILOBYTE * KILOBYTE) 51 #define GIGABYTE (KILOBYTE * KILOBYTE * KILOBYTE) 52 53 /* 54 * Round up the value to the nearest kilobyte 55 */ 56 #define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE) 57 58 /* 59 * The alignment should be a power of 2. 60 */ 61 #define P2ALIGN(x, align) ((x) & -(align)) 62 63 #define INVALID_ADDRESS (uintptr_t)(-1) 64 65 struct totals { 66 ulong_t total_size; 67 ulong_t total_swap; 68 ulong_t total_rss; 69 ulong_t total_anon; 70 ulong_t total_locked; 71 }; 72 73 /* 74 * -L option requires per-page information. The information is presented in an 75 * array of page_descr structures. 76 */ 77 typedef struct page_descr { 78 uintptr_t pd_start; /* start address of a page */ 79 size_t pd_pagesize; /* page size in bytes */ 80 lgrp_id_t pd_lgrp; /* lgroup of memory backing the page */ 81 int pd_valid; /* valid page description if non-zero */ 82 } page_descr_t; 83 84 /* 85 * Per-page information for a memory chunk. 86 * The meminfo(2) system call accepts up to MAX_MEMINFO_CNT pages at once. 87 * When we need to scan larger ranges we divide them in MAX_MEMINFO_CNT sized 88 * chunks. The chunk information is stored in the memory_chunk structure. 89 */ 90 typedef struct memory_chunk { 91 page_descr_t page_info[MAX_MEMINFO_CNT]; 92 uintptr_t end_addr; 93 uintptr_t chunk_start; /* Starting address */ 94 uintptr_t chunk_end; /* chunk_end is always <= end_addr */ 95 size_t page_size; 96 int page_index; /* Current page */ 97 int page_count; /* Number of pages */ 98 } memory_chunk_t; 99 100 static volatile int interrupt; 101 102 typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int); 103 104 static int xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *, 105 int); 106 static int rmapping_iter(struct ps_prochandle *, proc_map_f *, void *); 107 108 static int look_map(void *, const prmap_t *, const char *); 109 static int look_smap(void *, const prxmap_t *, const char *, int, int); 110 static int look_xmap(void *, const prxmap_t *, const char *, int, int); 111 static int look_xmap_nopgsz(void *, const prxmap_t *, const char *, 112 int, int); 113 114 static int gather_map(void *, const prmap_t *, const char *); 115 static int gather_xmap(void *, const prxmap_t *, const char *, int, int); 116 static int iter_map(proc_map_f *, void *); 117 static int iter_xmap(proc_xmap_f *, void *); 118 static int parse_addr_range(char *, uintptr_t *, uintptr_t *); 119 static void mem_chunk_init(memory_chunk_t *, uintptr_t, size_t); 120 121 static int perr(char *); 122 static void printK(long, int); 123 static char *mflags(uint_t); 124 125 static size_t get_contiguous_region(memory_chunk_t *, uintptr_t, 126 uintptr_t, size_t, lgrp_id_t *); 127 static void mem_chunk_get(memory_chunk_t *, uintptr_t); 128 static lgrp_id_t addr_to_lgrp(memory_chunk_t *, uintptr_t, size_t *); 129 static char *lgrp2str(lgrp_id_t); 130 131 static int address_in_range(uintptr_t, uintptr_t, size_t); 132 static size_t adjust_addr_range(uintptr_t, uintptr_t, size_t, 133 uintptr_t *, uintptr_t *); 134 135 static int lflag = 0; 136 static int Lflag = 0; 137 static int aflag = 0; 138 139 /* 140 * The -A address range is represented as a pair of addresses 141 * <start_addr, end_addr>. Either one of these may be unspecified (set to 142 * INVALID_ADDRESS). If both are unspecified, no address range restrictions are 143 * in place. 144 */ 145 static uintptr_t start_addr = INVALID_ADDRESS; 146 static uintptr_t end_addr = INVALID_ADDRESS; 147 148 static int addr_width, size_width; 149 static char *command; 150 static char *procname; 151 static struct ps_prochandle *Pr; 152 153 static void intr(int); 154 155 typedef struct lwpstack { 156 lwpid_t lwps_lwpid; 157 stack_t lwps_stack; 158 } lwpstack_t; 159 160 typedef struct { 161 prxmap_t md_xmap; 162 prmap_t md_map; 163 char *md_objname; 164 boolean_t md_last; 165 int md_doswap; 166 } mapdata_t; 167 168 static mapdata_t *maps; 169 static int map_count; 170 static int map_alloc; 171 172 static lwpstack_t *stacks = NULL; 173 static uint_t nstacks = 0; 174 175 #define MAX_TRIES 5 176 177 static int 178 getstack(void *data, const lwpstatus_t *lsp) 179 { 180 int *np = (int *)data; 181 182 if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 183 stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 184 stacks[*np].lwps_lwpid = lsp->pr_lwpid; 185 (*np)++; 186 } 187 188 if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 189 stacks[*np].lwps_lwpid = lsp->pr_lwpid; 190 (*np)++; 191 } 192 193 return (0); 194 } 195 196 /* 197 * We compare the high memory addresses since stacks are faulted in from 198 * high memory addresses to low memory addresses, and our prmap_t 199 * structures identify only the range of addresses that have been faulted 200 * in so far. 201 */ 202 static int 203 cmpstacks(const void *ap, const void *bp) 204 { 205 const lwpstack_t *as = ap; 206 const lwpstack_t *bs = bp; 207 uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 208 uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 209 210 if (a < b) 211 return (1); 212 if (a > b) 213 return (-1); 214 return (0); 215 } 216 217 218 int 219 main(int argc, char **argv) 220 { 221 int rflag = 0, sflag = 0, xflag = 0, Fflag = 0; 222 int errflg = 0, Sflag = 0; 223 int rc = 0; 224 int opt; 225 const char *bar8 = "-------"; 226 const char *bar16 = "----------"; 227 const char *bar; 228 struct rlimit rlim; 229 struct stat64 statbuf; 230 char buf[128]; 231 int mapfd; 232 233 if ((command = strrchr(argv[0], '/')) != NULL) 234 command++; 235 else 236 command = argv[0]; 237 238 while ((opt = getopt(argc, argv, "arsxSlLFA:")) != EOF) { 239 switch (opt) { 240 case 'a': /* include shared mappings in -[xS] */ 241 aflag = 1; 242 break; 243 case 'r': /* show reserved mappings */ 244 rflag = 1; 245 break; 246 case 's': /* show hardware page sizes */ 247 sflag = 1; 248 break; 249 case 'S': /* show swap reservations */ 250 Sflag = 1; 251 break; 252 case 'x': /* show extended mappings */ 253 xflag = 1; 254 break; 255 case 'l': /* show unresolved link map names */ 256 lflag = 1; 257 break; 258 case 'L': /* show lgroup information */ 259 Lflag = 1; 260 break; 261 case 'F': /* force grabbing (no O_EXCL) */ 262 Fflag = PGRAB_FORCE; 263 break; 264 case 'A': 265 if (parse_addr_range(optarg, &start_addr, &end_addr) 266 != 0) 267 errflg++; 268 break; 269 default: 270 errflg = 1; 271 break; 272 } 273 } 274 275 argc -= optind; 276 argv += optind; 277 278 if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || 279 (aflag && (!xflag && !Sflag)) || 280 (Lflag && (xflag || Sflag))) { 281 errflg = 1; 282 } 283 284 if (errflg || argc <= 0) { 285 (void) fprintf(stderr, 286 "usage:\t%s [-rslF] [-A start[,end]] { pid | core } ...\n", 287 command); 288 (void) fprintf(stderr, 289 "\t\t(report process address maps)\n"); 290 (void) fprintf(stderr, 291 "\t%s -L [-rslF] [-A start[,end]] pid ...\n", command); 292 (void) fprintf(stderr, 293 "\t\t(report process address maps lgroups mappings)\n"); 294 (void) fprintf(stderr, 295 "\t%s -x [-aslF] [-A start[,end]] pid ...\n", command); 296 (void) fprintf(stderr, 297 "\t\t(show resident/anon/locked mapping details)\n"); 298 (void) fprintf(stderr, 299 "\t%s -S [-alF] [-A start[,end]] { pid | core } ...\n", 300 command); 301 (void) fprintf(stderr, 302 "\t\t(show swap reservations)\n\n"); 303 (void) fprintf(stderr, 304 "\t-a: include shared mappings in -[xS] summary\n"); 305 (void) fprintf(stderr, 306 "\t-r: show reserved address maps\n"); 307 (void) fprintf(stderr, 308 "\t-s: show hardware page sizes\n"); 309 (void) fprintf(stderr, 310 "\t-l: show unresolved dynamic linker map names\n"); 311 (void) fprintf(stderr, 312 "\t-F: force grabbing of the target process\n"); 313 (void) fprintf(stderr, 314 "\t-L: show lgroup mappings\n"); 315 (void) fprintf(stderr, 316 "\t-A start,end: limit output to the specified range\n"); 317 return (2); 318 } 319 320 /* 321 * Make sure we'll have enough file descriptors to handle a target 322 * that has many many mappings. 323 */ 324 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 325 rlim.rlim_cur = rlim.rlim_max; 326 (void) setrlimit(RLIMIT_NOFILE, &rlim); 327 (void) enable_extended_FILE_stdio(-1, -1); 328 } 329 330 while (argc-- > 0) { 331 char *arg; 332 int gcode; 333 psinfo_t psinfo; 334 int tries = 0; 335 int prg_gflags = PGRAB_RDONLY; 336 int prr_flags = 0; 337 338 if (Lflag) { 339 prg_gflags = PGRAB_RETAIN | Fflag; 340 prr_flags = PRELEASE_RETAIN; 341 } 342 343 if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, 344 prg_gflags, &gcode)) == NULL) { 345 (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 346 command, arg, Pgrab_error(gcode)); 347 rc++; 348 continue; 349 } 350 351 procname = arg; /* for perr() */ 352 353 addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 354 size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 355 bar = addr_width == 8 ? bar8 : bar16; 356 (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 357 proc_unctrl_psinfo(&psinfo); 358 359 if (Pstate(Pr) != PS_DEAD) { 360 (void) snprintf(buf, sizeof (buf), 361 "/proc/%d/map", (int)psinfo.pr_pid); 362 if ((mapfd = open(buf, O_RDONLY)) < 0) { 363 (void) fprintf(stderr, "%s: cannot " 364 "examine %s: lost control of " 365 "process\n", command, arg); 366 rc++; 367 Prelease(Pr, prr_flags); 368 continue; 369 } 370 } else { 371 mapfd = -1; 372 } 373 374 again: 375 map_count = 0; 376 377 if (Pstate(Pr) == PS_DEAD) { 378 (void) printf("core '%s' of %d:\t%.70s\n", 379 arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 380 381 if (rflag || sflag || xflag || Sflag || Lflag) { 382 (void) printf(" -%c option is not compatible " 383 "with core files\n", xflag ? 'x' : 384 sflag ? 's' : rflag ? 'r' : 385 Lflag ? 'L' : 'S'); 386 Prelease(Pr, prr_flags); 387 rc++; 388 continue; 389 } 390 391 } else { 392 (void) printf("%d:\t%.70s\n", 393 (int)psinfo.pr_pid, psinfo.pr_psargs); 394 } 395 396 if (Lflag) { 397 /* 398 * The implementation of -L option creates an agent LWP 399 * in the target process address space. The agent LWP 400 * issues meminfo(2) system calls on behalf of the 401 * target process. If we are interrupted prematurely, 402 * the target process remains in the stopped state with 403 * the agent still attached to it. To prevent such 404 * situation we catch signals from terminal and 405 * terminate gracefully. 406 */ 407 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 408 (void) sigset(SIGHUP, intr); 409 if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 410 (void) sigset(SIGINT, intr); 411 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 412 (void) sigset(SIGQUIT, intr); 413 (void) sigset(SIGPIPE, intr); 414 (void) sigset(SIGTERM, intr); 415 } 416 417 if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 418 struct totals t; 419 420 /* 421 * Since we're grabbing the process readonly, we need 422 * to make sure the address space doesn't change during 423 * execution. 424 */ 425 if (Pstate(Pr) != PS_DEAD) { 426 if (tries++ == MAX_TRIES) { 427 Prelease(Pr, prr_flags); 428 (void) close(mapfd); 429 (void) fprintf(stderr, "%s: cannot " 430 "examine %s: address space is " 431 "changing\n", command, arg); 432 continue; 433 } 434 435 if (fstat64(mapfd, &statbuf) != 0) { 436 Prelease(Pr, prr_flags); 437 (void) close(mapfd); 438 (void) fprintf(stderr, "%s: cannot " 439 "examine %s: lost control of " 440 "process\n", command, arg); 441 continue; 442 } 443 } 444 445 nstacks = psinfo.pr_nlwp * 2; 446 stacks = calloc(nstacks, sizeof (stacks[0])); 447 if (stacks != NULL) { 448 int n = 0; 449 (void) Plwp_iter(Pr, getstack, &n); 450 qsort(stacks, nstacks, sizeof (stacks[0]), 451 cmpstacks); 452 } 453 454 (void) memset(&t, 0, sizeof (t)); 455 456 if (Pgetauxval(Pr, AT_BASE) != -1L && 457 Prd_agent(Pr) == NULL) { 458 (void) fprintf(stderr, "%s: warning: " 459 "librtld_db failed to initialize; " 460 "shared library information will not be " 461 "available\n", command); 462 } 463 464 /* 465 * Gather data 466 */ 467 if (xflag) 468 rc += xmapping_iter(Pr, gather_xmap, NULL, 0); 469 else if (Sflag) 470 rc += xmapping_iter(Pr, gather_xmap, NULL, 1); 471 else { 472 if (rflag) 473 rc += rmapping_iter(Pr, gather_map, 474 NULL); 475 else if (sflag) 476 rc += xmapping_iter(Pr, gather_xmap, 477 NULL, 0); 478 else 479 rc += Pmapping_iter(Pr, gather_map, 480 NULL); 481 } 482 483 /* 484 * Ensure mappings are consistent. 485 */ 486 if (Pstate(Pr) != PS_DEAD) { 487 struct stat64 newbuf; 488 489 if (fstat64(mapfd, &newbuf) != 0 || 490 memcmp(&newbuf.st_mtim, &statbuf.st_mtim, 491 sizeof (newbuf.st_mtim)) != 0) { 492 if (stacks != NULL) { 493 free(stacks); 494 stacks = NULL; 495 } 496 goto again; 497 } 498 } 499 500 /* 501 * Display data. 502 */ 503 if (xflag) { 504 (void) printf("%*s%*s%*s%*s%*s " 505 "%sMode Mapped File\n", 506 addr_width, "Address", 507 size_width, "Kbytes", 508 size_width, "RSS", 509 size_width, "Anon", 510 size_width, "Locked", 511 sflag ? "Pgsz " : ""); 512 513 rc += iter_xmap(sflag ? look_xmap : 514 look_xmap_nopgsz, &t); 515 516 (void) printf("%s%s %s %s %s %s\n", 517 addr_width == 8 ? "-" : "------", 518 bar, bar, bar, bar, bar); 519 520 (void) printf("%stotal Kb", addr_width == 16 ? 521 " " : ""); 522 523 printK(t.total_size, size_width); 524 printK(t.total_rss, size_width); 525 printK(t.total_anon, size_width); 526 printK(t.total_locked, size_width); 527 528 (void) printf("\n"); 529 530 } else if (Sflag) { 531 (void) printf("%*s%*s%*s Mode" 532 " Mapped File\n", 533 addr_width, "Address", 534 size_width, "Kbytes", 535 size_width, "Swap"); 536 537 rc += iter_xmap(look_xmap_nopgsz, &t); 538 539 (void) printf("%s%s %s %s\n", 540 addr_width == 8 ? "-" : "------", 541 bar, bar, bar); 542 543 (void) printf("%stotal Kb", addr_width == 16 ? 544 " " : ""); 545 546 printK(t.total_size, size_width); 547 printK(t.total_swap, size_width); 548 549 (void) printf("\n"); 550 551 } else { 552 553 if (rflag) { 554 rc += iter_map(look_map, &t); 555 } else if (sflag) { 556 if (Lflag) { 557 (void) printf("%*s %*s %4s" 558 " %-6s %s %s\n", 559 addr_width, "Address", 560 size_width, 561 "Bytes", "Pgsz", "Mode ", 562 "Lgrp", "Mapped File"); 563 rc += iter_xmap(look_smap, &t); 564 } else { 565 (void) printf("%*s %*s %4s" 566 " %-6s %s\n", 567 addr_width, "Address", 568 size_width, 569 "Bytes", "Pgsz", "Mode ", 570 "Mapped File"); 571 rc += iter_xmap(look_smap, &t); 572 } 573 } else { 574 rc += iter_map(look_map, &t); 575 } 576 577 (void) printf(" %stotal %*luK\n", 578 addr_width == 16 ? 579 " " : "", 580 size_width, t.total_size); 581 } 582 583 if (stacks != NULL) { 584 free(stacks); 585 stacks = NULL; 586 } 587 588 } 589 590 Prelease(Pr, prr_flags); 591 if (mapfd != -1) 592 (void) close(mapfd); 593 } 594 595 return (rc); 596 } 597 598 static char * 599 make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 600 char *buf, size_t bufsz) 601 { 602 const pstatus_t *Psp = Pstatus(Pr); 603 const psinfo_t *pi = Ppsinfo(Pr); 604 char fname[100]; 605 struct stat statb; 606 int len; 607 char zname[ZONENAME_MAX]; 608 char zpath[PATH_MAX]; 609 char objname[PATH_MAX]; 610 611 if (!lflag && strcmp(mapname, "a.out") == 0 && 612 Pexecname(Pr, buf, bufsz) != NULL) 613 return (buf); 614 615 if (Pobjname(Pr, addr, objname, sizeof (objname)) != NULL) { 616 (void) strncpy(buf, objname, bufsz); 617 618 if (lflag) 619 return (buf); 620 621 if ((len = resolvepath(buf, buf, bufsz)) > 0) { 622 buf[len] = '\0'; 623 return (buf); 624 } 625 626 /* 627 * If the target is in a non-global zone, attempt to prepend 628 * the zone path in order to give the global-zone caller the 629 * real path to the file. 630 */ 631 if (getzonenamebyid(pi->pr_zoneid, zname, 632 sizeof (zname)) != -1 && strcmp(zname, "global") != 0) { 633 typedef int (*fptr)(char *, char *, size_t); 634 fptr zone_get_zonepath; 635 void *dlhdl; 636 637 if (((dlhdl = 638 dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) || 639 ((zone_get_zonepath = 640 (fptr) dlsym(dlhdl, "zone_get_zonepath")) == NULL)) 641 return (NULL); 642 643 if ((*zone_get_zonepath)(zname, zpath, sizeof (zpath)) 644 == Z_OK) { 645 (void) strncat(zpath, "/root", 646 MAXPATHLEN - strlen(zpath)); 647 648 if (bufsz <= strlen(zpath)) { 649 (void) dlclose(dlhdl); 650 return (NULL); 651 } 652 653 (void) strncpy(buf, zpath, bufsz); 654 (void) strncat(buf, objname, 655 bufsz - strlen(zpath)); 656 } 657 (void) dlclose(dlhdl); 658 } 659 660 if ((len = resolvepath(buf, buf, bufsz)) > 0) { 661 buf[len] = '\0'; 662 return (buf); 663 } 664 } 665 666 if (Pstate(Pr) != PS_DEAD && *mapname != '\0') { 667 (void) snprintf(fname, sizeof (fname), "/proc/%d/path/%s", 668 (int)Psp->pr_pid, mapname); 669 len = readlink(fname, buf, bufsz - 1); 670 if (len >= 0) { 671 buf[len] = '\0'; 672 return (buf); 673 } else { /* there is no path and readlink() error */ 674 (void) snprintf(fname, sizeof (fname), 675 "/proc/%d/object/%s", (int)Psp->pr_pid, mapname); 676 if (stat(fname, &statb) == 0) { 677 dev_t dev = statb.st_dev; 678 ino_t ino = statb.st_ino; 679 (void) snprintf(buf, bufsz, 680 "dev:%lu,%lu ino:%lu", 681 (ulong_t)major(dev), 682 (ulong_t)minor(dev), ino); 683 return (buf); 684 } 685 } 686 } 687 688 return (NULL); 689 } 690 691 static char * 692 anon_name(char *name, const pstatus_t *Psp, 693 uintptr_t vaddr, size_t size, int mflags, int shmid) 694 { 695 if (mflags & MA_ISM) { 696 if (shmid == -1) 697 (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 698 (mflags & MA_NORESERVE) ? "ism" : "dism"); 699 else 700 (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 701 (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 702 } else if (mflags & MA_SHM) { 703 if (shmid == -1) 704 (void) sprintf(name, " [ shmid=null ]"); 705 else 706 (void) sprintf(name, " [ shmid=0x%x ]", shmid); 707 } else if (vaddr + size > Psp->pr_stkbase && 708 vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 709 (void) strcpy(name, " [ stack ]"); 710 } else if ((mflags & MA_ANON) && 711 vaddr + size > Psp->pr_brkbase && 712 vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 713 (void) strcpy(name, " [ heap ]"); 714 } else { 715 lwpstack_t key, *stk; 716 717 key.lwps_stack.ss_sp = (void *)vaddr; 718 key.lwps_stack.ss_size = size; 719 if (nstacks > 0 && 720 (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 721 cmpstacks)) != NULL) { 722 (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 723 (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 724 "altstack" : "stack", 725 stk->lwps_lwpid); 726 } else if (Pstate(Pr) != PS_DEAD) { 727 (void) strcpy(name, " [ anon ]"); 728 } else { 729 return (NULL); 730 } 731 } 732 733 return (name); 734 } 735 736 static int 737 rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd) 738 { 739 char mapname[PATH_MAX]; 740 int mapfd, nmap, i, rc; 741 struct stat st; 742 prmap_t *prmapp, *pmp; 743 ssize_t n; 744 745 (void) snprintf(mapname, sizeof (mapname), 746 "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid); 747 748 if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 749 if (mapfd >= 0) 750 (void) close(mapfd); 751 return (perr(mapname)); 752 } 753 754 nmap = st.st_size / sizeof (prmap_t); 755 prmapp = malloc((nmap + 1) * sizeof (prmap_t)); 756 757 if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) { 758 (void) close(mapfd); 759 free(prmapp); 760 return (perr("read rmap")); 761 } 762 763 (void) close(mapfd); 764 nmap = n / sizeof (prmap_t); 765 766 for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 767 if ((rc = func(cd, pmp, NULL)) != 0) { 768 free(prmapp); 769 return (rc); 770 } 771 } 772 773 free(prmapp); 774 return (0); 775 } 776 777 static int 778 xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap) 779 { 780 char mapname[PATH_MAX]; 781 int mapfd, nmap, i, rc; 782 struct stat st; 783 prxmap_t *prmapp, *pmp; 784 ssize_t n; 785 786 (void) snprintf(mapname, sizeof (mapname), 787 "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid); 788 789 if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 790 if (mapfd >= 0) 791 (void) close(mapfd); 792 return (perr(mapname)); 793 } 794 795 nmap = st.st_size / sizeof (prxmap_t); 796 nmap *= 2; 797 again: 798 prmapp = malloc((nmap + 1) * sizeof (prxmap_t)); 799 800 if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) { 801 (void) close(mapfd); 802 free(prmapp); 803 return (perr("read xmap")); 804 } 805 806 if (nmap < n / sizeof (prxmap_t)) { 807 free(prmapp); 808 nmap *= 2; 809 goto again; 810 } 811 812 (void) close(mapfd); 813 nmap = n / sizeof (prxmap_t); 814 815 for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 816 if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) { 817 free(prmapp); 818 return (rc); 819 } 820 } 821 822 /* 823 * Mark the last element. 824 */ 825 if (map_count > 0) 826 maps[map_count - 1].md_last = B_TRUE; 827 828 free(prmapp); 829 return (0); 830 } 831 832 /*ARGSUSED*/ 833 static int 834 look_map(void *data, const prmap_t *pmp, const char *object_name) 835 { 836 struct totals *t = data; 837 const pstatus_t *Psp = Pstatus(Pr); 838 size_t size; 839 char mname[PATH_MAX]; 840 char *lname = NULL; 841 size_t psz = pmp->pr_pagesize; 842 uintptr_t vaddr = pmp->pr_vaddr; 843 uintptr_t segment_end = vaddr + pmp->pr_size; 844 lgrp_id_t lgrp; 845 memory_chunk_t mchunk; 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 segment_end <= 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 ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 860 lname = anon_name(mname, Psp, pmp->pr_vaddr, 861 pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 862 } 863 864 /* 865 * Adjust the address range if -A is specified. 866 */ 867 size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 868 &vaddr, &segment_end); 869 870 if (size == 0) 871 return (0); 872 873 if (!Lflag) { 874 /* 875 * Display the whole mapping 876 */ 877 size = ROUNDUP_KB(size); 878 879 (void) printf(lname ? 880 "%.*lX %*luK %-6s %s\n" : 881 "%.*lX %*luK %s\n", 882 addr_width, vaddr, 883 size_width - 1, size, mflags(pmp->pr_mflags), lname); 884 885 t->total_size += size; 886 return (0); 887 } 888 889 /* 890 * We need to display lgroups backing physical memory, so we break the 891 * segment into individual pages and coalesce pages with the same lgroup 892 * into one "segment". 893 */ 894 895 /* 896 * Initialize address descriptions for the mapping. 897 */ 898 mem_chunk_init(&mchunk, segment_end, psz); 899 size = 0; 900 901 /* 902 * Walk mapping (page by page) and display contiguous ranges of memory 903 * allocated to same lgroup. 904 */ 905 do { 906 size_t size_contig; 907 908 /* 909 * Get contiguous region of memory starting from vaddr allocated 910 * from the same lgroup. 911 */ 912 size_contig = get_contiguous_region(&mchunk, vaddr, 913 segment_end, pmp->pr_pagesize, &lgrp); 914 915 (void) printf(lname ? "%.*lX %*luK %-6s%s %s\n" : 916 "%.*lX %*luK %s %s\n", 917 addr_width, vaddr, 918 size_width - 1, size_contig / KILOBYTE, 919 mflags(pmp->pr_mflags), 920 lgrp2str(lgrp), lname); 921 922 vaddr += size_contig; 923 size += size_contig; 924 } while (vaddr < segment_end && !interrupt); 925 926 /* Update the total size */ 927 t->total_size += ROUNDUP_KB(size); 928 return (0); 929 } 930 931 static void 932 printK(long value, int width) 933 { 934 if (value == 0) 935 (void) printf(width == 8 ? " -" : " -"); 936 else 937 (void) printf(" %*lu", width - 1, value); 938 } 939 940 static const char * 941 pagesize(const prxmap_t *pmp) 942 { 943 int pagesize = pmp->pr_hatpagesize; 944 static char buf[32]; 945 946 if (pagesize == 0) { 947 return ("-"); /* no underlying HAT mapping */ 948 } 949 950 if (pagesize >= KILOBYTE && (pagesize % KILOBYTE) == 0) { 951 if ((pagesize % GIGABYTE) == 0) 952 (void) snprintf(buf, sizeof (buf), "%dG", 953 pagesize / GIGABYTE); 954 else if ((pagesize % MEGABYTE) == 0) 955 (void) snprintf(buf, sizeof (buf), "%dM", 956 pagesize / MEGABYTE); 957 else 958 (void) snprintf(buf, sizeof (buf), "%dK", 959 pagesize / KILOBYTE); 960 } else 961 (void) snprintf(buf, sizeof (buf), "%db", pagesize); 962 963 return (buf); 964 } 965 966 /*ARGSUSED*/ 967 static int 968 look_smap(void *data, 969 const prxmap_t *pmp, 970 const char *object_name, 971 int last, int doswap) 972 { 973 struct totals *t = data; 974 const pstatus_t *Psp = Pstatus(Pr); 975 size_t size; 976 char mname[PATH_MAX]; 977 char *lname = NULL; 978 const char *format; 979 size_t psz = pmp->pr_pagesize; 980 uintptr_t vaddr = pmp->pr_vaddr; 981 uintptr_t segment_end = vaddr + pmp->pr_size; 982 lgrp_id_t lgrp; 983 memory_chunk_t mchunk; 984 985 /* 986 * If the mapping is not anon or not part of the heap, make a name 987 * for it. We don't want to report the heap as a.out's data. 988 */ 989 if (!(pmp->pr_mflags & MA_ANON) || 990 pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 991 pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 992 lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 993 mname, sizeof (mname)); 994 } 995 996 if (lname == NULL && 997 ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 998 lname = anon_name(mname, Psp, pmp->pr_vaddr, 999 pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 1000 } 1001 1002 /* 1003 * Adjust the address range if -A is specified. 1004 */ 1005 size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 1006 &vaddr, &segment_end); 1007 1008 if (size == 0) 1009 return (0); 1010 1011 if (!Lflag) { 1012 /* 1013 * Display the whole mapping 1014 */ 1015 if (lname != NULL) 1016 format = "%.*lX %*luK %4s %-6s %s\n"; 1017 else 1018 format = "%.*lX %*luK %4s %s\n"; 1019 1020 size = ROUNDUP_KB(size); 1021 1022 (void) printf(format, addr_width, vaddr, size_width - 1, size, 1023 pagesize(pmp), mflags(pmp->pr_mflags), lname); 1024 1025 t->total_size += size; 1026 return (0); 1027 } 1028 1029 if (lname != NULL) 1030 format = "%.*lX %*luK %4s %-6s%s %s\n"; 1031 else 1032 format = "%.*lX %*luK %4s%s %s\n"; 1033 1034 /* 1035 * We need to display lgroups backing physical memory, so we break the 1036 * segment into individual pages and coalesce pages with the same lgroup 1037 * into one "segment". 1038 */ 1039 1040 /* 1041 * Initialize address descriptions for the mapping. 1042 */ 1043 mem_chunk_init(&mchunk, segment_end, psz); 1044 size = 0; 1045 1046 /* 1047 * Walk mapping (page by page) and display contiguous ranges of memory 1048 * allocated to same lgroup. 1049 */ 1050 do { 1051 size_t size_contig; 1052 1053 /* 1054 * Get contiguous region of memory starting from vaddr allocated 1055 * from the same lgroup. 1056 */ 1057 size_contig = get_contiguous_region(&mchunk, vaddr, 1058 segment_end, pmp->pr_pagesize, &lgrp); 1059 1060 (void) printf(format, addr_width, vaddr, 1061 size_width - 1, size_contig / KILOBYTE, 1062 pagesize(pmp), mflags(pmp->pr_mflags), 1063 lgrp2str(lgrp), lname); 1064 1065 vaddr += size_contig; 1066 size += size_contig; 1067 } while (vaddr < segment_end && !interrupt); 1068 1069 t->total_size += ROUNDUP_KB(size); 1070 return (0); 1071 } 1072 1073 #define ANON(x) ((aflag || (((x)->pr_mflags & MA_SHARED) == 0)) ? \ 1074 ((x)->pr_anon) : 0) 1075 1076 /*ARGSUSED*/ 1077 static int 1078 look_xmap(void *data, 1079 const prxmap_t *pmp, 1080 const char *object_name, 1081 int last, int doswap) 1082 { 1083 struct totals *t = data; 1084 const pstatus_t *Psp = Pstatus(Pr); 1085 char mname[PATH_MAX]; 1086 char *lname = NULL; 1087 char *ln; 1088 1089 /* 1090 * If the mapping is not anon or not part of the heap, make a name 1091 * for it. We don't want to report the heap as a.out's data. 1092 */ 1093 if (!(pmp->pr_mflags & MA_ANON) || 1094 pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 1095 pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 1096 lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 1097 mname, sizeof (mname)); 1098 } 1099 1100 if (lname != NULL) { 1101 if ((ln = strrchr(lname, '/')) != NULL) 1102 lname = ln + 1; 1103 } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 1104 lname = anon_name(mname, Psp, pmp->pr_vaddr, 1105 pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 1106 } 1107 1108 (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 1109 1110 printK(ROUNDUP_KB(pmp->pr_size), size_width); 1111 printK(pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE), size_width); 1112 printK(ANON(pmp) * (pmp->pr_pagesize / KILOBYTE), size_width); 1113 printK(pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE), size_width); 1114 (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n", 1115 pagesize(pmp), mflags(pmp->pr_mflags), lname); 1116 1117 t->total_size += ROUNDUP_KB(pmp->pr_size); 1118 t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE); 1119 t->total_anon += ANON(pmp) * (pmp->pr_pagesize / KILOBYTE); 1120 t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE)); 1121 1122 return (0); 1123 } 1124 1125 /*ARGSUSED*/ 1126 static int 1127 look_xmap_nopgsz(void *data, 1128 const prxmap_t *pmp, 1129 const char *object_name, 1130 int last, int doswap) 1131 { 1132 struct totals *t = data; 1133 const pstatus_t *Psp = Pstatus(Pr); 1134 char mname[PATH_MAX]; 1135 char *lname = NULL; 1136 char *ln; 1137 static uintptr_t prev_vaddr; 1138 static size_t prev_size; 1139 static offset_t prev_offset; 1140 static int prev_mflags; 1141 static char *prev_lname; 1142 static char prev_mname[PATH_MAX]; 1143 static ulong_t prev_rss; 1144 static ulong_t prev_anon; 1145 static ulong_t prev_locked; 1146 static ulong_t prev_swap; 1147 int merged = 0; 1148 static int first = 1; 1149 ulong_t swap = 0; 1150 int kperpage; 1151 1152 /* 1153 * Calculate swap reservations 1154 */ 1155 if (pmp->pr_mflags & MA_SHARED) { 1156 if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) { 1157 /* Swap reserved for entire non-ism SHM */ 1158 swap = pmp->pr_size / pmp->pr_pagesize; 1159 } 1160 } else if (pmp->pr_mflags & MA_NORESERVE) { 1161 /* Swap reserved on fault for each anon page */ 1162 swap = pmp->pr_anon; 1163 } else if (pmp->pr_mflags & MA_WRITE) { 1164 /* Swap reserve for entire writable segment */ 1165 swap = pmp->pr_size / pmp->pr_pagesize; 1166 } 1167 1168 /* 1169 * If the mapping is not anon or not part of the heap, make a name 1170 * for it. We don't want to report the heap as a.out's data. 1171 */ 1172 if (!(pmp->pr_mflags & MA_ANON) || 1173 pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 1174 pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 1175 lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 1176 mname, sizeof (mname)); 1177 } 1178 1179 if (lname != NULL) { 1180 if ((ln = strrchr(lname, '/')) != NULL) 1181 lname = ln + 1; 1182 } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 1183 lname = anon_name(mname, Psp, pmp->pr_vaddr, 1184 pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 1185 } 1186 1187 kperpage = pmp->pr_pagesize / KILOBYTE; 1188 1189 t->total_size += ROUNDUP_KB(pmp->pr_size); 1190 t->total_rss += pmp->pr_rss * kperpage; 1191 t->total_anon += ANON(pmp) * kperpage; 1192 t->total_locked += pmp->pr_locked * kperpage; 1193 t->total_swap += swap * kperpage; 1194 1195 if (first == 1) { 1196 first = 0; 1197 prev_vaddr = pmp->pr_vaddr; 1198 prev_size = pmp->pr_size; 1199 prev_offset = pmp->pr_offset; 1200 prev_mflags = pmp->pr_mflags; 1201 if (lname == NULL) { 1202 prev_lname = NULL; 1203 } else { 1204 (void) strcpy(prev_mname, lname); 1205 prev_lname = prev_mname; 1206 } 1207 prev_rss = pmp->pr_rss * kperpage; 1208 prev_anon = ANON(pmp) * kperpage; 1209 prev_locked = pmp->pr_locked * kperpage; 1210 prev_swap = swap * kperpage; 1211 if (last == 0) { 1212 return (0); 1213 } 1214 merged = 1; 1215 } else if (prev_vaddr + prev_size == pmp->pr_vaddr && 1216 prev_mflags == pmp->pr_mflags && 1217 ((prev_mflags & MA_ISM) || 1218 prev_offset + prev_size == pmp->pr_offset) && 1219 ((lname == NULL && prev_lname == NULL) || 1220 (lname != NULL && prev_lname != NULL && 1221 strcmp(lname, prev_lname) == 0))) { 1222 prev_size += pmp->pr_size; 1223 prev_rss += pmp->pr_rss * kperpage; 1224 prev_anon += ANON(pmp) * kperpage; 1225 prev_locked += pmp->pr_locked * kperpage; 1226 prev_swap += swap * kperpage; 1227 if (last == 0) { 1228 return (0); 1229 } 1230 merged = 1; 1231 } 1232 1233 (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr); 1234 printK(ROUNDUP_KB(prev_size), size_width); 1235 1236 if (doswap) 1237 printK(prev_swap, size_width); 1238 else { 1239 printK(prev_rss, size_width); 1240 printK(prev_anon, size_width); 1241 printK(prev_locked, size_width); 1242 } 1243 (void) printf(prev_lname ? " %-6s %s\n" : "%s\n", 1244 mflags(prev_mflags), prev_lname); 1245 1246 if (last == 0) { 1247 prev_vaddr = pmp->pr_vaddr; 1248 prev_size = pmp->pr_size; 1249 prev_offset = pmp->pr_offset; 1250 prev_mflags = pmp->pr_mflags; 1251 if (lname == NULL) { 1252 prev_lname = NULL; 1253 } else { 1254 (void) strcpy(prev_mname, lname); 1255 prev_lname = prev_mname; 1256 } 1257 prev_rss = pmp->pr_rss * kperpage; 1258 prev_anon = ANON(pmp) * kperpage; 1259 prev_locked = pmp->pr_locked * kperpage; 1260 prev_swap = swap * kperpage; 1261 } else if (merged == 0) { 1262 (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 1263 printK(ROUNDUP_KB(pmp->pr_size), size_width); 1264 if (doswap) 1265 printK(swap * kperpage, size_width); 1266 else { 1267 printK(pmp->pr_rss * kperpage, size_width); 1268 printK(ANON(pmp) * kperpage, size_width); 1269 printK(pmp->pr_locked * kperpage, size_width); 1270 } 1271 (void) printf(lname ? " %-6s %s\n" : " %s\n", 1272 mflags(pmp->pr_mflags), lname); 1273 } 1274 1275 if (last != 0) 1276 first = 1; 1277 1278 return (0); 1279 } 1280 1281 static int 1282 perr(char *s) 1283 { 1284 if (s) 1285 (void) fprintf(stderr, "%s: ", procname); 1286 else 1287 s = procname; 1288 perror(s); 1289 return (1); 1290 } 1291 1292 static char * 1293 mflags(uint_t arg) 1294 { 1295 static char code_buf[80]; 1296 char *str = code_buf; 1297 1298 /* 1299 * rwxsR 1300 * 1301 * r - segment is readable 1302 * w - segment is writable 1303 * x - segment is executable 1304 * s - segment is shared 1305 * R - segment is mapped MAP_NORESERVE 1306 * 1307 */ 1308 (void) sprintf(str, "%c%c%c%c%c%c", 1309 arg & MA_READ ? 'r' : '-', 1310 arg & MA_WRITE ? 'w' : '-', 1311 arg & MA_EXEC ? 'x' : '-', 1312 arg & MA_SHARED ? 's' : '-', 1313 arg & MA_NORESERVE ? 'R' : '-', 1314 arg & MA_RESERVED1 ? '*' : ' '); 1315 1316 return (str); 1317 } 1318 1319 static mapdata_t * 1320 nextmap(void) 1321 { 1322 mapdata_t *newmaps; 1323 int next; 1324 1325 if (map_count == map_alloc) { 1326 if (map_alloc == 0) 1327 next = 16; 1328 else 1329 next = map_alloc * 2; 1330 1331 newmaps = realloc(maps, next * sizeof (mapdata_t)); 1332 if (newmaps == NULL) { 1333 (void) perr("failed to allocate maps"); 1334 exit(1); 1335 } 1336 (void) memset(newmaps + map_alloc, '\0', 1337 (next - map_alloc) * sizeof (mapdata_t)); 1338 1339 map_alloc = next; 1340 maps = newmaps; 1341 } 1342 1343 return (&maps[map_count++]); 1344 } 1345 1346 /*ARGSUSED*/ 1347 static int 1348 gather_map(void *ignored, const prmap_t *map, const char *objname) 1349 { 1350 mapdata_t *data; 1351 1352 /* Skip mappings which are outside the range specified by -A */ 1353 if (!address_in_range(map->pr_vaddr, 1354 map->pr_vaddr + map->pr_size, map->pr_pagesize)) 1355 return (0); 1356 1357 data = nextmap(); 1358 data->md_map = *map; 1359 if (data->md_objname != NULL) 1360 free(data->md_objname); 1361 data->md_objname = objname ? strdup(objname) : NULL; 1362 1363 return (0); 1364 } 1365 1366 /*ARGSUSED*/ 1367 static int 1368 gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname, 1369 int last, int doswap) 1370 { 1371 mapdata_t *data; 1372 1373 /* Skip mappings which are outside the range specified by -A */ 1374 if (!address_in_range(xmap->pr_vaddr, 1375 xmap->pr_vaddr + xmap->pr_size, xmap->pr_pagesize)) 1376 return (0); 1377 1378 data = nextmap(); 1379 data->md_xmap = *xmap; 1380 if (data->md_objname != NULL) 1381 free(data->md_objname); 1382 data->md_objname = objname ? strdup(objname) : NULL; 1383 data->md_last = last; 1384 data->md_doswap = doswap; 1385 1386 return (0); 1387 } 1388 1389 static int 1390 iter_map(proc_map_f *func, void *data) 1391 { 1392 int i; 1393 int ret; 1394 1395 for (i = 0; i < map_count; i++) { 1396 if (interrupt) 1397 break; 1398 if ((ret = func(data, &maps[i].md_map, 1399 maps[i].md_objname)) != 0) 1400 return (ret); 1401 } 1402 1403 return (0); 1404 } 1405 1406 static int 1407 iter_xmap(proc_xmap_f *func, void *data) 1408 { 1409 int i; 1410 int ret; 1411 1412 for (i = 0; i < map_count; i++) { 1413 if (interrupt) 1414 break; 1415 if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname, 1416 maps[i].md_last, maps[i].md_doswap)) != 0) 1417 return (ret); 1418 } 1419 1420 return (0); 1421 } 1422 1423 /* 1424 * Convert lgroup ID to string. 1425 * returns dash when lgroup ID is invalid. 1426 */ 1427 static char * 1428 lgrp2str(lgrp_id_t lgrp) 1429 { 1430 static char lgrp_buf[20]; 1431 char *str = lgrp_buf; 1432 1433 (void) sprintf(str, lgrp == LGRP_NONE ? " -" : "%4d", lgrp); 1434 return (str); 1435 } 1436 1437 /* 1438 * Parse address range specification for -A option. 1439 * The address range may have the following forms: 1440 * 1441 * address 1442 * start and end is set to address 1443 * address, 1444 * start is set to address, end is set to INVALID_ADDRESS 1445 * ,address 1446 * start is set to 0, end is set to address 1447 * address1,address2 1448 * start is set to address1, end is set to address2 1449 * 1450 */ 1451 static int 1452 parse_addr_range(char *input_str, uintptr_t *start, uintptr_t *end) 1453 { 1454 char *startp = input_str; 1455 char *endp = strchr(input_str, ','); 1456 ulong_t s = (ulong_t)INVALID_ADDRESS; 1457 ulong_t e = (ulong_t)INVALID_ADDRESS; 1458 1459 if (endp != NULL) { 1460 /* 1461 * Comma is present. If there is nothing after comma, the end 1462 * remains set at INVALID_ADDRESS. Otherwise it is set to the 1463 * value after comma. 1464 */ 1465 *endp = '\0'; 1466 endp++; 1467 1468 if ((*endp != '\0') && sscanf(endp, "%lx", &e) != 1) 1469 return (1); 1470 } 1471 1472 if (startp != NULL) { 1473 /* 1474 * Read the start address, if it is specified. If the address is 1475 * missing, start will be set to INVALID_ADDRESS. 1476 */ 1477 if ((*startp != '\0') && sscanf(startp, "%lx", &s) != 1) 1478 return (1); 1479 } 1480 1481 /* If there is no comma, end becomes equal to start */ 1482 if (endp == NULL) 1483 e = s; 1484 1485 /* 1486 * ,end implies 0..end range 1487 */ 1488 if (e != INVALID_ADDRESS && s == INVALID_ADDRESS) 1489 s = 0; 1490 1491 *start = (uintptr_t)s; 1492 *end = (uintptr_t)e; 1493 1494 /* Return error if neither start nor end address were specified */ 1495 return (! (s != INVALID_ADDRESS || e != INVALID_ADDRESS)); 1496 } 1497 1498 /* 1499 * Check whether any portion of [start, end] segment is within the 1500 * [start_addr, end_addr] range. 1501 * 1502 * Return values: 1503 * 0 - address is outside the range 1504 * 1 - address is within the range 1505 */ 1506 static int 1507 address_in_range(uintptr_t start, uintptr_t end, size_t psz) 1508 { 1509 int rc = 1; 1510 1511 /* 1512 * Nothing to do if there is no address range specified with -A 1513 */ 1514 if (start_addr != INVALID_ADDRESS || end_addr != INVALID_ADDRESS) { 1515 /* The segment end is below the range start */ 1516 if ((start_addr != INVALID_ADDRESS) && 1517 (end < P2ALIGN(start_addr, psz))) 1518 rc = 0; 1519 1520 /* The segment start is above the range end */ 1521 if ((end_addr != INVALID_ADDRESS) && 1522 (start > P2ALIGN(end_addr + psz, psz))) 1523 rc = 0; 1524 } 1525 return (rc); 1526 } 1527 1528 /* 1529 * Returns an intersection of the [start, end] interval and the range specified 1530 * by -A flag [start_addr, end_addr]. Unspecified parts of the address range 1531 * have value INVALID_ADDRESS. 1532 * 1533 * The start_addr address is rounded down to the beginning of page and end_addr 1534 * is rounded up to the end of page. 1535 * 1536 * Returns the size of the resulting interval or zero if the interval is empty 1537 * or invalid. 1538 */ 1539 static size_t 1540 adjust_addr_range(uintptr_t start, uintptr_t end, size_t psz, 1541 uintptr_t *new_start, uintptr_t *new_end) 1542 { 1543 uintptr_t from; /* start_addr rounded down */ 1544 uintptr_t to; /* end_addr rounded up */ 1545 1546 /* 1547 * Round down the lower address of the range to the beginning of page. 1548 */ 1549 if (start_addr == INVALID_ADDRESS) { 1550 /* 1551 * No start_addr specified by -A, the lower part of the interval 1552 * does not change. 1553 */ 1554 *new_start = start; 1555 } else { 1556 from = P2ALIGN(start_addr, psz); 1557 /* 1558 * If end address is outside the range, return an empty 1559 * interval 1560 */ 1561 if (end < from) { 1562 *new_start = *new_end = 0; 1563 return (0); 1564 } 1565 /* 1566 * The adjusted start address is the maximum of requested start 1567 * and the aligned start_addr of the -A range. 1568 */ 1569 *new_start = start < from ? from : start; 1570 } 1571 1572 /* 1573 * Round up the higher address of the range to the end of page. 1574 */ 1575 if (end_addr == INVALID_ADDRESS) { 1576 /* 1577 * No end_addr specified by -A, the upper part of the interval 1578 * does not change. 1579 */ 1580 *new_end = end; 1581 } else { 1582 /* 1583 * If only one address is specified and it is the beginning of a 1584 * segment, get information about the whole segment. This 1585 * function is called once per segment and the 'end' argument is 1586 * always the end of a segment, so just use the 'end' value. 1587 */ 1588 to = (end_addr == start_addr && start == start_addr) ? 1589 end : 1590 P2ALIGN(end_addr + psz, psz); 1591 /* 1592 * If start address is outside the range, return an empty 1593 * interval 1594 */ 1595 if (start > to) { 1596 *new_start = *new_end = 0; 1597 return (0); 1598 } 1599 /* 1600 * The adjusted end address is the minimum of requested end 1601 * and the aligned end_addr of the -A range. 1602 */ 1603 *new_end = end > to ? to : end; 1604 } 1605 1606 /* 1607 * Make sure that the resulting interval is legal. 1608 */ 1609 if (*new_end < *new_start) 1610 *new_start = *new_end = 0; 1611 1612 /* Return the size of the interval */ 1613 return (*new_end - *new_start); 1614 } 1615 1616 /* 1617 * Initialize memory_info data structure with information about a new segment. 1618 */ 1619 static void 1620 mem_chunk_init(memory_chunk_t *chunk, uintptr_t end, size_t psz) 1621 { 1622 chunk->end_addr = end; 1623 chunk->page_size = psz; 1624 chunk->page_index = 0; 1625 chunk->chunk_start = chunk->chunk_end = 0; 1626 } 1627 1628 /* 1629 * Create a new chunk of addresses starting from vaddr. 1630 * Pass the whole chunk to pr_meminfo to collect lgroup and page size 1631 * information for each page in the chunk. 1632 */ 1633 static void 1634 mem_chunk_get(memory_chunk_t *chunk, uintptr_t vaddr) 1635 { 1636 page_descr_t *pdp = chunk->page_info; 1637 size_t psz = chunk->page_size; 1638 uintptr_t addr = vaddr; 1639 uint64_t inaddr[MAX_MEMINFO_CNT]; 1640 uint64_t outdata[2 * MAX_MEMINFO_CNT]; 1641 uint_t info[2] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; 1642 uint_t validity[MAX_MEMINFO_CNT]; 1643 uint64_t *dataptr = inaddr; 1644 uint64_t *outptr = outdata; 1645 uint_t *valptr = validity; 1646 int i, j, rc; 1647 1648 chunk->chunk_start = vaddr; 1649 chunk->page_index = 0; /* reset index for the new chunk */ 1650 1651 /* 1652 * Fill in MAX_MEMINFO_CNT wotrh of pages starting from vaddr. Also, 1653 * copy starting address of each page to inaddr array for pr_meminfo. 1654 */ 1655 for (i = 0, pdp = chunk->page_info; 1656 (i < MAX_MEMINFO_CNT) && (addr <= chunk->end_addr); 1657 i++, pdp++, dataptr++, addr += psz) { 1658 *dataptr = (uint64_t)addr; 1659 pdp->pd_start = addr; 1660 pdp->pd_lgrp = LGRP_NONE; 1661 pdp->pd_valid = 0; 1662 pdp->pd_pagesize = 0; 1663 } 1664 1665 /* Mark the number of entries in the chunk and the last address */ 1666 chunk->page_count = i; 1667 chunk->chunk_end = addr - psz; 1668 1669 if (interrupt) 1670 return; 1671 1672 /* Call meminfo for all collected addresses */ 1673 rc = pr_meminfo(Pr, inaddr, i, info, 2, outdata, validity); 1674 if (rc < 0) { 1675 (void) perr("can not get memory information"); 1676 return; 1677 } 1678 1679 /* Verify validity of each result and fill in the addrs array */ 1680 pdp = chunk->page_info; 1681 for (j = 0; j < i; j++, pdp++, valptr++, outptr += 2) { 1682 /* Skip invalid address pointers */ 1683 if ((*valptr & 1) == 0) { 1684 continue; 1685 } 1686 1687 /* Is lgroup information available? */ 1688 if ((*valptr & 2) != 0) { 1689 pdp->pd_lgrp = (lgrp_id_t)*outptr; 1690 pdp->pd_valid = 1; 1691 } 1692 1693 /* Is page size informaion available? */ 1694 if ((*valptr & 4) != 0) { 1695 pdp->pd_pagesize = *(outptr + 1); 1696 } 1697 } 1698 } 1699 1700 /* 1701 * Starting from address 'vaddr' find the region with pages allocated from the 1702 * same lgroup. 1703 * 1704 * Arguments: 1705 * mchunk Initialized memory chunk structure 1706 * vaddr Starting address of the region 1707 * maxaddr Upper bound of the region 1708 * pagesize Default page size to use 1709 * ret_lgrp On exit contains the lgroup ID of all pages in the 1710 * region. 1711 * 1712 * Returns: 1713 * Size of the contiguous region in bytes 1714 * The lgroup ID of all pages in the region in ret_lgrp argument. 1715 */ 1716 static size_t 1717 get_contiguous_region(memory_chunk_t *mchunk, uintptr_t vaddr, 1718 uintptr_t maxaddr, size_t pagesize, lgrp_id_t *ret_lgrp) 1719 { 1720 size_t size_contig = 0; 1721 lgrp_id_t lgrp; /* Lgroup of the region start */ 1722 lgrp_id_t curr_lgrp; /* Lgroup of the current page */ 1723 size_t psz = pagesize; /* Pagesize to use */ 1724 1725 /* Set both lgroup IDs to the lgroup of the first page */ 1726 curr_lgrp = lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1727 1728 /* 1729 * Starting from vaddr, walk page by page until either the end 1730 * of the segment is reached or a page is allocated from a different 1731 * lgroup. Also stop if interrupted from keyboard. 1732 */ 1733 while ((vaddr < maxaddr) && (curr_lgrp == lgrp) && !interrupt) { 1734 /* 1735 * Get lgroup ID and the page size of the current page. 1736 */ 1737 curr_lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1738 /* If there is no page size information, use the default */ 1739 if (psz == 0) 1740 psz = pagesize; 1741 1742 if (curr_lgrp == lgrp) { 1743 /* 1744 * This page belongs to the contiguous region. 1745 * Increase the region size and advance to the new page. 1746 */ 1747 size_contig += psz; 1748 vaddr += psz; 1749 } 1750 } 1751 1752 /* Return the region lgroup ID and the size */ 1753 *ret_lgrp = lgrp; 1754 return (size_contig); 1755 } 1756 1757 /* 1758 * Given a virtual address, return its lgroup and page size. If there is meminfo 1759 * information for an address, use it, otherwise shift the chunk window to the 1760 * vaddr and create a new chunk with known meminfo information. 1761 */ 1762 static lgrp_id_t 1763 addr_to_lgrp(memory_chunk_t *chunk, uintptr_t vaddr, size_t *psz) 1764 { 1765 page_descr_t *pdp; 1766 lgrp_id_t lgrp = LGRP_NONE; 1767 int i; 1768 1769 *psz = chunk->page_size; 1770 1771 if (interrupt) 1772 return (0); 1773 1774 /* 1775 * Is there information about this address? If not, create a new chunk 1776 * starting from vaddr and apply pr_meminfo() to the whole chunk. 1777 */ 1778 if (vaddr < chunk->chunk_start || vaddr > chunk->chunk_end) { 1779 /* 1780 * This address is outside the chunk, get the new chunk and 1781 * collect meminfo information for it. 1782 */ 1783 mem_chunk_get(chunk, vaddr); 1784 } 1785 1786 /* 1787 * Find information about the address. 1788 */ 1789 pdp = &chunk->page_info[chunk->page_index]; 1790 for (i = chunk->page_index; i < chunk->page_count; i++, pdp++) { 1791 if (pdp->pd_start == vaddr) { 1792 if (pdp->pd_valid) { 1793 lgrp = pdp->pd_lgrp; 1794 /* 1795 * Override page size information if it is 1796 * present. 1797 */ 1798 if (pdp->pd_pagesize > 0) 1799 *psz = pdp->pd_pagesize; 1800 } 1801 break; 1802 } 1803 } 1804 /* 1805 * Remember where we ended - the next search will start here. 1806 * We can query for the lgrp for the same address again, so do not 1807 * advance index past the current value. 1808 */ 1809 chunk->page_index = i; 1810 1811 return (lgrp); 1812 } 1813 1814 /* ARGSUSED */ 1815 static void 1816 intr(int sig) 1817 { 1818 interrupt = 1; 1819 } 1820