1*c6402783Sakolb /* 2*c6402783Sakolb * CDDL HEADER START 3*c6402783Sakolb * 4*c6402783Sakolb * The contents of this file are subject to the terms of the 5*c6402783Sakolb * Common Development and Distribution License (the "License"). 6*c6402783Sakolb * You may not use this file except in compliance with the License. 7*c6402783Sakolb * 8*c6402783Sakolb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*c6402783Sakolb * or http://www.opensolaris.org/os/licensing. 10*c6402783Sakolb * See the License for the specific language governing permissions 11*c6402783Sakolb * and limitations under the License. 12*c6402783Sakolb * 13*c6402783Sakolb * When distributing Covered Code, include this CDDL HEADER in each 14*c6402783Sakolb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*c6402783Sakolb * If applicable, add the following below this CDDL HEADER, with the 16*c6402783Sakolb * fields enclosed by brackets "[]" replaced with your own identifying 17*c6402783Sakolb * information: Portions Copyright [yyyy] [name of copyright owner] 18*c6402783Sakolb * 19*c6402783Sakolb * CDDL HEADER END 20*c6402783Sakolb */ 21*c6402783Sakolb 22*c6402783Sakolb /* 23*c6402783Sakolb * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*c6402783Sakolb * Use is subject to license terms. 25*c6402783Sakolb */ 26*c6402783Sakolb 27*c6402783Sakolb #pragma ident "%Z%%M% %I% %E% SMI" 28*c6402783Sakolb 29*c6402783Sakolb /* 30*c6402783Sakolb * pmadvise 31*c6402783Sakolb * 32*c6402783Sakolb * ptool wrapper for madvise(3C) to apply memory advice to running processes 33*c6402783Sakolb * 34*c6402783Sakolb * usage: pmadvise -o option[,option] [-v] [-F] pid ... 35*c6402783Sakolb * (Give "advice" about a process's memory) 36*c6402783Sakolb * -o option[,option]: options are 37*c6402783Sakolb * private=<advice> 38*c6402783Sakolb * shared=<advice> 39*c6402783Sakolb * heap=<advice> 40*c6402783Sakolb * stack=<advice> 41*c6402783Sakolb * <segaddr>[:<length>]=<advice> 42*c6402783Sakolb * valid <advice> is one of: 43*c6402783Sakolb * normal, random, sequential, willneed, dontneed, 44*c6402783Sakolb * free, access_lwp, access_many, access_default 45*c6402783Sakolb * -v: verbose output 46*c6402783Sakolb * -F: force grabbing of the target process(es) 47*c6402783Sakolb * pid: process id list 48*c6402783Sakolb * 49*c6402783Sakolb * 50*c6402783Sakolb * Advice passed to this tool are organized into various lists described here: 51*c6402783Sakolb * rawadv_list: includes all specific advice from command line (specific 52*c6402783Sakolb * advice being those given to a particular address range rather 53*c6402783Sakolb * than a type like "heap" or "stack". In contrast, these 54*c6402783Sakolb * types are referred to as generic advice). Duplicates allowed. 55*c6402783Sakolb * List ordered by addr, then by size (largest size first). 56*c6402783Sakolb * Created once per run. 57*c6402783Sakolb * merged_list: includes all specific advice from the rawadv_list as well as 58*c6402783Sakolb * all generic advice. This must be recreated for each process 59*c6402783Sakolb * as the generic advice will apply to different regions for 60*c6402783Sakolb * different processes. Duplicates allowed. List ordered by addr, 61*c6402783Sakolb * then by size (largest size first). Created once per pid. 62*c6402783Sakolb * chopped_list: used for verbose output only. This list parses the merged 63*c6402783Sakolb * list such that it eliminates any overlap and combines the 64*c6402783Sakolb * advice. Easiest to think of this visually: if you take all 65*c6402783Sakolb * the advice in the merged list and lay them down on a memory 66*c6402783Sakolb * range of the entire process (laying on top of each other when 67*c6402783Sakolb * necessary), then flatten them into one layer, combining advice 68*c6402783Sakolb * in the case of overlap, you get the chopped_list of advice. 69*c6402783Sakolb * Duplicate entries not allowed (since there is no overlap by 70*c6402783Sakolb * definition in this list). List ordered by addr. Created once 71*c6402783Sakolb * per pid. 72*c6402783Sakolb * 73*c6402783Sakolb * Example: 74*c6402783Sakolb * merged_list: |-----adv1----|---------adv3---------| 75*c6402783Sakolb * |--adv2--|--adv4--|-----adv5----| 76*c6402783Sakolb * || 77*c6402783Sakolb * \/ 78*c6402783Sakolb * chopped_list: |adv1|-adv1,2-|-adv3,4-|----adv3,5---| 79*c6402783Sakolb * 80*c6402783Sakolb * maplist: list of memory mappings for a particular process. Used to create 81*c6402783Sakolb * generic advice entries for merged_list and for pmap like verbose 82*c6402783Sakolb * output. Created once per pid. 83*c6402783Sakolb * 84*c6402783Sakolb * Multiple lists are necessary because the actual advice applied given a set 85*c6402783Sakolb * of generic and specific advice changes from process to process, so for each 86*c6402783Sakolb * pid pmadvise is passed, it must create a new merged_list from which to apply 87*c6402783Sakolb * advice (and a new chopped_list if verbose output is requested). 88*c6402783Sakolb * 89*c6402783Sakolb * Pseudo-code: 90*c6402783Sakolb * I. Input advice from command line 91*c6402783Sakolb * II. Create [raw advice list] of specific advice 92*c6402783Sakolb * III. Iterate through PIDs: 93*c6402783Sakolb * A. Create [map list] 94*c6402783Sakolb * B. Merge generic advice and [raw advice list] into [merged list] 95*c6402783Sakolb * C. Apply advice from [merged list]; upon error: 96*c6402783Sakolb * i. output madvise error message 97*c6402783Sakolb * ii. remove element from [merged list] 98*c6402783Sakolb * D. If verbose output: 99*c6402783Sakolb * i. Create [chopped list] from [merged list] 100*c6402783Sakolb * ii. Iterate through [map list]: 101*c6402783Sakolb * a. output advice as given by [merged list] 102*c6402783Sakolb * iii. Delete [chopped list] 103*c6402783Sakolb * E. Delete [merged list] 104*c6402783Sakolb * F. Delete [map list] 105*c6402783Sakolb */ 106*c6402783Sakolb 107*c6402783Sakolb #include <stdio.h> 108*c6402783Sakolb #include <stdlib.h> 109*c6402783Sakolb #include <unistd.h> 110*c6402783Sakolb #include <ctype.h> 111*c6402783Sakolb #include <fcntl.h> 112*c6402783Sakolb #include <string.h> 113*c6402783Sakolb #include <dirent.h> 114*c6402783Sakolb #include <limits.h> 115*c6402783Sakolb #include <link.h> 116*c6402783Sakolb #include <libelf.h> 117*c6402783Sakolb #include <locale.h> 118*c6402783Sakolb #include <sys/types.h> 119*c6402783Sakolb #include <sys/mman.h> 120*c6402783Sakolb #include <sys/stat.h> 121*c6402783Sakolb #include <sys/mkdev.h> 122*c6402783Sakolb #include <assert.h> 123*c6402783Sakolb #include <libproc.h> 124*c6402783Sakolb #include <libgen.h> 125*c6402783Sakolb #include <signal.h> 126*c6402783Sakolb 127*c6402783Sakolb #ifndef TEXT_DOMAIN /* should be defined by cc -D */ 128*c6402783Sakolb #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */ 129*c6402783Sakolb #endif 130*c6402783Sakolb 131*c6402783Sakolb #define KILOBYTE 1024 132*c6402783Sakolb 133*c6402783Sakolb /* 134*c6402783Sakolb * Round up the value to the nearest kilobyte 135*c6402783Sakolb */ 136*c6402783Sakolb #define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE) 137*c6402783Sakolb 138*c6402783Sakolb #define NO_ADVICE 0 139*c6402783Sakolb 140*c6402783Sakolb /* 141*c6402783Sakolb * The following definitions are used as the third argument in insert_addr() 142*c6402783Sakolb * NODUPS = no duplicates are not allowed, thus if the addr being inserted 143*c6402783Sakolb * already exists in the list, return without inserting again. 144*c6402783Sakolb * 145*c6402783Sakolb * YESDUPS = yes duplicates are allowed, thus always insert the addr 146*c6402783Sakolb * regardless of whether it already exists in the list or not. 147*c6402783Sakolb */ 148*c6402783Sakolb #define NODUPS 1 149*c6402783Sakolb #define YESDUPS 0 150*c6402783Sakolb 151*c6402783Sakolb /* 152*c6402783Sakolb * Advice that can be passed to madvise fit into three groups that each 153*c6402783Sakolb * contain 3 mutually exclusive options. These groups are defined below: 154*c6402783Sakolb * Group 1: normal, random, sequential 155*c6402783Sakolb * Group 2: willneed, dontneed, free 156*c6402783Sakolb * Group 3: default, accesslwp, accessmany 157*c6402783Sakolb * Thus, advice that includes (at most) one from each group is valid. 158*c6402783Sakolb * 159*c6402783Sakolb * The following #define's are used as masks to determine which group(s) a 160*c6402783Sakolb * particular advice fall under. 161*c6402783Sakolb */ 162*c6402783Sakolb 163*c6402783Sakolb #define GRP1_ADV (1 << MADV_NORMAL | 1 << MADV_RANDOM | \ 164*c6402783Sakolb 1 << MADV_SEQUENTIAL) 165*c6402783Sakolb #define GRP2_ADV (1 << MADV_WILLNEED | 1 << MADV_DONTNEED | \ 166*c6402783Sakolb 1 << MADV_FREE) 167*c6402783Sakolb #define GRP3_ADV (1 << MADV_ACCESS_DEFAULT | 1 << MADV_ACCESS_LWP | \ 168*c6402783Sakolb 1 << MADV_ACCESS_MANY) 169*c6402783Sakolb 170*c6402783Sakolb static int create_maplist(void *, const prmap_t *, const char *); 171*c6402783Sakolb static int pr_madvise(struct ps_prochandle *, caddr_t, size_t, int); 172*c6402783Sakolb 173*c6402783Sakolb static char *mflags(uint_t); 174*c6402783Sakolb static char *advtostr(int); 175*c6402783Sakolb 176*c6402783Sakolb static int addr_width, size_width; 177*c6402783Sakolb static char *progname; 178*c6402783Sakolb static struct ps_prochandle *Pr; 179*c6402783Sakolb 180*c6402783Sakolb typedef struct lwpstack { 181*c6402783Sakolb lwpid_t lwps_lwpid; 182*c6402783Sakolb stack_t lwps_stack; 183*c6402783Sakolb } lwpstack_t; 184*c6402783Sakolb 185*c6402783Sakolb static lwpstack_t *stacks; 186*c6402783Sakolb static uint_t nstacks; 187*c6402783Sakolb 188*c6402783Sakolb /* 189*c6402783Sakolb * Used to set the advice type var (at_map) when parsing the arguments to 190*c6402783Sakolb * pmadvise. Later, when creating the map list, at_map is used as a mask 191*c6402783Sakolb * to determine if any generic advice applies to each memory mapping. 192*c6402783Sakolb */ 193*c6402783Sakolb enum atype_enum { 194*c6402783Sakolb AT_PRIVM, 195*c6402783Sakolb AT_SHARED, 196*c6402783Sakolb AT_HEAP, 197*c6402783Sakolb AT_STACK, 198*c6402783Sakolb AT_SEG, 199*c6402783Sakolb AT_NTYPES 200*c6402783Sakolb }; 201*c6402783Sakolb 202*c6402783Sakolb static char *suboptstr[] = { 203*c6402783Sakolb "private", 204*c6402783Sakolb "shared", 205*c6402783Sakolb "heap", 206*c6402783Sakolb "stack", 207*c6402783Sakolb NULL 208*c6402783Sakolb }; 209*c6402783Sakolb 210*c6402783Sakolb 211*c6402783Sakolb int generic_adv[] = {NO_ADVICE, NO_ADVICE, NO_ADVICE, NO_ADVICE}; 212*c6402783Sakolb int at_map = 0; 213*c6402783Sakolb 214*c6402783Sakolb typedef struct saddr_struct { 215*c6402783Sakolb uintptr_t addr; 216*c6402783Sakolb size_t length; 217*c6402783Sakolb int adv; 218*c6402783Sakolb struct saddr_struct *next; 219*c6402783Sakolb } saddr_t; 220*c6402783Sakolb static int apply_advice(saddr_t **); 221*c6402783Sakolb static void set_advice(int *, int); 222*c6402783Sakolb static void create_choplist(saddr_t **, saddr_t *); 223*c6402783Sakolb 224*c6402783Sakolb /* 225*c6402783Sakolb * The segment address advice from the command line 226*c6402783Sakolb */ 227*c6402783Sakolb saddr_t *rawadv_list = NULL; 228*c6402783Sakolb /* 229*c6402783Sakolb * The rawadv_list + list entries for the generic advice (if any). 230*c6402783Sakolb * This must be recreated for each PID as the memory maps might be different. 231*c6402783Sakolb */ 232*c6402783Sakolb saddr_t *merged_list = NULL; 233*c6402783Sakolb /* 234*c6402783Sakolb * The merged_list cut up so as to remove all overlap 235*c6402783Sakolb * e.g. if merged_list contained two entries: 236*c6402783Sakolb * 237*c6402783Sakolb * [0x38000:0x3e000) = adv1 238*c6402783Sakolb * [0x3a000:0x3c000) = adv2 239*c6402783Sakolb * 240*c6402783Sakolb * the chopped list will contain three entries: 241*c6402783Sakolb * 242*c6402783Sakolb * [0x38000:0x3a000) = adv1 243*c6402783Sakolb * [0x3a000:0x3c000) = adv1,adv2 244*c6402783Sakolb * [0x3c000:0x3e000) = adv1 245*c6402783Sakolb * 246*c6402783Sakolb */ 247*c6402783Sakolb saddr_t *chopped_list = NULL; 248*c6402783Sakolb 249*c6402783Sakolb typedef struct mapnode_struct { 250*c6402783Sakolb prmap_t *pmp; 251*c6402783Sakolb char label[PATH_MAX]; 252*c6402783Sakolb int mtypes; 253*c6402783Sakolb struct mapnode_struct *next; 254*c6402783Sakolb } mapnode_t; 255*c6402783Sakolb 256*c6402783Sakolb mapnode_t *maplist_head = NULL; 257*c6402783Sakolb mapnode_t *maplist_tail = NULL; 258*c6402783Sakolb static void print_advice(saddr_t *, mapnode_t *); 259*c6402783Sakolb 260*c6402783Sakolb int opt_verbose; 261*c6402783Sakolb 262*c6402783Sakolb static char *advicestr[] = { 263*c6402783Sakolb "normal", 264*c6402783Sakolb "random", 265*c6402783Sakolb "sequential", 266*c6402783Sakolb "willneed", 267*c6402783Sakolb "dontneed", 268*c6402783Sakolb "free", 269*c6402783Sakolb "access_default", 270*c6402783Sakolb "access_lwp", 271*c6402783Sakolb "access_many" 272*c6402783Sakolb }; 273*c6402783Sakolb 274*c6402783Sakolb /* 275*c6402783Sakolb * How many signals caught from terminal 276*c6402783Sakolb * We bail out as soon as possible when interrupt is set 277*c6402783Sakolb */ 278*c6402783Sakolb static int interrupt = 0; 279*c6402783Sakolb 280*c6402783Sakolb /* 281*c6402783Sakolb * Interrupt handler 282*c6402783Sakolb */ 283*c6402783Sakolb static void intr(int); 284*c6402783Sakolb 285*c6402783Sakolb /* 286*c6402783Sakolb * Iterative function passed to Plwp_iter to 287*c6402783Sakolb * get alt and main stacks for given lwp. 288*c6402783Sakolb */ 289*c6402783Sakolb static int 290*c6402783Sakolb getstack(void *data, const lwpstatus_t *lsp) 291*c6402783Sakolb { 292*c6402783Sakolb int *np = (int *)data; 293*c6402783Sakolb 294*c6402783Sakolb if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 295*c6402783Sakolb stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 296*c6402783Sakolb stacks[*np].lwps_lwpid = lsp->pr_lwpid; 297*c6402783Sakolb (*np)++; 298*c6402783Sakolb } 299*c6402783Sakolb 300*c6402783Sakolb if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 301*c6402783Sakolb stacks[*np].lwps_lwpid = lsp->pr_lwpid; 302*c6402783Sakolb (*np)++; 303*c6402783Sakolb } 304*c6402783Sakolb 305*c6402783Sakolb return (0); 306*c6402783Sakolb } 307*c6402783Sakolb 308*c6402783Sakolb /* 309*c6402783Sakolb * We compare the high memory addresses since stacks are faulted in from 310*c6402783Sakolb * high memory addresses to low memory addresses, and our prmap_t 311*c6402783Sakolb * structures identify only the range of addresses that have been faulted 312*c6402783Sakolb * in so far. 313*c6402783Sakolb */ 314*c6402783Sakolb static int 315*c6402783Sakolb cmpstacks(const void *ap, const void *bp) 316*c6402783Sakolb { 317*c6402783Sakolb const lwpstack_t *as = ap; 318*c6402783Sakolb const lwpstack_t *bs = bp; 319*c6402783Sakolb uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 320*c6402783Sakolb uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 321*c6402783Sakolb 322*c6402783Sakolb if (a < b) 323*c6402783Sakolb return (1); 324*c6402783Sakolb if (a > b) 325*c6402783Sakolb return (-1); 326*c6402783Sakolb return (0); 327*c6402783Sakolb } 328*c6402783Sakolb 329*c6402783Sakolb /* 330*c6402783Sakolb * Prints usage and exits 331*c6402783Sakolb */ 332*c6402783Sakolb static void 333*c6402783Sakolb usage() 334*c6402783Sakolb { 335*c6402783Sakolb (void) fprintf(stderr, 336*c6402783Sakolb gettext("usage:\t%s -o option[,option] [-v] [-F] pid ...\n"), 337*c6402783Sakolb progname); 338*c6402783Sakolb (void) fprintf(stderr, 339*c6402783Sakolb gettext(" (Give \"advice\" about a process's memory)\n" 340*c6402783Sakolb " -o option[,option]: options are\n" 341*c6402783Sakolb " private=<advice>\n" 342*c6402783Sakolb " shared=<advice>\n" 343*c6402783Sakolb " heap=<advice>\n" 344*c6402783Sakolb " stack=<advice>\n" 345*c6402783Sakolb " <segaddr>[:<length>]=<advice>\n" 346*c6402783Sakolb " valid <advice> is one of:\n" 347*c6402783Sakolb " normal, random, sequential, willneed, dontneed,\n" 348*c6402783Sakolb " free, access_lwp, access_many, access_default\n" 349*c6402783Sakolb " -v: verbose output\n" 350*c6402783Sakolb " -F: force grabbing of the target process(es)\n" 351*c6402783Sakolb " pid: process id list\n")); 352*c6402783Sakolb exit(2); 353*c6402783Sakolb } 354*c6402783Sakolb 355*c6402783Sakolb /* 356*c6402783Sakolb * Function to parse advice from options string 357*c6402783Sakolb */ 358*c6402783Sakolb static int 359*c6402783Sakolb get_advice(char *optarg) 360*c6402783Sakolb { 361*c6402783Sakolb /* 362*c6402783Sakolb * Determine which advice is given, we use shifted values as 363*c6402783Sakolb * multiple pieces of advice may apply for a particular region. 364*c6402783Sakolb * (See comment above regarding GRP[1,2,3]_ADV definitions for 365*c6402783Sakolb * breakdown of advice groups). 366*c6402783Sakolb */ 367*c6402783Sakolb if (strcmp(optarg, "access_default") == 0) 368*c6402783Sakolb return (1 << MADV_ACCESS_DEFAULT); 369*c6402783Sakolb else if (strcmp(optarg, "access_many") == 0) 370*c6402783Sakolb return (1 << MADV_ACCESS_MANY); 371*c6402783Sakolb else if (strcmp(optarg, "access_lwp") == 0) 372*c6402783Sakolb return (1 << MADV_ACCESS_LWP); 373*c6402783Sakolb else if (strcmp(optarg, "sequential") == 0) 374*c6402783Sakolb return (1 << MADV_SEQUENTIAL); 375*c6402783Sakolb else if (strcmp(optarg, "willneed") == 0) 376*c6402783Sakolb return (1 << MADV_WILLNEED); 377*c6402783Sakolb else if (strcmp(optarg, "dontneed") == 0) 378*c6402783Sakolb return (1 << MADV_DONTNEED); 379*c6402783Sakolb else if (strcmp(optarg, "random") == 0) 380*c6402783Sakolb return (1 << MADV_RANDOM); 381*c6402783Sakolb else if (strcmp(optarg, "normal") == 0) 382*c6402783Sakolb return (1 << MADV_NORMAL); 383*c6402783Sakolb else if (strcmp(optarg, "free") == 0) 384*c6402783Sakolb return (1 << MADV_FREE); 385*c6402783Sakolb else { 386*c6402783Sakolb (void) fprintf(stderr, gettext("%s: invalid advice: %s\n"), 387*c6402783Sakolb progname, optarg); 388*c6402783Sakolb usage(); 389*c6402783Sakolb return (-1); 390*c6402783Sakolb } 391*c6402783Sakolb } 392*c6402783Sakolb 393*c6402783Sakolb /* 394*c6402783Sakolb * Function to convert character size indicators into actual size 395*c6402783Sakolb * (i.e., 123M => sz = 123 * 1024 * 1024) 396*c6402783Sakolb */ 397*c6402783Sakolb static size_t 398*c6402783Sakolb atosz(char *optarg, char **endptr) 399*c6402783Sakolb { 400*c6402783Sakolb size_t sz = 0; 401*c6402783Sakolb 402*c6402783Sakolb if (optarg == NULL || optarg[0] == '\0') 403*c6402783Sakolb return (0); 404*c6402783Sakolb 405*c6402783Sakolb sz = strtoll(optarg, endptr, 0); 406*c6402783Sakolb 407*c6402783Sakolb switch (**endptr) { 408*c6402783Sakolb case 'E': 409*c6402783Sakolb case 'e': 410*c6402783Sakolb sz *= KILOBYTE; 411*c6402783Sakolb /* FALLTHRU */ 412*c6402783Sakolb case 'P': 413*c6402783Sakolb case 'p': 414*c6402783Sakolb sz *= KILOBYTE; 415*c6402783Sakolb /* FALLTHRU */ 416*c6402783Sakolb case 'T': 417*c6402783Sakolb case 't': 418*c6402783Sakolb sz *= KILOBYTE; 419*c6402783Sakolb /* FALLTHRU */ 420*c6402783Sakolb case 'G': 421*c6402783Sakolb case 'g': 422*c6402783Sakolb sz *= KILOBYTE; 423*c6402783Sakolb /* FALLTHRU */ 424*c6402783Sakolb case 'M': 425*c6402783Sakolb case 'm': 426*c6402783Sakolb sz *= KILOBYTE; 427*c6402783Sakolb /* FALLTHRU */ 428*c6402783Sakolb case 'K': 429*c6402783Sakolb case 'k': 430*c6402783Sakolb sz *= KILOBYTE; 431*c6402783Sakolb /* FALLTHRU */ 432*c6402783Sakolb case 'B': 433*c6402783Sakolb case 'b': 434*c6402783Sakolb (*endptr)++; 435*c6402783Sakolb /* FALLTHRU */ 436*c6402783Sakolb default: 437*c6402783Sakolb break; 438*c6402783Sakolb } 439*c6402783Sakolb return (sz); 440*c6402783Sakolb } 441*c6402783Sakolb 442*c6402783Sakolb /* 443*c6402783Sakolb * Inserts newaddr into list. dups indicates whether we allow duplicate 444*c6402783Sakolb * addr entries in the list (valid values are NODUPS and YESDUPS). 445*c6402783Sakolb */ 446*c6402783Sakolb static void 447*c6402783Sakolb insert_addr(saddr_t **list, saddr_t *newaddr, int dups) 448*c6402783Sakolb { 449*c6402783Sakolb saddr_t *prev = *list; 450*c6402783Sakolb saddr_t *psaddr; 451*c6402783Sakolb 452*c6402783Sakolb if (*list == NULL) { 453*c6402783Sakolb newaddr->next = *list; 454*c6402783Sakolb *list = newaddr; 455*c6402783Sakolb return; 456*c6402783Sakolb } 457*c6402783Sakolb 458*c6402783Sakolb for (psaddr = (*list)->next; psaddr != NULL; psaddr = psaddr->next) { 459*c6402783Sakolb if ((dups == NODUPS) && (psaddr->addr == newaddr->addr)) { 460*c6402783Sakolb free(newaddr); 461*c6402783Sakolb return; 462*c6402783Sakolb } 463*c6402783Sakolb 464*c6402783Sakolb /* 465*c6402783Sakolb * primary level of comparison is by address; smaller addr 1st 466*c6402783Sakolb * secondary level of comparison is by length; bigger length 1st 467*c6402783Sakolb */ 468*c6402783Sakolb if ((psaddr->addr > newaddr->addr) || 469*c6402783Sakolb (psaddr->addr == newaddr->addr && 470*c6402783Sakolb psaddr->length < newaddr->length)) 471*c6402783Sakolb break; 472*c6402783Sakolb 473*c6402783Sakolb prev = psaddr; 474*c6402783Sakolb } 475*c6402783Sakolb 476*c6402783Sakolb prev->next = newaddr; 477*c6402783Sakolb newaddr->next = psaddr; 478*c6402783Sakolb } 479*c6402783Sakolb 480*c6402783Sakolb /* 481*c6402783Sakolb * Deletes given element from list 482*c6402783Sakolb */ 483*c6402783Sakolb static void 484*c6402783Sakolb delete_addr(saddr_t **list, saddr_t *delme) 485*c6402783Sakolb { 486*c6402783Sakolb saddr_t *prev = *list; 487*c6402783Sakolb 488*c6402783Sakolb if (delme == *list) { 489*c6402783Sakolb *list = delme->next; 490*c6402783Sakolb free(delme); 491*c6402783Sakolb return; 492*c6402783Sakolb } 493*c6402783Sakolb 494*c6402783Sakolb while (prev != NULL && prev->next != delme) { 495*c6402783Sakolb prev = prev->next; 496*c6402783Sakolb } 497*c6402783Sakolb 498*c6402783Sakolb if (prev) { 499*c6402783Sakolb prev->next = delme->next; 500*c6402783Sakolb free(delme); 501*c6402783Sakolb } 502*c6402783Sakolb } 503*c6402783Sakolb 504*c6402783Sakolb /* 505*c6402783Sakolb * Delete entire list 506*c6402783Sakolb */ 507*c6402783Sakolb static void 508*c6402783Sakolb delete_list(saddr_t **list) 509*c6402783Sakolb { 510*c6402783Sakolb saddr_t *psaddr = *list; 511*c6402783Sakolb 512*c6402783Sakolb while (psaddr != NULL) { 513*c6402783Sakolb saddr_t *temp = psaddr; 514*c6402783Sakolb 515*c6402783Sakolb psaddr = psaddr->next; 516*c6402783Sakolb free(temp); 517*c6402783Sakolb } 518*c6402783Sakolb *list = NULL; 519*c6402783Sakolb } 520*c6402783Sakolb 521*c6402783Sakolb static saddr_t * 522*c6402783Sakolb parse_suboptions(char *value) 523*c6402783Sakolb { 524*c6402783Sakolb char *endptr; 525*c6402783Sakolb saddr_t *psaddr = malloc(sizeof (saddr_t)); 526*c6402783Sakolb 527*c6402783Sakolb /* 528*c6402783Sakolb * This must (better) be a segment addr 529*c6402783Sakolb */ 530*c6402783Sakolb psaddr->addr = 531*c6402783Sakolb strtoull(value, &endptr, 16); 532*c6402783Sakolb 533*c6402783Sakolb /* 534*c6402783Sakolb * Check to make sure strtoul worked correctly (a properly formatted 535*c6402783Sakolb * string will terminate in a ':' (if size is given) or an '=' (if size 536*c6402783Sakolb * is not specified). Also check to make sure a 0 addr wasn't returned 537*c6402783Sakolb * indicating strtoll was unable to convert). 538*c6402783Sakolb */ 539*c6402783Sakolb if ((psaddr->addr == 0) || (*endptr != ':' && *endptr != '=')) { 540*c6402783Sakolb free(psaddr); 541*c6402783Sakolb (void) fprintf(stderr, 542*c6402783Sakolb gettext("%s: invalid option %s\n"), 543*c6402783Sakolb progname, value); 544*c6402783Sakolb usage(); 545*c6402783Sakolb } else { 546*c6402783Sakolb /* init other fields */ 547*c6402783Sakolb psaddr->length = 0; 548*c6402783Sakolb psaddr->adv = NO_ADVICE; 549*c6402783Sakolb psaddr->next = NULL; 550*c6402783Sakolb 551*c6402783Sakolb /* skip past address */ 552*c6402783Sakolb value = endptr; 553*c6402783Sakolb 554*c6402783Sakolb /* check for length */ 555*c6402783Sakolb if (*value == ':') { 556*c6402783Sakolb /* skip the ":" */ 557*c6402783Sakolb value++; 558*c6402783Sakolb psaddr->length = atosz(value, &endptr); 559*c6402783Sakolb } 560*c6402783Sakolb 561*c6402783Sakolb if (*endptr != '=') { 562*c6402783Sakolb (void) fprintf(stderr, 563*c6402783Sakolb gettext("%s: invalid option %s\n"), 564*c6402783Sakolb progname, value); 565*c6402783Sakolb /* 566*c6402783Sakolb * if improperly formatted, free mem, print usage, and 567*c6402783Sakolb * exit Note: usage ends with a call to exit() 568*c6402783Sakolb */ 569*c6402783Sakolb free(psaddr); 570*c6402783Sakolb usage(); 571*c6402783Sakolb } 572*c6402783Sakolb /* skip the "=" */ 573*c6402783Sakolb value = endptr + 1; 574*c6402783Sakolb at_map |= (1 << AT_SEG); 575*c6402783Sakolb psaddr->adv = 576*c6402783Sakolb get_advice(value); 577*c6402783Sakolb } 578*c6402783Sakolb 579*c6402783Sakolb return (psaddr); 580*c6402783Sakolb } 581*c6402783Sakolb 582*c6402783Sakolb /* 583*c6402783Sakolb * Create labels for non-anon, non-heap mappings 584*c6402783Sakolb */ 585*c6402783Sakolb static char * 586*c6402783Sakolb make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 587*c6402783Sakolb char *buf, size_t bufsz) 588*c6402783Sakolb { 589*c6402783Sakolb const pstatus_t *Psp = Pstatus(Pr); 590*c6402783Sakolb char fname[100]; 591*c6402783Sakolb struct stat statb; 592*c6402783Sakolb int len; 593*c6402783Sakolb 594*c6402783Sakolb if (strcmp(mapname, "a.out") == 0 && 595*c6402783Sakolb Pexecname(Pr, buf, bufsz) != NULL) 596*c6402783Sakolb return (buf); 597*c6402783Sakolb 598*c6402783Sakolb if (Pobjname(Pr, addr, buf, bufsz) != NULL) { 599*c6402783Sakolb if ((len = resolvepath(buf, buf, bufsz)) > 0) { 600*c6402783Sakolb buf[len] = '\0'; 601*c6402783Sakolb return (buf); 602*c6402783Sakolb } 603*c6402783Sakolb } 604*c6402783Sakolb 605*c6402783Sakolb if (*mapname != '\0') { 606*c6402783Sakolb (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s", 607*c6402783Sakolb (int)Psp->pr_pid, mapname); 608*c6402783Sakolb if (stat(fname, &statb) == 0) { 609*c6402783Sakolb dev_t dev = statb.st_dev; 610*c6402783Sakolb ino_t ino = statb.st_ino; 611*c6402783Sakolb (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", 612*c6402783Sakolb (ulong_t)major(dev), (ulong_t)minor(dev), ino); 613*c6402783Sakolb return (buf); 614*c6402783Sakolb } 615*c6402783Sakolb } 616*c6402783Sakolb 617*c6402783Sakolb return (NULL); 618*c6402783Sakolb } 619*c6402783Sakolb 620*c6402783Sakolb /* 621*c6402783Sakolb * Create label for anon mappings 622*c6402783Sakolb */ 623*c6402783Sakolb static char * 624*c6402783Sakolb anon_name(char *name, const pstatus_t *Psp, 625*c6402783Sakolb uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypes) 626*c6402783Sakolb { 627*c6402783Sakolb if (mflags & MA_ISM) { 628*c6402783Sakolb if (shmid == -1) 629*c6402783Sakolb (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 630*c6402783Sakolb (mflags & MA_NORESERVE) ? "ism" : "dism"); 631*c6402783Sakolb else 632*c6402783Sakolb (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 633*c6402783Sakolb (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 634*c6402783Sakolb *mtypes |= (1 << AT_SHARED); 635*c6402783Sakolb } else if (mflags & MA_SHM) { 636*c6402783Sakolb if (shmid == -1) 637*c6402783Sakolb (void) sprintf(name, " [ shmid=null ]"); 638*c6402783Sakolb else 639*c6402783Sakolb (void) sprintf(name, " [ shmid=0x%x ]", shmid); 640*c6402783Sakolb *mtypes |= (1 << AT_SHARED); 641*c6402783Sakolb 642*c6402783Sakolb } else if (vaddr + size > Psp->pr_stkbase && 643*c6402783Sakolb vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 644*c6402783Sakolb (void) strcpy(name, " [ stack ]"); 645*c6402783Sakolb *mtypes |= (1 << AT_STACK); 646*c6402783Sakolb 647*c6402783Sakolb } else if ((mflags & MA_ANON) && 648*c6402783Sakolb vaddr + size > Psp->pr_brkbase && 649*c6402783Sakolb vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 650*c6402783Sakolb (void) strcpy(name, " [ heap ]"); 651*c6402783Sakolb *mtypes |= (1 << AT_HEAP); 652*c6402783Sakolb 653*c6402783Sakolb } else { 654*c6402783Sakolb lwpstack_t key, *stk; 655*c6402783Sakolb 656*c6402783Sakolb key.lwps_stack.ss_sp = (void *)vaddr; 657*c6402783Sakolb key.lwps_stack.ss_size = size; 658*c6402783Sakolb if (nstacks > 0 && 659*c6402783Sakolb (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 660*c6402783Sakolb cmpstacks)) != NULL) { 661*c6402783Sakolb (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 662*c6402783Sakolb (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 663*c6402783Sakolb "altstack" : "stack", 664*c6402783Sakolb stk->lwps_lwpid); 665*c6402783Sakolb *mtypes |= (1 << AT_STACK); 666*c6402783Sakolb } else { 667*c6402783Sakolb (void) strcpy(name, " [ anon ]"); 668*c6402783Sakolb *mtypes |= (1 << AT_PRIVM); 669*c6402783Sakolb } 670*c6402783Sakolb } 671*c6402783Sakolb 672*c6402783Sakolb return (name); 673*c6402783Sakolb } 674*c6402783Sakolb 675*c6402783Sakolb /* 676*c6402783Sakolb * Create linked list of mappings for current process 677*c6402783Sakolb * In addition, add generic advice and raw advice 678*c6402783Sakolb * entries to merged_list. 679*c6402783Sakolb */ 680*c6402783Sakolb /* ARGSUSED */ 681*c6402783Sakolb static int 682*c6402783Sakolb create_maplist(void *arg, const prmap_t *pmp, const char *object_name) 683*c6402783Sakolb { 684*c6402783Sakolb const pstatus_t *Psp = Pstatus(Pr); 685*c6402783Sakolb mapnode_t *newmap = malloc(sizeof (mapnode_t)); 686*c6402783Sakolb saddr_t *newaddr; 687*c6402783Sakolb saddr_t *psaddr; 688*c6402783Sakolb char *lname = NULL; 689*c6402783Sakolb int i; 690*c6402783Sakolb 691*c6402783Sakolb if (interrupt) 692*c6402783Sakolb return (0); 693*c6402783Sakolb 694*c6402783Sakolb newmap->pmp = malloc(sizeof (prmap_t)); 695*c6402783Sakolb newmap->label[0] = '\0'; 696*c6402783Sakolb newmap->mtypes = 0; 697*c6402783Sakolb newmap->next = NULL; 698*c6402783Sakolb (void) memcpy(newmap->pmp, pmp, sizeof (prmap_t)); 699*c6402783Sakolb 700*c6402783Sakolb /* 701*c6402783Sakolb * If the mapping is not anon or not part of the heap, make a name 702*c6402783Sakolb * for it. We don't want to report the heap as a.out's data. 703*c6402783Sakolb */ 704*c6402783Sakolb if (!(pmp->pr_mflags & MA_ANON) || 705*c6402783Sakolb (pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 706*c6402783Sakolb pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize)) { 707*c6402783Sakolb lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 708*c6402783Sakolb newmap->label, sizeof (newmap->label)); 709*c6402783Sakolb if (pmp->pr_mflags & MA_SHARED) 710*c6402783Sakolb newmap->mtypes |= 1 << AT_SHARED; 711*c6402783Sakolb else 712*c6402783Sakolb newmap->mtypes |= 1 << AT_PRIVM; 713*c6402783Sakolb } 714*c6402783Sakolb 715*c6402783Sakolb if (lname == NULL && (pmp->pr_mflags & MA_ANON)) { 716*c6402783Sakolb lname = anon_name(newmap->label, Psp, pmp->pr_vaddr, 717*c6402783Sakolb pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, 718*c6402783Sakolb &newmap->mtypes); 719*c6402783Sakolb } 720*c6402783Sakolb 721*c6402783Sakolb /* 722*c6402783Sakolb * Add raw advice that applies to this mapping to the merged_list 723*c6402783Sakolb */ 724*c6402783Sakolb psaddr = rawadv_list; 725*c6402783Sakolb /* 726*c6402783Sakolb * Advance to point in rawadv_list that applies to this mapping 727*c6402783Sakolb */ 728*c6402783Sakolb while (psaddr && psaddr->addr < pmp->pr_vaddr) 729*c6402783Sakolb psaddr = psaddr->next; 730*c6402783Sakolb /* 731*c6402783Sakolb * Copy over to merged_list, check to see if size needs to be filled in 732*c6402783Sakolb */ 733*c6402783Sakolb while (psaddr && psaddr->addr < (pmp->pr_vaddr + pmp->pr_size)) { 734*c6402783Sakolb newaddr = malloc(sizeof (saddr_t)); 735*c6402783Sakolb (void) memcpy(newaddr, psaddr, sizeof (saddr_t)); 736*c6402783Sakolb insert_addr(&merged_list, newaddr, YESDUPS); 737*c6402783Sakolb /* 738*c6402783Sakolb * For raw advice that is given without size, try to default 739*c6402783Sakolb * size to size of mapping (only allowed if raw adv addr is 740*c6402783Sakolb * equal to beginning of mapping). Don't change the entry 741*c6402783Sakolb * in rawadv_list, only in the merged_list as the mappings 742*c6402783Sakolb * (and thus the default sizes) will be different for 743*c6402783Sakolb * different processes. 744*c6402783Sakolb */ 745*c6402783Sakolb if ((pmp->pr_vaddr == psaddr->addr) && (psaddr->length == 0)) 746*c6402783Sakolb newaddr->length = pmp->pr_size; 747*c6402783Sakolb psaddr = psaddr->next; 748*c6402783Sakolb } 749*c6402783Sakolb 750*c6402783Sakolb /* 751*c6402783Sakolb * Put mapping into merged list with no advice, then 752*c6402783Sakolb * check to see if any generic advice applies. 753*c6402783Sakolb */ 754*c6402783Sakolb newaddr = malloc(sizeof (saddr_t)); 755*c6402783Sakolb newaddr->addr = pmp->pr_vaddr; 756*c6402783Sakolb newaddr->length = pmp->pr_size; 757*c6402783Sakolb newaddr->adv = NO_ADVICE; 758*c6402783Sakolb insert_addr(&merged_list, newaddr, YESDUPS); 759*c6402783Sakolb 760*c6402783Sakolb newmap->mtypes &= at_map; 761*c6402783Sakolb for (i = AT_STACK; i >= AT_PRIVM; i--) { 762*c6402783Sakolb if (newmap->mtypes & (1 << i)) { 763*c6402783Sakolb assert(generic_adv[i] != NO_ADVICE); 764*c6402783Sakolb newaddr->adv = generic_adv[i]; 765*c6402783Sakolb break; 766*c6402783Sakolb } 767*c6402783Sakolb } 768*c6402783Sakolb 769*c6402783Sakolb /* 770*c6402783Sakolb * Add to linked list of mappings 771*c6402783Sakolb */ 772*c6402783Sakolb if (maplist_tail == NULL) { 773*c6402783Sakolb maplist_head = maplist_tail = newmap; 774*c6402783Sakolb } else { 775*c6402783Sakolb maplist_tail->next = newmap; 776*c6402783Sakolb maplist_tail = newmap; 777*c6402783Sakolb } 778*c6402783Sakolb 779*c6402783Sakolb 780*c6402783Sakolb return (0); 781*c6402783Sakolb } 782*c6402783Sakolb 783*c6402783Sakolb /* 784*c6402783Sakolb * Traverse advice list and apply all applicable advice to each region 785*c6402783Sakolb */ 786*c6402783Sakolb static int 787*c6402783Sakolb apply_advice(saddr_t **advicelist) 788*c6402783Sakolb { 789*c6402783Sakolb saddr_t *psaddr = *advicelist; 790*c6402783Sakolb saddr_t *next; 791*c6402783Sakolb int i; 792*c6402783Sakolb 793*c6402783Sakolb 794*c6402783Sakolb while (!interrupt && psaddr != NULL) { 795*c6402783Sakolb /* 796*c6402783Sakolb * Save next pointer since element may be removed before 797*c6402783Sakolb * we get a chance to advance psaddr. 798*c6402783Sakolb */ 799*c6402783Sakolb next = psaddr->next; 800*c6402783Sakolb 801*c6402783Sakolb /* 802*c6402783Sakolb * Since mappings have been added to the merged list 803*c6402783Sakolb * even if no generic advice was given for the map, 804*c6402783Sakolb * check to make sure advice exists before bothering 805*c6402783Sakolb * with the for loop. 806*c6402783Sakolb */ 807*c6402783Sakolb if (psaddr->adv != NO_ADVICE) { 808*c6402783Sakolb for (i = MADV_NORMAL; i <= MADV_ACCESS_MANY; i++) { 809*c6402783Sakolb if ((psaddr->adv & (1 << i)) && 810*c6402783Sakolb (pr_madvise(Pr, (caddr_t)psaddr->addr, 811*c6402783Sakolb psaddr->length, i) < 0)) { 812*c6402783Sakolb /* 813*c6402783Sakolb * madvise(3C) call failed trying to 814*c6402783Sakolb * apply advice output error and remove 815*c6402783Sakolb * from advice list 816*c6402783Sakolb */ 817*c6402783Sakolb (void) fprintf(stderr, 818*c6402783Sakolb gettext("Error applying " 819*c6402783Sakolb "advice (%s) to memory range " 820*c6402783Sakolb "[%lx, %lx):\n"), 821*c6402783Sakolb advicestr[i], (ulong_t)psaddr->addr, 822*c6402783Sakolb (ulong_t)psaddr->addr + 823*c6402783Sakolb psaddr->length); 824*c6402783Sakolb perror("madvise"); 825*c6402783Sakolb /* 826*c6402783Sakolb * Clear this advice from the advice 827*c6402783Sakolb * mask. If no more advice is given 828*c6402783Sakolb * for this element, remove element 829*c6402783Sakolb * from list. 830*c6402783Sakolb */ 831*c6402783Sakolb psaddr->adv &= ~(1 << i); 832*c6402783Sakolb if (psaddr->adv == 0) { 833*c6402783Sakolb delete_addr(advicelist, psaddr); 834*c6402783Sakolb break; 835*c6402783Sakolb } 836*c6402783Sakolb } 837*c6402783Sakolb } 838*c6402783Sakolb } 839*c6402783Sakolb psaddr = next; 840*c6402783Sakolb } 841*c6402783Sakolb return (0); 842*c6402783Sakolb } 843*c6402783Sakolb 844*c6402783Sakolb /* 845*c6402783Sakolb * Set advice but keep mutual exclusive property of advice groupings 846*c6402783Sakolb */ 847*c6402783Sakolb static void 848*c6402783Sakolb set_advice(int *combined_adv, int new_adv) { 849*c6402783Sakolb /* 850*c6402783Sakolb * Since advice falls in 3 groups of mutually exclusive options, 851*c6402783Sakolb * clear previous value if new advice overwrites that group. 852*c6402783Sakolb */ 853*c6402783Sakolb 854*c6402783Sakolb /* 855*c6402783Sakolb * If this is the first advice to be applied, clear invalid value (-1) 856*c6402783Sakolb */ 857*c6402783Sakolb if (*combined_adv == -1) 858*c6402783Sakolb *combined_adv = 0; 859*c6402783Sakolb 860*c6402783Sakolb if (new_adv & GRP1_ADV) 861*c6402783Sakolb *combined_adv &= ~GRP1_ADV; 862*c6402783Sakolb else if (new_adv & GRP2_ADV) 863*c6402783Sakolb *combined_adv &= ~GRP2_ADV; 864*c6402783Sakolb else 865*c6402783Sakolb *combined_adv &= ~GRP3_ADV; 866*c6402783Sakolb 867*c6402783Sakolb *combined_adv |= new_adv; 868*c6402783Sakolb } 869*c6402783Sakolb 870*c6402783Sakolb /* 871*c6402783Sakolb * Create chopped list from merged list for use with verbose output 872*c6402783Sakolb */ 873*c6402783Sakolb static void 874*c6402783Sakolb create_choplist(saddr_t **choppedlist, saddr_t *mergedlist) 875*c6402783Sakolb { 876*c6402783Sakolb saddr_t *mlptr, *clptr; 877*c6402783Sakolb 878*c6402783Sakolb for (mlptr = mergedlist; mlptr != NULL; mlptr = mlptr->next) { 879*c6402783Sakolb clptr = malloc(sizeof (saddr_t)); 880*c6402783Sakolb clptr->addr = mlptr->addr; 881*c6402783Sakolb clptr->length = 0; 882*c6402783Sakolb /* 883*c6402783Sakolb * Initialize the adv to -1 as an indicator for invalid 884*c6402783Sakolb * elements in the chopped list (created from gaps between 885*c6402783Sakolb * memory maps). 886*c6402783Sakolb */ 887*c6402783Sakolb clptr->adv = -1; 888*c6402783Sakolb clptr->next = NULL; 889*c6402783Sakolb insert_addr(choppedlist, clptr, NODUPS); 890*c6402783Sakolb 891*c6402783Sakolb clptr = malloc(sizeof (saddr_t)); 892*c6402783Sakolb clptr->addr = mlptr->addr + mlptr->length; 893*c6402783Sakolb clptr->length = 0; 894*c6402783Sakolb /* 895*c6402783Sakolb * Again, initialize to -1 as an indicatorfor invalid elements 896*c6402783Sakolb */ 897*c6402783Sakolb clptr->adv = -1; 898*c6402783Sakolb clptr->next = NULL; 899*c6402783Sakolb insert_addr(choppedlist, clptr, NODUPS); 900*c6402783Sakolb } 901*c6402783Sakolb 902*c6402783Sakolb for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) { 903*c6402783Sakolb if (clptr->next) 904*c6402783Sakolb clptr->length = clptr->next->addr - clptr->addr; 905*c6402783Sakolb else { 906*c6402783Sakolb /* 907*c6402783Sakolb * must be last element, now that we've calculated 908*c6402783Sakolb * all segment lengths, we can remove this node 909*c6402783Sakolb */ 910*c6402783Sakolb delete_addr(choppedlist, clptr); 911*c6402783Sakolb } 912*c6402783Sakolb } 913*c6402783Sakolb 914*c6402783Sakolb for (mlptr = mergedlist; mlptr != NULL; mlptr = mlptr->next) { 915*c6402783Sakolb for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) { 916*c6402783Sakolb if (mlptr->addr <= clptr->addr && 917*c6402783Sakolb mlptr->addr + mlptr->length >= 918*c6402783Sakolb clptr->addr + clptr->length) 919*c6402783Sakolb /* 920*c6402783Sakolb * set_advice() will take care of conflicting 921*c6402783Sakolb * advice by taking only the last advice 922*c6402783Sakolb * applied for each of the 3 groups of advice. 923*c6402783Sakolb */ 924*c6402783Sakolb set_advice(&clptr->adv, mlptr->adv); 925*c6402783Sakolb if (mlptr->addr + mlptr->length < 926*c6402783Sakolb clptr->addr) 927*c6402783Sakolb break; 928*c6402783Sakolb } 929*c6402783Sakolb } 930*c6402783Sakolb } 931*c6402783Sakolb 932*c6402783Sakolb /* 933*c6402783Sakolb * Print advice in pmap style for verbose output 934*c6402783Sakolb */ 935*c6402783Sakolb static void 936*c6402783Sakolb print_advice(saddr_t *advlist, mapnode_t *maplist) 937*c6402783Sakolb { 938*c6402783Sakolb saddr_t *psaddr = advlist; 939*c6402783Sakolb mapnode_t *pmapnode; 940*c6402783Sakolb char *advice; 941*c6402783Sakolb 942*c6402783Sakolb pmapnode = maplist; 943*c6402783Sakolb 944*c6402783Sakolb while (psaddr) { 945*c6402783Sakolb /* 946*c6402783Sakolb * Using indicator flag from create_choppedlist, we know 947*c6402783Sakolb * which entries in the chopped_list are gaps and should 948*c6402783Sakolb * not be printed. 949*c6402783Sakolb */ 950*c6402783Sakolb if (psaddr->adv == -1) { 951*c6402783Sakolb psaddr = psaddr->next; 952*c6402783Sakolb continue; 953*c6402783Sakolb } 954*c6402783Sakolb 955*c6402783Sakolb while (pmapnode && (pmapnode->pmp->pr_vaddr + 956*c6402783Sakolb pmapnode->pmp->pr_size <= psaddr->addr)) 957*c6402783Sakolb pmapnode = pmapnode->next; 958*c6402783Sakolb 959*c6402783Sakolb advice = advtostr(psaddr->adv); 960*c6402783Sakolb 961*c6402783Sakolb /* 962*c6402783Sakolb * Print segment mapping and advice if there is any, or just a 963*c6402783Sakolb * segment mapping. 964*c6402783Sakolb */ 965*c6402783Sakolb if (strlen(advice) > 0) { 966*c6402783Sakolb (void) printf("%.*lX %*uK %6s %s\t%s\n", 967*c6402783Sakolb addr_width, (ulong_t)psaddr->addr, size_width - 1, 968*c6402783Sakolb (int)ROUNDUP_KB(psaddr->length), 969*c6402783Sakolb mflags(pmapnode->pmp->pr_mflags), pmapnode->label, 970*c6402783Sakolb advice); 971*c6402783Sakolb } else { 972*c6402783Sakolb (void) printf("%.*lX %*uK %6s %s\n", 973*c6402783Sakolb addr_width, (ulong_t)psaddr->addr, size_width - 1, 974*c6402783Sakolb (int)ROUNDUP_KB(psaddr->length), 975*c6402783Sakolb mflags(pmapnode->pmp->pr_mflags), pmapnode->label); 976*c6402783Sakolb } 977*c6402783Sakolb psaddr = psaddr->next; 978*c6402783Sakolb 979*c6402783Sakolb } 980*c6402783Sakolb } 981*c6402783Sakolb 982*c6402783Sakolb /* 983*c6402783Sakolb * Call madvise(3c) in the context of the target process 984*c6402783Sakolb */ 985*c6402783Sakolb static int 986*c6402783Sakolb pr_madvise(struct ps_prochandle *Pr, caddr_t addr, size_t len, int advice) 987*c6402783Sakolb { 988*c6402783Sakolb return (pr_memcntl(Pr, addr, len, MC_ADVISE, 989*c6402783Sakolb (caddr_t)(uintptr_t)advice, 0, 0)); 990*c6402783Sakolb } 991*c6402783Sakolb 992*c6402783Sakolb static char * 993*c6402783Sakolb mflags(uint_t arg) 994*c6402783Sakolb { 995*c6402783Sakolb static char code_buf[80]; 996*c6402783Sakolb 997*c6402783Sakolb /* 998*c6402783Sakolb * rwxsR 999*c6402783Sakolb * 1000*c6402783Sakolb * r - segment is readable 1001*c6402783Sakolb * w - segment is writable 1002*c6402783Sakolb * x - segment is executable 1003*c6402783Sakolb * s - segment is shared 1004*c6402783Sakolb * R - segment is mapped MAP_NORESERVE 1005*c6402783Sakolb * 1006*c6402783Sakolb */ 1007*c6402783Sakolb (void) snprintf(code_buf, sizeof (code_buf), "%c%c%c%c%c ", 1008*c6402783Sakolb arg & MA_READ ? 'r' : '-', 1009*c6402783Sakolb arg & MA_WRITE ? 'w' : '-', 1010*c6402783Sakolb arg & MA_EXEC ? 'x' : '-', 1011*c6402783Sakolb arg & MA_SHARED ? 's' : '-', 1012*c6402783Sakolb arg & MA_NORESERVE ? 'R' : '-'); 1013*c6402783Sakolb 1014*c6402783Sakolb return (code_buf); 1015*c6402783Sakolb } 1016*c6402783Sakolb 1017*c6402783Sakolb /* 1018*c6402783Sakolb * Convert advice to a string containing a commented list of applicable advice 1019*c6402783Sakolb */ 1020*c6402783Sakolb static char * 1021*c6402783Sakolb advtostr(int adv) 1022*c6402783Sakolb { 1023*c6402783Sakolb static char buf[50]; 1024*c6402783Sakolb int i; 1025*c6402783Sakolb 1026*c6402783Sakolb *buf = '\0'; 1027*c6402783Sakolb 1028*c6402783Sakolb if (adv != NO_ADVICE) { 1029*c6402783Sakolb for (i = MADV_NORMAL; i <= MADV_ACCESS_MANY; i++) { 1030*c6402783Sakolb if (adv & (1 << i)) { 1031*c6402783Sakolb /* 1032*c6402783Sakolb * check if it's the first advice entry 1033*c6402783Sakolb */ 1034*c6402783Sakolb if (*buf == '\0') 1035*c6402783Sakolb (void) snprintf(buf, sizeof (buf) - 1, 1036*c6402783Sakolb "<= %s", advicestr[i]); 1037*c6402783Sakolb else 1038*c6402783Sakolb (void) snprintf(buf, sizeof (buf) - 1, 1039*c6402783Sakolb "%s,%s", buf, advicestr[i]); 1040*c6402783Sakolb } 1041*c6402783Sakolb } 1042*c6402783Sakolb } 1043*c6402783Sakolb 1044*c6402783Sakolb return (buf); 1045*c6402783Sakolb } 1046*c6402783Sakolb 1047*c6402783Sakolb /* 1048*c6402783Sakolb * Handler for catching signals from terminal 1049*c6402783Sakolb */ 1050*c6402783Sakolb /* ARGSUSED */ 1051*c6402783Sakolb static void 1052*c6402783Sakolb intr(int sig) 1053*c6402783Sakolb { 1054*c6402783Sakolb interrupt++; 1055*c6402783Sakolb } 1056*c6402783Sakolb 1057*c6402783Sakolb int 1058*c6402783Sakolb main(int argc, char **argv) 1059*c6402783Sakolb { 1060*c6402783Sakolb int Fflag = 0; 1061*c6402783Sakolb int rc = 0; 1062*c6402783Sakolb int opt, subopt; 1063*c6402783Sakolb int tmpadv; 1064*c6402783Sakolb char *options, *value; 1065*c6402783Sakolb saddr_t *psaddr; 1066*c6402783Sakolb mapnode_t *pmapnode, *tempmapnode; 1067*c6402783Sakolb 1068*c6402783Sakolb (void) setlocale(LC_ALL, ""); 1069*c6402783Sakolb (void) textdomain(TEXT_DOMAIN); 1070*c6402783Sakolb 1071*c6402783Sakolb /* 1072*c6402783Sakolb * Get name of program for error messages 1073*c6402783Sakolb */ 1074*c6402783Sakolb progname = basename(argv[0]); 1075*c6402783Sakolb 1076*c6402783Sakolb /* 1077*c6402783Sakolb * Not much to do when only name of program given 1078*c6402783Sakolb */ 1079*c6402783Sakolb if (argc == 1) 1080*c6402783Sakolb usage(); 1081*c6402783Sakolb 1082*c6402783Sakolb /* 1083*c6402783Sakolb * Catch signals from terminal, so they can be handled asynchronously 1084*c6402783Sakolb * when we're ready instead of when we're not (;-) 1085*c6402783Sakolb */ 1086*c6402783Sakolb if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 1087*c6402783Sakolb (void) sigset(SIGHUP, intr); 1088*c6402783Sakolb if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 1089*c6402783Sakolb (void) sigset(SIGINT, intr); 1090*c6402783Sakolb if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 1091*c6402783Sakolb (void) sigset(SIGQUIT, intr); 1092*c6402783Sakolb (void) sigset(SIGPIPE, intr); 1093*c6402783Sakolb (void) sigset(SIGTERM, intr); 1094*c6402783Sakolb 1095*c6402783Sakolb /* 1096*c6402783Sakolb * Parse options, record generic advice if any and create 1097*c6402783Sakolb * rawadv_list from specific address advice. 1098*c6402783Sakolb */ 1099*c6402783Sakolb 1100*c6402783Sakolb while ((opt = getopt(argc, argv, "Fo:v")) != EOF) { 1101*c6402783Sakolb switch (opt) { 1102*c6402783Sakolb case 'o': 1103*c6402783Sakolb options = optarg; 1104*c6402783Sakolb while (*options != '\0') { 1105*c6402783Sakolb subopt = getsubopt(&options, suboptstr, 1106*c6402783Sakolb &value); 1107*c6402783Sakolb switch (subopt) { 1108*c6402783Sakolb case AT_PRIVM: 1109*c6402783Sakolb case AT_HEAP: 1110*c6402783Sakolb case AT_SHARED: 1111*c6402783Sakolb case AT_STACK: 1112*c6402783Sakolb at_map |= (1 << subopt); 1113*c6402783Sakolb tmpadv = get_advice(value); 1114*c6402783Sakolb set_advice(&generic_adv[subopt], 1115*c6402783Sakolb tmpadv); 1116*c6402783Sakolb break; 1117*c6402783Sakolb default: 1118*c6402783Sakolb at_map |= (1 << AT_SEG); 1119*c6402783Sakolb psaddr = parse_suboptions(value); 1120*c6402783Sakolb if (psaddr == NULL) { 1121*c6402783Sakolb usage(); 1122*c6402783Sakolb } else { 1123*c6402783Sakolb insert_addr(&rawadv_list, 1124*c6402783Sakolb psaddr, YESDUPS); 1125*c6402783Sakolb } 1126*c6402783Sakolb break; 1127*c6402783Sakolb } 1128*c6402783Sakolb } 1129*c6402783Sakolb break; 1130*c6402783Sakolb case 'v': 1131*c6402783Sakolb opt_verbose = 1; 1132*c6402783Sakolb break; 1133*c6402783Sakolb case 'F': /* force grabbing (no O_EXCL) */ 1134*c6402783Sakolb Fflag = PGRAB_FORCE; 1135*c6402783Sakolb break; 1136*c6402783Sakolb default: 1137*c6402783Sakolb usage(); 1138*c6402783Sakolb break; 1139*c6402783Sakolb } 1140*c6402783Sakolb } 1141*c6402783Sakolb 1142*c6402783Sakolb argc -= optind; 1143*c6402783Sakolb argv += optind; 1144*c6402783Sakolb 1145*c6402783Sakolb if (argc <= 0) { 1146*c6402783Sakolb usage(); 1147*c6402783Sakolb } 1148*c6402783Sakolb 1149*c6402783Sakolb /* 1150*c6402783Sakolb * Iterate through all pid arguments, create new merged_list, maplist, 1151*c6402783Sakolb * (and chopped_list if using verbose output) based on each process' 1152*c6402783Sakolb * memory map. 1153*c6402783Sakolb */ 1154*c6402783Sakolb 1155*c6402783Sakolb while (!interrupt && argc-- > 0) { 1156*c6402783Sakolb char *arg; 1157*c6402783Sakolb int gcode; 1158*c6402783Sakolb psinfo_t psinfo; 1159*c6402783Sakolb 1160*c6402783Sakolb if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_PIDS, 1161*c6402783Sakolb PGRAB_RETAIN | Fflag, &gcode)) == NULL) { 1162*c6402783Sakolb (void) fprintf(stderr, 1163*c6402783Sakolb gettext("%s: cannot examine %s: %s\n"), 1164*c6402783Sakolb progname, arg, Pgrab_error(gcode)); 1165*c6402783Sakolb rc++; 1166*c6402783Sakolb continue; 1167*c6402783Sakolb } 1168*c6402783Sakolb 1169*c6402783Sakolb 1170*c6402783Sakolb addr_width = 1171*c6402783Sakolb (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 1172*c6402783Sakolb size_width = 1173*c6402783Sakolb (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 1174*c6402783Sakolb (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 1175*c6402783Sakolb 1176*c6402783Sakolb if (opt_verbose) { 1177*c6402783Sakolb proc_unctrl_psinfo(&psinfo); 1178*c6402783Sakolb (void) printf("%d:\t%.70s\n", 1179*c6402783Sakolb (int)psinfo.pr_pid, psinfo.pr_psargs); 1180*c6402783Sakolb } 1181*c6402783Sakolb 1182*c6402783Sakolb /* 1183*c6402783Sakolb * Get mappings for a process unless it is a system process. 1184*c6402783Sakolb */ 1185*c6402783Sakolb if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 1186*c6402783Sakolb nstacks = psinfo.pr_nlwp * 2; 1187*c6402783Sakolb stacks = calloc(nstacks, sizeof (stacks[0])); 1188*c6402783Sakolb if (stacks != NULL) { 1189*c6402783Sakolb int n = 0; 1190*c6402783Sakolb (void) Plwp_iter(Pr, getstack, &n); 1191*c6402783Sakolb qsort(stacks, nstacks, sizeof (stacks[0]), 1192*c6402783Sakolb cmpstacks); 1193*c6402783Sakolb } 1194*c6402783Sakolb 1195*c6402783Sakolb if (Pgetauxval(Pr, AT_BASE) != -1L && 1196*c6402783Sakolb Prd_agent(Pr) == NULL) { 1197*c6402783Sakolb (void) fprintf(stderr, 1198*c6402783Sakolb gettext("%s: warning: " 1199*c6402783Sakolb "librtld_db failed to initialize; " 1200*c6402783Sakolb "shared library information will not " 1201*c6402783Sakolb "be available\n"), 1202*c6402783Sakolb progname); 1203*c6402783Sakolb } 1204*c6402783Sakolb 1205*c6402783Sakolb /* 1206*c6402783Sakolb * Create linked list of mappings for current process 1207*c6402783Sakolb * In addition, add generic advice and raw advice 1208*c6402783Sakolb * entries to merged_list. 1209*c6402783Sakolb * e.g. if rawadv_list contains: 1210*c6402783Sakolb * [0x38000,0x3a000) = adv1 1211*c6402783Sakolb * [0x3a000,0x3c000) = adv2 1212*c6402783Sakolb * and there is generic advice: 1213*c6402783Sakolb * heap = adv3 1214*c6402783Sakolb * where heap corresponds to 0x38000, then merged_list 1215*c6402783Sakolb * will contain: 1216*c6402783Sakolb * ... (include all other mappings from process) 1217*c6402783Sakolb * [0x38000,0x3c000) = adv3 1218*c6402783Sakolb * [0x38000,0x3a000) = adv1 1219*c6402783Sakolb * [0x3a000,0x3c000) = adv2 1220*c6402783Sakolb * ... (include all other mappings from process) 1221*c6402783Sakolb */ 1222*c6402783Sakolb assert(merged_list == NULL); 1223*c6402783Sakolb maplist_head = maplist_tail = NULL; 1224*c6402783Sakolb rc += Pmapping_iter(Pr, (proc_map_f *)create_maplist, 1225*c6402783Sakolb NULL); 1226*c6402783Sakolb 1227*c6402783Sakolb /* 1228*c6402783Sakolb * Apply advice by iterating through merged list 1229*c6402783Sakolb */ 1230*c6402783Sakolb (void) apply_advice(&merged_list); 1231*c6402783Sakolb 1232*c6402783Sakolb if (opt_verbose) { 1233*c6402783Sakolb assert(chopped_list == NULL); 1234*c6402783Sakolb /* 1235*c6402783Sakolb * Create chopped_list from merged_list 1236*c6402783Sakolb */ 1237*c6402783Sakolb create_choplist(&chopped_list, merged_list); 1238*c6402783Sakolb 1239*c6402783Sakolb /* 1240*c6402783Sakolb * Iterate through maplist and output as 1241*c6402783Sakolb * given by chopped_list 1242*c6402783Sakolb */ 1243*c6402783Sakolb print_advice(chopped_list, maplist_head); 1244*c6402783Sakolb delete_list(&chopped_list); 1245*c6402783Sakolb } 1246*c6402783Sakolb 1247*c6402783Sakolb delete_list(&merged_list); 1248*c6402783Sakolb 1249*c6402783Sakolb /* 1250*c6402783Sakolb * Clear maplist 1251*c6402783Sakolb */ 1252*c6402783Sakolb pmapnode = maplist_head; 1253*c6402783Sakolb while (pmapnode) { 1254*c6402783Sakolb tempmapnode = pmapnode; 1255*c6402783Sakolb pmapnode = pmapnode->next; 1256*c6402783Sakolb free(tempmapnode); 1257*c6402783Sakolb } 1258*c6402783Sakolb 1259*c6402783Sakolb if (stacks != NULL) { 1260*c6402783Sakolb free(stacks); 1261*c6402783Sakolb stacks = NULL; 1262*c6402783Sakolb } 1263*c6402783Sakolb } 1264*c6402783Sakolb 1265*c6402783Sakolb Prelease(Pr, 0); 1266*c6402783Sakolb } 1267*c6402783Sakolb 1268*c6402783Sakolb return (rc); 1269*c6402783Sakolb } 1270