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 /* 23*a5b881a7Seh208807 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <stdio.h> 30004388ebScasper #include <stdio_ext.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <unistd.h> 337c478bd9Sstevel@tonic-gate #include <ctype.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <dirent.h> 377c478bd9Sstevel@tonic-gate #include <limits.h> 387c478bd9Sstevel@tonic-gate #include <link.h> 397c478bd9Sstevel@tonic-gate #include <libelf.h> 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 41c6402783Sakolb #include <signal.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 44c6402783Sakolb #include <sys/mman.h> 45c6402783Sakolb #include <sys/lgrp_user.h> 467c478bd9Sstevel@tonic-gate #include <libproc.h> 479acbbeafSnn35248 #include <libzonecfg.h> 487c478bd9Sstevel@tonic-gate 49c6402783Sakolb #define KILOBYTE 1024 50c6402783Sakolb #define MEGABYTE (KILOBYTE * KILOBYTE) 51c6402783Sakolb #define GIGABYTE (KILOBYTE * KILOBYTE * KILOBYTE) 52c6402783Sakolb 53c6402783Sakolb /* 54c6402783Sakolb * Round up the value to the nearest kilobyte 55c6402783Sakolb */ 56c6402783Sakolb #define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE) 57c6402783Sakolb 58c6402783Sakolb /* 59c6402783Sakolb * The alignment should be a power of 2. 60c6402783Sakolb */ 61c6402783Sakolb #define P2ALIGN(x, align) ((x) & -(align)) 62c6402783Sakolb 63c6402783Sakolb #define INVALID_ADDRESS (uintptr_t)(-1) 64c6402783Sakolb 657c478bd9Sstevel@tonic-gate struct totals { 667c478bd9Sstevel@tonic-gate ulong_t total_size; 677c478bd9Sstevel@tonic-gate ulong_t total_swap; 687c478bd9Sstevel@tonic-gate ulong_t total_rss; 697c478bd9Sstevel@tonic-gate ulong_t total_anon; 707c478bd9Sstevel@tonic-gate ulong_t total_locked; 717c478bd9Sstevel@tonic-gate }; 727c478bd9Sstevel@tonic-gate 73c6402783Sakolb /* 74c6402783Sakolb * -L option requires per-page information. The information is presented in an 75c6402783Sakolb * array of page_descr structures. 76c6402783Sakolb */ 77c6402783Sakolb typedef struct page_descr { 78c6402783Sakolb uintptr_t pd_start; /* start address of a page */ 79c6402783Sakolb size_t pd_pagesize; /* page size in bytes */ 80c6402783Sakolb lgrp_id_t pd_lgrp; /* lgroup of memory backing the page */ 81c6402783Sakolb int pd_valid; /* valid page description if non-zero */ 82c6402783Sakolb } page_descr_t; 83c6402783Sakolb 84c6402783Sakolb /* 85c6402783Sakolb * Per-page information for a memory chunk. 86c6402783Sakolb * The meminfo(2) system call accepts up to MAX_MEMINFO_CNT pages at once. 87c6402783Sakolb * When we need to scan larger ranges we divide them in MAX_MEMINFO_CNT sized 88c6402783Sakolb * chunks. The chunk information is stored in the memory_chunk structure. 89c6402783Sakolb */ 90c6402783Sakolb typedef struct memory_chunk { 91c6402783Sakolb page_descr_t page_info[MAX_MEMINFO_CNT]; 92c6402783Sakolb uintptr_t end_addr; 93c6402783Sakolb uintptr_t chunk_start; /* Starting address */ 94c6402783Sakolb uintptr_t chunk_end; /* chunk_end is always <= end_addr */ 95c6402783Sakolb size_t page_size; 96c6402783Sakolb int page_index; /* Current page */ 97c6402783Sakolb int page_count; /* Number of pages */ 98c6402783Sakolb } memory_chunk_t; 99c6402783Sakolb 100c6402783Sakolb static volatile int interrupt; 101c6402783Sakolb 1027c478bd9Sstevel@tonic-gate typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate static int xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *, 1057c478bd9Sstevel@tonic-gate int); 1067c478bd9Sstevel@tonic-gate static int rmapping_iter(struct ps_prochandle *, proc_map_f *, void *); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static int look_map(void *, const prmap_t *, const char *); 1097c478bd9Sstevel@tonic-gate static int look_smap(void *, const prxmap_t *, const char *, int, int); 1107c478bd9Sstevel@tonic-gate static int look_xmap(void *, const prxmap_t *, const char *, int, int); 1117c478bd9Sstevel@tonic-gate static int look_xmap_nopgsz(void *, const prxmap_t *, const char *, 1127c478bd9Sstevel@tonic-gate int, int); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate static int gather_map(void *, const prmap_t *, const char *); 1157c478bd9Sstevel@tonic-gate static int gather_xmap(void *, const prxmap_t *, const char *, int, int); 1167c478bd9Sstevel@tonic-gate static int iter_map(proc_map_f *, void *); 1177c478bd9Sstevel@tonic-gate static int iter_xmap(proc_xmap_f *, void *); 118c6402783Sakolb static int parse_addr_range(char *, uintptr_t *, uintptr_t *); 119c6402783Sakolb static void mem_chunk_init(memory_chunk_t *, uintptr_t, size_t); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate static int perr(char *); 1227c478bd9Sstevel@tonic-gate static void printK(long, int); 1237c478bd9Sstevel@tonic-gate static char *mflags(uint_t); 1247c478bd9Sstevel@tonic-gate 125c6402783Sakolb static size_t get_contiguous_region(memory_chunk_t *, uintptr_t, 126c6402783Sakolb uintptr_t, size_t, lgrp_id_t *); 127c6402783Sakolb static void mem_chunk_get(memory_chunk_t *, uintptr_t); 128c6402783Sakolb static lgrp_id_t addr_to_lgrp(memory_chunk_t *, uintptr_t, size_t *); 129c6402783Sakolb static char *lgrp2str(lgrp_id_t); 130c6402783Sakolb 131c6402783Sakolb static int address_in_range(uintptr_t, uintptr_t, size_t); 132c6402783Sakolb static size_t adjust_addr_range(uintptr_t, uintptr_t, size_t, 133c6402783Sakolb uintptr_t *, uintptr_t *); 134c6402783Sakolb 1357c478bd9Sstevel@tonic-gate static int lflag = 0; 136c6402783Sakolb static int Lflag = 0; 1377c478bd9Sstevel@tonic-gate static int aflag = 0; 138c6402783Sakolb 139c6402783Sakolb /* 140c6402783Sakolb * The -A address range is represented as a pair of addresses 141c6402783Sakolb * <start_addr, end_addr>. Either one of these may be unspecified (set to 142c6402783Sakolb * INVALID_ADDRESS). If both are unspecified, no address range restrictions are 143c6402783Sakolb * in place. 144c6402783Sakolb */ 145c6402783Sakolb static uintptr_t start_addr = INVALID_ADDRESS; 146c6402783Sakolb static uintptr_t end_addr = INVALID_ADDRESS; 147c6402783Sakolb 1487c478bd9Sstevel@tonic-gate static int addr_width, size_width; 1497c478bd9Sstevel@tonic-gate static char *command; 1507c478bd9Sstevel@tonic-gate static char *procname; 1517c478bd9Sstevel@tonic-gate static struct ps_prochandle *Pr; 1527c478bd9Sstevel@tonic-gate 153c6402783Sakolb static void intr(int); 154c6402783Sakolb 1557c478bd9Sstevel@tonic-gate typedef struct lwpstack { 1567c478bd9Sstevel@tonic-gate lwpid_t lwps_lwpid; 1577c478bd9Sstevel@tonic-gate stack_t lwps_stack; 1587c478bd9Sstevel@tonic-gate } lwpstack_t; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate typedef struct { 1617c478bd9Sstevel@tonic-gate prxmap_t md_xmap; 1627c478bd9Sstevel@tonic-gate prmap_t md_map; 1637c478bd9Sstevel@tonic-gate char *md_objname; 164c6402783Sakolb boolean_t md_last; 1657c478bd9Sstevel@tonic-gate int md_doswap; 1667c478bd9Sstevel@tonic-gate } mapdata_t; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate static mapdata_t *maps; 1697c478bd9Sstevel@tonic-gate static int map_count; 1707c478bd9Sstevel@tonic-gate static int map_alloc; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static lwpstack_t *stacks = NULL; 1737c478bd9Sstevel@tonic-gate static uint_t nstacks = 0; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate #define MAX_TRIES 5 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate static int 1787c478bd9Sstevel@tonic-gate getstack(void *data, const lwpstatus_t *lsp) 1797c478bd9Sstevel@tonic-gate { 1807c478bd9Sstevel@tonic-gate int *np = (int *)data; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1837c478bd9Sstevel@tonic-gate stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 1847c478bd9Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1857c478bd9Sstevel@tonic-gate (*np)++; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1897c478bd9Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1907c478bd9Sstevel@tonic-gate (*np)++; 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate return (0); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * We compare the high memory addresses since stacks are faulted in from 1987c478bd9Sstevel@tonic-gate * high memory addresses to low memory addresses, and our prmap_t 1997c478bd9Sstevel@tonic-gate * structures identify only the range of addresses that have been faulted 2007c478bd9Sstevel@tonic-gate * in so far. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate static int 2037c478bd9Sstevel@tonic-gate cmpstacks(const void *ap, const void *bp) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate const lwpstack_t *as = ap; 2067c478bd9Sstevel@tonic-gate const lwpstack_t *bs = bp; 2077c478bd9Sstevel@tonic-gate uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 2087c478bd9Sstevel@tonic-gate uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate if (a < b) 2117c478bd9Sstevel@tonic-gate return (1); 2127c478bd9Sstevel@tonic-gate if (a > b) 2137c478bd9Sstevel@tonic-gate return (-1); 2147c478bd9Sstevel@tonic-gate return (0); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate int 2197c478bd9Sstevel@tonic-gate main(int argc, char **argv) 2207c478bd9Sstevel@tonic-gate { 221c6402783Sakolb int rflag = 0, sflag = 0, xflag = 0, Fflag = 0; 2227c478bd9Sstevel@tonic-gate int errflg = 0, Sflag = 0; 2237c478bd9Sstevel@tonic-gate int rc = 0; 2247c478bd9Sstevel@tonic-gate int opt; 2257c478bd9Sstevel@tonic-gate const char *bar8 = "-------"; 2267c478bd9Sstevel@tonic-gate const char *bar16 = "----------"; 2277c478bd9Sstevel@tonic-gate const char *bar; 2287c478bd9Sstevel@tonic-gate struct rlimit rlim; 2297c478bd9Sstevel@tonic-gate struct stat64 statbuf; 2307c478bd9Sstevel@tonic-gate char buf[128]; 2317c478bd9Sstevel@tonic-gate int mapfd; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 2347c478bd9Sstevel@tonic-gate command++; 2357c478bd9Sstevel@tonic-gate else 2367c478bd9Sstevel@tonic-gate command = argv[0]; 2377c478bd9Sstevel@tonic-gate 238c6402783Sakolb while ((opt = getopt(argc, argv, "arsxSlLFA:")) != EOF) { 2397c478bd9Sstevel@tonic-gate switch (opt) { 2407c478bd9Sstevel@tonic-gate case 'a': /* include shared mappings in -[xS] */ 2417c478bd9Sstevel@tonic-gate aflag = 1; 2427c478bd9Sstevel@tonic-gate break; 2437c478bd9Sstevel@tonic-gate case 'r': /* show reserved mappings */ 2447c478bd9Sstevel@tonic-gate rflag = 1; 2457c478bd9Sstevel@tonic-gate break; 2467c478bd9Sstevel@tonic-gate case 's': /* show hardware page sizes */ 2477c478bd9Sstevel@tonic-gate sflag = 1; 2487c478bd9Sstevel@tonic-gate break; 2497c478bd9Sstevel@tonic-gate case 'S': /* show swap reservations */ 2507c478bd9Sstevel@tonic-gate Sflag = 1; 2517c478bd9Sstevel@tonic-gate break; 2527c478bd9Sstevel@tonic-gate case 'x': /* show extended mappings */ 2537c478bd9Sstevel@tonic-gate xflag = 1; 2547c478bd9Sstevel@tonic-gate break; 2557c478bd9Sstevel@tonic-gate case 'l': /* show unresolved link map names */ 2567c478bd9Sstevel@tonic-gate lflag = 1; 2577c478bd9Sstevel@tonic-gate break; 258c6402783Sakolb case 'L': /* show lgroup information */ 259c6402783Sakolb Lflag = 1; 260c6402783Sakolb break; 261c6402783Sakolb case 'F': /* force grabbing (no O_EXCL) */ 262c6402783Sakolb Fflag = PGRAB_FORCE; 263c6402783Sakolb break; 264c6402783Sakolb case 'A': 265c6402783Sakolb if (parse_addr_range(optarg, &start_addr, &end_addr) 266c6402783Sakolb != 0) 267c6402783Sakolb errflg++; 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate default: 2707c478bd9Sstevel@tonic-gate errflg = 1; 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate argc -= optind; 2767c478bd9Sstevel@tonic-gate argv += optind; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || 279c6402783Sakolb (aflag && (!xflag && !Sflag)) || 280c6402783Sakolb (Lflag && (xflag || Sflag))) { 2817c478bd9Sstevel@tonic-gate errflg = 1; 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if (errflg || argc <= 0) { 2857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 286c6402783Sakolb "usage:\t%s [-rslF] [-A start[,end]] { pid | core } ...\n", 287c6402783Sakolb command); 2887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2897c478bd9Sstevel@tonic-gate "\t\t(report process address maps)\n"); 2907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 291c6402783Sakolb "\t%s -L [-rslF] [-A start[,end]] pid ...\n", command); 292c6402783Sakolb (void) fprintf(stderr, 293c6402783Sakolb "\t\t(report process address maps lgroups mappings)\n"); 294c6402783Sakolb (void) fprintf(stderr, 295c6402783Sakolb "\t%s -x [-aslF] [-A start[,end]] pid ...\n", command); 2967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2977c478bd9Sstevel@tonic-gate "\t\t(show resident/anon/locked mapping details)\n"); 2987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 299c6402783Sakolb "\t%s -S [-alF] [-A start[,end]] { pid | core } ...\n", 300c6402783Sakolb command); 3017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3027c478bd9Sstevel@tonic-gate "\t\t(show swap reservations)\n\n"); 3037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3047c478bd9Sstevel@tonic-gate "\t-a: include shared mappings in -[xS] summary\n"); 3057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3067c478bd9Sstevel@tonic-gate "\t-r: show reserved address maps\n"); 3077c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3087c478bd9Sstevel@tonic-gate "\t-s: show hardware page sizes\n"); 3097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3107c478bd9Sstevel@tonic-gate "\t-l: show unresolved dynamic linker map names\n"); 3117c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3127c478bd9Sstevel@tonic-gate "\t-F: force grabbing of the target process\n"); 313c6402783Sakolb (void) fprintf(stderr, 314c6402783Sakolb "\t-L: show lgroup mappings\n"); 315c6402783Sakolb (void) fprintf(stderr, 316c6402783Sakolb "\t-A start,end: limit output to the specified range\n"); 3177c478bd9Sstevel@tonic-gate return (2); 3187c478bd9Sstevel@tonic-gate } 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 3227c478bd9Sstevel@tonic-gate * that has many many mappings. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 3257c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 3267c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 327004388ebScasper (void) enable_extended_FILE_stdio(-1, -1); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate while (argc-- > 0) { 3317c478bd9Sstevel@tonic-gate char *arg; 3327c478bd9Sstevel@tonic-gate int gcode; 3337c478bd9Sstevel@tonic-gate psinfo_t psinfo; 3347c478bd9Sstevel@tonic-gate int tries = 0; 335c6402783Sakolb int prg_gflags = PGRAB_RDONLY; 336c6402783Sakolb int prr_flags = 0; 337c6402783Sakolb 338c6402783Sakolb if (Lflag) { 339c6402783Sakolb prg_gflags = PGRAB_RETAIN | Fflag; 340c6402783Sakolb prr_flags = PRELEASE_RETAIN; 341c6402783Sakolb } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, 344c6402783Sakolb prg_gflags, &gcode)) == NULL) { 3457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 3467c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 3477c478bd9Sstevel@tonic-gate rc++; 3487c478bd9Sstevel@tonic-gate continue; 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate procname = arg; /* for perr() */ 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 3547c478bd9Sstevel@tonic-gate size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 3557c478bd9Sstevel@tonic-gate bar = addr_width == 8 ? bar8 : bar16; 3567c478bd9Sstevel@tonic-gate (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 3577c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 3607c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 3617c478bd9Sstevel@tonic-gate "/proc/%d/map", (int)psinfo.pr_pid); 3627c478bd9Sstevel@tonic-gate if ((mapfd = open(buf, O_RDONLY)) < 0) { 3637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 3647c478bd9Sstevel@tonic-gate "examine %s: lost control of " 3657c478bd9Sstevel@tonic-gate "process\n", command, arg); 3667c478bd9Sstevel@tonic-gate rc++; 367c6402783Sakolb Prelease(Pr, prr_flags); 3687c478bd9Sstevel@tonic-gate continue; 3697c478bd9Sstevel@tonic-gate } 3707c478bd9Sstevel@tonic-gate } else { 3717c478bd9Sstevel@tonic-gate mapfd = -1; 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate again: 3757c478bd9Sstevel@tonic-gate map_count = 0; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 3787c478bd9Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 3797c478bd9Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 3807c478bd9Sstevel@tonic-gate 381c6402783Sakolb if (rflag || sflag || xflag || Sflag || Lflag) { 3827c478bd9Sstevel@tonic-gate (void) printf(" -%c option is not compatible " 3837c478bd9Sstevel@tonic-gate "with core files\n", xflag ? 'x' : 384c6402783Sakolb sflag ? 's' : rflag ? 'r' : 385c6402783Sakolb Lflag ? 'L' : 'S'); 386c6402783Sakolb Prelease(Pr, prr_flags); 3877c478bd9Sstevel@tonic-gate rc++; 3887c478bd9Sstevel@tonic-gate continue; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate } else { 3927c478bd9Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 3937c478bd9Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 396c6402783Sakolb if (Lflag) { 397c6402783Sakolb /* 398c6402783Sakolb * The implementation of -L option creates an agent LWP 399c6402783Sakolb * in the target process address space. The agent LWP 400c6402783Sakolb * issues meminfo(2) system calls on behalf of the 401c6402783Sakolb * target process. If we are interrupted prematurely, 402c6402783Sakolb * the target process remains in the stopped state with 403c6402783Sakolb * the agent still attached to it. To prevent such 404c6402783Sakolb * situation we catch signals from terminal and 405c6402783Sakolb * terminate gracefully. 406c6402783Sakolb */ 407c6402783Sakolb if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 408c6402783Sakolb (void) sigset(SIGHUP, intr); 409c6402783Sakolb if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 410c6402783Sakolb (void) sigset(SIGINT, intr); 411c6402783Sakolb if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 412c6402783Sakolb (void) sigset(SIGQUIT, intr); 413c6402783Sakolb (void) sigset(SIGPIPE, intr); 414c6402783Sakolb (void) sigset(SIGTERM, intr); 415c6402783Sakolb } 416c6402783Sakolb 4177c478bd9Sstevel@tonic-gate if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 4187c478bd9Sstevel@tonic-gate struct totals t; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * Since we're grabbing the process readonly, we need 4227c478bd9Sstevel@tonic-gate * to make sure the address space doesn't change during 4237c478bd9Sstevel@tonic-gate * execution. 4247c478bd9Sstevel@tonic-gate */ 4257c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 4267c478bd9Sstevel@tonic-gate if (tries++ == MAX_TRIES) { 427c6402783Sakolb Prelease(Pr, prr_flags); 4287c478bd9Sstevel@tonic-gate (void) close(mapfd); 4297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 4307c478bd9Sstevel@tonic-gate "examine %s: address space is " 4317c478bd9Sstevel@tonic-gate "changing\n", command, arg); 4327c478bd9Sstevel@tonic-gate continue; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if (fstat64(mapfd, &statbuf) != 0) { 436c6402783Sakolb Prelease(Pr, prr_flags); 4377c478bd9Sstevel@tonic-gate (void) close(mapfd); 4387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 4397c478bd9Sstevel@tonic-gate "examine %s: lost control of " 4407c478bd9Sstevel@tonic-gate "process\n", command, arg); 4417c478bd9Sstevel@tonic-gate continue; 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate nstacks = psinfo.pr_nlwp * 2; 4467c478bd9Sstevel@tonic-gate stacks = calloc(nstacks, sizeof (stacks[0])); 4477c478bd9Sstevel@tonic-gate if (stacks != NULL) { 4487c478bd9Sstevel@tonic-gate int n = 0; 4497c478bd9Sstevel@tonic-gate (void) Plwp_iter(Pr, getstack, &n); 4507c478bd9Sstevel@tonic-gate qsort(stacks, nstacks, sizeof (stacks[0]), 4517c478bd9Sstevel@tonic-gate cmpstacks); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate (void) memset(&t, 0, sizeof (t)); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && 4577c478bd9Sstevel@tonic-gate Prd_agent(Pr) == NULL) { 4587c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: " 4597c478bd9Sstevel@tonic-gate "librtld_db failed to initialize; " 4607c478bd9Sstevel@tonic-gate "shared library information will not be " 4617c478bd9Sstevel@tonic-gate "available\n", command); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate /* 4657c478bd9Sstevel@tonic-gate * Gather data 4667c478bd9Sstevel@tonic-gate */ 4677c478bd9Sstevel@tonic-gate if (xflag) 4687c478bd9Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 0); 4697c478bd9Sstevel@tonic-gate else if (Sflag) 4707c478bd9Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 1); 4717c478bd9Sstevel@tonic-gate else { 4727c478bd9Sstevel@tonic-gate if (rflag) 4737c478bd9Sstevel@tonic-gate rc += rmapping_iter(Pr, gather_map, 4747c478bd9Sstevel@tonic-gate NULL); 4757c478bd9Sstevel@tonic-gate else if (sflag) 4767c478bd9Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, 4777c478bd9Sstevel@tonic-gate NULL, 0); 4787c478bd9Sstevel@tonic-gate else 4797c478bd9Sstevel@tonic-gate rc += Pmapping_iter(Pr, gather_map, 4807c478bd9Sstevel@tonic-gate NULL); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * Ensure mappings are consistent. 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 4877c478bd9Sstevel@tonic-gate struct stat64 newbuf; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (fstat64(mapfd, &newbuf) != 0 || 4907c478bd9Sstevel@tonic-gate memcmp(&newbuf.st_mtim, &statbuf.st_mtim, 4917c478bd9Sstevel@tonic-gate sizeof (newbuf.st_mtim)) != 0) { 4927c478bd9Sstevel@tonic-gate if (stacks != NULL) { 4937c478bd9Sstevel@tonic-gate free(stacks); 4947c478bd9Sstevel@tonic-gate stacks = NULL; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate goto again; 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Display data. 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate if (xflag) { 5047c478bd9Sstevel@tonic-gate (void) printf("%*s%*s%*s%*s%*s " 5057c478bd9Sstevel@tonic-gate "%sMode Mapped File\n", 5067c478bd9Sstevel@tonic-gate addr_width, "Address", 5077c478bd9Sstevel@tonic-gate size_width, "Kbytes", 5087c478bd9Sstevel@tonic-gate size_width, "RSS", 5097c478bd9Sstevel@tonic-gate size_width, "Anon", 5107c478bd9Sstevel@tonic-gate size_width, "Locked", 5117c478bd9Sstevel@tonic-gate sflag ? "Pgsz " : ""); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate rc += iter_xmap(sflag ? look_xmap : 5147c478bd9Sstevel@tonic-gate look_xmap_nopgsz, &t); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate (void) printf("%s%s %s %s %s %s\n", 5177c478bd9Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 5187c478bd9Sstevel@tonic-gate bar, bar, bar, bar, bar); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 5217c478bd9Sstevel@tonic-gate " " : ""); 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate printK(t.total_size, size_width); 5247c478bd9Sstevel@tonic-gate printK(t.total_rss, size_width); 5257c478bd9Sstevel@tonic-gate printK(t.total_anon, size_width); 5267c478bd9Sstevel@tonic-gate printK(t.total_locked, size_width); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate (void) printf("\n"); 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate } else if (Sflag) { 531c6402783Sakolb (void) printf("%*s%*s%*s Mode" 532c6402783Sakolb " Mapped File\n", 5337c478bd9Sstevel@tonic-gate addr_width, "Address", 5347c478bd9Sstevel@tonic-gate size_width, "Kbytes", 5357c478bd9Sstevel@tonic-gate size_width, "Swap"); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate rc += iter_xmap(look_xmap_nopgsz, &t); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate (void) printf("%s%s %s %s\n", 5407c478bd9Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 5417c478bd9Sstevel@tonic-gate bar, bar, bar); 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 5447c478bd9Sstevel@tonic-gate " " : ""); 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate printK(t.total_size, size_width); 5477c478bd9Sstevel@tonic-gate printK(t.total_swap, size_width); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate (void) printf("\n"); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate } else { 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate if (rflag) { 5547c478bd9Sstevel@tonic-gate rc += iter_map(look_map, &t); 5557c478bd9Sstevel@tonic-gate } else if (sflag) { 556c6402783Sakolb if (Lflag) { 557c6402783Sakolb (void) printf("%*s %*s %4s" 558c6402783Sakolb " %-6s %s %s\n", 559c6402783Sakolb addr_width, "Address", 560c6402783Sakolb size_width, 561c6402783Sakolb "Bytes", "Pgsz", "Mode ", 562c6402783Sakolb "Lgrp", "Mapped File"); 563c6402783Sakolb rc += iter_xmap(look_smap, &t); 564c6402783Sakolb } else { 565c6402783Sakolb (void) printf("%*s %*s %4s" 566c6402783Sakolb " %-6s %s\n", 567c6402783Sakolb addr_width, "Address", 568c6402783Sakolb size_width, 5697c478bd9Sstevel@tonic-gate "Bytes", "Pgsz", "Mode ", 5707c478bd9Sstevel@tonic-gate "Mapped File"); 5717c478bd9Sstevel@tonic-gate rc += iter_xmap(look_smap, &t); 572c6402783Sakolb } 5737c478bd9Sstevel@tonic-gate } else { 5747c478bd9Sstevel@tonic-gate rc += iter_map(look_map, &t); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate (void) printf(" %stotal %*luK\n", 5787c478bd9Sstevel@tonic-gate addr_width == 16 ? 5797c478bd9Sstevel@tonic-gate " " : "", 5807c478bd9Sstevel@tonic-gate size_width, t.total_size); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate if (stacks != NULL) { 5847c478bd9Sstevel@tonic-gate free(stacks); 5857c478bd9Sstevel@tonic-gate stacks = NULL; 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 590c6402783Sakolb Prelease(Pr, prr_flags); 5917c478bd9Sstevel@tonic-gate if (mapfd != -1) 5927c478bd9Sstevel@tonic-gate (void) close(mapfd); 5937c478bd9Sstevel@tonic-gate } 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate return (rc); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate static char * 5997c478bd9Sstevel@tonic-gate make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 6007c478bd9Sstevel@tonic-gate char *buf, size_t bufsz) 6017c478bd9Sstevel@tonic-gate { 6027c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 6039acbbeafSnn35248 const psinfo_t *pi = Ppsinfo(Pr); 6047c478bd9Sstevel@tonic-gate char fname[100]; 6057c478bd9Sstevel@tonic-gate struct stat statb; 6067c478bd9Sstevel@tonic-gate int len; 6079acbbeafSnn35248 char zname[ZONENAME_MAX]; 6089acbbeafSnn35248 char zpath[PATH_MAX]; 6099acbbeafSnn35248 char objname[PATH_MAX]; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (!lflag && strcmp(mapname, "a.out") == 0 && 6127c478bd9Sstevel@tonic-gate Pexecname(Pr, buf, bufsz) != NULL) 6137c478bd9Sstevel@tonic-gate return (buf); 6147c478bd9Sstevel@tonic-gate 6159acbbeafSnn35248 if (Pobjname(Pr, addr, objname, sizeof (objname)) != NULL) { 6169acbbeafSnn35248 (void) strncpy(buf, objname, bufsz); 6179acbbeafSnn35248 6187c478bd9Sstevel@tonic-gate if (lflag) 6197c478bd9Sstevel@tonic-gate return (buf); 6209acbbeafSnn35248 6219acbbeafSnn35248 if ((len = resolvepath(buf, buf, bufsz)) > 0) { 6229acbbeafSnn35248 buf[len] = '\0'; 6239acbbeafSnn35248 return (buf); 6249acbbeafSnn35248 } 6259acbbeafSnn35248 6269acbbeafSnn35248 /* 6279acbbeafSnn35248 * If the target is in a non-global zone, attempt to prepend 6289acbbeafSnn35248 * the zone path in order to give the global-zone caller the 6299acbbeafSnn35248 * real path to the file. 6309acbbeafSnn35248 */ 6319acbbeafSnn35248 if (getzonenamebyid(pi->pr_zoneid, zname, 6329acbbeafSnn35248 sizeof (zname)) != -1 && strcmp(zname, "global") != 0 && 6339acbbeafSnn35248 zone_get_zonepath(zname, zpath, sizeof (zpath)) == Z_OK) { 6349acbbeafSnn35248 (void) strncat(zpath, "/root", 6359acbbeafSnn35248 MAXPATHLEN - strlen(zpath)); 6369acbbeafSnn35248 6379acbbeafSnn35248 if (bufsz <= strlen(zpath)) 6389acbbeafSnn35248 return (NULL); 6399acbbeafSnn35248 6409acbbeafSnn35248 (void) strncpy(buf, zpath, bufsz); 6419acbbeafSnn35248 (void) strncat(buf, objname, bufsz - strlen(zpath)); 6429acbbeafSnn35248 } 6439acbbeafSnn35248 6447c478bd9Sstevel@tonic-gate if ((len = resolvepath(buf, buf, bufsz)) > 0) { 6457c478bd9Sstevel@tonic-gate buf[len] = '\0'; 6467c478bd9Sstevel@tonic-gate return (buf); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD && *mapname != '\0') { 651*a5b881a7Seh208807 (void) snprintf(fname, sizeof (fname), "/proc/%d/path/%s", 6527c478bd9Sstevel@tonic-gate (int)Psp->pr_pid, mapname); 653*a5b881a7Seh208807 len = readlink(fname, buf, bufsz - 1); 654*a5b881a7Seh208807 if (len >= 0) { 655*a5b881a7Seh208807 buf[len] = '\0'; 656*a5b881a7Seh208807 return (buf); 657*a5b881a7Seh208807 } else { /* there is no path and readlink() error */ 658*a5b881a7Seh208807 (void) snprintf(fname, sizeof (fname), 659*a5b881a7Seh208807 "/proc/%d/object/%s", (int)Psp->pr_pid, mapname); 6607c478bd9Sstevel@tonic-gate if (stat(fname, &statb) == 0) { 6617c478bd9Sstevel@tonic-gate dev_t dev = statb.st_dev; 6627c478bd9Sstevel@tonic-gate ino_t ino = statb.st_ino; 663*a5b881a7Seh208807 (void) snprintf(buf, bufsz, 664*a5b881a7Seh208807 "dev:%lu,%lu ino:%lu", 665*a5b881a7Seh208807 (ulong_t)major(dev), 666*a5b881a7Seh208807 (ulong_t)minor(dev), ino); 6677c478bd9Sstevel@tonic-gate return (buf); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate } 670*a5b881a7Seh208807 } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate return (NULL); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate static char * 6767c478bd9Sstevel@tonic-gate anon_name(char *name, const pstatus_t *Psp, 6777c478bd9Sstevel@tonic-gate uintptr_t vaddr, size_t size, int mflags, int shmid) 6787c478bd9Sstevel@tonic-gate { 6797c478bd9Sstevel@tonic-gate if (mflags & MA_ISM) { 6807c478bd9Sstevel@tonic-gate if (shmid == -1) 6817c478bd9Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 6827c478bd9Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism"); 6837c478bd9Sstevel@tonic-gate else 6847c478bd9Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 6857c478bd9Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 6867c478bd9Sstevel@tonic-gate } else if (mflags & MA_SHM) { 6877c478bd9Sstevel@tonic-gate if (shmid == -1) 6887c478bd9Sstevel@tonic-gate (void) sprintf(name, " [ shmid=null ]"); 6897c478bd9Sstevel@tonic-gate else 6907c478bd9Sstevel@tonic-gate (void) sprintf(name, " [ shmid=0x%x ]", shmid); 6917c478bd9Sstevel@tonic-gate } else if (vaddr + size > Psp->pr_stkbase && 6927c478bd9Sstevel@tonic-gate vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 6937c478bd9Sstevel@tonic-gate (void) strcpy(name, " [ stack ]"); 6947c478bd9Sstevel@tonic-gate } else if ((mflags & MA_ANON) && 6957c478bd9Sstevel@tonic-gate vaddr + size > Psp->pr_brkbase && 6967c478bd9Sstevel@tonic-gate vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 6977c478bd9Sstevel@tonic-gate (void) strcpy(name, " [ heap ]"); 6987c478bd9Sstevel@tonic-gate } else { 6997c478bd9Sstevel@tonic-gate lwpstack_t key, *stk; 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate key.lwps_stack.ss_sp = (void *)vaddr; 7027c478bd9Sstevel@tonic-gate key.lwps_stack.ss_size = size; 7037c478bd9Sstevel@tonic-gate if (nstacks > 0 && 7047c478bd9Sstevel@tonic-gate (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 7057c478bd9Sstevel@tonic-gate cmpstacks)) != NULL) { 7067c478bd9Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 7077c478bd9Sstevel@tonic-gate (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 7087c478bd9Sstevel@tonic-gate "altstack" : "stack", 7097c478bd9Sstevel@tonic-gate stk->lwps_lwpid); 7107c478bd9Sstevel@tonic-gate } else if (Pstate(Pr) != PS_DEAD) { 7117c478bd9Sstevel@tonic-gate (void) strcpy(name, " [ anon ]"); 7127c478bd9Sstevel@tonic-gate } else { 7137c478bd9Sstevel@tonic-gate return (NULL); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate return (name); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate static int 7217c478bd9Sstevel@tonic-gate rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd) 7227c478bd9Sstevel@tonic-gate { 7237c478bd9Sstevel@tonic-gate char mapname[PATH_MAX]; 7247c478bd9Sstevel@tonic-gate int mapfd, nmap, i, rc; 7257c478bd9Sstevel@tonic-gate struct stat st; 7267c478bd9Sstevel@tonic-gate prmap_t *prmapp, *pmp; 7277c478bd9Sstevel@tonic-gate ssize_t n; 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 7307c478bd9Sstevel@tonic-gate "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 7337c478bd9Sstevel@tonic-gate if (mapfd >= 0) 7347c478bd9Sstevel@tonic-gate (void) close(mapfd); 7357c478bd9Sstevel@tonic-gate return (perr(mapname)); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate nmap = st.st_size / sizeof (prmap_t); 7397c478bd9Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prmap_t)); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) { 7427c478bd9Sstevel@tonic-gate (void) close(mapfd); 7437c478bd9Sstevel@tonic-gate free(prmapp); 7447c478bd9Sstevel@tonic-gate return (perr("read rmap")); 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate (void) close(mapfd); 7487c478bd9Sstevel@tonic-gate nmap = n / sizeof (prmap_t); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 7517c478bd9Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL)) != 0) { 7527c478bd9Sstevel@tonic-gate free(prmapp); 7537c478bd9Sstevel@tonic-gate return (rc); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate free(prmapp); 7587c478bd9Sstevel@tonic-gate return (0); 7597c478bd9Sstevel@tonic-gate } 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate static int 7627c478bd9Sstevel@tonic-gate xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap) 7637c478bd9Sstevel@tonic-gate { 7647c478bd9Sstevel@tonic-gate char mapname[PATH_MAX]; 7657c478bd9Sstevel@tonic-gate int mapfd, nmap, i, rc; 7667c478bd9Sstevel@tonic-gate struct stat st; 7677c478bd9Sstevel@tonic-gate prxmap_t *prmapp, *pmp; 7687c478bd9Sstevel@tonic-gate ssize_t n; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 7717c478bd9Sstevel@tonic-gate "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid); 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 7747c478bd9Sstevel@tonic-gate if (mapfd >= 0) 7757c478bd9Sstevel@tonic-gate (void) close(mapfd); 7767c478bd9Sstevel@tonic-gate return (perr(mapname)); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate nmap = st.st_size / sizeof (prxmap_t); 7807c478bd9Sstevel@tonic-gate nmap *= 2; 7817c478bd9Sstevel@tonic-gate again: 7827c478bd9Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prxmap_t)); 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) { 7857c478bd9Sstevel@tonic-gate (void) close(mapfd); 7867c478bd9Sstevel@tonic-gate free(prmapp); 7877c478bd9Sstevel@tonic-gate return (perr("read xmap")); 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate if (nmap < n / sizeof (prxmap_t)) { 7917c478bd9Sstevel@tonic-gate free(prmapp); 7927c478bd9Sstevel@tonic-gate nmap *= 2; 7937c478bd9Sstevel@tonic-gate goto again; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate (void) close(mapfd); 7977c478bd9Sstevel@tonic-gate nmap = n / sizeof (prxmap_t); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 8007c478bd9Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) { 8017c478bd9Sstevel@tonic-gate free(prmapp); 8027c478bd9Sstevel@tonic-gate return (rc); 8037c478bd9Sstevel@tonic-gate } 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 806c6402783Sakolb /* 807c6402783Sakolb * Mark the last element. 808c6402783Sakolb */ 809c6402783Sakolb if (map_count > 0) 810c6402783Sakolb maps[map_count - 1].md_last = B_TRUE; 811c6402783Sakolb 8127c478bd9Sstevel@tonic-gate free(prmapp); 8137c478bd9Sstevel@tonic-gate return (0); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8177c478bd9Sstevel@tonic-gate static int 8187c478bd9Sstevel@tonic-gate look_map(void *data, const prmap_t *pmp, const char *object_name) 8197c478bd9Sstevel@tonic-gate { 8207c478bd9Sstevel@tonic-gate struct totals *t = data; 8217c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 822c6402783Sakolb size_t size; 8237c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 8247c478bd9Sstevel@tonic-gate char *lname = NULL; 825c6402783Sakolb size_t psz = pmp->pr_pagesize; 826c6402783Sakolb uintptr_t vaddr = pmp->pr_vaddr; 827c6402783Sakolb uintptr_t segment_end = vaddr + pmp->pr_size; 828c6402783Sakolb lgrp_id_t lgrp; 829c6402783Sakolb memory_chunk_t mchunk; 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* 8327c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 8337c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 8347c478bd9Sstevel@tonic-gate */ 8357c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 836c6402783Sakolb segment_end <= Psp->pr_brkbase || 8377c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 8387c478bd9Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 8397c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 8407c478bd9Sstevel@tonic-gate } 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate if (lname == NULL && 8437c478bd9Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 8447c478bd9Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 8457c478bd9Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 848c6402783Sakolb /* 849c6402783Sakolb * Adjust the address range if -A is specified. 850c6402783Sakolb */ 851c6402783Sakolb size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 852c6402783Sakolb &vaddr, &segment_end); 853c6402783Sakolb 854c6402783Sakolb if (size == 0) 855c6402783Sakolb return (0); 856c6402783Sakolb 857c6402783Sakolb if (!Lflag) { 858c6402783Sakolb /* 859c6402783Sakolb * Display the whole mapping 860c6402783Sakolb */ 861c6402783Sakolb size = ROUNDUP_KB(size); 862c6402783Sakolb 863c6402783Sakolb (void) printf(lname ? 864c6402783Sakolb "%.*lX %*luK %-6s %s\n" : 865c6402783Sakolb "%.*lX %*luK %s\n", 866c6402783Sakolb addr_width, vaddr, 8677c478bd9Sstevel@tonic-gate size_width - 1, size, mflags(pmp->pr_mflags), lname); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate t->total_size += size; 8707c478bd9Sstevel@tonic-gate return (0); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate 873c6402783Sakolb /* 874c6402783Sakolb * We need to display lgroups backing physical memory, so we break the 875c6402783Sakolb * segment into individual pages and coalesce pages with the same lgroup 876c6402783Sakolb * into one "segment". 877c6402783Sakolb */ 878c6402783Sakolb 879c6402783Sakolb /* 880c6402783Sakolb * Initialize address descriptions for the mapping. 881c6402783Sakolb */ 882c6402783Sakolb mem_chunk_init(&mchunk, segment_end, psz); 883c6402783Sakolb size = 0; 884c6402783Sakolb 885c6402783Sakolb /* 886c6402783Sakolb * Walk mapping (page by page) and display contiguous ranges of memory 887c6402783Sakolb * allocated to same lgroup. 888c6402783Sakolb */ 889c6402783Sakolb do { 890c6402783Sakolb size_t size_contig; 891c6402783Sakolb 892c6402783Sakolb /* 893c6402783Sakolb * Get contiguous region of memory starting from vaddr allocated 894c6402783Sakolb * from the same lgroup. 895c6402783Sakolb */ 896c6402783Sakolb size_contig = get_contiguous_region(&mchunk, vaddr, 897c6402783Sakolb segment_end, pmp->pr_pagesize, &lgrp); 898c6402783Sakolb 899c6402783Sakolb (void) printf(lname ? "%.*lX %*luK %-6s%s %s\n" : 900c6402783Sakolb "%.*lX %*luK %s %s\n", 901c6402783Sakolb addr_width, vaddr, 902c6402783Sakolb size_width - 1, size_contig / KILOBYTE, 903c6402783Sakolb mflags(pmp->pr_mflags), 904c6402783Sakolb lgrp2str(lgrp), lname); 905c6402783Sakolb 906c6402783Sakolb vaddr += size_contig; 907c6402783Sakolb size += size_contig; 908c6402783Sakolb } while (vaddr < segment_end && !interrupt); 909c6402783Sakolb 910c6402783Sakolb /* Update the total size */ 911c6402783Sakolb t->total_size += ROUNDUP_KB(size); 912c6402783Sakolb return (0); 913c6402783Sakolb } 914c6402783Sakolb 9157c478bd9Sstevel@tonic-gate static void 9167c478bd9Sstevel@tonic-gate printK(long value, int width) 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate if (value == 0) 9197c478bd9Sstevel@tonic-gate (void) printf(width == 8 ? " -" : " -"); 9207c478bd9Sstevel@tonic-gate else 9217c478bd9Sstevel@tonic-gate (void) printf(" %*lu", width - 1, value); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate static const char * 9257c478bd9Sstevel@tonic-gate pagesize(const prxmap_t *pmp) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate int pagesize = pmp->pr_hatpagesize; 9287c478bd9Sstevel@tonic-gate static char buf[32]; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate if (pagesize == 0) { 9317c478bd9Sstevel@tonic-gate return ("-"); /* no underlying HAT mapping */ 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 934c6402783Sakolb if (pagesize >= KILOBYTE && (pagesize % KILOBYTE) == 0) { 935c6402783Sakolb if ((pagesize % GIGABYTE) == 0) 9367c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dG", 937c6402783Sakolb pagesize / GIGABYTE); 938c6402783Sakolb else if ((pagesize % MEGABYTE) == 0) 9397c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dM", 940c6402783Sakolb pagesize / MEGABYTE); 9417c478bd9Sstevel@tonic-gate else 9427c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dK", 943c6402783Sakolb pagesize / KILOBYTE); 9447c478bd9Sstevel@tonic-gate } else 9457c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%db", pagesize); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate return (buf); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 9517c478bd9Sstevel@tonic-gate static int 9527c478bd9Sstevel@tonic-gate look_smap(void *data, 9537c478bd9Sstevel@tonic-gate const prxmap_t *pmp, 9547c478bd9Sstevel@tonic-gate const char *object_name, 9557c478bd9Sstevel@tonic-gate int last, int doswap) 9567c478bd9Sstevel@tonic-gate { 9577c478bd9Sstevel@tonic-gate struct totals *t = data; 9587c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 959c6402783Sakolb size_t size; 9607c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 9617c478bd9Sstevel@tonic-gate char *lname = NULL; 9627c478bd9Sstevel@tonic-gate const char *format; 963c6402783Sakolb size_t psz = pmp->pr_pagesize; 964c6402783Sakolb uintptr_t vaddr = pmp->pr_vaddr; 965c6402783Sakolb uintptr_t segment_end = vaddr + pmp->pr_size; 966c6402783Sakolb lgrp_id_t lgrp; 967c6402783Sakolb memory_chunk_t mchunk; 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 9717c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 9727c478bd9Sstevel@tonic-gate */ 9737c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 9747c478bd9Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 9757c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 9767c478bd9Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 9777c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate if (lname == NULL && 9817c478bd9Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 9827c478bd9Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 9837c478bd9Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 986c6402783Sakolb /* 987c6402783Sakolb * Adjust the address range if -A is specified. 988c6402783Sakolb */ 989c6402783Sakolb size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 990c6402783Sakolb &vaddr, &segment_end); 991c6402783Sakolb 992c6402783Sakolb if (size == 0) 993c6402783Sakolb return (0); 994c6402783Sakolb 995c6402783Sakolb if (!Lflag) { 996c6402783Sakolb /* 997c6402783Sakolb * Display the whole mapping 998c6402783Sakolb */ 9997c478bd9Sstevel@tonic-gate if (lname != NULL) 10007c478bd9Sstevel@tonic-gate format = "%.*lX %*luK %4s %-6s %s\n"; 10017c478bd9Sstevel@tonic-gate else 10027c478bd9Sstevel@tonic-gate format = "%.*lX %*luK %4s %s\n"; 10037c478bd9Sstevel@tonic-gate 1004c6402783Sakolb size = ROUNDUP_KB(size); 1005c6402783Sakolb 1006c6402783Sakolb (void) printf(format, addr_width, vaddr, size_width - 1, size, 10077c478bd9Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate t->total_size += size; 10107c478bd9Sstevel@tonic-gate return (0); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate 1013c6402783Sakolb if (lname != NULL) 1014c6402783Sakolb format = "%.*lX %*luK %4s %-6s%s %s\n"; 1015c6402783Sakolb else 1016c6402783Sakolb format = "%.*lX %*luK %4s%s %s\n"; 1017c6402783Sakolb 1018c6402783Sakolb /* 1019c6402783Sakolb * We need to display lgroups backing physical memory, so we break the 1020c6402783Sakolb * segment into individual pages and coalesce pages with the same lgroup 1021c6402783Sakolb * into one "segment". 1022c6402783Sakolb */ 1023c6402783Sakolb 1024c6402783Sakolb /* 1025c6402783Sakolb * Initialize address descriptions for the mapping. 1026c6402783Sakolb */ 1027c6402783Sakolb mem_chunk_init(&mchunk, segment_end, psz); 1028c6402783Sakolb size = 0; 1029c6402783Sakolb 1030c6402783Sakolb /* 1031c6402783Sakolb * Walk mapping (page by page) and display contiguous ranges of memory 1032c6402783Sakolb * allocated to same lgroup. 1033c6402783Sakolb */ 1034c6402783Sakolb do { 1035c6402783Sakolb size_t size_contig; 1036c6402783Sakolb 1037c6402783Sakolb /* 1038c6402783Sakolb * Get contiguous region of memory starting from vaddr allocated 1039c6402783Sakolb * from the same lgroup. 1040c6402783Sakolb */ 1041c6402783Sakolb size_contig = get_contiguous_region(&mchunk, vaddr, 1042c6402783Sakolb segment_end, pmp->pr_pagesize, &lgrp); 1043c6402783Sakolb 1044c6402783Sakolb (void) printf(format, addr_width, vaddr, 1045c6402783Sakolb size_width - 1, size_contig / KILOBYTE, 1046c6402783Sakolb pagesize(pmp), mflags(pmp->pr_mflags), 1047c6402783Sakolb lgrp2str(lgrp), lname); 1048c6402783Sakolb 1049c6402783Sakolb vaddr += size_contig; 1050c6402783Sakolb size += size_contig; 1051c6402783Sakolb } while (vaddr < segment_end && !interrupt); 1052c6402783Sakolb 1053c6402783Sakolb t->total_size += ROUNDUP_KB(size); 1054c6402783Sakolb return (0); 1055c6402783Sakolb } 1056c6402783Sakolb 10577c478bd9Sstevel@tonic-gate #define ANON(x) ((aflag || (((x)->pr_mflags & MA_SHARED) == 0)) ? \ 10587c478bd9Sstevel@tonic-gate ((x)->pr_anon) : 0) 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10617c478bd9Sstevel@tonic-gate static int 10627c478bd9Sstevel@tonic-gate look_xmap(void *data, 10637c478bd9Sstevel@tonic-gate const prxmap_t *pmp, 10647c478bd9Sstevel@tonic-gate const char *object_name, 10657c478bd9Sstevel@tonic-gate int last, int doswap) 10667c478bd9Sstevel@tonic-gate { 10677c478bd9Sstevel@tonic-gate struct totals *t = data; 10687c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 10697c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 10707c478bd9Sstevel@tonic-gate char *lname = NULL; 10717c478bd9Sstevel@tonic-gate char *ln; 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 10757c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 10767c478bd9Sstevel@tonic-gate */ 10777c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 10787c478bd9Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 10797c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 10807c478bd9Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 10817c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate if (lname != NULL) { 10857c478bd9Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 10867c478bd9Sstevel@tonic-gate lname = ln + 1; 10877c478bd9Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 10887c478bd9Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 10897c478bd9Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 10937c478bd9Sstevel@tonic-gate 1094c6402783Sakolb printK(ROUNDUP_KB(pmp->pr_size), size_width); 1095c6402783Sakolb printK(pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE), size_width); 1096c6402783Sakolb printK(ANON(pmp) * (pmp->pr_pagesize / KILOBYTE), size_width); 1097c6402783Sakolb printK(pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE), size_width); 10987c478bd9Sstevel@tonic-gate (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n", 10997c478bd9Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 11007c478bd9Sstevel@tonic-gate 1101c6402783Sakolb t->total_size += ROUNDUP_KB(pmp->pr_size); 1102c6402783Sakolb t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE); 1103c6402783Sakolb t->total_anon += ANON(pmp) * (pmp->pr_pagesize / KILOBYTE); 1104c6402783Sakolb t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE)); 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate return (0); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11107c478bd9Sstevel@tonic-gate static int 11117c478bd9Sstevel@tonic-gate look_xmap_nopgsz(void *data, 11127c478bd9Sstevel@tonic-gate const prxmap_t *pmp, 11137c478bd9Sstevel@tonic-gate const char *object_name, 11147c478bd9Sstevel@tonic-gate int last, int doswap) 11157c478bd9Sstevel@tonic-gate { 11167c478bd9Sstevel@tonic-gate struct totals *t = data; 11177c478bd9Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 11187c478bd9Sstevel@tonic-gate char mname[PATH_MAX]; 11197c478bd9Sstevel@tonic-gate char *lname = NULL; 11207c478bd9Sstevel@tonic-gate char *ln; 11217c478bd9Sstevel@tonic-gate static uintptr_t prev_vaddr; 11227c478bd9Sstevel@tonic-gate static size_t prev_size; 11237c478bd9Sstevel@tonic-gate static offset_t prev_offset; 11247c478bd9Sstevel@tonic-gate static int prev_mflags; 11257c478bd9Sstevel@tonic-gate static char *prev_lname; 11267c478bd9Sstevel@tonic-gate static char prev_mname[PATH_MAX]; 11277c478bd9Sstevel@tonic-gate static ulong_t prev_rss; 11287c478bd9Sstevel@tonic-gate static ulong_t prev_anon; 11297c478bd9Sstevel@tonic-gate static ulong_t prev_locked; 11307c478bd9Sstevel@tonic-gate static ulong_t prev_swap; 11317c478bd9Sstevel@tonic-gate int merged = 0; 11327c478bd9Sstevel@tonic-gate static int first = 1; 11337c478bd9Sstevel@tonic-gate ulong_t swap = 0; 11347c478bd9Sstevel@tonic-gate int kperpage; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * Calculate swap reservations 11387c478bd9Sstevel@tonic-gate */ 11397c478bd9Sstevel@tonic-gate if (pmp->pr_mflags & MA_SHARED) { 11407c478bd9Sstevel@tonic-gate if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) { 11417c478bd9Sstevel@tonic-gate /* Swap reserved for entire non-ism SHM */ 11427c478bd9Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 11437c478bd9Sstevel@tonic-gate } 11447c478bd9Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_NORESERVE) { 11457c478bd9Sstevel@tonic-gate /* Swap reserved on fault for each anon page */ 11467c478bd9Sstevel@tonic-gate swap = pmp->pr_anon; 11477c478bd9Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_WRITE) { 11487c478bd9Sstevel@tonic-gate /* Swap reserve for entire writable segment */ 11497c478bd9Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate /* 11537c478bd9Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 11547c478bd9Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 11577c478bd9Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 11587c478bd9Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 11597c478bd9Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 11607c478bd9Sstevel@tonic-gate mname, sizeof (mname)); 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (lname != NULL) { 11647c478bd9Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 11657c478bd9Sstevel@tonic-gate lname = ln + 1; 11667c478bd9Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 11677c478bd9Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 11687c478bd9Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate 1171c6402783Sakolb kperpage = pmp->pr_pagesize / KILOBYTE; 11727c478bd9Sstevel@tonic-gate 1173c6402783Sakolb t->total_size += ROUNDUP_KB(pmp->pr_size); 11747c478bd9Sstevel@tonic-gate t->total_rss += pmp->pr_rss * kperpage; 11757c478bd9Sstevel@tonic-gate t->total_anon += ANON(pmp) * kperpage; 11767c478bd9Sstevel@tonic-gate t->total_locked += pmp->pr_locked * kperpage; 11777c478bd9Sstevel@tonic-gate t->total_swap += swap * kperpage; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate if (first == 1) { 11807c478bd9Sstevel@tonic-gate first = 0; 11817c478bd9Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 11827c478bd9Sstevel@tonic-gate prev_size = pmp->pr_size; 11837c478bd9Sstevel@tonic-gate prev_offset = pmp->pr_offset; 11847c478bd9Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 11857c478bd9Sstevel@tonic-gate if (lname == NULL) { 11867c478bd9Sstevel@tonic-gate prev_lname = NULL; 11877c478bd9Sstevel@tonic-gate } else { 11887c478bd9Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 11897c478bd9Sstevel@tonic-gate prev_lname = prev_mname; 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 11927c478bd9Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 11937c478bd9Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 11947c478bd9Sstevel@tonic-gate prev_swap = swap * kperpage; 11957c478bd9Sstevel@tonic-gate if (last == 0) { 11967c478bd9Sstevel@tonic-gate return (0); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate merged = 1; 11997c478bd9Sstevel@tonic-gate } else if (prev_vaddr + prev_size == pmp->pr_vaddr && 12007c478bd9Sstevel@tonic-gate prev_mflags == pmp->pr_mflags && 12017c478bd9Sstevel@tonic-gate ((prev_mflags & MA_ISM) || 12027c478bd9Sstevel@tonic-gate prev_offset + prev_size == pmp->pr_offset) && 12037c478bd9Sstevel@tonic-gate ((lname == NULL && prev_lname == NULL) || 12047c478bd9Sstevel@tonic-gate (lname != NULL && prev_lname != NULL && 12057c478bd9Sstevel@tonic-gate strcmp(lname, prev_lname) == 0))) { 12067c478bd9Sstevel@tonic-gate prev_size += pmp->pr_size; 12077c478bd9Sstevel@tonic-gate prev_rss += pmp->pr_rss * kperpage; 12087c478bd9Sstevel@tonic-gate prev_anon += ANON(pmp) * kperpage; 12097c478bd9Sstevel@tonic-gate prev_locked += pmp->pr_locked * kperpage; 12107c478bd9Sstevel@tonic-gate prev_swap += swap * kperpage; 12117c478bd9Sstevel@tonic-gate if (last == 0) { 12127c478bd9Sstevel@tonic-gate return (0); 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate merged = 1; 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr); 1218c6402783Sakolb printK(ROUNDUP_KB(prev_size), size_width); 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate if (doswap) 12217c478bd9Sstevel@tonic-gate printK(prev_swap, size_width); 12227c478bd9Sstevel@tonic-gate else { 12237c478bd9Sstevel@tonic-gate printK(prev_rss, size_width); 12247c478bd9Sstevel@tonic-gate printK(prev_anon, size_width); 12257c478bd9Sstevel@tonic-gate printK(prev_locked, size_width); 12267c478bd9Sstevel@tonic-gate } 12277c478bd9Sstevel@tonic-gate (void) printf(prev_lname ? " %-6s %s\n" : "%s\n", 12287c478bd9Sstevel@tonic-gate mflags(prev_mflags), prev_lname); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (last == 0) { 12317c478bd9Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 12327c478bd9Sstevel@tonic-gate prev_size = pmp->pr_size; 12337c478bd9Sstevel@tonic-gate prev_offset = pmp->pr_offset; 12347c478bd9Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 12357c478bd9Sstevel@tonic-gate if (lname == NULL) { 12367c478bd9Sstevel@tonic-gate prev_lname = NULL; 12377c478bd9Sstevel@tonic-gate } else { 12387c478bd9Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 12397c478bd9Sstevel@tonic-gate prev_lname = prev_mname; 12407c478bd9Sstevel@tonic-gate } 12417c478bd9Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 12427c478bd9Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 12437c478bd9Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 12447c478bd9Sstevel@tonic-gate prev_swap = swap * kperpage; 12457c478bd9Sstevel@tonic-gate } else if (merged == 0) { 12467c478bd9Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 1247c6402783Sakolb printK(ROUNDUP_KB(pmp->pr_size), size_width); 12487c478bd9Sstevel@tonic-gate if (doswap) 12497c478bd9Sstevel@tonic-gate printK(swap * kperpage, size_width); 12507c478bd9Sstevel@tonic-gate else { 12517c478bd9Sstevel@tonic-gate printK(pmp->pr_rss * kperpage, size_width); 12527c478bd9Sstevel@tonic-gate printK(ANON(pmp) * kperpage, size_width); 12537c478bd9Sstevel@tonic-gate printK(pmp->pr_locked * kperpage, size_width); 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate (void) printf(lname ? " %-6s %s\n" : " %s\n", 12567c478bd9Sstevel@tonic-gate mflags(pmp->pr_mflags), lname); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate if (last != 0) 12607c478bd9Sstevel@tonic-gate first = 1; 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate return (0); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate static int 12667c478bd9Sstevel@tonic-gate perr(char *s) 12677c478bd9Sstevel@tonic-gate { 12687c478bd9Sstevel@tonic-gate if (s) 12697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 12707c478bd9Sstevel@tonic-gate else 12717c478bd9Sstevel@tonic-gate s = procname; 12727c478bd9Sstevel@tonic-gate perror(s); 12737c478bd9Sstevel@tonic-gate return (1); 12747c478bd9Sstevel@tonic-gate } 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate static char * 12777c478bd9Sstevel@tonic-gate mflags(uint_t arg) 12787c478bd9Sstevel@tonic-gate { 12797c478bd9Sstevel@tonic-gate static char code_buf[80]; 12807c478bd9Sstevel@tonic-gate char *str = code_buf; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate /* 12837c478bd9Sstevel@tonic-gate * rwxsR 12847c478bd9Sstevel@tonic-gate * 12857c478bd9Sstevel@tonic-gate * r - segment is readable 12867c478bd9Sstevel@tonic-gate * w - segment is writable 12877c478bd9Sstevel@tonic-gate * x - segment is executable 12887c478bd9Sstevel@tonic-gate * s - segment is shared 12897c478bd9Sstevel@tonic-gate * R - segment is mapped MAP_NORESERVE 12907c478bd9Sstevel@tonic-gate * 12917c478bd9Sstevel@tonic-gate */ 12927c478bd9Sstevel@tonic-gate (void) sprintf(str, "%c%c%c%c%c%c", 12937c478bd9Sstevel@tonic-gate arg & MA_READ ? 'r' : '-', 12947c478bd9Sstevel@tonic-gate arg & MA_WRITE ? 'w' : '-', 12957c478bd9Sstevel@tonic-gate arg & MA_EXEC ? 'x' : '-', 12967c478bd9Sstevel@tonic-gate arg & MA_SHARED ? 's' : '-', 12977c478bd9Sstevel@tonic-gate arg & MA_NORESERVE ? 'R' : '-', 12987c478bd9Sstevel@tonic-gate arg & MA_RESERVED1 ? '*' : ' '); 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate return (str); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate static mapdata_t * 13047c478bd9Sstevel@tonic-gate nextmap(void) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate mapdata_t *newmaps; 13077c478bd9Sstevel@tonic-gate int next; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (map_count == map_alloc) { 13107c478bd9Sstevel@tonic-gate if (map_alloc == 0) 13117c478bd9Sstevel@tonic-gate next = 16; 13127c478bd9Sstevel@tonic-gate else 13137c478bd9Sstevel@tonic-gate next = map_alloc * 2; 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate newmaps = realloc(maps, next * sizeof (mapdata_t)); 13167c478bd9Sstevel@tonic-gate if (newmaps == NULL) { 13177c478bd9Sstevel@tonic-gate (void) perr("failed to allocate maps"); 13187c478bd9Sstevel@tonic-gate exit(1); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate (void) memset(newmaps + map_alloc, '\0', 13217c478bd9Sstevel@tonic-gate (next - map_alloc) * sizeof (mapdata_t)); 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate map_alloc = next; 13247c478bd9Sstevel@tonic-gate maps = newmaps; 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate 13277c478bd9Sstevel@tonic-gate return (&maps[map_count++]); 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13317c478bd9Sstevel@tonic-gate static int 13327c478bd9Sstevel@tonic-gate gather_map(void *ignored, const prmap_t *map, const char *objname) 13337c478bd9Sstevel@tonic-gate { 1334c6402783Sakolb mapdata_t *data; 13357c478bd9Sstevel@tonic-gate 1336c6402783Sakolb /* Skip mappings which are outside the range specified by -A */ 1337c6402783Sakolb if (!address_in_range(map->pr_vaddr, 1338c6402783Sakolb map->pr_vaddr + map->pr_size, map->pr_pagesize)) 1339c6402783Sakolb return (0); 1340c6402783Sakolb 1341c6402783Sakolb data = nextmap(); 13427c478bd9Sstevel@tonic-gate data->md_map = *map; 13437c478bd9Sstevel@tonic-gate if (data->md_objname != NULL) 13447c478bd9Sstevel@tonic-gate free(data->md_objname); 13457c478bd9Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate return (0); 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 13517c478bd9Sstevel@tonic-gate static int 13527c478bd9Sstevel@tonic-gate gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname, 13537c478bd9Sstevel@tonic-gate int last, int doswap) 13547c478bd9Sstevel@tonic-gate { 1355c6402783Sakolb mapdata_t *data; 13567c478bd9Sstevel@tonic-gate 1357c6402783Sakolb /* Skip mappings which are outside the range specified by -A */ 1358c6402783Sakolb if (!address_in_range(xmap->pr_vaddr, 1359c6402783Sakolb xmap->pr_vaddr + xmap->pr_size, xmap->pr_pagesize)) 1360c6402783Sakolb return (0); 1361c6402783Sakolb 1362c6402783Sakolb data = nextmap(); 13637c478bd9Sstevel@tonic-gate data->md_xmap = *xmap; 13647c478bd9Sstevel@tonic-gate if (data->md_objname != NULL) 13657c478bd9Sstevel@tonic-gate free(data->md_objname); 13667c478bd9Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 13677c478bd9Sstevel@tonic-gate data->md_last = last; 13687c478bd9Sstevel@tonic-gate data->md_doswap = doswap; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate return (0); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate static int 13747c478bd9Sstevel@tonic-gate iter_map(proc_map_f *func, void *data) 13757c478bd9Sstevel@tonic-gate { 13767c478bd9Sstevel@tonic-gate int i; 13777c478bd9Sstevel@tonic-gate int ret; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1380c6402783Sakolb if (interrupt) 1381c6402783Sakolb break; 13827c478bd9Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_map, 13837c478bd9Sstevel@tonic-gate maps[i].md_objname)) != 0) 13847c478bd9Sstevel@tonic-gate return (ret); 13857c478bd9Sstevel@tonic-gate } 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate return (0); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate static int 13917c478bd9Sstevel@tonic-gate iter_xmap(proc_xmap_f *func, void *data) 13927c478bd9Sstevel@tonic-gate { 13937c478bd9Sstevel@tonic-gate int i; 13947c478bd9Sstevel@tonic-gate int ret; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1397c6402783Sakolb if (interrupt) 1398c6402783Sakolb break; 13997c478bd9Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname, 14007c478bd9Sstevel@tonic-gate maps[i].md_last, maps[i].md_doswap)) != 0) 14017c478bd9Sstevel@tonic-gate return (ret); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate return (0); 14057c478bd9Sstevel@tonic-gate } 1406c6402783Sakolb 1407c6402783Sakolb /* 1408c6402783Sakolb * Convert lgroup ID to string. 1409c6402783Sakolb * returns dash when lgroup ID is invalid. 1410c6402783Sakolb */ 1411c6402783Sakolb static char * 1412c6402783Sakolb lgrp2str(lgrp_id_t lgrp) 1413c6402783Sakolb { 1414c6402783Sakolb static char lgrp_buf[20]; 1415c6402783Sakolb char *str = lgrp_buf; 1416c6402783Sakolb 1417c6402783Sakolb (void) sprintf(str, lgrp == LGRP_NONE ? " -" : "%4d", lgrp); 1418c6402783Sakolb return (str); 1419c6402783Sakolb } 1420c6402783Sakolb 1421c6402783Sakolb /* 1422c6402783Sakolb * Parse address range specification for -A option. 1423c6402783Sakolb * The address range may have the following forms: 1424c6402783Sakolb * 1425c6402783Sakolb * address 1426c6402783Sakolb * start and end is set to address 1427c6402783Sakolb * address, 1428c6402783Sakolb * start is set to address, end is set to INVALID_ADDRESS 1429c6402783Sakolb * ,address 1430c6402783Sakolb * start is set to 0, end is set to address 1431c6402783Sakolb * address1,address2 1432c6402783Sakolb * start is set to address1, end is set to address2 1433c6402783Sakolb * 1434c6402783Sakolb */ 1435c6402783Sakolb static int 1436c6402783Sakolb parse_addr_range(char *input_str, uintptr_t *start, uintptr_t *end) 1437c6402783Sakolb { 1438c6402783Sakolb char *startp = input_str; 1439c6402783Sakolb char *endp = strchr(input_str, ','); 1440c6402783Sakolb ulong_t s = (ulong_t)INVALID_ADDRESS; 1441c6402783Sakolb ulong_t e = (ulong_t)INVALID_ADDRESS; 1442c6402783Sakolb 1443c6402783Sakolb if (endp != NULL) { 1444c6402783Sakolb /* 1445c6402783Sakolb * Comma is present. If there is nothing after comma, the end 1446c6402783Sakolb * remains set at INVALID_ADDRESS. Otherwise it is set to the 1447c6402783Sakolb * value after comma. 1448c6402783Sakolb */ 1449c6402783Sakolb *endp = '\0'; 1450c6402783Sakolb endp++; 1451c6402783Sakolb 1452c6402783Sakolb if ((*endp != '\0') && sscanf(endp, "%lx", &e) != 1) 1453c6402783Sakolb return (1); 1454c6402783Sakolb } 1455c6402783Sakolb 1456c6402783Sakolb if (startp != NULL) { 1457c6402783Sakolb /* 1458c6402783Sakolb * Read the start address, if it is specified. If the address is 1459c6402783Sakolb * missing, start will be set to INVALID_ADDRESS. 1460c6402783Sakolb */ 1461c6402783Sakolb if ((*startp != '\0') && sscanf(startp, "%lx", &s) != 1) 1462c6402783Sakolb return (1); 1463c6402783Sakolb } 1464c6402783Sakolb 1465c6402783Sakolb /* If there is no comma, end becomes equal to start */ 1466c6402783Sakolb if (endp == NULL) 1467c6402783Sakolb e = s; 1468c6402783Sakolb 1469c6402783Sakolb /* 1470c6402783Sakolb * ,end implies 0..end range 1471c6402783Sakolb */ 1472c6402783Sakolb if (e != INVALID_ADDRESS && s == INVALID_ADDRESS) 1473c6402783Sakolb s = 0; 1474c6402783Sakolb 1475c6402783Sakolb *start = (uintptr_t)s; 1476c6402783Sakolb *end = (uintptr_t)e; 1477c6402783Sakolb 1478c6402783Sakolb /* Return error if neither start nor end address were specified */ 1479c6402783Sakolb return (! (s != INVALID_ADDRESS || e != INVALID_ADDRESS)); 1480c6402783Sakolb } 1481c6402783Sakolb 1482c6402783Sakolb /* 1483c6402783Sakolb * Check whether any portion of [start, end] segment is within the 1484c6402783Sakolb * [start_addr, end_addr] range. 1485c6402783Sakolb * 1486c6402783Sakolb * Return values: 1487c6402783Sakolb * 0 - address is outside the range 1488c6402783Sakolb * 1 - address is within the range 1489c6402783Sakolb */ 1490c6402783Sakolb static int 1491c6402783Sakolb address_in_range(uintptr_t start, uintptr_t end, size_t psz) 1492c6402783Sakolb { 1493c6402783Sakolb int rc = 1; 1494c6402783Sakolb 1495c6402783Sakolb /* 1496c6402783Sakolb * Nothing to do if there is no address range specified with -A 1497c6402783Sakolb */ 1498c6402783Sakolb if (start_addr != INVALID_ADDRESS || end_addr != INVALID_ADDRESS) { 1499c6402783Sakolb /* The segment end is below the range start */ 1500c6402783Sakolb if ((start_addr != INVALID_ADDRESS) && 1501c6402783Sakolb (end < P2ALIGN(start_addr, psz))) 1502c6402783Sakolb rc = 0; 1503c6402783Sakolb 1504c6402783Sakolb /* The segment start is above the range end */ 1505c6402783Sakolb if ((end_addr != INVALID_ADDRESS) && 1506c6402783Sakolb (start > P2ALIGN(end_addr + psz, psz))) 1507c6402783Sakolb rc = 0; 1508c6402783Sakolb } 1509c6402783Sakolb return (rc); 1510c6402783Sakolb } 1511c6402783Sakolb 1512c6402783Sakolb /* 1513c6402783Sakolb * Returns an intersection of the [start, end] interval and the range specified 1514c6402783Sakolb * by -A flag [start_addr, end_addr]. Unspecified parts of the address range 1515c6402783Sakolb * have value INVALID_ADDRESS. 1516c6402783Sakolb * 1517c6402783Sakolb * The start_addr address is rounded down to the beginning of page and end_addr 1518c6402783Sakolb * is rounded up to the end of page. 1519c6402783Sakolb * 1520c6402783Sakolb * Returns the size of the resulting interval or zero if the interval is empty 1521c6402783Sakolb * or invalid. 1522c6402783Sakolb */ 1523c6402783Sakolb static size_t 1524c6402783Sakolb adjust_addr_range(uintptr_t start, uintptr_t end, size_t psz, 1525c6402783Sakolb uintptr_t *new_start, uintptr_t *new_end) 1526c6402783Sakolb { 1527c6402783Sakolb uintptr_t from; /* start_addr rounded down */ 1528c6402783Sakolb uintptr_t to; /* end_addr rounded up */ 1529c6402783Sakolb 1530c6402783Sakolb /* 1531c6402783Sakolb * Round down the lower address of the range to the beginning of page. 1532c6402783Sakolb */ 1533c6402783Sakolb if (start_addr == INVALID_ADDRESS) { 1534c6402783Sakolb /* 1535c6402783Sakolb * No start_addr specified by -A, the lower part of the interval 1536c6402783Sakolb * does not change. 1537c6402783Sakolb */ 1538c6402783Sakolb *new_start = start; 1539c6402783Sakolb } else { 1540c6402783Sakolb from = P2ALIGN(start_addr, psz); 1541c6402783Sakolb /* 1542c6402783Sakolb * If end address is outside the range, return an empty 1543c6402783Sakolb * interval 1544c6402783Sakolb */ 1545c6402783Sakolb if (end < from) { 1546c6402783Sakolb *new_start = *new_end = 0; 1547c6402783Sakolb return (0); 1548c6402783Sakolb } 1549c6402783Sakolb /* 1550c6402783Sakolb * The adjusted start address is the maximum of requested start 1551c6402783Sakolb * and the aligned start_addr of the -A range. 1552c6402783Sakolb */ 1553c6402783Sakolb *new_start = start < from ? from : start; 1554c6402783Sakolb } 1555c6402783Sakolb 1556c6402783Sakolb /* 1557c6402783Sakolb * Round up the higher address of the range to the end of page. 1558c6402783Sakolb */ 1559c6402783Sakolb if (end_addr == INVALID_ADDRESS) { 1560c6402783Sakolb /* 1561c6402783Sakolb * No end_addr specified by -A, the upper part of the interval 1562c6402783Sakolb * does not change. 1563c6402783Sakolb */ 1564c6402783Sakolb *new_end = end; 1565c6402783Sakolb } else { 1566c6402783Sakolb /* 1567c6402783Sakolb * If only one address is specified and it is the beginning of a 1568c6402783Sakolb * segment, get information about the whole segment. This 1569c6402783Sakolb * function is called once per segment and the 'end' argument is 1570c6402783Sakolb * always the end of a segment, so just use the 'end' value. 1571c6402783Sakolb */ 1572c6402783Sakolb to = (end_addr == start_addr && start == start_addr) ? 1573c6402783Sakolb end : 1574c6402783Sakolb P2ALIGN(end_addr + psz, psz); 1575c6402783Sakolb /* 1576c6402783Sakolb * If start address is outside the range, return an empty 1577c6402783Sakolb * interval 1578c6402783Sakolb */ 1579c6402783Sakolb if (start > to) { 1580c6402783Sakolb *new_start = *new_end = 0; 1581c6402783Sakolb return (0); 1582c6402783Sakolb } 1583c6402783Sakolb /* 1584c6402783Sakolb * The adjusted end address is the minimum of requested end 1585c6402783Sakolb * and the aligned end_addr of the -A range. 1586c6402783Sakolb */ 1587c6402783Sakolb *new_end = end > to ? to : end; 1588c6402783Sakolb } 1589c6402783Sakolb 1590c6402783Sakolb /* 1591c6402783Sakolb * Make sure that the resulting interval is legal. 1592c6402783Sakolb */ 1593c6402783Sakolb if (*new_end < *new_start) 1594c6402783Sakolb *new_start = *new_end = 0; 1595c6402783Sakolb 1596c6402783Sakolb /* Return the size of the interval */ 1597c6402783Sakolb return (*new_end - *new_start); 1598c6402783Sakolb } 1599c6402783Sakolb 1600c6402783Sakolb /* 1601c6402783Sakolb * Initialize memory_info data structure with information about a new segment. 1602c6402783Sakolb */ 1603c6402783Sakolb static void 1604c6402783Sakolb mem_chunk_init(memory_chunk_t *chunk, uintptr_t end, size_t psz) 1605c6402783Sakolb { 1606c6402783Sakolb chunk->end_addr = end; 1607c6402783Sakolb chunk->page_size = psz; 1608c6402783Sakolb chunk->page_index = 0; 1609c6402783Sakolb chunk->chunk_start = chunk->chunk_end = 0; 1610c6402783Sakolb } 1611c6402783Sakolb 1612c6402783Sakolb /* 1613c6402783Sakolb * Create a new chunk of addresses starting from vaddr. 1614c6402783Sakolb * Pass the whole chunk to pr_meminfo to collect lgroup and page size 1615c6402783Sakolb * information for each page in the chunk. 1616c6402783Sakolb */ 1617c6402783Sakolb static void 1618c6402783Sakolb mem_chunk_get(memory_chunk_t *chunk, uintptr_t vaddr) 1619c6402783Sakolb { 1620c6402783Sakolb page_descr_t *pdp = chunk->page_info; 1621c6402783Sakolb size_t psz = chunk->page_size; 1622c6402783Sakolb uintptr_t addr = vaddr; 1623c6402783Sakolb uint64_t inaddr[MAX_MEMINFO_CNT]; 1624c6402783Sakolb uint64_t outdata[2 * MAX_MEMINFO_CNT]; 1625c6402783Sakolb uint_t info[2] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; 1626c6402783Sakolb uint_t validity[MAX_MEMINFO_CNT]; 1627c6402783Sakolb uint64_t *dataptr = inaddr; 1628c6402783Sakolb uint64_t *outptr = outdata; 1629c6402783Sakolb uint_t *valptr = validity; 1630c6402783Sakolb int i, j, rc; 1631c6402783Sakolb 1632c6402783Sakolb chunk->chunk_start = vaddr; 1633c6402783Sakolb chunk->page_index = 0; /* reset index for the new chunk */ 1634c6402783Sakolb 1635c6402783Sakolb /* 1636c6402783Sakolb * Fill in MAX_MEMINFO_CNT wotrh of pages starting from vaddr. Also, 1637c6402783Sakolb * copy starting address of each page to inaddr array for pr_meminfo. 1638c6402783Sakolb */ 1639c6402783Sakolb for (i = 0, pdp = chunk->page_info; 1640c6402783Sakolb (i < MAX_MEMINFO_CNT) && (addr <= chunk->end_addr); 1641c6402783Sakolb i++, pdp++, dataptr++, addr += psz) { 1642c6402783Sakolb *dataptr = (uint64_t)addr; 1643c6402783Sakolb pdp->pd_start = addr; 1644c6402783Sakolb pdp->pd_lgrp = LGRP_NONE; 1645c6402783Sakolb pdp->pd_valid = 0; 1646c6402783Sakolb pdp->pd_pagesize = 0; 1647c6402783Sakolb } 1648c6402783Sakolb 1649c6402783Sakolb /* Mark the number of entries in the chunk and the last address */ 1650c6402783Sakolb chunk->page_count = i; 1651c6402783Sakolb chunk->chunk_end = addr - psz; 1652c6402783Sakolb 1653c6402783Sakolb if (interrupt) 1654c6402783Sakolb return; 1655c6402783Sakolb 1656c6402783Sakolb /* Call meminfo for all collected addresses */ 1657c6402783Sakolb rc = pr_meminfo(Pr, inaddr, i, info, 2, outdata, validity); 1658c6402783Sakolb if (rc < 0) { 1659c6402783Sakolb (void) perr("can not get memory information"); 1660c6402783Sakolb return; 1661c6402783Sakolb } 1662c6402783Sakolb 1663c6402783Sakolb /* Verify validity of each result and fill in the addrs array */ 1664c6402783Sakolb pdp = chunk->page_info; 1665c6402783Sakolb for (j = 0; j < i; j++, pdp++, valptr++, outptr += 2) { 1666c6402783Sakolb /* Skip invalid address pointers */ 1667c6402783Sakolb if ((*valptr & 1) == 0) { 1668c6402783Sakolb continue; 1669c6402783Sakolb } 1670c6402783Sakolb 1671c6402783Sakolb /* Is lgroup information available? */ 1672c6402783Sakolb if ((*valptr & 2) != 0) { 1673c6402783Sakolb pdp->pd_lgrp = (lgrp_id_t)*outptr; 1674c6402783Sakolb pdp->pd_valid = 1; 1675c6402783Sakolb } 1676c6402783Sakolb 1677c6402783Sakolb /* Is page size informaion available? */ 1678c6402783Sakolb if ((*valptr & 4) != 0) { 1679c6402783Sakolb pdp->pd_pagesize = *(outptr + 1); 1680c6402783Sakolb } 1681c6402783Sakolb } 1682c6402783Sakolb } 1683c6402783Sakolb 1684c6402783Sakolb /* 1685c6402783Sakolb * Starting from address 'vaddr' find the region with pages allocated from the 1686c6402783Sakolb * same lgroup. 1687c6402783Sakolb * 1688c6402783Sakolb * Arguments: 1689c6402783Sakolb * mchunk Initialized memory chunk structure 1690c6402783Sakolb * vaddr Starting address of the region 1691c6402783Sakolb * maxaddr Upper bound of the region 1692c6402783Sakolb * pagesize Default page size to use 1693c6402783Sakolb * ret_lgrp On exit contains the lgroup ID of all pages in the 1694c6402783Sakolb * region. 1695c6402783Sakolb * 1696c6402783Sakolb * Returns: 1697c6402783Sakolb * Size of the contiguous region in bytes 1698c6402783Sakolb * The lgroup ID of all pages in the region in ret_lgrp argument. 1699c6402783Sakolb */ 1700c6402783Sakolb static size_t 1701c6402783Sakolb get_contiguous_region(memory_chunk_t *mchunk, uintptr_t vaddr, 1702c6402783Sakolb uintptr_t maxaddr, size_t pagesize, lgrp_id_t *ret_lgrp) 1703c6402783Sakolb { 1704c6402783Sakolb size_t size_contig = 0; 1705c6402783Sakolb lgrp_id_t lgrp; /* Lgroup of the region start */ 1706c6402783Sakolb lgrp_id_t curr_lgrp; /* Lgroup of the current page */ 1707c6402783Sakolb size_t psz = pagesize; /* Pagesize to use */ 1708c6402783Sakolb 1709c6402783Sakolb /* Set both lgroup IDs to the lgroup of the first page */ 1710c6402783Sakolb curr_lgrp = lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1711c6402783Sakolb 1712c6402783Sakolb /* 1713c6402783Sakolb * Starting from vaddr, walk page by page until either the end 1714c6402783Sakolb * of the segment is reached or a page is allocated from a different 1715c6402783Sakolb * lgroup. Also stop if interrupted from keyboard. 1716c6402783Sakolb */ 1717c6402783Sakolb while ((vaddr < maxaddr) && (curr_lgrp == lgrp) && !interrupt) { 1718c6402783Sakolb /* 1719c6402783Sakolb * Get lgroup ID and the page size of the current page. 1720c6402783Sakolb */ 1721c6402783Sakolb curr_lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1722c6402783Sakolb /* If there is no page size information, use the default */ 1723c6402783Sakolb if (psz == 0) 1724c6402783Sakolb psz = pagesize; 1725c6402783Sakolb 1726c6402783Sakolb if (curr_lgrp == lgrp) { 1727c6402783Sakolb /* 1728c6402783Sakolb * This page belongs to the contiguous region. 1729c6402783Sakolb * Increase the region size and advance to the new page. 1730c6402783Sakolb */ 1731c6402783Sakolb size_contig += psz; 1732c6402783Sakolb vaddr += psz; 1733c6402783Sakolb } 1734c6402783Sakolb } 1735c6402783Sakolb 1736c6402783Sakolb /* Return the region lgroup ID and the size */ 1737c6402783Sakolb *ret_lgrp = lgrp; 1738c6402783Sakolb return (size_contig); 1739c6402783Sakolb } 1740c6402783Sakolb 1741c6402783Sakolb /* 1742c6402783Sakolb * Given a virtual address, return its lgroup and page size. If there is meminfo 1743c6402783Sakolb * information for an address, use it, otherwise shift the chunk window to the 1744c6402783Sakolb * vaddr and create a new chunk with known meminfo information. 1745c6402783Sakolb */ 1746c6402783Sakolb static lgrp_id_t 1747c6402783Sakolb addr_to_lgrp(memory_chunk_t *chunk, uintptr_t vaddr, size_t *psz) 1748c6402783Sakolb { 1749c6402783Sakolb page_descr_t *pdp; 1750c6402783Sakolb lgrp_id_t lgrp = LGRP_NONE; 1751c6402783Sakolb int i; 1752c6402783Sakolb 1753c6402783Sakolb *psz = chunk->page_size; 1754c6402783Sakolb 1755c6402783Sakolb if (interrupt) 1756c6402783Sakolb return (0); 1757c6402783Sakolb 1758c6402783Sakolb /* 1759c6402783Sakolb * Is there information about this address? If not, create a new chunk 1760c6402783Sakolb * starting from vaddr and apply pr_meminfo() to the whole chunk. 1761c6402783Sakolb */ 1762c6402783Sakolb if (vaddr < chunk->chunk_start || vaddr > chunk->chunk_end) { 1763c6402783Sakolb /* 1764c6402783Sakolb * This address is outside the chunk, get the new chunk and 1765c6402783Sakolb * collect meminfo information for it. 1766c6402783Sakolb */ 1767c6402783Sakolb mem_chunk_get(chunk, vaddr); 1768c6402783Sakolb } 1769c6402783Sakolb 1770c6402783Sakolb /* 1771c6402783Sakolb * Find information about the address. 1772c6402783Sakolb */ 1773c6402783Sakolb pdp = &chunk->page_info[chunk->page_index]; 1774c6402783Sakolb for (i = chunk->page_index; i < chunk->page_count; i++, pdp++) { 1775c6402783Sakolb if (pdp->pd_start == vaddr) { 1776c6402783Sakolb if (pdp->pd_valid) { 1777c6402783Sakolb lgrp = pdp->pd_lgrp; 1778c6402783Sakolb /* 1779c6402783Sakolb * Override page size information if it is 1780c6402783Sakolb * present. 1781c6402783Sakolb */ 1782c6402783Sakolb if (pdp->pd_pagesize > 0) 1783c6402783Sakolb *psz = pdp->pd_pagesize; 1784c6402783Sakolb } 1785c6402783Sakolb break; 1786c6402783Sakolb } 1787c6402783Sakolb } 1788c6402783Sakolb /* 1789c6402783Sakolb * Remember where we ended - the next search will start here. 1790c6402783Sakolb * We can query for the lgrp for the same address again, so do not 1791c6402783Sakolb * advance index past the current value. 1792c6402783Sakolb */ 1793c6402783Sakolb chunk->page_index = i; 1794c6402783Sakolb 1795c6402783Sakolb return (lgrp); 1796c6402783Sakolb } 1797c6402783Sakolb 1798c6402783Sakolb /* ARGSUSED */ 1799c6402783Sakolb static void 1800c6402783Sakolb intr(int sig) 1801c6402783Sakolb { 1802c6402783Sakolb interrupt = 1; 1803c6402783Sakolb } 1804