10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51914Scasper * Common Development and Distribution License (the "License"). 61914Scasper * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*2685Sakolb 220Sstevel@tonic-gate /* 231914Scasper * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <stdio.h> 301914Scasper #include <stdio_ext.h> 310Sstevel@tonic-gate #include <stdlib.h> 320Sstevel@tonic-gate #include <unistd.h> 330Sstevel@tonic-gate #include <ctype.h> 340Sstevel@tonic-gate #include <fcntl.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <dirent.h> 370Sstevel@tonic-gate #include <limits.h> 380Sstevel@tonic-gate #include <link.h> 390Sstevel@tonic-gate #include <libelf.h> 400Sstevel@tonic-gate #include <sys/types.h> 41*2685Sakolb #include <signal.h> 420Sstevel@tonic-gate #include <sys/stat.h> 430Sstevel@tonic-gate #include <sys/mkdev.h> 44*2685Sakolb #include <sys/mman.h> 45*2685Sakolb #include <sys/lgrp_user.h> 460Sstevel@tonic-gate #include <libproc.h> 470Sstevel@tonic-gate 48*2685Sakolb #define KILOBYTE 1024 49*2685Sakolb #define MEGABYTE (KILOBYTE * KILOBYTE) 50*2685Sakolb #define GIGABYTE (KILOBYTE * KILOBYTE * KILOBYTE) 51*2685Sakolb 52*2685Sakolb /* 53*2685Sakolb * Round up the value to the nearest kilobyte 54*2685Sakolb */ 55*2685Sakolb #define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE) 56*2685Sakolb 57*2685Sakolb /* 58*2685Sakolb * The alignment should be a power of 2. 59*2685Sakolb */ 60*2685Sakolb #define P2ALIGN(x, align) ((x) & -(align)) 61*2685Sakolb 62*2685Sakolb #define INVALID_ADDRESS (uintptr_t)(-1) 63*2685Sakolb 640Sstevel@tonic-gate struct totals { 650Sstevel@tonic-gate ulong_t total_size; 660Sstevel@tonic-gate ulong_t total_swap; 670Sstevel@tonic-gate ulong_t total_rss; 680Sstevel@tonic-gate ulong_t total_anon; 690Sstevel@tonic-gate ulong_t total_locked; 700Sstevel@tonic-gate }; 710Sstevel@tonic-gate 72*2685Sakolb /* 73*2685Sakolb * -L option requires per-page information. The information is presented in an 74*2685Sakolb * array of page_descr structures. 75*2685Sakolb */ 76*2685Sakolb typedef struct page_descr { 77*2685Sakolb uintptr_t pd_start; /* start address of a page */ 78*2685Sakolb size_t pd_pagesize; /* page size in bytes */ 79*2685Sakolb lgrp_id_t pd_lgrp; /* lgroup of memory backing the page */ 80*2685Sakolb int pd_valid; /* valid page description if non-zero */ 81*2685Sakolb } page_descr_t; 82*2685Sakolb 83*2685Sakolb /* 84*2685Sakolb * Per-page information for a memory chunk. 85*2685Sakolb * The meminfo(2) system call accepts up to MAX_MEMINFO_CNT pages at once. 86*2685Sakolb * When we need to scan larger ranges we divide them in MAX_MEMINFO_CNT sized 87*2685Sakolb * chunks. The chunk information is stored in the memory_chunk structure. 88*2685Sakolb */ 89*2685Sakolb typedef struct memory_chunk { 90*2685Sakolb page_descr_t page_info[MAX_MEMINFO_CNT]; 91*2685Sakolb uintptr_t end_addr; 92*2685Sakolb uintptr_t chunk_start; /* Starting address */ 93*2685Sakolb uintptr_t chunk_end; /* chunk_end is always <= end_addr */ 94*2685Sakolb size_t page_size; 95*2685Sakolb int page_index; /* Current page */ 96*2685Sakolb int page_count; /* Number of pages */ 97*2685Sakolb } memory_chunk_t; 98*2685Sakolb 99*2685Sakolb static volatile int interrupt; 100*2685Sakolb 1010Sstevel@tonic-gate typedef int proc_xmap_f(void *, const prxmap_t *, const char *, int, int); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate static int xmapping_iter(struct ps_prochandle *, proc_xmap_f *, void *, 1040Sstevel@tonic-gate int); 1050Sstevel@tonic-gate static int rmapping_iter(struct ps_prochandle *, proc_map_f *, void *); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static int look_map(void *, const prmap_t *, const char *); 1080Sstevel@tonic-gate static int look_smap(void *, const prxmap_t *, const char *, int, int); 1090Sstevel@tonic-gate static int look_xmap(void *, const prxmap_t *, const char *, int, int); 1100Sstevel@tonic-gate static int look_xmap_nopgsz(void *, const prxmap_t *, const char *, 1110Sstevel@tonic-gate int, int); 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static int gather_map(void *, const prmap_t *, const char *); 1140Sstevel@tonic-gate static int gather_xmap(void *, const prxmap_t *, const char *, int, int); 1150Sstevel@tonic-gate static int iter_map(proc_map_f *, void *); 1160Sstevel@tonic-gate static int iter_xmap(proc_xmap_f *, void *); 117*2685Sakolb static int parse_addr_range(char *, uintptr_t *, uintptr_t *); 118*2685Sakolb static void mem_chunk_init(memory_chunk_t *, uintptr_t, size_t); 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate static int perr(char *); 1210Sstevel@tonic-gate static void printK(long, int); 1220Sstevel@tonic-gate static char *mflags(uint_t); 1230Sstevel@tonic-gate 124*2685Sakolb static size_t get_contiguous_region(memory_chunk_t *, uintptr_t, 125*2685Sakolb uintptr_t, size_t, lgrp_id_t *); 126*2685Sakolb static void mem_chunk_get(memory_chunk_t *, uintptr_t); 127*2685Sakolb static lgrp_id_t addr_to_lgrp(memory_chunk_t *, uintptr_t, size_t *); 128*2685Sakolb static char *lgrp2str(lgrp_id_t); 129*2685Sakolb 130*2685Sakolb static int address_in_range(uintptr_t, uintptr_t, size_t); 131*2685Sakolb static size_t adjust_addr_range(uintptr_t, uintptr_t, size_t, 132*2685Sakolb uintptr_t *, uintptr_t *); 133*2685Sakolb 1340Sstevel@tonic-gate static int lflag = 0; 135*2685Sakolb static int Lflag = 0; 1360Sstevel@tonic-gate static int aflag = 0; 137*2685Sakolb 138*2685Sakolb /* 139*2685Sakolb * The -A address range is represented as a pair of addresses 140*2685Sakolb * <start_addr, end_addr>. Either one of these may be unspecified (set to 141*2685Sakolb * INVALID_ADDRESS). If both are unspecified, no address range restrictions are 142*2685Sakolb * in place. 143*2685Sakolb */ 144*2685Sakolb static uintptr_t start_addr = INVALID_ADDRESS; 145*2685Sakolb static uintptr_t end_addr = INVALID_ADDRESS; 146*2685Sakolb 1470Sstevel@tonic-gate static int addr_width, size_width; 1480Sstevel@tonic-gate static char *command; 1490Sstevel@tonic-gate static char *procname; 1500Sstevel@tonic-gate static struct ps_prochandle *Pr; 1510Sstevel@tonic-gate 152*2685Sakolb static void intr(int); 153*2685Sakolb 1540Sstevel@tonic-gate typedef struct lwpstack { 1550Sstevel@tonic-gate lwpid_t lwps_lwpid; 1560Sstevel@tonic-gate stack_t lwps_stack; 1570Sstevel@tonic-gate } lwpstack_t; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate typedef struct { 1600Sstevel@tonic-gate prxmap_t md_xmap; 1610Sstevel@tonic-gate prmap_t md_map; 1620Sstevel@tonic-gate char *md_objname; 163*2685Sakolb boolean_t md_last; 1640Sstevel@tonic-gate int md_doswap; 1650Sstevel@tonic-gate } mapdata_t; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate static mapdata_t *maps; 1680Sstevel@tonic-gate static int map_count; 1690Sstevel@tonic-gate static int map_alloc; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate static lwpstack_t *stacks = NULL; 1720Sstevel@tonic-gate static uint_t nstacks = 0; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate #define MAX_TRIES 5 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate static int 1770Sstevel@tonic-gate getstack(void *data, const lwpstatus_t *lsp) 1780Sstevel@tonic-gate { 1790Sstevel@tonic-gate int *np = (int *)data; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1820Sstevel@tonic-gate stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 1830Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1840Sstevel@tonic-gate (*np)++; 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 1880Sstevel@tonic-gate stacks[*np].lwps_lwpid = lsp->pr_lwpid; 1890Sstevel@tonic-gate (*np)++; 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate return (0); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate /* 1960Sstevel@tonic-gate * We compare the high memory addresses since stacks are faulted in from 1970Sstevel@tonic-gate * high memory addresses to low memory addresses, and our prmap_t 1980Sstevel@tonic-gate * structures identify only the range of addresses that have been faulted 1990Sstevel@tonic-gate * in so far. 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate static int 2020Sstevel@tonic-gate cmpstacks(const void *ap, const void *bp) 2030Sstevel@tonic-gate { 2040Sstevel@tonic-gate const lwpstack_t *as = ap; 2050Sstevel@tonic-gate const lwpstack_t *bs = bp; 2060Sstevel@tonic-gate uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 2070Sstevel@tonic-gate uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate if (a < b) 2100Sstevel@tonic-gate return (1); 2110Sstevel@tonic-gate if (a > b) 2120Sstevel@tonic-gate return (-1); 2130Sstevel@tonic-gate return (0); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate int 2180Sstevel@tonic-gate main(int argc, char **argv) 2190Sstevel@tonic-gate { 220*2685Sakolb int rflag = 0, sflag = 0, xflag = 0, Fflag = 0; 2210Sstevel@tonic-gate int errflg = 0, Sflag = 0; 2220Sstevel@tonic-gate int rc = 0; 2230Sstevel@tonic-gate int opt; 2240Sstevel@tonic-gate const char *bar8 = "-------"; 2250Sstevel@tonic-gate const char *bar16 = "----------"; 2260Sstevel@tonic-gate const char *bar; 2270Sstevel@tonic-gate struct rlimit rlim; 2280Sstevel@tonic-gate struct stat64 statbuf; 2290Sstevel@tonic-gate char buf[128]; 2300Sstevel@tonic-gate int mapfd; 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 2330Sstevel@tonic-gate command++; 2340Sstevel@tonic-gate else 2350Sstevel@tonic-gate command = argv[0]; 2360Sstevel@tonic-gate 237*2685Sakolb while ((opt = getopt(argc, argv, "arsxSlLFA:")) != EOF) { 2380Sstevel@tonic-gate switch (opt) { 2390Sstevel@tonic-gate case 'a': /* include shared mappings in -[xS] */ 2400Sstevel@tonic-gate aflag = 1; 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate case 'r': /* show reserved mappings */ 2430Sstevel@tonic-gate rflag = 1; 2440Sstevel@tonic-gate break; 2450Sstevel@tonic-gate case 's': /* show hardware page sizes */ 2460Sstevel@tonic-gate sflag = 1; 2470Sstevel@tonic-gate break; 2480Sstevel@tonic-gate case 'S': /* show swap reservations */ 2490Sstevel@tonic-gate Sflag = 1; 2500Sstevel@tonic-gate break; 2510Sstevel@tonic-gate case 'x': /* show extended mappings */ 2520Sstevel@tonic-gate xflag = 1; 2530Sstevel@tonic-gate break; 2540Sstevel@tonic-gate case 'l': /* show unresolved link map names */ 2550Sstevel@tonic-gate lflag = 1; 2560Sstevel@tonic-gate break; 257*2685Sakolb case 'L': /* show lgroup information */ 258*2685Sakolb Lflag = 1; 259*2685Sakolb break; 260*2685Sakolb case 'F': /* force grabbing (no O_EXCL) */ 261*2685Sakolb Fflag = PGRAB_FORCE; 262*2685Sakolb break; 263*2685Sakolb case 'A': 264*2685Sakolb if (parse_addr_range(optarg, &start_addr, &end_addr) 265*2685Sakolb != 0) 266*2685Sakolb errflg++; 2670Sstevel@tonic-gate break; 2680Sstevel@tonic-gate default: 2690Sstevel@tonic-gate errflg = 1; 2700Sstevel@tonic-gate break; 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate } 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate argc -= optind; 2750Sstevel@tonic-gate argv += optind; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if ((Sflag && (xflag || rflag || sflag)) || (xflag && rflag) || 278*2685Sakolb (aflag && (!xflag && !Sflag)) || 279*2685Sakolb (Lflag && (xflag || Sflag))) { 2800Sstevel@tonic-gate errflg = 1; 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate if (errflg || argc <= 0) { 2840Sstevel@tonic-gate (void) fprintf(stderr, 285*2685Sakolb "usage:\t%s [-rslF] [-A start[,end]] { pid | core } ...\n", 286*2685Sakolb command); 2870Sstevel@tonic-gate (void) fprintf(stderr, 2880Sstevel@tonic-gate "\t\t(report process address maps)\n"); 2890Sstevel@tonic-gate (void) fprintf(stderr, 290*2685Sakolb "\t%s -L [-rslF] [-A start[,end]] pid ...\n", command); 291*2685Sakolb (void) fprintf(stderr, 292*2685Sakolb "\t\t(report process address maps lgroups mappings)\n"); 293*2685Sakolb (void) fprintf(stderr, 294*2685Sakolb "\t%s -x [-aslF] [-A start[,end]] pid ...\n", command); 2950Sstevel@tonic-gate (void) fprintf(stderr, 2960Sstevel@tonic-gate "\t\t(show resident/anon/locked mapping details)\n"); 2970Sstevel@tonic-gate (void) fprintf(stderr, 298*2685Sakolb "\t%s -S [-alF] [-A start[,end]] { pid | core } ...\n", 299*2685Sakolb command); 3000Sstevel@tonic-gate (void) fprintf(stderr, 3010Sstevel@tonic-gate "\t\t(show swap reservations)\n\n"); 3020Sstevel@tonic-gate (void) fprintf(stderr, 3030Sstevel@tonic-gate "\t-a: include shared mappings in -[xS] summary\n"); 3040Sstevel@tonic-gate (void) fprintf(stderr, 3050Sstevel@tonic-gate "\t-r: show reserved address maps\n"); 3060Sstevel@tonic-gate (void) fprintf(stderr, 3070Sstevel@tonic-gate "\t-s: show hardware page sizes\n"); 3080Sstevel@tonic-gate (void) fprintf(stderr, 3090Sstevel@tonic-gate "\t-l: show unresolved dynamic linker map names\n"); 3100Sstevel@tonic-gate (void) fprintf(stderr, 3110Sstevel@tonic-gate "\t-F: force grabbing of the target process\n"); 312*2685Sakolb (void) fprintf(stderr, 313*2685Sakolb "\t-L: show lgroup mappings\n"); 314*2685Sakolb (void) fprintf(stderr, 315*2685Sakolb "\t-A start,end: limit output to the specified range\n"); 3160Sstevel@tonic-gate return (2); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 3210Sstevel@tonic-gate * that has many many mappings. 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 3240Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 3250Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 3261914Scasper (void) enable_extended_FILE_stdio(-1, -1); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate while (argc-- > 0) { 3300Sstevel@tonic-gate char *arg; 3310Sstevel@tonic-gate int gcode; 3320Sstevel@tonic-gate psinfo_t psinfo; 3330Sstevel@tonic-gate int tries = 0; 334*2685Sakolb int prg_gflags = PGRAB_RDONLY; 335*2685Sakolb int prr_flags = 0; 336*2685Sakolb 337*2685Sakolb if (Lflag) { 338*2685Sakolb prg_gflags = PGRAB_RETAIN | Fflag; 339*2685Sakolb prr_flags = PRELEASE_RETAIN; 340*2685Sakolb } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY, 343*2685Sakolb prg_gflags, &gcode)) == NULL) { 3440Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 3450Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 3460Sstevel@tonic-gate rc++; 3470Sstevel@tonic-gate continue; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate procname = arg; /* for perr() */ 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate addr_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 3530Sstevel@tonic-gate size_width = (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 3540Sstevel@tonic-gate bar = addr_width == 8 ? bar8 : bar16; 3550Sstevel@tonic-gate (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 3560Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 3590Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 3600Sstevel@tonic-gate "/proc/%d/map", (int)psinfo.pr_pid); 3610Sstevel@tonic-gate if ((mapfd = open(buf, O_RDONLY)) < 0) { 3620Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 3630Sstevel@tonic-gate "examine %s: lost control of " 3640Sstevel@tonic-gate "process\n", command, arg); 3650Sstevel@tonic-gate rc++; 366*2685Sakolb Prelease(Pr, prr_flags); 3670Sstevel@tonic-gate continue; 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate } else { 3700Sstevel@tonic-gate mapfd = -1; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate again: 3740Sstevel@tonic-gate map_count = 0; 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 3770Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 3780Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 3790Sstevel@tonic-gate 380*2685Sakolb if (rflag || sflag || xflag || Sflag || Lflag) { 3810Sstevel@tonic-gate (void) printf(" -%c option is not compatible " 3820Sstevel@tonic-gate "with core files\n", xflag ? 'x' : 383*2685Sakolb sflag ? 's' : rflag ? 'r' : 384*2685Sakolb Lflag ? 'L' : 'S'); 385*2685Sakolb Prelease(Pr, prr_flags); 3860Sstevel@tonic-gate rc++; 3870Sstevel@tonic-gate continue; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate } else { 3910Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 3920Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 395*2685Sakolb if (Lflag) { 396*2685Sakolb /* 397*2685Sakolb * The implementation of -L option creates an agent LWP 398*2685Sakolb * in the target process address space. The agent LWP 399*2685Sakolb * issues meminfo(2) system calls on behalf of the 400*2685Sakolb * target process. If we are interrupted prematurely, 401*2685Sakolb * the target process remains in the stopped state with 402*2685Sakolb * the agent still attached to it. To prevent such 403*2685Sakolb * situation we catch signals from terminal and 404*2685Sakolb * terminate gracefully. 405*2685Sakolb */ 406*2685Sakolb if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 407*2685Sakolb (void) sigset(SIGHUP, intr); 408*2685Sakolb if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 409*2685Sakolb (void) sigset(SIGINT, intr); 410*2685Sakolb if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 411*2685Sakolb (void) sigset(SIGQUIT, intr); 412*2685Sakolb (void) sigset(SIGPIPE, intr); 413*2685Sakolb (void) sigset(SIGTERM, intr); 414*2685Sakolb } 415*2685Sakolb 4160Sstevel@tonic-gate if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 4170Sstevel@tonic-gate struct totals t; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * Since we're grabbing the process readonly, we need 4210Sstevel@tonic-gate * to make sure the address space doesn't change during 4220Sstevel@tonic-gate * execution. 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 4250Sstevel@tonic-gate if (tries++ == MAX_TRIES) { 426*2685Sakolb Prelease(Pr, prr_flags); 4270Sstevel@tonic-gate (void) close(mapfd); 4280Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 4290Sstevel@tonic-gate "examine %s: address space is " 4300Sstevel@tonic-gate "changing\n", command, arg); 4310Sstevel@tonic-gate continue; 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate if (fstat64(mapfd, &statbuf) != 0) { 435*2685Sakolb Prelease(Pr, prr_flags); 4360Sstevel@tonic-gate (void) close(mapfd); 4370Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot " 4380Sstevel@tonic-gate "examine %s: lost control of " 4390Sstevel@tonic-gate "process\n", command, arg); 4400Sstevel@tonic-gate continue; 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate nstacks = psinfo.pr_nlwp * 2; 4450Sstevel@tonic-gate stacks = calloc(nstacks, sizeof (stacks[0])); 4460Sstevel@tonic-gate if (stacks != NULL) { 4470Sstevel@tonic-gate int n = 0; 4480Sstevel@tonic-gate (void) Plwp_iter(Pr, getstack, &n); 4490Sstevel@tonic-gate qsort(stacks, nstacks, sizeof (stacks[0]), 4500Sstevel@tonic-gate cmpstacks); 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate (void) memset(&t, 0, sizeof (t)); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && 4560Sstevel@tonic-gate Prd_agent(Pr) == NULL) { 4570Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: " 4580Sstevel@tonic-gate "librtld_db failed to initialize; " 4590Sstevel@tonic-gate "shared library information will not be " 4600Sstevel@tonic-gate "available\n", command); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Gather data 4650Sstevel@tonic-gate */ 4660Sstevel@tonic-gate if (xflag) 4670Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 0); 4680Sstevel@tonic-gate else if (Sflag) 4690Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, NULL, 1); 4700Sstevel@tonic-gate else { 4710Sstevel@tonic-gate if (rflag) 4720Sstevel@tonic-gate rc += rmapping_iter(Pr, gather_map, 4730Sstevel@tonic-gate NULL); 4740Sstevel@tonic-gate else if (sflag) 4750Sstevel@tonic-gate rc += xmapping_iter(Pr, gather_xmap, 4760Sstevel@tonic-gate NULL, 0); 4770Sstevel@tonic-gate else 4780Sstevel@tonic-gate rc += Pmapping_iter(Pr, gather_map, 4790Sstevel@tonic-gate NULL); 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* 4830Sstevel@tonic-gate * Ensure mappings are consistent. 4840Sstevel@tonic-gate */ 4850Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD) { 4860Sstevel@tonic-gate struct stat64 newbuf; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate if (fstat64(mapfd, &newbuf) != 0 || 4890Sstevel@tonic-gate memcmp(&newbuf.st_mtim, &statbuf.st_mtim, 4900Sstevel@tonic-gate sizeof (newbuf.st_mtim)) != 0) { 4910Sstevel@tonic-gate if (stacks != NULL) { 4920Sstevel@tonic-gate free(stacks); 4930Sstevel@tonic-gate stacks = NULL; 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate goto again; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * Display data. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate if (xflag) { 5030Sstevel@tonic-gate (void) printf("%*s%*s%*s%*s%*s " 5040Sstevel@tonic-gate "%sMode Mapped File\n", 5050Sstevel@tonic-gate addr_width, "Address", 5060Sstevel@tonic-gate size_width, "Kbytes", 5070Sstevel@tonic-gate size_width, "RSS", 5080Sstevel@tonic-gate size_width, "Anon", 5090Sstevel@tonic-gate size_width, "Locked", 5100Sstevel@tonic-gate sflag ? "Pgsz " : ""); 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate rc += iter_xmap(sflag ? look_xmap : 5130Sstevel@tonic-gate look_xmap_nopgsz, &t); 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate (void) printf("%s%s %s %s %s %s\n", 5160Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 5170Sstevel@tonic-gate bar, bar, bar, bar, bar); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 5200Sstevel@tonic-gate " " : ""); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate printK(t.total_size, size_width); 5230Sstevel@tonic-gate printK(t.total_rss, size_width); 5240Sstevel@tonic-gate printK(t.total_anon, size_width); 5250Sstevel@tonic-gate printK(t.total_locked, size_width); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate (void) printf("\n"); 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate } else if (Sflag) { 530*2685Sakolb (void) printf("%*s%*s%*s Mode" 531*2685Sakolb " Mapped File\n", 5320Sstevel@tonic-gate addr_width, "Address", 5330Sstevel@tonic-gate size_width, "Kbytes", 5340Sstevel@tonic-gate size_width, "Swap"); 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate rc += iter_xmap(look_xmap_nopgsz, &t); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate (void) printf("%s%s %s %s\n", 5390Sstevel@tonic-gate addr_width == 8 ? "-" : "------", 5400Sstevel@tonic-gate bar, bar, bar); 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate (void) printf("%stotal Kb", addr_width == 16 ? 5430Sstevel@tonic-gate " " : ""); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate printK(t.total_size, size_width); 5460Sstevel@tonic-gate printK(t.total_swap, size_width); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate (void) printf("\n"); 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate } else { 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate if (rflag) { 5530Sstevel@tonic-gate rc += iter_map(look_map, &t); 5540Sstevel@tonic-gate } else if (sflag) { 555*2685Sakolb if (Lflag) { 556*2685Sakolb (void) printf("%*s %*s %4s" 557*2685Sakolb " %-6s %s %s\n", 558*2685Sakolb addr_width, "Address", 559*2685Sakolb size_width, 560*2685Sakolb "Bytes", "Pgsz", "Mode ", 561*2685Sakolb "Lgrp", "Mapped File"); 562*2685Sakolb rc += iter_xmap(look_smap, &t); 563*2685Sakolb } else { 564*2685Sakolb (void) printf("%*s %*s %4s" 565*2685Sakolb " %-6s %s\n", 566*2685Sakolb addr_width, "Address", 567*2685Sakolb size_width, 568*2685Sakolb "Bytes", "Pgsz", "Mode ", 569*2685Sakolb "Mapped File"); 570*2685Sakolb rc += iter_xmap(look_smap, &t); 571*2685Sakolb } 5720Sstevel@tonic-gate } else { 5730Sstevel@tonic-gate rc += iter_map(look_map, &t); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate (void) printf(" %stotal %*luK\n", 5770Sstevel@tonic-gate addr_width == 16 ? 5780Sstevel@tonic-gate " " : "", 5790Sstevel@tonic-gate size_width, t.total_size); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate if (stacks != NULL) { 5830Sstevel@tonic-gate free(stacks); 5840Sstevel@tonic-gate stacks = NULL; 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate } 5880Sstevel@tonic-gate 589*2685Sakolb Prelease(Pr, prr_flags); 5900Sstevel@tonic-gate if (mapfd != -1) 5910Sstevel@tonic-gate (void) close(mapfd); 5920Sstevel@tonic-gate } 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate return (rc); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate static char * 5980Sstevel@tonic-gate make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 5990Sstevel@tonic-gate char *buf, size_t bufsz) 6000Sstevel@tonic-gate { 6010Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 6020Sstevel@tonic-gate char fname[100]; 6030Sstevel@tonic-gate struct stat statb; 6040Sstevel@tonic-gate int len; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate if (!lflag && strcmp(mapname, "a.out") == 0 && 6070Sstevel@tonic-gate Pexecname(Pr, buf, bufsz) != NULL) 6080Sstevel@tonic-gate return (buf); 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate if (Pobjname(Pr, addr, buf, bufsz) != NULL) { 6110Sstevel@tonic-gate if (lflag) 6120Sstevel@tonic-gate return (buf); 6130Sstevel@tonic-gate if ((len = resolvepath(buf, buf, bufsz)) > 0) { 6140Sstevel@tonic-gate buf[len] = '\0'; 6150Sstevel@tonic-gate return (buf); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate if (Pstate(Pr) != PS_DEAD && *mapname != '\0') { 6200Sstevel@tonic-gate (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s", 6210Sstevel@tonic-gate (int)Psp->pr_pid, mapname); 6220Sstevel@tonic-gate if (stat(fname, &statb) == 0) { 6230Sstevel@tonic-gate dev_t dev = statb.st_dev; 6240Sstevel@tonic-gate ino_t ino = statb.st_ino; 6250Sstevel@tonic-gate (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", 6260Sstevel@tonic-gate (ulong_t)major(dev), (ulong_t)minor(dev), ino); 6270Sstevel@tonic-gate return (buf); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate return (NULL); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate static char * 6350Sstevel@tonic-gate anon_name(char *name, const pstatus_t *Psp, 6360Sstevel@tonic-gate uintptr_t vaddr, size_t size, int mflags, int shmid) 6370Sstevel@tonic-gate { 6380Sstevel@tonic-gate if (mflags & MA_ISM) { 6390Sstevel@tonic-gate if (shmid == -1) 6400Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 6410Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism"); 6420Sstevel@tonic-gate else 6430Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 6440Sstevel@tonic-gate (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 6450Sstevel@tonic-gate } else if (mflags & MA_SHM) { 6460Sstevel@tonic-gate if (shmid == -1) 6470Sstevel@tonic-gate (void) sprintf(name, " [ shmid=null ]"); 6480Sstevel@tonic-gate else 6490Sstevel@tonic-gate (void) sprintf(name, " [ shmid=0x%x ]", shmid); 6500Sstevel@tonic-gate } else if (vaddr + size > Psp->pr_stkbase && 6510Sstevel@tonic-gate vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 6520Sstevel@tonic-gate (void) strcpy(name, " [ stack ]"); 6530Sstevel@tonic-gate } else if ((mflags & MA_ANON) && 6540Sstevel@tonic-gate vaddr + size > Psp->pr_brkbase && 6550Sstevel@tonic-gate vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 6560Sstevel@tonic-gate (void) strcpy(name, " [ heap ]"); 6570Sstevel@tonic-gate } else { 6580Sstevel@tonic-gate lwpstack_t key, *stk; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate key.lwps_stack.ss_sp = (void *)vaddr; 6610Sstevel@tonic-gate key.lwps_stack.ss_size = size; 6620Sstevel@tonic-gate if (nstacks > 0 && 6630Sstevel@tonic-gate (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 6640Sstevel@tonic-gate cmpstacks)) != NULL) { 6650Sstevel@tonic-gate (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 6660Sstevel@tonic-gate (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 6670Sstevel@tonic-gate "altstack" : "stack", 6680Sstevel@tonic-gate stk->lwps_lwpid); 6690Sstevel@tonic-gate } else if (Pstate(Pr) != PS_DEAD) { 6700Sstevel@tonic-gate (void) strcpy(name, " [ anon ]"); 6710Sstevel@tonic-gate } else { 6720Sstevel@tonic-gate return (NULL); 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate return (name); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate static int 6800Sstevel@tonic-gate rmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd) 6810Sstevel@tonic-gate { 6820Sstevel@tonic-gate char mapname[PATH_MAX]; 6830Sstevel@tonic-gate int mapfd, nmap, i, rc; 6840Sstevel@tonic-gate struct stat st; 6850Sstevel@tonic-gate prmap_t *prmapp, *pmp; 6860Sstevel@tonic-gate ssize_t n; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 6890Sstevel@tonic-gate "/proc/%d/rmap", (int)Pstatus(Pr)->pr_pid); 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 6920Sstevel@tonic-gate if (mapfd >= 0) 6930Sstevel@tonic-gate (void) close(mapfd); 6940Sstevel@tonic-gate return (perr(mapname)); 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate nmap = st.st_size / sizeof (prmap_t); 6980Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prmap_t)); 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prmap_t), 0L)) < 0) { 7010Sstevel@tonic-gate (void) close(mapfd); 7020Sstevel@tonic-gate free(prmapp); 7030Sstevel@tonic-gate return (perr("read rmap")); 7040Sstevel@tonic-gate } 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate (void) close(mapfd); 7070Sstevel@tonic-gate nmap = n / sizeof (prmap_t); 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 7100Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL)) != 0) { 7110Sstevel@tonic-gate free(prmapp); 7120Sstevel@tonic-gate return (rc); 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate free(prmapp); 7170Sstevel@tonic-gate return (0); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate static int 7210Sstevel@tonic-gate xmapping_iter(struct ps_prochandle *Pr, proc_xmap_f *func, void *cd, int doswap) 7220Sstevel@tonic-gate { 7230Sstevel@tonic-gate char mapname[PATH_MAX]; 7240Sstevel@tonic-gate int mapfd, nmap, i, rc; 7250Sstevel@tonic-gate struct stat st; 7260Sstevel@tonic-gate prxmap_t *prmapp, *pmp; 7270Sstevel@tonic-gate ssize_t n; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate (void) snprintf(mapname, sizeof (mapname), 7300Sstevel@tonic-gate "/proc/%d/xmap", (int)Pstatus(Pr)->pr_pid); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate if ((mapfd = open(mapname, O_RDONLY)) < 0 || fstat(mapfd, &st) != 0) { 7330Sstevel@tonic-gate if (mapfd >= 0) 7340Sstevel@tonic-gate (void) close(mapfd); 7350Sstevel@tonic-gate return (perr(mapname)); 7360Sstevel@tonic-gate } 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate nmap = st.st_size / sizeof (prxmap_t); 7390Sstevel@tonic-gate nmap *= 2; 7400Sstevel@tonic-gate again: 7410Sstevel@tonic-gate prmapp = malloc((nmap + 1) * sizeof (prxmap_t)); 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if ((n = pread(mapfd, prmapp, (nmap + 1) * sizeof (prxmap_t), 0)) < 0) { 7440Sstevel@tonic-gate (void) close(mapfd); 7450Sstevel@tonic-gate free(prmapp); 7460Sstevel@tonic-gate return (perr("read xmap")); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (nmap < n / sizeof (prxmap_t)) { 7500Sstevel@tonic-gate free(prmapp); 7510Sstevel@tonic-gate nmap *= 2; 7520Sstevel@tonic-gate goto again; 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate (void) close(mapfd); 7560Sstevel@tonic-gate nmap = n / sizeof (prxmap_t); 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate for (i = 0, pmp = prmapp; i < nmap; i++, pmp++) { 7590Sstevel@tonic-gate if ((rc = func(cd, pmp, NULL, i == nmap - 1, doswap)) != 0) { 7600Sstevel@tonic-gate free(prmapp); 7610Sstevel@tonic-gate return (rc); 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate 765*2685Sakolb /* 766*2685Sakolb * Mark the last element. 767*2685Sakolb */ 768*2685Sakolb if (map_count > 0) 769*2685Sakolb maps[map_count - 1].md_last = B_TRUE; 770*2685Sakolb 7710Sstevel@tonic-gate free(prmapp); 7720Sstevel@tonic-gate return (0); 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate /*ARGSUSED*/ 7760Sstevel@tonic-gate static int 7770Sstevel@tonic-gate look_map(void *data, const prmap_t *pmp, const char *object_name) 7780Sstevel@tonic-gate { 7790Sstevel@tonic-gate struct totals *t = data; 7800Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 781*2685Sakolb size_t size; 7820Sstevel@tonic-gate char mname[PATH_MAX]; 7830Sstevel@tonic-gate char *lname = NULL; 784*2685Sakolb size_t psz = pmp->pr_pagesize; 785*2685Sakolb uintptr_t vaddr = pmp->pr_vaddr; 786*2685Sakolb uintptr_t segment_end = vaddr + pmp->pr_size; 787*2685Sakolb lgrp_id_t lgrp; 788*2685Sakolb memory_chunk_t mchunk; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate /* 7910Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 7920Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 7930Sstevel@tonic-gate */ 7940Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 795*2685Sakolb segment_end <= Psp->pr_brkbase || 7960Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 7970Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 7980Sstevel@tonic-gate mname, sizeof (mname)); 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate if (lname == NULL && 8020Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 8030Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 8040Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate 807*2685Sakolb /* 808*2685Sakolb * Adjust the address range if -A is specified. 809*2685Sakolb */ 810*2685Sakolb size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 811*2685Sakolb &vaddr, &segment_end); 812*2685Sakolb 813*2685Sakolb if (size == 0) 814*2685Sakolb return (0); 815*2685Sakolb 816*2685Sakolb if (!Lflag) { 817*2685Sakolb /* 818*2685Sakolb * Display the whole mapping 819*2685Sakolb */ 820*2685Sakolb size = ROUNDUP_KB(size); 821*2685Sakolb 822*2685Sakolb (void) printf(lname ? 823*2685Sakolb "%.*lX %*luK %-6s %s\n" : 824*2685Sakolb "%.*lX %*luK %s\n", 825*2685Sakolb addr_width, vaddr, 826*2685Sakolb size_width - 1, size, mflags(pmp->pr_mflags), lname); 827*2685Sakolb 828*2685Sakolb t->total_size += size; 829*2685Sakolb return (0); 830*2685Sakolb } 831*2685Sakolb 832*2685Sakolb /* 833*2685Sakolb * We need to display lgroups backing physical memory, so we break the 834*2685Sakolb * segment into individual pages and coalesce pages with the same lgroup 835*2685Sakolb * into one "segment". 836*2685Sakolb */ 8370Sstevel@tonic-gate 838*2685Sakolb /* 839*2685Sakolb * Initialize address descriptions for the mapping. 840*2685Sakolb */ 841*2685Sakolb mem_chunk_init(&mchunk, segment_end, psz); 842*2685Sakolb size = 0; 843*2685Sakolb 844*2685Sakolb /* 845*2685Sakolb * Walk mapping (page by page) and display contiguous ranges of memory 846*2685Sakolb * allocated to same lgroup. 847*2685Sakolb */ 848*2685Sakolb do { 849*2685Sakolb size_t size_contig; 850*2685Sakolb 851*2685Sakolb /* 852*2685Sakolb * Get contiguous region of memory starting from vaddr allocated 853*2685Sakolb * from the same lgroup. 854*2685Sakolb */ 855*2685Sakolb size_contig = get_contiguous_region(&mchunk, vaddr, 856*2685Sakolb segment_end, pmp->pr_pagesize, &lgrp); 857*2685Sakolb 858*2685Sakolb (void) printf(lname ? "%.*lX %*luK %-6s%s %s\n" : 859*2685Sakolb "%.*lX %*luK %s %s\n", 860*2685Sakolb addr_width, vaddr, 861*2685Sakolb size_width - 1, size_contig / KILOBYTE, 862*2685Sakolb mflags(pmp->pr_mflags), 863*2685Sakolb lgrp2str(lgrp), lname); 864*2685Sakolb 865*2685Sakolb vaddr += size_contig; 866*2685Sakolb size += size_contig; 867*2685Sakolb } while (vaddr < segment_end && !interrupt); 868*2685Sakolb 869*2685Sakolb /* Update the total size */ 870*2685Sakolb t->total_size += ROUNDUP_KB(size); 8710Sstevel@tonic-gate return (0); 8720Sstevel@tonic-gate } 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate static void 8750Sstevel@tonic-gate printK(long value, int width) 8760Sstevel@tonic-gate { 8770Sstevel@tonic-gate if (value == 0) 8780Sstevel@tonic-gate (void) printf(width == 8 ? " -" : " -"); 8790Sstevel@tonic-gate else 8800Sstevel@tonic-gate (void) printf(" %*lu", width - 1, value); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate static const char * 8840Sstevel@tonic-gate pagesize(const prxmap_t *pmp) 8850Sstevel@tonic-gate { 8860Sstevel@tonic-gate int pagesize = pmp->pr_hatpagesize; 8870Sstevel@tonic-gate static char buf[32]; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate if (pagesize == 0) { 8900Sstevel@tonic-gate return ("-"); /* no underlying HAT mapping */ 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 893*2685Sakolb if (pagesize >= KILOBYTE && (pagesize % KILOBYTE) == 0) { 894*2685Sakolb if ((pagesize % GIGABYTE) == 0) 8950Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dG", 896*2685Sakolb pagesize / GIGABYTE); 897*2685Sakolb else if ((pagesize % MEGABYTE) == 0) 8980Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dM", 899*2685Sakolb pagesize / MEGABYTE); 9000Sstevel@tonic-gate else 9010Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%dK", 902*2685Sakolb pagesize / KILOBYTE); 9030Sstevel@tonic-gate } else 9040Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%db", pagesize); 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate return (buf); 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /*ARGSUSED*/ 9100Sstevel@tonic-gate static int 9110Sstevel@tonic-gate look_smap(void *data, 9120Sstevel@tonic-gate const prxmap_t *pmp, 9130Sstevel@tonic-gate const char *object_name, 9140Sstevel@tonic-gate int last, int doswap) 9150Sstevel@tonic-gate { 9160Sstevel@tonic-gate struct totals *t = data; 9170Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 918*2685Sakolb size_t size; 9190Sstevel@tonic-gate char mname[PATH_MAX]; 9200Sstevel@tonic-gate char *lname = NULL; 9210Sstevel@tonic-gate const char *format; 922*2685Sakolb size_t psz = pmp->pr_pagesize; 923*2685Sakolb uintptr_t vaddr = pmp->pr_vaddr; 924*2685Sakolb uintptr_t segment_end = vaddr + pmp->pr_size; 925*2685Sakolb lgrp_id_t lgrp; 926*2685Sakolb memory_chunk_t mchunk; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate /* 9290Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 9300Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 9310Sstevel@tonic-gate */ 9320Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 9330Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 9340Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 9350Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 9360Sstevel@tonic-gate mname, sizeof (mname)); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate if (lname == NULL && 9400Sstevel@tonic-gate ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD)) { 9410Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 9420Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 945*2685Sakolb /* 946*2685Sakolb * Adjust the address range if -A is specified. 947*2685Sakolb */ 948*2685Sakolb size = adjust_addr_range(pmp->pr_vaddr, segment_end, psz, 949*2685Sakolb &vaddr, &segment_end); 950*2685Sakolb 951*2685Sakolb if (size == 0) 952*2685Sakolb return (0); 953*2685Sakolb 954*2685Sakolb if (!Lflag) { 955*2685Sakolb /* 956*2685Sakolb * Display the whole mapping 957*2685Sakolb */ 958*2685Sakolb if (lname != NULL) 959*2685Sakolb format = "%.*lX %*luK %4s %-6s %s\n"; 960*2685Sakolb else 961*2685Sakolb format = "%.*lX %*luK %4s %s\n"; 962*2685Sakolb 963*2685Sakolb size = ROUNDUP_KB(size); 964*2685Sakolb 965*2685Sakolb (void) printf(format, addr_width, vaddr, size_width - 1, size, 966*2685Sakolb pagesize(pmp), mflags(pmp->pr_mflags), lname); 967*2685Sakolb 968*2685Sakolb t->total_size += size; 969*2685Sakolb return (0); 970*2685Sakolb } 971*2685Sakolb 9720Sstevel@tonic-gate if (lname != NULL) 973*2685Sakolb format = "%.*lX %*luK %4s %-6s%s %s\n"; 9740Sstevel@tonic-gate else 975*2685Sakolb format = "%.*lX %*luK %4s%s %s\n"; 9760Sstevel@tonic-gate 977*2685Sakolb /* 978*2685Sakolb * We need to display lgroups backing physical memory, so we break the 979*2685Sakolb * segment into individual pages and coalesce pages with the same lgroup 980*2685Sakolb * into one "segment". 981*2685Sakolb */ 982*2685Sakolb 983*2685Sakolb /* 984*2685Sakolb * Initialize address descriptions for the mapping. 985*2685Sakolb */ 986*2685Sakolb mem_chunk_init(&mchunk, segment_end, psz); 987*2685Sakolb size = 0; 9880Sstevel@tonic-gate 989*2685Sakolb /* 990*2685Sakolb * Walk mapping (page by page) and display contiguous ranges of memory 991*2685Sakolb * allocated to same lgroup. 992*2685Sakolb */ 993*2685Sakolb do { 994*2685Sakolb size_t size_contig; 995*2685Sakolb 996*2685Sakolb /* 997*2685Sakolb * Get contiguous region of memory starting from vaddr allocated 998*2685Sakolb * from the same lgroup. 999*2685Sakolb */ 1000*2685Sakolb size_contig = get_contiguous_region(&mchunk, vaddr, 1001*2685Sakolb segment_end, pmp->pr_pagesize, &lgrp); 1002*2685Sakolb 1003*2685Sakolb (void) printf(format, addr_width, vaddr, 1004*2685Sakolb size_width - 1, size_contig / KILOBYTE, 1005*2685Sakolb pagesize(pmp), mflags(pmp->pr_mflags), 1006*2685Sakolb lgrp2str(lgrp), lname); 1007*2685Sakolb 1008*2685Sakolb vaddr += size_contig; 1009*2685Sakolb size += size_contig; 1010*2685Sakolb } while (vaddr < segment_end && !interrupt); 1011*2685Sakolb 1012*2685Sakolb t->total_size += ROUNDUP_KB(size); 10130Sstevel@tonic-gate return (0); 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate #define ANON(x) ((aflag || (((x)->pr_mflags & MA_SHARED) == 0)) ? \ 10170Sstevel@tonic-gate ((x)->pr_anon) : 0) 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate /*ARGSUSED*/ 10200Sstevel@tonic-gate static int 10210Sstevel@tonic-gate look_xmap(void *data, 10220Sstevel@tonic-gate const prxmap_t *pmp, 10230Sstevel@tonic-gate const char *object_name, 10240Sstevel@tonic-gate int last, int doswap) 10250Sstevel@tonic-gate { 10260Sstevel@tonic-gate struct totals *t = data; 10270Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 10280Sstevel@tonic-gate char mname[PATH_MAX]; 10290Sstevel@tonic-gate char *lname = NULL; 10300Sstevel@tonic-gate char *ln; 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate /* 10330Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 10340Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 10350Sstevel@tonic-gate */ 10360Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 10370Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 10380Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 10390Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 10400Sstevel@tonic-gate mname, sizeof (mname)); 10410Sstevel@tonic-gate } 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate if (lname != NULL) { 10440Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 10450Sstevel@tonic-gate lname = ln + 1; 10460Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 10470Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 10480Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 10490Sstevel@tonic-gate } 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 10520Sstevel@tonic-gate 1053*2685Sakolb printK(ROUNDUP_KB(pmp->pr_size), size_width); 1054*2685Sakolb printK(pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE), size_width); 1055*2685Sakolb printK(ANON(pmp) * (pmp->pr_pagesize / KILOBYTE), size_width); 1056*2685Sakolb printK(pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE), size_width); 10570Sstevel@tonic-gate (void) printf(lname ? " %4s %-6s %s\n" : " %4s %s\n", 10580Sstevel@tonic-gate pagesize(pmp), mflags(pmp->pr_mflags), lname); 10590Sstevel@tonic-gate 1060*2685Sakolb t->total_size += ROUNDUP_KB(pmp->pr_size); 1061*2685Sakolb t->total_rss += pmp->pr_rss * (pmp->pr_pagesize / KILOBYTE); 1062*2685Sakolb t->total_anon += ANON(pmp) * (pmp->pr_pagesize / KILOBYTE); 1063*2685Sakolb t->total_locked += (pmp->pr_locked * (pmp->pr_pagesize / KILOBYTE)); 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate return (0); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate /*ARGSUSED*/ 10690Sstevel@tonic-gate static int 10700Sstevel@tonic-gate look_xmap_nopgsz(void *data, 10710Sstevel@tonic-gate const prxmap_t *pmp, 10720Sstevel@tonic-gate const char *object_name, 10730Sstevel@tonic-gate int last, int doswap) 10740Sstevel@tonic-gate { 10750Sstevel@tonic-gate struct totals *t = data; 10760Sstevel@tonic-gate const pstatus_t *Psp = Pstatus(Pr); 10770Sstevel@tonic-gate char mname[PATH_MAX]; 10780Sstevel@tonic-gate char *lname = NULL; 10790Sstevel@tonic-gate char *ln; 10800Sstevel@tonic-gate static uintptr_t prev_vaddr; 10810Sstevel@tonic-gate static size_t prev_size; 10820Sstevel@tonic-gate static offset_t prev_offset; 10830Sstevel@tonic-gate static int prev_mflags; 10840Sstevel@tonic-gate static char *prev_lname; 10850Sstevel@tonic-gate static char prev_mname[PATH_MAX]; 10860Sstevel@tonic-gate static ulong_t prev_rss; 10870Sstevel@tonic-gate static ulong_t prev_anon; 10880Sstevel@tonic-gate static ulong_t prev_locked; 10890Sstevel@tonic-gate static ulong_t prev_swap; 10900Sstevel@tonic-gate int merged = 0; 10910Sstevel@tonic-gate static int first = 1; 10920Sstevel@tonic-gate ulong_t swap = 0; 10930Sstevel@tonic-gate int kperpage; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Calculate swap reservations 10970Sstevel@tonic-gate */ 10980Sstevel@tonic-gate if (pmp->pr_mflags & MA_SHARED) { 10990Sstevel@tonic-gate if (aflag && (pmp->pr_mflags & MA_NORESERVE) == 0) { 11000Sstevel@tonic-gate /* Swap reserved for entire non-ism SHM */ 11010Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_NORESERVE) { 11040Sstevel@tonic-gate /* Swap reserved on fault for each anon page */ 11050Sstevel@tonic-gate swap = pmp->pr_anon; 11060Sstevel@tonic-gate } else if (pmp->pr_mflags & MA_WRITE) { 11070Sstevel@tonic-gate /* Swap reserve for entire writable segment */ 11080Sstevel@tonic-gate swap = pmp->pr_size / pmp->pr_pagesize; 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate /* 11120Sstevel@tonic-gate * If the mapping is not anon or not part of the heap, make a name 11130Sstevel@tonic-gate * for it. We don't want to report the heap as a.out's data. 11140Sstevel@tonic-gate */ 11150Sstevel@tonic-gate if (!(pmp->pr_mflags & MA_ANON) || 11160Sstevel@tonic-gate pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 11170Sstevel@tonic-gate pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize) { 11180Sstevel@tonic-gate lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 11190Sstevel@tonic-gate mname, sizeof (mname)); 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate if (lname != NULL) { 11230Sstevel@tonic-gate if ((ln = strrchr(lname, '/')) != NULL) 11240Sstevel@tonic-gate lname = ln + 1; 11250Sstevel@tonic-gate } else if ((pmp->pr_mflags & MA_ANON) || Pstate(Pr) == PS_DEAD) { 11260Sstevel@tonic-gate lname = anon_name(mname, Psp, pmp->pr_vaddr, 11270Sstevel@tonic-gate pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate 1130*2685Sakolb kperpage = pmp->pr_pagesize / KILOBYTE; 11310Sstevel@tonic-gate 1132*2685Sakolb t->total_size += ROUNDUP_KB(pmp->pr_size); 11330Sstevel@tonic-gate t->total_rss += pmp->pr_rss * kperpage; 11340Sstevel@tonic-gate t->total_anon += ANON(pmp) * kperpage; 11350Sstevel@tonic-gate t->total_locked += pmp->pr_locked * kperpage; 11360Sstevel@tonic-gate t->total_swap += swap * kperpage; 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate if (first == 1) { 11390Sstevel@tonic-gate first = 0; 11400Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 11410Sstevel@tonic-gate prev_size = pmp->pr_size; 11420Sstevel@tonic-gate prev_offset = pmp->pr_offset; 11430Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 11440Sstevel@tonic-gate if (lname == NULL) { 11450Sstevel@tonic-gate prev_lname = NULL; 11460Sstevel@tonic-gate } else { 11470Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 11480Sstevel@tonic-gate prev_lname = prev_mname; 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 11510Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 11520Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 11530Sstevel@tonic-gate prev_swap = swap * kperpage; 11540Sstevel@tonic-gate if (last == 0) { 11550Sstevel@tonic-gate return (0); 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate merged = 1; 11580Sstevel@tonic-gate } else if (prev_vaddr + prev_size == pmp->pr_vaddr && 11590Sstevel@tonic-gate prev_mflags == pmp->pr_mflags && 11600Sstevel@tonic-gate ((prev_mflags & MA_ISM) || 11610Sstevel@tonic-gate prev_offset + prev_size == pmp->pr_offset) && 11620Sstevel@tonic-gate ((lname == NULL && prev_lname == NULL) || 11630Sstevel@tonic-gate (lname != NULL && prev_lname != NULL && 11640Sstevel@tonic-gate strcmp(lname, prev_lname) == 0))) { 11650Sstevel@tonic-gate prev_size += pmp->pr_size; 11660Sstevel@tonic-gate prev_rss += pmp->pr_rss * kperpage; 11670Sstevel@tonic-gate prev_anon += ANON(pmp) * kperpage; 11680Sstevel@tonic-gate prev_locked += pmp->pr_locked * kperpage; 11690Sstevel@tonic-gate prev_swap += swap * kperpage; 11700Sstevel@tonic-gate if (last == 0) { 11710Sstevel@tonic-gate return (0); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate merged = 1; 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)prev_vaddr); 1177*2685Sakolb printK(ROUNDUP_KB(prev_size), size_width); 11780Sstevel@tonic-gate 11790Sstevel@tonic-gate if (doswap) 11800Sstevel@tonic-gate printK(prev_swap, size_width); 11810Sstevel@tonic-gate else { 11820Sstevel@tonic-gate printK(prev_rss, size_width); 11830Sstevel@tonic-gate printK(prev_anon, size_width); 11840Sstevel@tonic-gate printK(prev_locked, size_width); 11850Sstevel@tonic-gate } 1186*2685Sakolb (void) printf(prev_lname ? " %-6s %s\n" : "%s\n", 11870Sstevel@tonic-gate mflags(prev_mflags), prev_lname); 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate if (last == 0) { 11900Sstevel@tonic-gate prev_vaddr = pmp->pr_vaddr; 11910Sstevel@tonic-gate prev_size = pmp->pr_size; 11920Sstevel@tonic-gate prev_offset = pmp->pr_offset; 11930Sstevel@tonic-gate prev_mflags = pmp->pr_mflags; 11940Sstevel@tonic-gate if (lname == NULL) { 11950Sstevel@tonic-gate prev_lname = NULL; 11960Sstevel@tonic-gate } else { 11970Sstevel@tonic-gate (void) strcpy(prev_mname, lname); 11980Sstevel@tonic-gate prev_lname = prev_mname; 11990Sstevel@tonic-gate } 12000Sstevel@tonic-gate prev_rss = pmp->pr_rss * kperpage; 12010Sstevel@tonic-gate prev_anon = ANON(pmp) * kperpage; 12020Sstevel@tonic-gate prev_locked = pmp->pr_locked * kperpage; 12030Sstevel@tonic-gate prev_swap = swap * kperpage; 12040Sstevel@tonic-gate } else if (merged == 0) { 12050Sstevel@tonic-gate (void) printf("%.*lX", addr_width, (ulong_t)pmp->pr_vaddr); 1206*2685Sakolb printK(ROUNDUP_KB(pmp->pr_size), size_width); 12070Sstevel@tonic-gate if (doswap) 12080Sstevel@tonic-gate printK(swap * kperpage, size_width); 12090Sstevel@tonic-gate else { 12100Sstevel@tonic-gate printK(pmp->pr_rss * kperpage, size_width); 12110Sstevel@tonic-gate printK(ANON(pmp) * kperpage, size_width); 12120Sstevel@tonic-gate printK(pmp->pr_locked * kperpage, size_width); 12130Sstevel@tonic-gate } 12140Sstevel@tonic-gate (void) printf(lname ? " %-6s %s\n" : " %s\n", 12150Sstevel@tonic-gate mflags(pmp->pr_mflags), lname); 12160Sstevel@tonic-gate } 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate if (last != 0) 12190Sstevel@tonic-gate first = 1; 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate return (0); 12220Sstevel@tonic-gate } 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate static int 12250Sstevel@tonic-gate perr(char *s) 12260Sstevel@tonic-gate { 12270Sstevel@tonic-gate if (s) 12280Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", procname); 12290Sstevel@tonic-gate else 12300Sstevel@tonic-gate s = procname; 12310Sstevel@tonic-gate perror(s); 12320Sstevel@tonic-gate return (1); 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate static char * 12360Sstevel@tonic-gate mflags(uint_t arg) 12370Sstevel@tonic-gate { 12380Sstevel@tonic-gate static char code_buf[80]; 12390Sstevel@tonic-gate char *str = code_buf; 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate /* 12420Sstevel@tonic-gate * rwxsR 12430Sstevel@tonic-gate * 12440Sstevel@tonic-gate * r - segment is readable 12450Sstevel@tonic-gate * w - segment is writable 12460Sstevel@tonic-gate * x - segment is executable 12470Sstevel@tonic-gate * s - segment is shared 12480Sstevel@tonic-gate * R - segment is mapped MAP_NORESERVE 12490Sstevel@tonic-gate * 12500Sstevel@tonic-gate */ 12510Sstevel@tonic-gate (void) sprintf(str, "%c%c%c%c%c%c", 12520Sstevel@tonic-gate arg & MA_READ ? 'r' : '-', 12530Sstevel@tonic-gate arg & MA_WRITE ? 'w' : '-', 12540Sstevel@tonic-gate arg & MA_EXEC ? 'x' : '-', 12550Sstevel@tonic-gate arg & MA_SHARED ? 's' : '-', 12560Sstevel@tonic-gate arg & MA_NORESERVE ? 'R' : '-', 12570Sstevel@tonic-gate arg & MA_RESERVED1 ? '*' : ' '); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate return (str); 12600Sstevel@tonic-gate } 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate static mapdata_t * 12630Sstevel@tonic-gate nextmap(void) 12640Sstevel@tonic-gate { 12650Sstevel@tonic-gate mapdata_t *newmaps; 12660Sstevel@tonic-gate int next; 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate if (map_count == map_alloc) { 12690Sstevel@tonic-gate if (map_alloc == 0) 12700Sstevel@tonic-gate next = 16; 12710Sstevel@tonic-gate else 12720Sstevel@tonic-gate next = map_alloc * 2; 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate newmaps = realloc(maps, next * sizeof (mapdata_t)); 12750Sstevel@tonic-gate if (newmaps == NULL) { 12760Sstevel@tonic-gate (void) perr("failed to allocate maps"); 12770Sstevel@tonic-gate exit(1); 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate (void) memset(newmaps + map_alloc, '\0', 12800Sstevel@tonic-gate (next - map_alloc) * sizeof (mapdata_t)); 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate map_alloc = next; 12830Sstevel@tonic-gate maps = newmaps; 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate return (&maps[map_count++]); 12870Sstevel@tonic-gate } 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate /*ARGSUSED*/ 12900Sstevel@tonic-gate static int 12910Sstevel@tonic-gate gather_map(void *ignored, const prmap_t *map, const char *objname) 12920Sstevel@tonic-gate { 1293*2685Sakolb mapdata_t *data; 12940Sstevel@tonic-gate 1295*2685Sakolb /* Skip mappings which are outside the range specified by -A */ 1296*2685Sakolb if (!address_in_range(map->pr_vaddr, 1297*2685Sakolb map->pr_vaddr + map->pr_size, map->pr_pagesize)) 1298*2685Sakolb return (0); 1299*2685Sakolb 1300*2685Sakolb data = nextmap(); 13010Sstevel@tonic-gate data->md_map = *map; 13020Sstevel@tonic-gate if (data->md_objname != NULL) 13030Sstevel@tonic-gate free(data->md_objname); 13040Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 13050Sstevel@tonic-gate 13060Sstevel@tonic-gate return (0); 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate /*ARGSUSED*/ 13100Sstevel@tonic-gate static int 13110Sstevel@tonic-gate gather_xmap(void *ignored, const prxmap_t *xmap, const char *objname, 13120Sstevel@tonic-gate int last, int doswap) 13130Sstevel@tonic-gate { 1314*2685Sakolb mapdata_t *data; 13150Sstevel@tonic-gate 1316*2685Sakolb /* Skip mappings which are outside the range specified by -A */ 1317*2685Sakolb if (!address_in_range(xmap->pr_vaddr, 1318*2685Sakolb xmap->pr_vaddr + xmap->pr_size, xmap->pr_pagesize)) 1319*2685Sakolb return (0); 1320*2685Sakolb 1321*2685Sakolb data = nextmap(); 13220Sstevel@tonic-gate data->md_xmap = *xmap; 13230Sstevel@tonic-gate if (data->md_objname != NULL) 13240Sstevel@tonic-gate free(data->md_objname); 13250Sstevel@tonic-gate data->md_objname = objname ? strdup(objname) : NULL; 13260Sstevel@tonic-gate data->md_last = last; 13270Sstevel@tonic-gate data->md_doswap = doswap; 13280Sstevel@tonic-gate 13290Sstevel@tonic-gate return (0); 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate static int 13330Sstevel@tonic-gate iter_map(proc_map_f *func, void *data) 13340Sstevel@tonic-gate { 13350Sstevel@tonic-gate int i; 13360Sstevel@tonic-gate int ret; 13370Sstevel@tonic-gate 13380Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1339*2685Sakolb if (interrupt) 1340*2685Sakolb break; 13410Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_map, 13420Sstevel@tonic-gate maps[i].md_objname)) != 0) 13430Sstevel@tonic-gate return (ret); 13440Sstevel@tonic-gate } 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate return (0); 13470Sstevel@tonic-gate } 13480Sstevel@tonic-gate 13490Sstevel@tonic-gate static int 13500Sstevel@tonic-gate iter_xmap(proc_xmap_f *func, void *data) 13510Sstevel@tonic-gate { 13520Sstevel@tonic-gate int i; 13530Sstevel@tonic-gate int ret; 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate for (i = 0; i < map_count; i++) { 1356*2685Sakolb if (interrupt) 1357*2685Sakolb break; 13580Sstevel@tonic-gate if ((ret = func(data, &maps[i].md_xmap, maps[i].md_objname, 13590Sstevel@tonic-gate maps[i].md_last, maps[i].md_doswap)) != 0) 13600Sstevel@tonic-gate return (ret); 13610Sstevel@tonic-gate } 13620Sstevel@tonic-gate 13630Sstevel@tonic-gate return (0); 13640Sstevel@tonic-gate } 1365*2685Sakolb 1366*2685Sakolb /* 1367*2685Sakolb * Convert lgroup ID to string. 1368*2685Sakolb * returns dash when lgroup ID is invalid. 1369*2685Sakolb */ 1370*2685Sakolb static char * 1371*2685Sakolb lgrp2str(lgrp_id_t lgrp) 1372*2685Sakolb { 1373*2685Sakolb static char lgrp_buf[20]; 1374*2685Sakolb char *str = lgrp_buf; 1375*2685Sakolb 1376*2685Sakolb (void) sprintf(str, lgrp == LGRP_NONE ? " -" : "%4d", lgrp); 1377*2685Sakolb return (str); 1378*2685Sakolb } 1379*2685Sakolb 1380*2685Sakolb /* 1381*2685Sakolb * Parse address range specification for -A option. 1382*2685Sakolb * The address range may have the following forms: 1383*2685Sakolb * 1384*2685Sakolb * address 1385*2685Sakolb * start and end is set to address 1386*2685Sakolb * address, 1387*2685Sakolb * start is set to address, end is set to INVALID_ADDRESS 1388*2685Sakolb * ,address 1389*2685Sakolb * start is set to 0, end is set to address 1390*2685Sakolb * address1,address2 1391*2685Sakolb * start is set to address1, end is set to address2 1392*2685Sakolb * 1393*2685Sakolb */ 1394*2685Sakolb static int 1395*2685Sakolb parse_addr_range(char *input_str, uintptr_t *start, uintptr_t *end) 1396*2685Sakolb { 1397*2685Sakolb char *startp = input_str; 1398*2685Sakolb char *endp = strchr(input_str, ','); 1399*2685Sakolb ulong_t s = (ulong_t)INVALID_ADDRESS; 1400*2685Sakolb ulong_t e = (ulong_t)INVALID_ADDRESS; 1401*2685Sakolb 1402*2685Sakolb if (endp != NULL) { 1403*2685Sakolb /* 1404*2685Sakolb * Comma is present. If there is nothing after comma, the end 1405*2685Sakolb * remains set at INVALID_ADDRESS. Otherwise it is set to the 1406*2685Sakolb * value after comma. 1407*2685Sakolb */ 1408*2685Sakolb *endp = '\0'; 1409*2685Sakolb endp++; 1410*2685Sakolb 1411*2685Sakolb if ((*endp != '\0') && sscanf(endp, "%lx", &e) != 1) 1412*2685Sakolb return (1); 1413*2685Sakolb } 1414*2685Sakolb 1415*2685Sakolb if (startp != NULL) { 1416*2685Sakolb /* 1417*2685Sakolb * Read the start address, if it is specified. If the address is 1418*2685Sakolb * missing, start will be set to INVALID_ADDRESS. 1419*2685Sakolb */ 1420*2685Sakolb if ((*startp != '\0') && sscanf(startp, "%lx", &s) != 1) 1421*2685Sakolb return (1); 1422*2685Sakolb } 1423*2685Sakolb 1424*2685Sakolb /* If there is no comma, end becomes equal to start */ 1425*2685Sakolb if (endp == NULL) 1426*2685Sakolb e = s; 1427*2685Sakolb 1428*2685Sakolb /* 1429*2685Sakolb * ,end implies 0..end range 1430*2685Sakolb */ 1431*2685Sakolb if (e != INVALID_ADDRESS && s == INVALID_ADDRESS) 1432*2685Sakolb s = 0; 1433*2685Sakolb 1434*2685Sakolb *start = (uintptr_t)s; 1435*2685Sakolb *end = (uintptr_t)e; 1436*2685Sakolb 1437*2685Sakolb /* Return error if neither start nor end address were specified */ 1438*2685Sakolb return (! (s != INVALID_ADDRESS || e != INVALID_ADDRESS)); 1439*2685Sakolb } 1440*2685Sakolb 1441*2685Sakolb /* 1442*2685Sakolb * Check whether any portion of [start, end] segment is within the 1443*2685Sakolb * [start_addr, end_addr] range. 1444*2685Sakolb * 1445*2685Sakolb * Return values: 1446*2685Sakolb * 0 - address is outside the range 1447*2685Sakolb * 1 - address is within the range 1448*2685Sakolb */ 1449*2685Sakolb static int 1450*2685Sakolb address_in_range(uintptr_t start, uintptr_t end, size_t psz) 1451*2685Sakolb { 1452*2685Sakolb int rc = 1; 1453*2685Sakolb 1454*2685Sakolb /* 1455*2685Sakolb * Nothing to do if there is no address range specified with -A 1456*2685Sakolb */ 1457*2685Sakolb if (start_addr != INVALID_ADDRESS || end_addr != INVALID_ADDRESS) { 1458*2685Sakolb /* The segment end is below the range start */ 1459*2685Sakolb if ((start_addr != INVALID_ADDRESS) && 1460*2685Sakolb (end < P2ALIGN(start_addr, psz))) 1461*2685Sakolb rc = 0; 1462*2685Sakolb 1463*2685Sakolb /* The segment start is above the range end */ 1464*2685Sakolb if ((end_addr != INVALID_ADDRESS) && 1465*2685Sakolb (start > P2ALIGN(end_addr + psz, psz))) 1466*2685Sakolb rc = 0; 1467*2685Sakolb } 1468*2685Sakolb return (rc); 1469*2685Sakolb } 1470*2685Sakolb 1471*2685Sakolb /* 1472*2685Sakolb * Returns an intersection of the [start, end] interval and the range specified 1473*2685Sakolb * by -A flag [start_addr, end_addr]. Unspecified parts of the address range 1474*2685Sakolb * have value INVALID_ADDRESS. 1475*2685Sakolb * 1476*2685Sakolb * The start_addr address is rounded down to the beginning of page and end_addr 1477*2685Sakolb * is rounded up to the end of page. 1478*2685Sakolb * 1479*2685Sakolb * Returns the size of the resulting interval or zero if the interval is empty 1480*2685Sakolb * or invalid. 1481*2685Sakolb */ 1482*2685Sakolb static size_t 1483*2685Sakolb adjust_addr_range(uintptr_t start, uintptr_t end, size_t psz, 1484*2685Sakolb uintptr_t *new_start, uintptr_t *new_end) 1485*2685Sakolb { 1486*2685Sakolb uintptr_t from; /* start_addr rounded down */ 1487*2685Sakolb uintptr_t to; /* end_addr rounded up */ 1488*2685Sakolb 1489*2685Sakolb /* 1490*2685Sakolb * Round down the lower address of the range to the beginning of page. 1491*2685Sakolb */ 1492*2685Sakolb if (start_addr == INVALID_ADDRESS) { 1493*2685Sakolb /* 1494*2685Sakolb * No start_addr specified by -A, the lower part of the interval 1495*2685Sakolb * does not change. 1496*2685Sakolb */ 1497*2685Sakolb *new_start = start; 1498*2685Sakolb } else { 1499*2685Sakolb from = P2ALIGN(start_addr, psz); 1500*2685Sakolb /* 1501*2685Sakolb * If end address is outside the range, return an empty 1502*2685Sakolb * interval 1503*2685Sakolb */ 1504*2685Sakolb if (end < from) { 1505*2685Sakolb *new_start = *new_end = 0; 1506*2685Sakolb return (0); 1507*2685Sakolb } 1508*2685Sakolb /* 1509*2685Sakolb * The adjusted start address is the maximum of requested start 1510*2685Sakolb * and the aligned start_addr of the -A range. 1511*2685Sakolb */ 1512*2685Sakolb *new_start = start < from ? from : start; 1513*2685Sakolb } 1514*2685Sakolb 1515*2685Sakolb /* 1516*2685Sakolb * Round up the higher address of the range to the end of page. 1517*2685Sakolb */ 1518*2685Sakolb if (end_addr == INVALID_ADDRESS) { 1519*2685Sakolb /* 1520*2685Sakolb * No end_addr specified by -A, the upper part of the interval 1521*2685Sakolb * does not change. 1522*2685Sakolb */ 1523*2685Sakolb *new_end = end; 1524*2685Sakolb } else { 1525*2685Sakolb /* 1526*2685Sakolb * If only one address is specified and it is the beginning of a 1527*2685Sakolb * segment, get information about the whole segment. This 1528*2685Sakolb * function is called once per segment and the 'end' argument is 1529*2685Sakolb * always the end of a segment, so just use the 'end' value. 1530*2685Sakolb */ 1531*2685Sakolb to = (end_addr == start_addr && start == start_addr) ? 1532*2685Sakolb end : 1533*2685Sakolb P2ALIGN(end_addr + psz, psz); 1534*2685Sakolb /* 1535*2685Sakolb * If start address is outside the range, return an empty 1536*2685Sakolb * interval 1537*2685Sakolb */ 1538*2685Sakolb if (start > to) { 1539*2685Sakolb *new_start = *new_end = 0; 1540*2685Sakolb return (0); 1541*2685Sakolb } 1542*2685Sakolb /* 1543*2685Sakolb * The adjusted end address is the minimum of requested end 1544*2685Sakolb * and the aligned end_addr of the -A range. 1545*2685Sakolb */ 1546*2685Sakolb *new_end = end > to ? to : end; 1547*2685Sakolb } 1548*2685Sakolb 1549*2685Sakolb /* 1550*2685Sakolb * Make sure that the resulting interval is legal. 1551*2685Sakolb */ 1552*2685Sakolb if (*new_end < *new_start) 1553*2685Sakolb *new_start = *new_end = 0; 1554*2685Sakolb 1555*2685Sakolb /* Return the size of the interval */ 1556*2685Sakolb return (*new_end - *new_start); 1557*2685Sakolb } 1558*2685Sakolb 1559*2685Sakolb /* 1560*2685Sakolb * Initialize memory_info data structure with information about a new segment. 1561*2685Sakolb */ 1562*2685Sakolb static void 1563*2685Sakolb mem_chunk_init(memory_chunk_t *chunk, uintptr_t end, size_t psz) 1564*2685Sakolb { 1565*2685Sakolb chunk->end_addr = end; 1566*2685Sakolb chunk->page_size = psz; 1567*2685Sakolb chunk->page_index = 0; 1568*2685Sakolb chunk->chunk_start = chunk->chunk_end = 0; 1569*2685Sakolb } 1570*2685Sakolb 1571*2685Sakolb /* 1572*2685Sakolb * Create a new chunk of addresses starting from vaddr. 1573*2685Sakolb * Pass the whole chunk to pr_meminfo to collect lgroup and page size 1574*2685Sakolb * information for each page in the chunk. 1575*2685Sakolb */ 1576*2685Sakolb static void 1577*2685Sakolb mem_chunk_get(memory_chunk_t *chunk, uintptr_t vaddr) 1578*2685Sakolb { 1579*2685Sakolb page_descr_t *pdp = chunk->page_info; 1580*2685Sakolb size_t psz = chunk->page_size; 1581*2685Sakolb uintptr_t addr = vaddr; 1582*2685Sakolb uint64_t inaddr[MAX_MEMINFO_CNT]; 1583*2685Sakolb uint64_t outdata[2 * MAX_MEMINFO_CNT]; 1584*2685Sakolb uint_t info[2] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; 1585*2685Sakolb uint_t validity[MAX_MEMINFO_CNT]; 1586*2685Sakolb uint64_t *dataptr = inaddr; 1587*2685Sakolb uint64_t *outptr = outdata; 1588*2685Sakolb uint_t *valptr = validity; 1589*2685Sakolb int i, j, rc; 1590*2685Sakolb 1591*2685Sakolb chunk->chunk_start = vaddr; 1592*2685Sakolb chunk->page_index = 0; /* reset index for the new chunk */ 1593*2685Sakolb 1594*2685Sakolb /* 1595*2685Sakolb * Fill in MAX_MEMINFO_CNT wotrh of pages starting from vaddr. Also, 1596*2685Sakolb * copy starting address of each page to inaddr array for pr_meminfo. 1597*2685Sakolb */ 1598*2685Sakolb for (i = 0, pdp = chunk->page_info; 1599*2685Sakolb (i < MAX_MEMINFO_CNT) && (addr <= chunk->end_addr); 1600*2685Sakolb i++, pdp++, dataptr++, addr += psz) { 1601*2685Sakolb *dataptr = (uint64_t)addr; 1602*2685Sakolb pdp->pd_start = addr; 1603*2685Sakolb pdp->pd_lgrp = LGRP_NONE; 1604*2685Sakolb pdp->pd_valid = 0; 1605*2685Sakolb pdp->pd_pagesize = 0; 1606*2685Sakolb } 1607*2685Sakolb 1608*2685Sakolb /* Mark the number of entries in the chunk and the last address */ 1609*2685Sakolb chunk->page_count = i; 1610*2685Sakolb chunk->chunk_end = addr - psz; 1611*2685Sakolb 1612*2685Sakolb if (interrupt) 1613*2685Sakolb return; 1614*2685Sakolb 1615*2685Sakolb /* Call meminfo for all collected addresses */ 1616*2685Sakolb rc = pr_meminfo(Pr, inaddr, i, info, 2, outdata, validity); 1617*2685Sakolb if (rc < 0) { 1618*2685Sakolb (void) perr("can not get memory information"); 1619*2685Sakolb return; 1620*2685Sakolb } 1621*2685Sakolb 1622*2685Sakolb /* Verify validity of each result and fill in the addrs array */ 1623*2685Sakolb pdp = chunk->page_info; 1624*2685Sakolb for (j = 0; j < i; j++, pdp++, valptr++, outptr += 2) { 1625*2685Sakolb /* Skip invalid address pointers */ 1626*2685Sakolb if ((*valptr & 1) == 0) { 1627*2685Sakolb continue; 1628*2685Sakolb } 1629*2685Sakolb 1630*2685Sakolb /* Is lgroup information available? */ 1631*2685Sakolb if ((*valptr & 2) != 0) { 1632*2685Sakolb pdp->pd_lgrp = (lgrp_id_t)*outptr; 1633*2685Sakolb pdp->pd_valid = 1; 1634*2685Sakolb } 1635*2685Sakolb 1636*2685Sakolb /* Is page size informaion available? */ 1637*2685Sakolb if ((*valptr & 4) != 0) { 1638*2685Sakolb pdp->pd_pagesize = *(outptr + 1); 1639*2685Sakolb } 1640*2685Sakolb } 1641*2685Sakolb } 1642*2685Sakolb 1643*2685Sakolb /* 1644*2685Sakolb * Starting from address 'vaddr' find the region with pages allocated from the 1645*2685Sakolb * same lgroup. 1646*2685Sakolb * 1647*2685Sakolb * Arguments: 1648*2685Sakolb * mchunk Initialized memory chunk structure 1649*2685Sakolb * vaddr Starting address of the region 1650*2685Sakolb * maxaddr Upper bound of the region 1651*2685Sakolb * pagesize Default page size to use 1652*2685Sakolb * ret_lgrp On exit contains the lgroup ID of all pages in the 1653*2685Sakolb * region. 1654*2685Sakolb * 1655*2685Sakolb * Returns: 1656*2685Sakolb * Size of the contiguous region in bytes 1657*2685Sakolb * The lgroup ID of all pages in the region in ret_lgrp argument. 1658*2685Sakolb */ 1659*2685Sakolb static size_t 1660*2685Sakolb get_contiguous_region(memory_chunk_t *mchunk, uintptr_t vaddr, 1661*2685Sakolb uintptr_t maxaddr, size_t pagesize, lgrp_id_t *ret_lgrp) 1662*2685Sakolb { 1663*2685Sakolb size_t size_contig = 0; 1664*2685Sakolb lgrp_id_t lgrp; /* Lgroup of the region start */ 1665*2685Sakolb lgrp_id_t curr_lgrp; /* Lgroup of the current page */ 1666*2685Sakolb size_t psz = pagesize; /* Pagesize to use */ 1667*2685Sakolb 1668*2685Sakolb /* Set both lgroup IDs to the lgroup of the first page */ 1669*2685Sakolb curr_lgrp = lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1670*2685Sakolb 1671*2685Sakolb /* 1672*2685Sakolb * Starting from vaddr, walk page by page until either the end 1673*2685Sakolb * of the segment is reached or a page is allocated from a different 1674*2685Sakolb * lgroup. Also stop if interrupted from keyboard. 1675*2685Sakolb */ 1676*2685Sakolb while ((vaddr < maxaddr) && (curr_lgrp == lgrp) && !interrupt) { 1677*2685Sakolb /* 1678*2685Sakolb * Get lgroup ID and the page size of the current page. 1679*2685Sakolb */ 1680*2685Sakolb curr_lgrp = addr_to_lgrp(mchunk, vaddr, &psz); 1681*2685Sakolb /* If there is no page size information, use the default */ 1682*2685Sakolb if (psz == 0) 1683*2685Sakolb psz = pagesize; 1684*2685Sakolb 1685*2685Sakolb if (curr_lgrp == lgrp) { 1686*2685Sakolb /* 1687*2685Sakolb * This page belongs to the contiguous region. 1688*2685Sakolb * Increase the region size and advance to the new page. 1689*2685Sakolb */ 1690*2685Sakolb size_contig += psz; 1691*2685Sakolb vaddr += psz; 1692*2685Sakolb } 1693*2685Sakolb } 1694*2685Sakolb 1695*2685Sakolb /* Return the region lgroup ID and the size */ 1696*2685Sakolb *ret_lgrp = lgrp; 1697*2685Sakolb return (size_contig); 1698*2685Sakolb } 1699*2685Sakolb 1700*2685Sakolb /* 1701*2685Sakolb * Given a virtual address, return its lgroup and page size. If there is meminfo 1702*2685Sakolb * information for an address, use it, otherwise shift the chunk window to the 1703*2685Sakolb * vaddr and create a new chunk with known meminfo information. 1704*2685Sakolb */ 1705*2685Sakolb static lgrp_id_t 1706*2685Sakolb addr_to_lgrp(memory_chunk_t *chunk, uintptr_t vaddr, size_t *psz) 1707*2685Sakolb { 1708*2685Sakolb page_descr_t *pdp; 1709*2685Sakolb lgrp_id_t lgrp = LGRP_NONE; 1710*2685Sakolb int i; 1711*2685Sakolb 1712*2685Sakolb *psz = chunk->page_size; 1713*2685Sakolb 1714*2685Sakolb if (interrupt) 1715*2685Sakolb return (0); 1716*2685Sakolb 1717*2685Sakolb /* 1718*2685Sakolb * Is there information about this address? If not, create a new chunk 1719*2685Sakolb * starting from vaddr and apply pr_meminfo() to the whole chunk. 1720*2685Sakolb */ 1721*2685Sakolb if (vaddr < chunk->chunk_start || vaddr > chunk->chunk_end) { 1722*2685Sakolb /* 1723*2685Sakolb * This address is outside the chunk, get the new chunk and 1724*2685Sakolb * collect meminfo information for it. 1725*2685Sakolb */ 1726*2685Sakolb mem_chunk_get(chunk, vaddr); 1727*2685Sakolb } 1728*2685Sakolb 1729*2685Sakolb /* 1730*2685Sakolb * Find information about the address. 1731*2685Sakolb */ 1732*2685Sakolb pdp = &chunk->page_info[chunk->page_index]; 1733*2685Sakolb for (i = chunk->page_index; i < chunk->page_count; i++, pdp++) { 1734*2685Sakolb if (pdp->pd_start == vaddr) { 1735*2685Sakolb if (pdp->pd_valid) { 1736*2685Sakolb lgrp = pdp->pd_lgrp; 1737*2685Sakolb /* 1738*2685Sakolb * Override page size information if it is 1739*2685Sakolb * present. 1740*2685Sakolb */ 1741*2685Sakolb if (pdp->pd_pagesize > 0) 1742*2685Sakolb *psz = pdp->pd_pagesize; 1743*2685Sakolb } 1744*2685Sakolb break; 1745*2685Sakolb } 1746*2685Sakolb } 1747*2685Sakolb /* 1748*2685Sakolb * Remember where we ended - the next search will start here. 1749*2685Sakolb * We can query for the lgrp for the same address again, so do not 1750*2685Sakolb * advance index past the current value. 1751*2685Sakolb */ 1752*2685Sakolb chunk->page_index = i; 1753*2685Sakolb 1754*2685Sakolb return (lgrp); 1755*2685Sakolb } 1756*2685Sakolb 1757*2685Sakolb /* ARGSUSED */ 1758*2685Sakolb static void 1759*2685Sakolb intr(int sig) 1760*2685Sakolb { 1761*2685Sakolb interrupt = 1; 1762*2685Sakolb } 1763