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