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