17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5004388ebScasper * Common Development and Distribution License (the "License"). 6004388ebScasper * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21c6402783Sakolb 227c478bd9Sstevel@tonic-gate /* 23c2b5bce0Ssp92102 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <stdio.h> 28004388ebScasper #include <stdio_ext.h> 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <unistd.h> 317c478bd9Sstevel@tonic-gate #include <ctype.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <string.h> 347c478bd9Sstevel@tonic-gate #include <dirent.h> 357c478bd9Sstevel@tonic-gate #include <limits.h> 367c478bd9Sstevel@tonic-gate #include <link.h> 377c478bd9Sstevel@tonic-gate #include <libelf.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 39c6402783Sakolb #include <signal.h> 407c478bd9Sstevel@tonic-gate #include <sys/stat.h> 417c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 42c6402783Sakolb #include <sys/mman.h> 43c6402783Sakolb #include <sys/lgrp_user.h> 447c478bd9Sstevel@tonic-gate #include <libproc.h> 45*186f7fbfSEdward Pilatowicz 46*186f7fbfSEdward Pilatowicz #include "pmap_common.h" 477c478bd9Sstevel@tonic-gate 48c6402783Sakolb #define KILOBYTE 1024 49c6402783Sakolb #define MEGABYTE (KILOBYTE * KILOBYTE) 50c6402783Sakolb #define GIGABYTE (KILOBYTE * KILOBYTE * KILOBYTE) 51c6402783Sakolb 52c6402783Sakolb /* 53c6402783Sakolb * Round up the value to the nearest kilobyte 54c6402783Sakolb */ 55c6402783Sakolb #define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE) 56c6402783Sakolb 57c6402783Sakolb /* 58c6402783Sakolb * The alignment should be a power of 2. 59c6402783Sakolb */ 60c6402783Sakolb #define P2ALIGN(x, align) ((x) & -(align)) 61c6402783Sakolb 62c6402783Sakolb #define INVALID_ADDRESS (uintptr_t)(-1) 63c6402783Sakolb 647c478bd9Sstevel@tonic-gate struct totals { 657c478bd9Sstevel@tonic-gate ulong_t total_size; 667c478bd9Sstevel@tonic-gate ulong_t total_swap; 677c478bd9Sstevel@tonic-gate ulong_t total_rss; 687c478bd9Sstevel@tonic-gate ulong_t total_anon; 697c478bd9Sstevel@tonic-gate ulong_t total_locked; 707c478bd9Sstevel@tonic-gate }; 717c478bd9Sstevel@tonic-gate 72c6402783Sakolb /* 73c6402783Sakolb * -L option requires per-page information. The information is presented in an 74c6402783Sakolb * array of page_descr structures. 75c6402783Sakolb */ 76c6402783Sakolb typedef struct page_descr { 77c6402783Sakolb uintptr_t pd_start; /* start address of a page */ 78c6402783Sakolb size_t pd_pagesize; /* page size in bytes */ 79c6402783Sakolb lgrp_id_t pd_lgrp; /* lgroup of memory backing the page */ 80c6402783Sakolb int pd_valid; /* valid page description if non-zero */ 81c6402783Sakolb } page_descr_t; 82c6402783Sakolb 83c6402783Sakolb /* 84c6402783Sakolb * Per-page information for a memory chunk. 85c6402783Sakolb * The meminfo(2) system call accepts up to MAX_MEMINFO_CNT pages at once. 86c6402783Sakolb * When we need to scan larger ranges we divide them in MAX_MEMINFO_CNT sized 87c6402783Sakolb * chunks. The chunk information is stored in the memory_chunk structure. 88c6402783Sakolb */ 89c6402783Sakolb typedef struct memory_chunk { 90c6402783Sakolb page_descr_t page_info[MAX_MEMINFO_CNT]; 91c6402783Sakolb uintptr_t end_addr; 92c6402783Sakolb uintptr_t chunk_start; /* Starting address */ 93c6402783Sakolb uintptr_t chunk_end; /* chunk_end is always <= end_addr */ 94c6402783Sakolb size_t page_size; 95c6402783Sakolb int page_index; /* Current page */ 96c6402783Sakolb int page_count; /* Number of pages */ 97c6402783Sakolb } memory_chunk_t; 98c6402783Sakolb 99c6402783Sakolb static volatile int interrupt; 100c6402783Sakolb 1017c478bd9Sstevel@tonic-gate typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate static int xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *, 1047c478bd9Sstevel@tonic-gate int); 1057c478bd9Sstevel@tonic-gate static int rmapping_iter(struct ps_prochandle *, proc_map_f *, void *); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate static int look_map(void *, const prmap_t *, const char *); 1087c478bd9Sstevel@tonic-gate static int look_smap(void *, const prxmap_t *, const char *, int, int); 1097c478bd9Sstevel@tonic-gate static int look_xmap(void *, const prxmap_t *, const char *, int, int); 1107c478bd9Sstevel@tonic-gate static int look_xmap_nopgsz(void *, const prxmap_t *, const char *, 1117c478bd9Sstevel@tonic-gate int, int); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate static int gather_map(void *, const prmap_t *, const char *); 1147c478bd9Sstevel@tonic-gate static int gather_xmap(void *, const prxmap_t *, const char *, int, int); 1157c478bd9Sstevel@tonic-gate static int iter_map(proc_map_f *, void *); 1167c478bd9Sstevel@tonic-gate static int iter_xmap(proc_xmap_f *, void *); 117c6402783Sakolb static int parse_addr_range(char *, uintptr_t *, uintptr_t *); 118c6402783Sakolb static void mem_chunk_init(memory_chunk_t *, uintptr_t, size_t); 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate static int perr(char *); 1217c478bd9Sstevel@tonic-gate static void printK(long, int); 1227c478bd9Sstevel@tonic-gate static char *mflags(uint_t); 1237c478bd9Sstevel@tonic-gate 124c6402783Sakolb static size_t get_contiguous_region(memory_chunk_t *, uintptr_t, 125c6402783Sakolb uintptr_t, size_t, lgrp_id_t *); 126c6402783Sakolb static void mem_chunk_get(memory_chunk_t *, uintptr_t); 127c6402783Sakolb static lgrp_id_t addr_to_lgrp(memory_chunk_t *, uintptr_t, size_t *); 128c6402783Sakolb static char *lgrp2str(lgrp_id_t); 129c6402783Sakolb 130c6402783Sakolb static int address_in_range(uintptr_t, uintptr_t, size_t); 131c6402783Sakolb static size_t adjust_addr_range(uintptr_t, uintptr_t, size_t, 132c6402783Sakolb uintptr_t *, uintptr_t *); 133c6402783Sakolb 1347c478bd9Sstevel@tonic-gate static int lflag = 0; 135c6402783Sakolb static int Lflag = 0; 1367c478bd9Sstevel@tonic-gate static int aflag = 0; 137c6402783Sakolb 138c6402783Sakolb /* 139c6402783Sakolb * The -A address range is represented as a pair of addresses 140c6402783Sakolb * <start_addr, end_addr>. Either one of these may be unspecified (set to 141c6402783Sakolb * INVALID_ADDRESS). If both are unspecified, no address range restrictions are 142c6402783Sakolb * in place. 143c6402783Sakolb */ 144c6402783Sakolb static uintptr_t start_addr = INVALID_ADDRESS; 145c6402783Sakolb static uintptr_t end_addr = INVALID_ADDRESS; 146c6402783Sakolb 1477c478bd9Sstevel@tonic-gate static int addr_width, size_width; 1487c478bd9Sstevel@tonic-gate static char *command; 1497c478bd9Sstevel@tonic-gate static char *procname; 1507c478bd9Sstevel@tonic-gate static struct ps_prochandle *Pr; 1517c478bd9Sstevel@tonic-gate 152c6402783Sakolb static void intr(int); 153c6402783Sakolb 1547c478bd9Sstevel@tonic-gate typedef struct { 1557c478bd9Sstevel@tonic-gate prxmap_t md_xmap; 1567c478bd9Sstevel@tonic-gate prmap_t md_map; 1577c478bd9Sstevel@tonic-gate char *md_objname; 158c6402783Sakolb boolean_t md_last; 1597c478bd9Sstevel@tonic-gate int md_doswap; 1607c478bd9Sstevel@tonic-gate } mapdata_t; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static mapdata_t *maps; 1637c478bd9Sstevel@tonic-gate static int map_count; 1647c478bd9Sstevel@tonic-gate static int map_alloc; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate static lwpstack_t *stacks = NULL; 1677c478bd9Sstevel@tonic-gate static uint_t nstacks = 0; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate #define MAX_TRIES 5 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate static int 1727c478bd9Sstevel@tonic-gate getstack(void *data, const lwpstatus_t *lsp) 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate int *np = (int *)data; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1777c478bd9Sstevel@tonic-gate stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 1787c478bd9Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1797c478bd9Sstevel@tonic-gate (*np)++; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1837c478bd9Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1847c478bd9Sstevel@tonic-gate (*np)++; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate return (0); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate int 1917c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1927c478bd9Sstevel@tonic-gate { 193c6402783Sakolb int rflag = 0, sflag = 0, xflag = 0, Fflag = 0; 1947c478bd9Sstevel@tonic-gate int errflg = 0, Sflag = 0; 1957c478bd9Sstevel@tonic-gate int rc = 0; 1967c478bd9Sstevel@tonic-gate int opt; 1977c478bd9Sstevel@tonic-gate const char *bar8 = "-------"; 1987c478bd9Sstevel@tonic-gate const char *bar16 = "----------"; 1997c478bd9Sstevel@tonic-gate const char *bar; 2007c478bd9Sstevel@tonic-gate struct rlimit rlim; 2017c478bd9Sstevel@tonic-gate struct stat64 statbuf; 2027c478bd9Sstevel@tonic-gate char buf[128]; 2037c478bd9Sstevel@tonic-gate int mapfd; 2047595fad9Sakolb int prg_gflags = PGRAB_RDONLY; 2057595fad9Sakolb int prr_flags = 0; 2067595fad9Sakolb boolean_t use_agent_lwp = B_FALSE; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 2097c478bd9Sstevel@tonic-gate command++; 2107c478bd9Sstevel@tonic-gate else 2117c478bd9Sstevel@tonic-gate command = argv[0]; 2127c478bd9Sstevel@tonic-gate 213c6402783Sakolb while ((opt = getopt(argc, argv, "arsxSlLFA:")) != EOF) { 2147c478bd9Sstevel@tonic-gate switch (opt) { 2157c478bd9Sstevel@tonic-gate case 'a': /* include shared mappings in -[xS] */ 2167c478bd9Sstevel@tonic-gate aflag = 1; 2177c478bd9Sstevel@tonic-gate break; 2187c478bd9Sstevel@tonic-gate case 'r': /* show reserved mappings */ 2197c478bd9Sstevel@tonic-gate rflag = 1; 2207c478bd9Sstevel@tonic-gate break; 2217c478bd9Sstevel@tonic-gate case 's': /* show hardware page sizes */ 2227c478bd9Sstevel@tonic-gate sflag = 1; 2237c478bd9Sstevel@tonic-gate break; 2247c478bd9Sstevel@tonic-gate case 'S': /* show swap reservations */ 2257c478bd9Sstevel@tonic-gate Sflag = 1; 2267c478bd9Sstevel@tonic-gate break; 2277c478bd9Sstevel@tonic-gate case 'x': /* show extended mappings */ 2287c478bd9Sstevel@tonic-gate xflag = 1; 2297c478bd9Sstevel@tonic-gate break; 2307c478bd9Sstevel@tonic-gate case 'l': /* show unresolved link map names */ 2317c478bd9Sstevel@tonic-gate lflag = 1; 2327c478bd9Sstevel@tonic-gate break; 233c6402783Sakolb case 'L': /* show lgroup information */ 234c6402783Sakolb Lflag = 1; 2357595fad9Sakolb use_agent_lwp = B_TRUE; 236c6402783Sakolb break; 237c6402783Sakolb case 'F': /* force grabbing (no O_EXCL) */ 238c6402783Sakolb Fflag = PGRAB_FORCE; 239c6402783Sakolb break; 240c6402783Sakolb case 'A': 241c6402783Sakolb if (parse_addr_range(optarg, &start_addr, &end_addr) 242c6402783Sakolb != 0) 243c6402783Sakolb errflg++; 2447c478bd9Sstevel@tonic-gate break; 2457c478bd9Sstevel@tonic-gate default: 2467c478bd9Sstevel@tonic-gate errflg = 1; 2477c478bd9Sstevel@tonic-gate break; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate argc -= optind; 2527c478bd9Sstevel@tonic-gate argv += optind; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || 255c6402783Sakolb (aflag && (!xflag && !Sflag)) || 256c6402783Sakolb (Lflag && (xflag || Sflag))) { 2577c478bd9Sstevel@tonic-gate errflg = 1; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate if (errflg || argc <= 0) { 2617c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 262c6402783Sakolb "usage:\t%s [-rslF] [-A start[,end]] { pid | core } ...\n", 263c6402783Sakolb command); 2647c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2657c478bd9Sstevel@tonic-gate "\t\t(report process address maps)\n"); 2667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 267c6402783Sakolb "\t%s -L [-rslF] [-A start[,end]] pid ...\n", command); 268c6402783Sakolb (void) fprintf(stderr, 269c6402783Sakolb "\t\t(report process address maps lgroups mappings)\n"); 270c6402783Sakolb (void) fprintf(stderr, 271c6402783Sakolb "\t%s -x [-aslF] [-A start[,end]] pid ...\n", command); 2727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2737c478bd9Sstevel@tonic-gate "\t\t(show resident/anon/locked mapping details)\n"); 2747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 275c6402783Sakolb "\t%s -S [-alF] [-A start[,end]] { pid | core } ...\n", 276c6402783Sakolb command); 2777c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2787c478bd9Sstevel@tonic-gate "\t\t(show swap reservations)\n\n"); 2797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2807c478bd9Sstevel@tonic-gate "\t-a: include shared mappings in -[xS] summary\n"); 2817c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2827c478bd9Sstevel@tonic-gate "\t-r: show reserved address maps\n"); 2837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2847c478bd9Sstevel@tonic-gate "\t-s: show hardware page sizes\n"); 2857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2867c478bd9Sstevel@tonic-gate "\t-l: show unresolved dynamic linker map names\n"); 2877c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2887c478bd9Sstevel@tonic-gate "\t-F: force grabbing of the target process\n"); 289c6402783Sakolb (void) fprintf(stderr, 290c6402783Sakolb "\t-L: show lgroup mappings\n"); 291c6402783Sakolb (void) fprintf(stderr, 292c6402783Sakolb "\t-A start,end: limit output to the specified range\n"); 2937c478bd9Sstevel@tonic-gate return (2); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 2987c478bd9Sstevel@tonic-gate * that has many many mappings. 2997c478bd9Sstevel@tonic-gate */ 3007c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 3017c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 3027c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 303004388ebScasper (void) enable_extended_FILE_stdio(-1, -1); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067595fad9Sakolb /* 3077595fad9Sakolb * The implementation of -L option creates an agent LWP in the target 3087595fad9Sakolb * process address space. The agent LWP issues meminfo(2) system calls 3097595fad9Sakolb * on behalf of the target process. If we are interrupted prematurely, 3107595fad9Sakolb * the target process remains in the stopped state with the agent still 3117595fad9Sakolb * attached to it. To prevent such situation we catch signals from 3127595fad9Sakolb * terminal and terminate gracefully. 3137595fad9Sakolb */ 3147595fad9Sakolb if (use_agent_lwp) { 3157595fad9Sakolb /* 3167595fad9Sakolb * Buffer output to stdout, stderr while process is grabbed. 3177595fad9Sakolb * Prevents infamous deadlocks due to pmap `pgrep xterm` and 3187595fad9Sakolb * other variants. 3197595fad9Sakolb */ 3207595fad9Sakolb (void) proc_initstdio(); 3217595fad9Sakolb 3227595fad9Sakolb prg_gflags = PGRAB_RETAIN | Fflag; 3237595fad9Sakolb prr_flags = PRELEASE_RETAIN; 3247595fad9Sakolb 3257595fad9Sakolb if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 3267595fad9Sakolb (void) sigset(SIGHUP, intr); 3277595fad9Sakolb if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 3287595fad9Sakolb (void) sigset(SIGINT, intr); 3297595fad9Sakolb if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 3307595fad9Sakolb (void) sigset(SIGQUIT, intr); 3317595fad9Sakolb (void) sigset(SIGPIPE, intr); 3327595fad9Sakolb (void) sigset(SIGTERM, intr); 3337595fad9Sakolb } 3347595fad9Sakolb 3357c478bd9Sstevel@tonic-gate while (argc-- > 0) { 3367c478bd9Sstevel@tonic-gate char *arg; 3377c478bd9Sstevel@tonic-gate int gcode; 3387c478bd9Sstevel@tonic-gate psinfo_t psinfo; 3397c478bd9Sstevel@tonic-gate int tries = 0; 340c6402783Sakolb 3417595fad9Sakolb if (use_agent_lwp) 3427595fad9Sakolb (void) proc_flushstdio(); 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, 345c6402783Sakolb prg_gflags, &gcode)) == NULL) { 3467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 3477c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 3487c478bd9Sstevel@tonic-gate rc++; 3497c478bd9Sstevel@tonic-gate continue; 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate procname = arg; /* for perr() */ 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 3557c478bd9Sstevel@tonic-gate size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 3567c478bd9Sstevel@tonic-gate bar = addr_width == 8 ? bar8 : bar16; 3577c478bd9Sstevel@tonic-gate (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 3587c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 3617c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 3627c478bd9Sstevel@tonic-gate "/proc/%d/map", (int)psinfo.pr_pid); 3637c478bd9Sstevel@tonic-gate if ((mapfd = open(buf, O_RDONLY)) < 0) { 3647c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 3657c478bd9Sstevel@tonic-gate "examine %s: lost control of " 3667c478bd9Sstevel@tonic-gate "process\n", command, arg); 3677c478bd9Sstevel@tonic-gate rc++; 368c6402783Sakolb Prelease(Pr, prr_flags); 3697c478bd9Sstevel@tonic-gate continue; 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate } else { 3727c478bd9Sstevel@tonic-gate mapfd = -1; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate again: 3767c478bd9Sstevel@tonic-gate map_count = 0; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 3797c478bd9Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 3807c478bd9Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 3817c478bd9Sstevel@tonic-gate 382c6402783Sakolb if (rflag || sflag || xflag || Sflag || Lflag) { 3837c478bd9Sstevel@tonic-gate (void) printf(" -%c option is not compatible " 3847c478bd9Sstevel@tonic-gate "with core files\n", xflag ? 'x' : 385c6402783Sakolb sflag ? 's' : rflag ? 'r' : 386c6402783Sakolb Lflag ? 'L' : 'S'); 387c6402783Sakolb Prelease(Pr, prr_flags); 3887c478bd9Sstevel@tonic-gate rc++; 3897c478bd9Sstevel@tonic-gate continue; 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate } else { 3937c478bd9Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 3947c478bd9Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 3987c478bd9Sstevel@tonic-gate struct totals t; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Since we're grabbing the process readonly, we need 4027c478bd9Sstevel@tonic-gate * to make sure the address space doesn't change during 4037c478bd9Sstevel@tonic-gate * execution. 4047c478bd9Sstevel@tonic-gate */ 4057c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 4067c478bd9Sstevel@tonic-gate if (tries++ == MAX_TRIES) { 407c6402783Sakolb Prelease(Pr, prr_flags); 4087c478bd9Sstevel@tonic-gate (void) close(mapfd); 4097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 4107c478bd9Sstevel@tonic-gate "examine %s: address space is " 4117c478bd9Sstevel@tonic-gate "changing\n", command, arg); 4127c478bd9Sstevel@tonic-gate continue; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate if (fstat64(mapfd, &statbuf) != 0) { 416c6402783Sakolb Prelease(Pr, prr_flags); 4177c478bd9Sstevel@tonic-gate (void) close(mapfd); 4187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 4197c478bd9Sstevel@tonic-gate "examine %s: lost control of " 4207c478bd9Sstevel@tonic-gate "process\n", command, arg); 4217c478bd9Sstevel@tonic-gate continue; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate nstacks = psinfo.pr_nlwp * 2; 4267c478bd9Sstevel@tonic-gate stacks = calloc(nstacks, sizeof (stacks[0])); 4277c478bd9Sstevel@tonic-gate if (stacks != NULL) { 4287c478bd9Sstevel@tonic-gate int n = 0; 4297c478bd9Sstevel@tonic-gate (void) Plwp_iter(Pr, getstack, &n); 4307c478bd9Sstevel@tonic-gate qsort(stacks, nstacks, sizeof (stacks[0]), 4317c478bd9Sstevel@tonic-gate cmpstacks); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate (void) memset(&t, 0, sizeof (t)); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && 4377c478bd9Sstevel@tonic-gate Prd_agent(Pr) == NULL) { 4387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: " 4397c478bd9Sstevel@tonic-gate "librtld_db failed to initialize; " 4407c478bd9Sstevel@tonic-gate "shared library information will not be " 4417c478bd9Sstevel@tonic-gate "available\n", command); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * Gather data 4467c478bd9Sstevel@tonic-gate */ 4477c478bd9Sstevel@tonic-gate if (xflag) 4487c478bd9Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 0); 4497c478bd9Sstevel@tonic-gate else if (Sflag) 4507c478bd9Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 1); 4517c478bd9Sstevel@tonic-gate else { 4527c478bd9Sstevel@tonic-gate if (rflag) 4537c478bd9Sstevel@tonic-gate rc += rmapping_iter(Pr, gather_map, 4547c478bd9Sstevel@tonic-gate NULL); 4557c478bd9Sstevel@tonic-gate else if (sflag) 4567c478bd9Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, 4577c478bd9Sstevel@tonic-gate NULL, 0); 458*186f7fbfSEdward Pilatowicz else if (lflag) 459*186f7fbfSEdward Pilatowicz rc += Pmapping_iter(Pr, 460*186f7fbfSEdward Pilatowicz gather_map, NULL); 4617c478bd9Sstevel@tonic-gate else 462*186f7fbfSEdward Pilatowicz rc += Pmapping_iter_resolved(Pr, 463*186f7fbfSEdward Pilatowicz gather_map, NULL); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * Ensure mappings are consistent. 4687c478bd9Sstevel@tonic-gate */ 4697c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 4707c478bd9Sstevel@tonic-gate struct stat64 newbuf; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (fstat64(mapfd, &newbuf) != 0 || 4737c478bd9Sstevel@tonic-gate memcmp(&newbuf.st_mtim, &statbuf.st_mtim, 4747c478bd9Sstevel@tonic-gate sizeof (newbuf.st_mtim)) != 0) { 4757c478bd9Sstevel@tonic-gate if (stacks != NULL) { 4767c478bd9Sstevel@tonic-gate free(stacks); 4777c478bd9Sstevel@tonic-gate stacks = NULL; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate goto again; 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * Display data. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate if (xflag) { 4877c478bd9Sstevel@tonic-gate (void) printf("%*s%*s%*s%*s%*s " 4887c478bd9Sstevel@tonic-gate "%sMode Mapped File\n", 4897c478bd9Sstevel@tonic-gate addr_width, "Address", 4907c478bd9Sstevel@tonic-gate size_width, "Kbytes", 4917c478bd9Sstevel@tonic-gate size_width, "RSS", 4927c478bd9Sstevel@tonic-gate size_width, "Anon", 4937c478bd9Sstevel@tonic-gate size_width, "Locked", 4947c478bd9Sstevel@tonic-gate sflag ? "Pgsz " : ""); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate rc += iter_xmap(sflag ? look_xmap : 4977c478bd9Sstevel@tonic-gate look_xmap_nopgsz, &t); 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate (void) printf("%s%s %s %s %s %s\n", 5007c478bd9Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 5017c478bd9Sstevel@tonic-gate bar, bar, bar, bar, bar); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 5047c478bd9Sstevel@tonic-gate " " : ""); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate printK(t.total_size, size_width); 5077c478bd9Sstevel@tonic-gate printK(t.total_rss, size_width); 5087c478bd9Sstevel@tonic-gate printK(t.total_anon, size_width); 5097c478bd9Sstevel@tonic-gate printK(t.total_locked, size_width); 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate (void) printf("\n"); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate } else if (Sflag) { 514c6402783Sakolb (void) printf("%*s%*s%*s Mode" 515c6402783Sakolb " Mapped File\n", 5167c478bd9Sstevel@tonic-gate addr_width, "Address", 5177c478bd9Sstevel@tonic-gate size_width, "Kbytes", 5187c478bd9Sstevel@tonic-gate size_width, "Swap"); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate rc += iter_xmap(look_xmap_nopgsz, &t); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate (void) printf("%s%s %s %s\n", 5237c478bd9Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 5247c478bd9Sstevel@tonic-gate bar, bar, bar); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 5277c478bd9Sstevel@tonic-gate " " : ""); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate printK(t.total_size, size_width); 5307c478bd9Sstevel@tonic-gate printK(t.total_swap, size_width); 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate (void) printf("\n"); 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate } else { 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate if (rflag) { 5377c478bd9Sstevel@tonic-gate rc += iter_map(look_map, &t); 5387c478bd9Sstevel@tonic-gate } else if (sflag) { 539c6402783Sakolb if (Lflag) { 540c6402783Sakolb (void) printf("%*s %*s %4s" 541c6402783Sakolb " %-6s %s %s\n", 542c6402783Sakolb addr_width, "Address", 543c6402783Sakolb size_width, 544c6402783Sakolb "Bytes", "Pgsz", "Mode ", 545c6402783Sakolb "Lgrp", "Mapped File"); 546c6402783Sakolb rc += iter_xmap(look_smap, &t); 547c6402783Sakolb } else { 548c6402783Sakolb (void) printf("%*s %*s %4s" 549c6402783Sakolb " %-6s %s\n", 550c6402783Sakolb addr_width, "Address", 551c6402783Sakolb size_width, 5527c478bd9Sstevel@tonic-gate "Bytes", "Pgsz", "Mode ", 5537c478bd9Sstevel@tonic-gate "Mapped File"); 5547c478bd9Sstevel@tonic-gate rc += iter_xmap(look_smap, &t); 555c6402783Sakolb } 5567c478bd9Sstevel@tonic-gate } else { 5577c478bd9Sstevel@tonic-gate rc += iter_map(look_map, &t); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate (void) printf(" %stotal %*luK\n", 5617c478bd9Sstevel@tonic-gate addr_width == 16 ? 5627c478bd9Sstevel@tonic-gate " " : "", 5637c478bd9Sstevel@tonic-gate size_width, t.total_size); 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate if (stacks != NULL) { 5677c478bd9Sstevel@tonic-gate free(stacks); 5687c478bd9Sstevel@tonic-gate stacks = NULL; 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 573c6402783Sakolb Prelease(Pr, prr_flags); 5747c478bd9Sstevel@tonic-gate if (mapfd != -1) 5757c478bd9Sstevel@tonic-gate (void) close(mapfd); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787595fad9Sakolb if (use_agent_lwp) 5797595fad9Sakolb (void) proc_finistdio(); 5807595fad9Sakolb 5817c478bd9Sstevel@tonic-gate return (rc); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate static int 5857c478bd9Sstevel@tonic-gate rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd) 5867c478bd9Sstevel@tonic-gate { 5877c478bd9Sstevel@tonic-gate char mapname[PATH_MAX]; 5887c478bd9Sstevel@tonic-gate int mapfd, nmap, i, rc; 5897c478bd9Sstevel@tonic-gate struct stat st; 5907c478bd9Sstevel@tonic-gate prmap_t *prmapp, *pmp; 5917c478bd9Sstevel@tonic-gate ssize_t n; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 5947c478bd9Sstevel@tonic-gate "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 5977c478bd9Sstevel@tonic-gate if (mapfd >= 0) 5987c478bd9Sstevel@tonic-gate (void) close(mapfd); 5997c478bd9Sstevel@tonic-gate return (perr(mapname)); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate nmap = st.st_size / sizeof (prmap_t); 6037c478bd9Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prmap_t)); 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) { 6067c478bd9Sstevel@tonic-gate (void) close(mapfd); 6077c478bd9Sstevel@tonic-gate free(prmapp); 6087c478bd9Sstevel@tonic-gate return (perr("read rmap")); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate (void) close(mapfd); 6127c478bd9Sstevel@tonic-gate nmap = n / sizeof (prmap_t); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 6157c478bd9Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL)) != 0) { 6167c478bd9Sstevel@tonic-gate free(prmapp); 6177c478bd9Sstevel@tonic-gate return (rc); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate free(prmapp); 6227c478bd9Sstevel@tonic-gate return (0); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate static int 6267c478bd9Sstevel@tonic-gate xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap) 6277c478bd9Sstevel@tonic-gate { 6287c478bd9Sstevel@tonic-gate char mapname[PATH_MAX]; 6297c478bd9Sstevel@tonic-gate int mapfd, nmap, i, rc; 6307c478bd9Sstevel@tonic-gate struct stat st; 6317c478bd9Sstevel@tonic-gate prxmap_t *prmapp, *pmp; 6327c478bd9Sstevel@tonic-gate ssize_t n; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 6357c478bd9Sstevel@tonic-gate "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 6387c478bd9Sstevel@tonic-gate if (mapfd >= 0) 6397c478bd9Sstevel@tonic-gate (void) close(mapfd); 6407c478bd9Sstevel@tonic-gate return (perr(mapname)); 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate nmap = st.st_size / sizeof (prxmap_t); 6447c478bd9Sstevel@tonic-gate nmap *= 2; 6457c478bd9Sstevel@tonic-gate again: 6467c478bd9Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prxmap_t)); 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) { 6497c478bd9Sstevel@tonic-gate (void) close(mapfd); 6507c478bd9Sstevel@tonic-gate free(prmapp); 6517c478bd9Sstevel@tonic-gate return (perr("read xmap")); 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate if (nmap < n / sizeof (prxmap_t)) { 6557c478bd9Sstevel@tonic-gate free(prmapp); 6567c478bd9Sstevel@tonic-gate nmap *= 2; 6577c478bd9Sstevel@tonic-gate goto again; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate (void) close(mapfd); 6617c478bd9Sstevel@tonic-gate nmap = n / sizeof (prxmap_t); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 6647c478bd9Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) { 6657c478bd9Sstevel@tonic-gate free(prmapp); 6667c478bd9Sstevel@tonic-gate return (rc); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 670c6402783Sakolb /* 671c6402783Sakolb * Mark the last element. 672c6402783Sakolb */ 673c6402783Sakolb if (map_count > 0) 674c6402783Sakolb maps[map_count - 1].md_last = B_TRUE; 675c6402783Sakolb 6767c478bd9Sstevel@tonic-gate free(prmapp); 6777c478bd9Sstevel@tonic-gate return (0); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6817c478bd9Sstevel@tonic-gate static int 6827c478bd9Sstevel@tonic-gate look_map(void *data, const prmap_t *pmp, const char *object_name) 6837c478bd9Sstevel@tonic-gate { 6847c478bd9Sstevel@tonic-gate struct totals *t = data; 6857c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 686c6402783Sakolb size_t size; 6877c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 6887c478bd9Sstevel@tonic-gate char *lname = NULL; 689c6402783Sakolb size_t psz = pmp->pr_pagesize; 690c6402783Sakolb uintptr_t vaddr = pmp->pr_vaddr; 691c6402783Sakolb uintptr_t segment_end = vaddr + pmp->pr_size; 692c6402783Sakolb lgrp_id_t lgrp; 693c6402783Sakolb memory_chunk_t mchunk; 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 6977c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 700c6402783Sakolb segment_end <= Psp->pr_brkbase || 7017c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 702*186f7fbfSEdward Pilatowicz lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname, 7037c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate if (lname == NULL && 7077c478bd9Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 708*186f7fbfSEdward Pilatowicz lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr, 709*186f7fbfSEdward Pilatowicz pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 712c6402783Sakolb /* 713c6402783Sakolb * Adjust the address range if -A is specified. 714c6402783Sakolb */ 715c6402783Sakolb size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 716c6402783Sakolb &vaddr, &segment_end); 717c6402783Sakolb 718c6402783Sakolb if (size == 0) 719c6402783Sakolb return (0); 720c6402783Sakolb 721c6402783Sakolb if (!Lflag) { 722c6402783Sakolb /* 723c6402783Sakolb * Display the whole mapping 724c6402783Sakolb */ 725c6402783Sakolb size = ROUNDUP_KB(size); 726c6402783Sakolb 727c6402783Sakolb (void) printf(lname ? 728c6402783Sakolb "%.*lX %*luK %-6s %s\n" : 729c6402783Sakolb "%.*lX %*luK %s\n", 730c6402783Sakolb addr_width, vaddr, 7317c478bd9Sstevel@tonic-gate size_width - 1, size, mflags(pmp->pr_mflags), lname); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate t->total_size += size; 7347c478bd9Sstevel@tonic-gate return (0); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 737c6402783Sakolb /* 738c6402783Sakolb * We need to display lgroups backing physical memory, so we break the 739c6402783Sakolb * segment into individual pages and coalesce pages with the same lgroup 740c6402783Sakolb * into one "segment". 741c6402783Sakolb */ 742c6402783Sakolb 743c6402783Sakolb /* 744c6402783Sakolb * Initialize address descriptions for the mapping. 745c6402783Sakolb */ 746c6402783Sakolb mem_chunk_init(&mchunk, segment_end, psz); 747c6402783Sakolb size = 0; 748c6402783Sakolb 749c6402783Sakolb /* 750c6402783Sakolb * Walk mapping (page by page) and display contiguous ranges of memory 751c6402783Sakolb * allocated to same lgroup. 752c6402783Sakolb */ 753c6402783Sakolb do { 754c6402783Sakolb size_t size_contig; 755c6402783Sakolb 756c6402783Sakolb /* 757c6402783Sakolb * Get contiguous region of memory starting from vaddr allocated 758c6402783Sakolb * from the same lgroup. 759c6402783Sakolb */ 760c6402783Sakolb size_contig = get_contiguous_region(&mchunk, vaddr, 761c6402783Sakolb segment_end, pmp->pr_pagesize, &lgrp); 762c6402783Sakolb 763c6402783Sakolb (void) printf(lname ? "%.*lX %*luK %-6s%s %s\n" : 764c6402783Sakolb "%.*lX %*luK %s %s\n", 765c6402783Sakolb addr_width, vaddr, 766c6402783Sakolb size_width - 1, size_contig / KILOBYTE, 767c6402783Sakolb mflags(pmp->pr_mflags), 768c6402783Sakolb lgrp2str(lgrp), lname); 769c6402783Sakolb 770c6402783Sakolb vaddr += size_contig; 771c6402783Sakolb size += size_contig; 772c6402783Sakolb } while (vaddr < segment_end && !interrupt); 773c6402783Sakolb 774c6402783Sakolb /* Update the total size */ 775c6402783Sakolb t->total_size += ROUNDUP_KB(size); 776c6402783Sakolb return (0); 777c6402783Sakolb } 778c6402783Sakolb 7797c478bd9Sstevel@tonic-gate static void 7807c478bd9Sstevel@tonic-gate printK(long value, int width) 7817c478bd9Sstevel@tonic-gate { 7827c478bd9Sstevel@tonic-gate if (value == 0) 7837c478bd9Sstevel@tonic-gate (void) printf(width == 8 ? " -" : " -"); 7847c478bd9Sstevel@tonic-gate else 7857c478bd9Sstevel@tonic-gate (void) printf(" %*lu", width - 1, value); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate static const char * 7897c478bd9Sstevel@tonic-gate pagesize(const prxmap_t *pmp) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate int pagesize = pmp->pr_hatpagesize; 7927c478bd9Sstevel@tonic-gate static char buf[32]; 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate if (pagesize == 0) { 7957c478bd9Sstevel@tonic-gate return ("-"); /* no underlying HAT mapping */ 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 798c6402783Sakolb if (pagesize >= KILOBYTE && (pagesize % KILOBYTE) == 0) { 799c6402783Sakolb if ((pagesize % GIGABYTE) == 0) 8007c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dG", 801c6402783Sakolb pagesize / GIGABYTE); 802c6402783Sakolb else if ((pagesize % MEGABYTE) == 0) 8037c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dM", 804c6402783Sakolb pagesize / MEGABYTE); 8057c478bd9Sstevel@tonic-gate else 8067c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dK", 807c6402783Sakolb pagesize / KILOBYTE); 8087c478bd9Sstevel@tonic-gate } else 8097c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%db", pagesize); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate return (buf); 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8157c478bd9Sstevel@tonic-gate static int 8167c478bd9Sstevel@tonic-gate look_smap(void *data, 8177c478bd9Sstevel@tonic-gate const prxmap_t *pmp, 8187c478bd9Sstevel@tonic-gate const char *object_name, 8197c478bd9Sstevel@tonic-gate int last, int doswap) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate struct totals *t = data; 8227c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 823c6402783Sakolb size_t size; 8247c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 8257c478bd9Sstevel@tonic-gate char *lname = NULL; 8267c478bd9Sstevel@tonic-gate const char *format; 827c6402783Sakolb size_t psz = pmp->pr_pagesize; 828c6402783Sakolb uintptr_t vaddr = pmp->pr_vaddr; 829c6402783Sakolb uintptr_t segment_end = vaddr + pmp->pr_size; 830c6402783Sakolb lgrp_id_t lgrp; 831c6402783Sakolb memory_chunk_t mchunk; 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 8357c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 8367c478bd9Sstevel@tonic-gate */ 8377c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 8387c478bd9Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 8397c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 840*186f7fbfSEdward Pilatowicz lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname, 8417c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if (lname == NULL && 8457c478bd9Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 846*186f7fbfSEdward Pilatowicz lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr, 847*186f7fbfSEdward Pilatowicz pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL); 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 850c6402783Sakolb /* 851c6402783Sakolb * Adjust the address range if -A is specified. 852c6402783Sakolb */ 853c6402783Sakolb size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 854c6402783Sakolb &vaddr, &segment_end); 855c6402783Sakolb 856c6402783Sakolb if (size == 0) 857c6402783Sakolb return (0); 858c6402783Sakolb 859c6402783Sakolb if (!Lflag) { 860c6402783Sakolb /* 861c6402783Sakolb * Display the whole mapping 862c6402783Sakolb */ 8637c478bd9Sstevel@tonic-gate if (lname != NULL) 8647c478bd9Sstevel@tonic-gate format = "%.*lX %*luK %4s %-6s %s\n"; 8657c478bd9Sstevel@tonic-gate else 8667c478bd9Sstevel@tonic-gate format = "%.*lX %*luK %4s %s\n"; 8677c478bd9Sstevel@tonic-gate 868c6402783Sakolb size = ROUNDUP_KB(size); 869c6402783Sakolb 870c6402783Sakolb (void) printf(format, addr_width, vaddr, size_width - 1, size, 8717c478bd9Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate t->total_size += size; 8747c478bd9Sstevel@tonic-gate return (0); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 877c6402783Sakolb if (lname != NULL) 878c6402783Sakolb format = "%.*lX %*luK %4s %-6s%s %s\n"; 879c6402783Sakolb else 880c6402783Sakolb format = "%.*lX %*luK %4s%s %s\n"; 881c6402783Sakolb 882c6402783Sakolb /* 883c6402783Sakolb * We need to display lgroups backing physical memory, so we break the 884c6402783Sakolb * segment into individual pages and coalesce pages with the same lgroup 885c6402783Sakolb * into one "segment". 886c6402783Sakolb */ 887c6402783Sakolb 888c6402783Sakolb /* 889c6402783Sakolb * Initialize address descriptions for the mapping. 890c6402783Sakolb */ 891c6402783Sakolb mem_chunk_init(&mchunk, segment_end, psz); 892c6402783Sakolb size = 0; 893c6402783Sakolb 894c6402783Sakolb /* 895c6402783Sakolb * Walk mapping (page by page) and display contiguous ranges of memory 896c6402783Sakolb * allocated to same lgroup. 897c6402783Sakolb */ 898c6402783Sakolb do { 899c6402783Sakolb size_t size_contig; 900c6402783Sakolb 901c6402783Sakolb /* 902c6402783Sakolb * Get contiguous region of memory starting from vaddr allocated 903c6402783Sakolb * from the same lgroup. 904c6402783Sakolb */ 905c6402783Sakolb size_contig = get_contiguous_region(&mchunk, vaddr, 906c6402783Sakolb segment_end, pmp->pr_pagesize, &lgrp); 907c6402783Sakolb 908c6402783Sakolb (void) printf(format, addr_width, vaddr, 909c6402783Sakolb size_width - 1, size_contig / KILOBYTE, 910c6402783Sakolb pagesize(pmp), mflags(pmp->pr_mflags), 911c6402783Sakolb lgrp2str(lgrp), lname); 912c6402783Sakolb 913c6402783Sakolb vaddr += size_contig; 914c6402783Sakolb size += size_contig; 915c6402783Sakolb } while (vaddr < segment_end && !interrupt); 916c6402783Sakolb 917c6402783Sakolb t->total_size += ROUNDUP_KB(size); 918c6402783Sakolb return (0); 919c6402783Sakolb } 920c6402783Sakolb 9217c478bd9Sstevel@tonic-gate #define ANON(x) ((aflag || (((x)->pr_mflags & MA_SHARED) == 0)) ? \ 9227c478bd9Sstevel@tonic-gate ((x)->pr_anon) : 0) 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9257c478bd9Sstevel@tonic-gate static int 9267c478bd9Sstevel@tonic-gate look_xmap(void *data, 9277c478bd9Sstevel@tonic-gate const prxmap_t *pmp, 9287c478bd9Sstevel@tonic-gate const char *object_name, 9297c478bd9Sstevel@tonic-gate int last, int doswap) 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate struct totals *t = data; 9327c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 9337c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 9347c478bd9Sstevel@tonic-gate char *lname = NULL; 9357c478bd9Sstevel@tonic-gate char *ln; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 9397c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 9407c478bd9Sstevel@tonic-gate */ 9417c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 9427c478bd9Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 9437c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 944*186f7fbfSEdward Pilatowicz lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname, 9457c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (lname != NULL) { 9497c478bd9Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 9507c478bd9Sstevel@tonic-gate lname = ln + 1; 9517c478bd9Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 952*186f7fbfSEdward Pilatowicz lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr, 953*186f7fbfSEdward Pilatowicz pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL); 9547c478bd9Sstevel@tonic-gate } 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 9577c478bd9Sstevel@tonic-gate 958c6402783Sakolb printK(ROUNDUP_KB(pmp->pr_size), size_width); 959c6402783Sakolb printK(pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE), size_width); 960c6402783Sakolb printK(ANON(pmp) * (pmp->pr_pagesize / KILOBYTE), size_width); 961c6402783Sakolb printK(pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE), size_width); 9627c478bd9Sstevel@tonic-gate (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n", 9637c478bd9Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 9647c478bd9Sstevel@tonic-gate 965c6402783Sakolb t->total_size += ROUNDUP_KB(pmp->pr_size); 966c6402783Sakolb t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE); 967c6402783Sakolb t->total_anon += ANON(pmp) * (pmp->pr_pagesize / KILOBYTE); 968c6402783Sakolb t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE)); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate return (0); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9747c478bd9Sstevel@tonic-gate static int 9757c478bd9Sstevel@tonic-gate look_xmap_nopgsz(void *data, 9767c478bd9Sstevel@tonic-gate const prxmap_t *pmp, 9777c478bd9Sstevel@tonic-gate const char *object_name, 9787c478bd9Sstevel@tonic-gate int last, int doswap) 9797c478bd9Sstevel@tonic-gate { 9807c478bd9Sstevel@tonic-gate struct totals *t = data; 9817c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 9827c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 9837c478bd9Sstevel@tonic-gate char *lname = NULL; 9847c478bd9Sstevel@tonic-gate char *ln; 9857c478bd9Sstevel@tonic-gate static uintptr_t prev_vaddr; 9867c478bd9Sstevel@tonic-gate static size_t prev_size; 9877c478bd9Sstevel@tonic-gate static offset_t prev_offset; 9887c478bd9Sstevel@tonic-gate static int prev_mflags; 9897c478bd9Sstevel@tonic-gate static char *prev_lname; 9907c478bd9Sstevel@tonic-gate static char prev_mname[PATH_MAX]; 9917c478bd9Sstevel@tonic-gate static ulong_t prev_rss; 9927c478bd9Sstevel@tonic-gate static ulong_t prev_anon; 9937c478bd9Sstevel@tonic-gate static ulong_t prev_locked; 9947c478bd9Sstevel@tonic-gate static ulong_t prev_swap; 9957c478bd9Sstevel@tonic-gate int merged = 0; 9967c478bd9Sstevel@tonic-gate static int first = 1; 9977c478bd9Sstevel@tonic-gate ulong_t swap = 0; 9987c478bd9Sstevel@tonic-gate int kperpage; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate /* 10017c478bd9Sstevel@tonic-gate * Calculate swap reservations 10027c478bd9Sstevel@tonic-gate */ 10037c478bd9Sstevel@tonic-gate if (pmp->pr_mflags & MA_SHARED) { 10047c478bd9Sstevel@tonic-gate if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) { 10057c478bd9Sstevel@tonic-gate /* Swap reserved for entire non-ism SHM */ 10067c478bd9Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_NORESERVE) { 10097c478bd9Sstevel@tonic-gate /* Swap reserved on fault for each anon page */ 10107c478bd9Sstevel@tonic-gate swap = pmp->pr_anon; 10117c478bd9Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_WRITE) { 10127c478bd9Sstevel@tonic-gate /* Swap reserve for entire writable segment */ 10137c478bd9Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 10187c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 10197c478bd9Sstevel@tonic-gate */ 10207c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 10217c478bd9Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 10227c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 1023*186f7fbfSEdward Pilatowicz lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname, 10247c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate if (lname != NULL) { 10287c478bd9Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 10297c478bd9Sstevel@tonic-gate lname = ln + 1; 10307c478bd9Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 1031*186f7fbfSEdward Pilatowicz lname = anon_name(mname, Psp, stacks, nstacks, pmp->pr_vaddr, 1032*186f7fbfSEdward Pilatowicz pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, NULL); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 1035c6402783Sakolb kperpage = pmp->pr_pagesize / KILOBYTE; 10367c478bd9Sstevel@tonic-gate 1037c6402783Sakolb t->total_size += ROUNDUP_KB(pmp->pr_size); 10387c478bd9Sstevel@tonic-gate t->total_rss += pmp->pr_rss * kperpage; 10397c478bd9Sstevel@tonic-gate t->total_anon += ANON(pmp) * kperpage; 10407c478bd9Sstevel@tonic-gate t->total_locked += pmp->pr_locked * kperpage; 10417c478bd9Sstevel@tonic-gate t->total_swap += swap * kperpage; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate if (first == 1) { 10447c478bd9Sstevel@tonic-gate first = 0; 10457c478bd9Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 10467c478bd9Sstevel@tonic-gate prev_size = pmp->pr_size; 10477c478bd9Sstevel@tonic-gate prev_offset = pmp->pr_offset; 10487c478bd9Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 10497c478bd9Sstevel@tonic-gate if (lname == NULL) { 10507c478bd9Sstevel@tonic-gate prev_lname = NULL; 10517c478bd9Sstevel@tonic-gate } else { 10527c478bd9Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 10537c478bd9Sstevel@tonic-gate prev_lname = prev_mname; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 10567c478bd9Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 10577c478bd9Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 10587c478bd9Sstevel@tonic-gate prev_swap = swap * kperpage; 10597c478bd9Sstevel@tonic-gate if (last == 0) { 10607c478bd9Sstevel@tonic-gate return (0); 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate merged = 1; 10637c478bd9Sstevel@tonic-gate } else if (prev_vaddr + prev_size == pmp->pr_vaddr && 10647c478bd9Sstevel@tonic-gate prev_mflags == pmp->pr_mflags && 10657c478bd9Sstevel@tonic-gate ((prev_mflags & MA_ISM) || 10667c478bd9Sstevel@tonic-gate prev_offset + prev_size == pmp->pr_offset) && 10677c478bd9Sstevel@tonic-gate ((lname == NULL && prev_lname == NULL) || 10687c478bd9Sstevel@tonic-gate (lname != NULL && prev_lname != NULL && 10697c478bd9Sstevel@tonic-gate strcmp(lname, prev_lname) == 0))) { 10707c478bd9Sstevel@tonic-gate prev_size += pmp->pr_size; 10717c478bd9Sstevel@tonic-gate prev_rss += pmp->pr_rss * kperpage; 10727c478bd9Sstevel@tonic-gate prev_anon += ANON(pmp) * kperpage; 10737c478bd9Sstevel@tonic-gate prev_locked += pmp->pr_locked * kperpage; 10747c478bd9Sstevel@tonic-gate prev_swap += swap * kperpage; 10757c478bd9Sstevel@tonic-gate if (last == 0) { 10767c478bd9Sstevel@tonic-gate return (0); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate merged = 1; 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr); 1082c6402783Sakolb printK(ROUNDUP_KB(prev_size), size_width); 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate if (doswap) 10857c478bd9Sstevel@tonic-gate printK(prev_swap, size_width); 10867c478bd9Sstevel@tonic-gate else { 10877c478bd9Sstevel@tonic-gate printK(prev_rss, size_width); 10887c478bd9Sstevel@tonic-gate printK(prev_anon, size_width); 10897c478bd9Sstevel@tonic-gate printK(prev_locked, size_width); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate (void) printf(prev_lname ? " %-6s %s\n" : "%s\n", 10927c478bd9Sstevel@tonic-gate mflags(prev_mflags), prev_lname); 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate if (last == 0) { 10957c478bd9Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 10967c478bd9Sstevel@tonic-gate prev_size = pmp->pr_size; 10977c478bd9Sstevel@tonic-gate prev_offset = pmp->pr_offset; 10987c478bd9Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 10997c478bd9Sstevel@tonic-gate if (lname == NULL) { 11007c478bd9Sstevel@tonic-gate prev_lname = NULL; 11017c478bd9Sstevel@tonic-gate } else { 11027c478bd9Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 11037c478bd9Sstevel@tonic-gate prev_lname = prev_mname; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 11067c478bd9Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 11077c478bd9Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 11087c478bd9Sstevel@tonic-gate prev_swap = swap * kperpage; 11097c478bd9Sstevel@tonic-gate } else if (merged == 0) { 11107c478bd9Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 1111c6402783Sakolb printK(ROUNDUP_KB(pmp->pr_size), size_width); 11127c478bd9Sstevel@tonic-gate if (doswap) 11137c478bd9Sstevel@tonic-gate printK(swap * kperpage, size_width); 11147c478bd9Sstevel@tonic-gate else { 11157c478bd9Sstevel@tonic-gate printK(pmp->pr_rss * kperpage, size_width); 11167c478bd9Sstevel@tonic-gate printK(ANON(pmp) * kperpage, size_width); 11177c478bd9Sstevel@tonic-gate printK(pmp->pr_locked * kperpage, size_width); 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate (void) printf(lname ? " %-6s %s\n" : " %s\n", 11207c478bd9Sstevel@tonic-gate mflags(pmp->pr_mflags), lname); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate if (last != 0) 11247c478bd9Sstevel@tonic-gate first = 1; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate return (0); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate static int 11307c478bd9Sstevel@tonic-gate perr(char *s) 11317c478bd9Sstevel@tonic-gate { 11327c478bd9Sstevel@tonic-gate if (s) 11337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 11347c478bd9Sstevel@tonic-gate else 11357c478bd9Sstevel@tonic-gate s = procname; 11367c478bd9Sstevel@tonic-gate perror(s); 11377c478bd9Sstevel@tonic-gate return (1); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate static char * 11417c478bd9Sstevel@tonic-gate mflags(uint_t arg) 11427c478bd9Sstevel@tonic-gate { 11437c478bd9Sstevel@tonic-gate static char code_buf[80]; 11447c478bd9Sstevel@tonic-gate char *str = code_buf; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * rwxsR 11487c478bd9Sstevel@tonic-gate * 11497c478bd9Sstevel@tonic-gate * r - segment is readable 11507c478bd9Sstevel@tonic-gate * w - segment is writable 11517c478bd9Sstevel@tonic-gate * x - segment is executable 11527c478bd9Sstevel@tonic-gate * s - segment is shared 11537c478bd9Sstevel@tonic-gate * R - segment is mapped MAP_NORESERVE 11547c478bd9Sstevel@tonic-gate * 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate (void) sprintf(str, "%c%c%c%c%c%c", 11577c478bd9Sstevel@tonic-gate arg & MA_READ ? 'r' : '-', 11587c478bd9Sstevel@tonic-gate arg & MA_WRITE ? 'w' : '-', 11597c478bd9Sstevel@tonic-gate arg & MA_EXEC ? 'x' : '-', 11607c478bd9Sstevel@tonic-gate arg & MA_SHARED ? 's' : '-', 11617c478bd9Sstevel@tonic-gate arg & MA_NORESERVE ? 'R' : '-', 11627c478bd9Sstevel@tonic-gate arg & MA_RESERVED1 ? '*' : ' '); 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate return (str); 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate static mapdata_t * 11687c478bd9Sstevel@tonic-gate nextmap(void) 11697c478bd9Sstevel@tonic-gate { 11707c478bd9Sstevel@tonic-gate mapdata_t *newmaps; 11717c478bd9Sstevel@tonic-gate int next; 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate if (map_count == map_alloc) { 11747c478bd9Sstevel@tonic-gate if (map_alloc == 0) 11757c478bd9Sstevel@tonic-gate next = 16; 11767c478bd9Sstevel@tonic-gate else 11777c478bd9Sstevel@tonic-gate next = map_alloc * 2; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate newmaps = realloc(maps, next * sizeof (mapdata_t)); 11807c478bd9Sstevel@tonic-gate if (newmaps == NULL) { 11817c478bd9Sstevel@tonic-gate (void) perr("failed to allocate maps"); 11827c478bd9Sstevel@tonic-gate exit(1); 11837c478bd9Sstevel@tonic-gate } 11847c478bd9Sstevel@tonic-gate (void) memset(newmaps + map_alloc, '\0', 11857c478bd9Sstevel@tonic-gate (next - map_alloc) * sizeof (mapdata_t)); 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate map_alloc = next; 11887c478bd9Sstevel@tonic-gate maps = newmaps; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate return (&maps[map_count++]); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11957c478bd9Sstevel@tonic-gate static int 11967c478bd9Sstevel@tonic-gate gather_map(void *ignored, const prmap_t *map, const char *objname) 11977c478bd9Sstevel@tonic-gate { 1198c6402783Sakolb mapdata_t *data; 11997c478bd9Sstevel@tonic-gate 1200c6402783Sakolb /* Skip mappings which are outside the range specified by -A */ 1201c6402783Sakolb if (!address_in_range(map->pr_vaddr, 1202c6402783Sakolb map->pr_vaddr + map->pr_size, map->pr_pagesize)) 1203c6402783Sakolb return (0); 1204c6402783Sakolb 1205c6402783Sakolb data = nextmap(); 12067c478bd9Sstevel@tonic-gate data->md_map = *map; 12077c478bd9Sstevel@tonic-gate if (data->md_objname != NULL) 12087c478bd9Sstevel@tonic-gate free(data->md_objname); 12097c478bd9Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate return (0); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12157c478bd9Sstevel@tonic-gate static int 12167c478bd9Sstevel@tonic-gate gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname, 12177c478bd9Sstevel@tonic-gate int last, int doswap) 12187c478bd9Sstevel@tonic-gate { 1219c6402783Sakolb mapdata_t *data; 12207c478bd9Sstevel@tonic-gate 1221c6402783Sakolb /* Skip mappings which are outside the range specified by -A */ 1222c6402783Sakolb if (!address_in_range(xmap->pr_vaddr, 1223c6402783Sakolb xmap->pr_vaddr + xmap->pr_size, xmap->pr_pagesize)) 1224c6402783Sakolb return (0); 1225c6402783Sakolb 1226c6402783Sakolb data = nextmap(); 12277c478bd9Sstevel@tonic-gate data->md_xmap = *xmap; 12287c478bd9Sstevel@tonic-gate if (data->md_objname != NULL) 12297c478bd9Sstevel@tonic-gate free(data->md_objname); 12307c478bd9Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 12317c478bd9Sstevel@tonic-gate data->md_last = last; 12327c478bd9Sstevel@tonic-gate data->md_doswap = doswap; 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate return (0); 12357c478bd9Sstevel@tonic-gate } 12367c478bd9Sstevel@tonic-gate 12377c478bd9Sstevel@tonic-gate static int 12387c478bd9Sstevel@tonic-gate iter_map(proc_map_f *func, void *data) 12397c478bd9Sstevel@tonic-gate { 12407c478bd9Sstevel@tonic-gate int i; 12417c478bd9Sstevel@tonic-gate int ret; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1244c6402783Sakolb if (interrupt) 1245c6402783Sakolb break; 12467c478bd9Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_map, 12477c478bd9Sstevel@tonic-gate maps[i].md_objname)) != 0) 12487c478bd9Sstevel@tonic-gate return (ret); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate return (0); 12527c478bd9Sstevel@tonic-gate } 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate static int 12557c478bd9Sstevel@tonic-gate iter_xmap(proc_xmap_f *func, void *data) 12567c478bd9Sstevel@tonic-gate { 12577c478bd9Sstevel@tonic-gate int i; 12587c478bd9Sstevel@tonic-gate int ret; 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1261c6402783Sakolb if (interrupt) 1262c6402783Sakolb break; 12637c478bd9Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname, 12647c478bd9Sstevel@tonic-gate maps[i].md_last, maps[i].md_doswap)) != 0) 12657c478bd9Sstevel@tonic-gate return (ret); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate return (0); 12697c478bd9Sstevel@tonic-gate } 1270c6402783Sakolb 1271c6402783Sakolb /* 1272c6402783Sakolb * Convert lgroup ID to string. 1273c6402783Sakolb * returns dash when lgroup ID is invalid. 1274c6402783Sakolb */ 1275c6402783Sakolb static char * 1276c6402783Sakolb lgrp2str(lgrp_id_t lgrp) 1277c6402783Sakolb { 1278c6402783Sakolb static char lgrp_buf[20]; 1279c6402783Sakolb char *str = lgrp_buf; 1280c6402783Sakolb 1281c6402783Sakolb (void) sprintf(str, lgrp == LGRP_NONE ? " -" : "%4d", lgrp); 1282c6402783Sakolb return (str); 1283c6402783Sakolb } 1284c6402783Sakolb 1285c6402783Sakolb /* 1286c6402783Sakolb * Parse address range specification for -A option. 1287c6402783Sakolb * The address range may have the following forms: 1288c6402783Sakolb * 1289c6402783Sakolb * address 1290c6402783Sakolb * start and end is set to address 1291c6402783Sakolb * address, 1292c6402783Sakolb * start is set to address, end is set to INVALID_ADDRESS 1293c6402783Sakolb * ,address 1294c6402783Sakolb * start is set to 0, end is set to address 1295c6402783Sakolb * address1,address2 1296c6402783Sakolb * start is set to address1, end is set to address2 1297c6402783Sakolb * 1298c6402783Sakolb */ 1299c6402783Sakolb static int 1300c6402783Sakolb parse_addr_range(char *input_str, uintptr_t *start, uintptr_t *end) 1301c6402783Sakolb { 1302c6402783Sakolb char *startp = input_str; 1303c6402783Sakolb char *endp = strchr(input_str, ','); 1304c6402783Sakolb ulong_t s = (ulong_t)INVALID_ADDRESS; 1305c6402783Sakolb ulong_t e = (ulong_t)INVALID_ADDRESS; 1306c6402783Sakolb 1307c6402783Sakolb if (endp != NULL) { 1308c6402783Sakolb /* 1309c6402783Sakolb * Comma is present. If there is nothing after comma, the end 1310c6402783Sakolb * remains set at INVALID_ADDRESS. Otherwise it is set to the 1311c6402783Sakolb * value after comma. 1312c6402783Sakolb */ 1313c6402783Sakolb *endp = '\0'; 1314c6402783Sakolb endp++; 1315c6402783Sakolb 1316c6402783Sakolb if ((*endp != '\0') && sscanf(endp, "%lx", &e) != 1) 1317c6402783Sakolb return (1); 1318c6402783Sakolb } 1319c6402783Sakolb 1320c6402783Sakolb if (startp != NULL) { 1321c6402783Sakolb /* 1322c6402783Sakolb * Read the start address, if it is specified. If the address is 1323c6402783Sakolb * missing, start will be set to INVALID_ADDRESS. 1324c6402783Sakolb */ 1325c6402783Sakolb if ((*startp != '\0') && sscanf(startp, "%lx", &s) != 1) 1326c6402783Sakolb return (1); 1327c6402783Sakolb } 1328c6402783Sakolb 1329c6402783Sakolb /* If there is no comma, end becomes equal to start */ 1330c6402783Sakolb if (endp == NULL) 1331c6402783Sakolb e = s; 1332c6402783Sakolb 1333c6402783Sakolb /* 1334c6402783Sakolb * ,end implies 0..end range 1335c6402783Sakolb */ 1336c6402783Sakolb if (e != INVALID_ADDRESS && s == INVALID_ADDRESS) 1337c6402783Sakolb s = 0; 1338c6402783Sakolb 1339c6402783Sakolb *start = (uintptr_t)s; 1340c6402783Sakolb *end = (uintptr_t)e; 1341c6402783Sakolb 1342c6402783Sakolb /* Return error if neither start nor end address were specified */ 1343c6402783Sakolb return (! (s != INVALID_ADDRESS || e != INVALID_ADDRESS)); 1344c6402783Sakolb } 1345c6402783Sakolb 1346c6402783Sakolb /* 1347c6402783Sakolb * Check whether any portion of [start, end] segment is within the 1348c6402783Sakolb * [start_addr, end_addr] range. 1349c6402783Sakolb * 1350c6402783Sakolb * Return values: 1351c6402783Sakolb * 0 - address is outside the range 1352c6402783Sakolb * 1 - address is within the range 1353c6402783Sakolb */ 1354c6402783Sakolb static int 1355c6402783Sakolb address_in_range(uintptr_t start, uintptr_t end, size_t psz) 1356c6402783Sakolb { 1357c6402783Sakolb int rc = 1; 1358c6402783Sakolb 1359c6402783Sakolb /* 1360c6402783Sakolb * Nothing to do if there is no address range specified with -A 1361c6402783Sakolb */ 1362c6402783Sakolb if (start_addr != INVALID_ADDRESS || end_addr != INVALID_ADDRESS) { 1363c6402783Sakolb /* The segment end is below the range start */ 1364c6402783Sakolb if ((start_addr != INVALID_ADDRESS) && 1365c6402783Sakolb (end < P2ALIGN(start_addr, psz))) 1366c6402783Sakolb rc = 0; 1367c6402783Sakolb 1368c6402783Sakolb /* The segment start is above the range end */ 1369c6402783Sakolb if ((end_addr != INVALID_ADDRESS) && 1370c6402783Sakolb (start > P2ALIGN(end_addr + psz, psz))) 1371c6402783Sakolb rc = 0; 1372c6402783Sakolb } 1373c6402783Sakolb return (rc); 1374c6402783Sakolb } 1375c6402783Sakolb 1376c6402783Sakolb /* 1377c6402783Sakolb * Returns an intersection of the [start, end] interval and the range specified 1378c6402783Sakolb * by -A flag [start_addr, end_addr]. Unspecified parts of the address range 1379c6402783Sakolb * have value INVALID_ADDRESS. 1380c6402783Sakolb * 1381c6402783Sakolb * The start_addr address is rounded down to the beginning of page and end_addr 1382c6402783Sakolb * is rounded up to the end of page. 1383c6402783Sakolb * 1384c6402783Sakolb * Returns the size of the resulting interval or zero if the interval is empty 1385c6402783Sakolb * or invalid. 1386c6402783Sakolb */ 1387c6402783Sakolb static size_t 1388c6402783Sakolb adjust_addr_range(uintptr_t start, uintptr_t end, size_t psz, 1389c6402783Sakolb uintptr_t *new_start, uintptr_t *new_end) 1390c6402783Sakolb { 1391c6402783Sakolb uintptr_t from; /* start_addr rounded down */ 1392c6402783Sakolb uintptr_t to; /* end_addr rounded up */ 1393c6402783Sakolb 1394c6402783Sakolb /* 1395c6402783Sakolb * Round down the lower address of the range to the beginning of page. 1396c6402783Sakolb */ 1397c6402783Sakolb if (start_addr == INVALID_ADDRESS) { 1398c6402783Sakolb /* 1399c6402783Sakolb * No start_addr specified by -A, the lower part of the interval 1400c6402783Sakolb * does not change. 1401c6402783Sakolb */ 1402c6402783Sakolb *new_start = start; 1403c6402783Sakolb } else { 1404c6402783Sakolb from = P2ALIGN(start_addr, psz); 1405c6402783Sakolb /* 1406c6402783Sakolb * If end address is outside the range, return an empty 1407c6402783Sakolb * interval 1408c6402783Sakolb */ 1409c6402783Sakolb if (end < from) { 1410c6402783Sakolb *new_start = *new_end = 0; 1411c6402783Sakolb return (0); 1412c6402783Sakolb } 1413c6402783Sakolb /* 1414c6402783Sakolb * The adjusted start address is the maximum of requested start 1415c6402783Sakolb * and the aligned start_addr of the -A range. 1416c6402783Sakolb */ 1417c6402783Sakolb *new_start = start < from ? from : start; 1418c6402783Sakolb } 1419c6402783Sakolb 1420c6402783Sakolb /* 1421c6402783Sakolb * Round up the higher address of the range to the end of page. 1422c6402783Sakolb */ 1423c6402783Sakolb if (end_addr == INVALID_ADDRESS) { 1424c6402783Sakolb /* 1425c6402783Sakolb * No end_addr specified by -A, the upper part of the interval 1426c6402783Sakolb * does not change. 1427c6402783Sakolb */ 1428c6402783Sakolb *new_end = end; 1429c6402783Sakolb } else { 1430c6402783Sakolb /* 1431c6402783Sakolb * If only one address is specified and it is the beginning of a 1432c6402783Sakolb * segment, get information about the whole segment. This 1433c6402783Sakolb * function is called once per segment and the 'end' argument is 1434c6402783Sakolb * always the end of a segment, so just use the 'end' value. 1435c6402783Sakolb */ 1436c6402783Sakolb to = (end_addr == start_addr && start == start_addr) ? 1437c6402783Sakolb end : 1438c6402783Sakolb P2ALIGN(end_addr + psz, psz); 1439c6402783Sakolb /* 1440c6402783Sakolb * If start address is outside the range, return an empty 1441c6402783Sakolb * interval 1442c6402783Sakolb */ 1443c6402783Sakolb if (start > to) { 1444c6402783Sakolb *new_start = *new_end = 0; 1445c6402783Sakolb return (0); 1446c6402783Sakolb } 1447c6402783Sakolb /* 1448c6402783Sakolb * The adjusted end address is the minimum of requested end 1449c6402783Sakolb * and the aligned end_addr of the -A range. 1450c6402783Sakolb */ 1451c6402783Sakolb *new_end = end > to ? to : end; 1452c6402783Sakolb } 1453c6402783Sakolb 1454c6402783Sakolb /* 1455c6402783Sakolb * Make sure that the resulting interval is legal. 1456c6402783Sakolb */ 1457c6402783Sakolb if (*new_end < *new_start) 1458c6402783Sakolb *new_start = *new_end = 0; 1459c6402783Sakolb 1460c6402783Sakolb /* Return the size of the interval */ 1461c6402783Sakolb return (*new_end - *new_start); 1462c6402783Sakolb } 1463c6402783Sakolb 1464c6402783Sakolb /* 1465c6402783Sakolb * Initialize memory_info data structure with information about a new segment. 1466c6402783Sakolb */ 1467c6402783Sakolb static void 1468c6402783Sakolb mem_chunk_init(memory_chunk_t *chunk, uintptr_t end, size_t psz) 1469c6402783Sakolb { 1470c6402783Sakolb chunk->end_addr = end; 1471c6402783Sakolb chunk->page_size = psz; 1472c6402783Sakolb chunk->page_index = 0; 1473c6402783Sakolb chunk->chunk_start = chunk->chunk_end = 0; 1474c6402783Sakolb } 1475c6402783Sakolb 1476c6402783Sakolb /* 1477c6402783Sakolb * Create a new chunk of addresses starting from vaddr. 1478c6402783Sakolb * Pass the whole chunk to pr_meminfo to collect lgroup and page size 1479c6402783Sakolb * information for each page in the chunk. 1480c6402783Sakolb */ 1481c6402783Sakolb static void 1482c6402783Sakolb mem_chunk_get(memory_chunk_t *chunk, uintptr_t vaddr) 1483c6402783Sakolb { 1484c6402783Sakolb page_descr_t *pdp = chunk->page_info; 1485c6402783Sakolb size_t psz = chunk->page_size; 1486c6402783Sakolb uintptr_t addr = vaddr; 1487c6402783Sakolb uint64_t inaddr[MAX_MEMINFO_CNT]; 1488c6402783Sakolb uint64_t outdata[2 * MAX_MEMINFO_CNT]; 1489c6402783Sakolb uint_t info[2] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; 1490c6402783Sakolb uint_t validity[MAX_MEMINFO_CNT]; 1491c6402783Sakolb uint64_t *dataptr = inaddr; 1492c6402783Sakolb uint64_t *outptr = outdata; 1493c6402783Sakolb uint_t *valptr = validity; 1494c6402783Sakolb int i, j, rc; 1495c6402783Sakolb 1496c6402783Sakolb chunk->chunk_start = vaddr; 1497c6402783Sakolb chunk->page_index = 0; /* reset index for the new chunk */ 1498c6402783Sakolb 1499c6402783Sakolb /* 1500c6402783Sakolb * Fill in MAX_MEMINFO_CNT wotrh of pages starting from vaddr. Also, 1501c6402783Sakolb * copy starting address of each page to inaddr array for pr_meminfo. 1502c6402783Sakolb */ 1503c6402783Sakolb for (i = 0, pdp = chunk->page_info; 1504c6402783Sakolb (i < MAX_MEMINFO_CNT) && (addr <= chunk->end_addr); 1505c6402783Sakolb i++, pdp++, dataptr++, addr += psz) { 1506c6402783Sakolb *dataptr = (uint64_t)addr; 1507c6402783Sakolb pdp->pd_start = addr; 1508c6402783Sakolb pdp->pd_lgrp = LGRP_NONE; 1509c6402783Sakolb pdp->pd_valid = 0; 1510c6402783Sakolb pdp->pd_pagesize = 0; 1511c6402783Sakolb } 1512c6402783Sakolb 1513c6402783Sakolb /* Mark the number of entries in the chunk and the last address */ 1514c6402783Sakolb chunk->page_count = i; 1515c6402783Sakolb chunk->chunk_end = addr - psz; 1516c6402783Sakolb 1517c6402783Sakolb if (interrupt) 1518c6402783Sakolb return; 1519c6402783Sakolb 1520c6402783Sakolb /* Call meminfo for all collected addresses */ 1521c6402783Sakolb rc = pr_meminfo(Pr, inaddr, i, info, 2, outdata, validity); 1522c6402783Sakolb if (rc < 0) { 1523c6402783Sakolb (void) perr("can not get memory information"); 1524c6402783Sakolb return; 1525c6402783Sakolb } 1526c6402783Sakolb 1527c6402783Sakolb /* Verify validity of each result and fill in the addrs array */ 1528c6402783Sakolb pdp = chunk->page_info; 1529c6402783Sakolb for (j = 0; j < i; j++, pdp++, valptr++, outptr += 2) { 1530c6402783Sakolb /* Skip invalid address pointers */ 1531c6402783Sakolb if ((*valptr & 1) == 0) { 1532c6402783Sakolb continue; 1533c6402783Sakolb } 1534c6402783Sakolb 1535c6402783Sakolb /* Is lgroup information available? */ 1536c6402783Sakolb if ((*valptr & 2) != 0) { 1537c6402783Sakolb pdp->pd_lgrp = (lgrp_id_t)*outptr; 1538c6402783Sakolb pdp->pd_valid = 1; 1539c6402783Sakolb } 1540c6402783Sakolb 1541c6402783Sakolb /* Is page size informaion available? */ 1542c6402783Sakolb if ((*valptr & 4) != 0) { 1543c6402783Sakolb pdp->pd_pagesize = *(outptr + 1); 1544c6402783Sakolb } 1545c6402783Sakolb } 1546c6402783Sakolb } 1547c6402783Sakolb 1548c6402783Sakolb /* 1549c6402783Sakolb * Starting from address 'vaddr' find the region with pages allocated from the 1550c6402783Sakolb * same lgroup. 1551c6402783Sakolb * 1552c6402783Sakolb * Arguments: 1553c6402783Sakolb * mchunk Initialized memory chunk structure 1554c6402783Sakolb * vaddr Starting address of the region 1555c6402783Sakolb * maxaddr Upper bound of the region 1556c6402783Sakolb * pagesize Default page size to use 1557c6402783Sakolb * ret_lgrp On exit contains the lgroup ID of all pages in the 1558c6402783Sakolb * region. 1559c6402783Sakolb * 1560c6402783Sakolb * Returns: 1561c6402783Sakolb * Size of the contiguous region in bytes 1562c6402783Sakolb * The lgroup ID of all pages in the region in ret_lgrp argument. 1563c6402783Sakolb */ 1564c6402783Sakolb static size_t 1565c6402783Sakolb get_contiguous_region(memory_chunk_t *mchunk, uintptr_t vaddr, 1566c6402783Sakolb uintptr_t maxaddr, size_t pagesize, lgrp_id_t *ret_lgrp) 1567c6402783Sakolb { 1568c6402783Sakolb size_t size_contig = 0; 1569c6402783Sakolb lgrp_id_t lgrp; /* Lgroup of the region start */ 1570c6402783Sakolb lgrp_id_t curr_lgrp; /* Lgroup of the current page */ 1571c6402783Sakolb size_t psz = pagesize; /* Pagesize to use */ 1572c6402783Sakolb 1573c6402783Sakolb /* Set both lgroup IDs to the lgroup of the first page */ 1574c6402783Sakolb curr_lgrp = lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1575c6402783Sakolb 1576c6402783Sakolb /* 1577c6402783Sakolb * Starting from vaddr, walk page by page until either the end 1578c6402783Sakolb * of the segment is reached or a page is allocated from a different 1579c6402783Sakolb * lgroup. Also stop if interrupted from keyboard. 1580c6402783Sakolb */ 1581c6402783Sakolb while ((vaddr < maxaddr) && (curr_lgrp == lgrp) && !interrupt) { 1582c6402783Sakolb /* 1583c6402783Sakolb * Get lgroup ID and the page size of the current page. 1584c6402783Sakolb */ 1585c6402783Sakolb curr_lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1586c6402783Sakolb /* If there is no page size information, use the default */ 1587c6402783Sakolb if (psz == 0) 1588c6402783Sakolb psz = pagesize; 1589c6402783Sakolb 1590c6402783Sakolb if (curr_lgrp == lgrp) { 1591c6402783Sakolb /* 1592c6402783Sakolb * This page belongs to the contiguous region. 1593c6402783Sakolb * Increase the region size and advance to the new page. 1594c6402783Sakolb */ 1595c6402783Sakolb size_contig += psz; 1596c6402783Sakolb vaddr += psz; 1597c6402783Sakolb } 1598c6402783Sakolb } 1599c6402783Sakolb 1600c6402783Sakolb /* Return the region lgroup ID and the size */ 1601c6402783Sakolb *ret_lgrp = lgrp; 1602c6402783Sakolb return (size_contig); 1603c6402783Sakolb } 1604c6402783Sakolb 1605c6402783Sakolb /* 1606c6402783Sakolb * Given a virtual address, return its lgroup and page size. If there is meminfo 1607c6402783Sakolb * information for an address, use it, otherwise shift the chunk window to the 1608c6402783Sakolb * vaddr and create a new chunk with known meminfo information. 1609c6402783Sakolb */ 1610c6402783Sakolb static lgrp_id_t 1611c6402783Sakolb addr_to_lgrp(memory_chunk_t *chunk, uintptr_t vaddr, size_t *psz) 1612c6402783Sakolb { 1613c6402783Sakolb page_descr_t *pdp; 1614c6402783Sakolb lgrp_id_t lgrp = LGRP_NONE; 1615c6402783Sakolb int i; 1616c6402783Sakolb 1617c6402783Sakolb *psz = chunk->page_size; 1618c6402783Sakolb 1619c6402783Sakolb if (interrupt) 1620c6402783Sakolb return (0); 1621c6402783Sakolb 1622c6402783Sakolb /* 1623c6402783Sakolb * Is there information about this address? If not, create a new chunk 1624c6402783Sakolb * starting from vaddr and apply pr_meminfo() to the whole chunk. 1625c6402783Sakolb */ 1626c6402783Sakolb if (vaddr < chunk->chunk_start || vaddr > chunk->chunk_end) { 1627c6402783Sakolb /* 1628c6402783Sakolb * This address is outside the chunk, get the new chunk and 1629c6402783Sakolb * collect meminfo information for it. 1630c6402783Sakolb */ 1631c6402783Sakolb mem_chunk_get(chunk, vaddr); 1632c6402783Sakolb } 1633c6402783Sakolb 1634c6402783Sakolb /* 1635c6402783Sakolb * Find information about the address. 1636c6402783Sakolb */ 1637c6402783Sakolb pdp = &chunk->page_info[chunk->page_index]; 1638c6402783Sakolb for (i = chunk->page_index; i < chunk->page_count; i++, pdp++) { 1639c6402783Sakolb if (pdp->pd_start == vaddr) { 1640c6402783Sakolb if (pdp->pd_valid) { 1641c6402783Sakolb lgrp = pdp->pd_lgrp; 1642c6402783Sakolb /* 1643c6402783Sakolb * Override page size information if it is 1644c6402783Sakolb * present. 1645c6402783Sakolb */ 1646c6402783Sakolb if (pdp->pd_pagesize > 0) 1647c6402783Sakolb *psz = pdp->pd_pagesize; 1648c6402783Sakolb } 1649c6402783Sakolb break; 1650c6402783Sakolb } 1651c6402783Sakolb } 1652c6402783Sakolb /* 1653c6402783Sakolb * Remember where we ended - the next search will start here. 1654c6402783Sakolb * We can query for the lgrp for the same address again, so do not 1655c6402783Sakolb * advance index past the current value. 1656c6402783Sakolb */ 1657c6402783Sakolb chunk->page_index = i; 1658c6402783Sakolb 1659c6402783Sakolb return (lgrp); 1660c6402783Sakolb } 1661c6402783Sakolb 1662c6402783Sakolb /* ARGSUSED */ 1663c6402783Sakolb static void 1664c6402783Sakolb intr(int sig) 1665c6402783Sakolb { 1666c6402783Sakolb interrupt = 1; 1667c6402783Sakolb } 1668