12685Sakolb /* 22685Sakolb * CDDL HEADER START 32685Sakolb * 42685Sakolb * The contents of this file are subject to the terms of the 52685Sakolb * Common Development and Distribution License (the "License"). 62685Sakolb * You may not use this file except in compliance with the License. 72685Sakolb * 82685Sakolb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92685Sakolb * or http://www.opensolaris.org/os/licensing. 102685Sakolb * See the License for the specific language governing permissions 112685Sakolb * and limitations under the License. 122685Sakolb * 132685Sakolb * When distributing Covered Code, include this CDDL HEADER in each 142685Sakolb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152685Sakolb * If applicable, add the following below this CDDL HEADER, with the 162685Sakolb * fields enclosed by brackets "[]" replaced with your own identifying 172685Sakolb * information: Portions Copyright [yyyy] [name of copyright owner] 182685Sakolb * 192685Sakolb * CDDL HEADER END 202685Sakolb */ 212685Sakolb 222685Sakolb /* 23*7032Sakolb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 242685Sakolb * Use is subject to license terms. 252685Sakolb */ 262685Sakolb 272685Sakolb #pragma ident "%Z%%M% %I% %E% SMI" 282685Sakolb 292685Sakolb /* 302685Sakolb * pmadvise 312685Sakolb * 322685Sakolb * ptool wrapper for madvise(3C) to apply memory advice to running processes 332685Sakolb * 342685Sakolb * usage: pmadvise -o option[,option] [-v] [-F] pid ... 352685Sakolb * (Give "advice" about a process's memory) 362685Sakolb * -o option[,option]: options are 372685Sakolb * private=<advice> 382685Sakolb * shared=<advice> 392685Sakolb * heap=<advice> 402685Sakolb * stack=<advice> 412685Sakolb * <segaddr>[:<length>]=<advice> 422685Sakolb * valid <advice> is one of: 432685Sakolb * normal, random, sequential, willneed, dontneed, 442685Sakolb * free, access_lwp, access_many, access_default 452685Sakolb * -v: verbose output 462685Sakolb * -F: force grabbing of the target process(es) 472685Sakolb * pid: process id list 482685Sakolb * 492685Sakolb * 502685Sakolb * Advice passed to this tool are organized into various lists described here: 512685Sakolb * rawadv_list: includes all specific advice from command line (specific 522685Sakolb * advice being those given to a particular address range rather 532685Sakolb * than a type like "heap" or "stack". In contrast, these 542685Sakolb * types are referred to as generic advice). Duplicates allowed. 552685Sakolb * List ordered by addr, then by size (largest size first). 562685Sakolb * Created once per run. 572685Sakolb * merged_list: includes all specific advice from the rawadv_list as well as 582685Sakolb * all generic advice. This must be recreated for each process 592685Sakolb * as the generic advice will apply to different regions for 602685Sakolb * different processes. Duplicates allowed. List ordered by addr, 612685Sakolb * then by size (largest size first). Created once per pid. 622685Sakolb * chopped_list: used for verbose output only. This list parses the merged 632685Sakolb * list such that it eliminates any overlap and combines the 642685Sakolb * advice. Easiest to think of this visually: if you take all 652685Sakolb * the advice in the merged list and lay them down on a memory 662685Sakolb * range of the entire process (laying on top of each other when 672685Sakolb * necessary), then flatten them into one layer, combining advice 682685Sakolb * in the case of overlap, you get the chopped_list of advice. 692685Sakolb * Duplicate entries not allowed (since there is no overlap by 702685Sakolb * definition in this list). List ordered by addr. Created once 712685Sakolb * per pid. 722685Sakolb * 732685Sakolb * Example: 742685Sakolb * merged_list: |-----adv1----|---------adv3---------| 752685Sakolb * |--adv2--|--adv4--|-----adv5----| 762685Sakolb * || 772685Sakolb * \/ 782685Sakolb * chopped_list: |adv1|-adv1,2-|-adv3,4-|----adv3,5---| 792685Sakolb * 802685Sakolb * maplist: list of memory mappings for a particular process. Used to create 812685Sakolb * generic advice entries for merged_list and for pmap like verbose 822685Sakolb * output. Created once per pid. 832685Sakolb * 842685Sakolb * Multiple lists are necessary because the actual advice applied given a set 852685Sakolb * of generic and specific advice changes from process to process, so for each 862685Sakolb * pid pmadvise is passed, it must create a new merged_list from which to apply 872685Sakolb * advice (and a new chopped_list if verbose output is requested). 882685Sakolb * 892685Sakolb * Pseudo-code: 902685Sakolb * I. Input advice from command line 912685Sakolb * II. Create [raw advice list] of specific advice 922685Sakolb * III. Iterate through PIDs: 932685Sakolb * A. Create [map list] 942685Sakolb * B. Merge generic advice and [raw advice list] into [merged list] 952685Sakolb * C. Apply advice from [merged list]; upon error: 962685Sakolb * i. output madvise error message 972685Sakolb * ii. remove element from [merged list] 982685Sakolb * D. If verbose output: 992685Sakolb * i. Create [chopped list] from [merged list] 1002685Sakolb * ii. Iterate through [map list]: 1012685Sakolb * a. output advice as given by [merged list] 1022685Sakolb * iii. Delete [chopped list] 1032685Sakolb * E. Delete [merged list] 1042685Sakolb * F. Delete [map list] 1052685Sakolb */ 1062685Sakolb 1072685Sakolb #include <stdio.h> 1082685Sakolb #include <stdlib.h> 1092685Sakolb #include <unistd.h> 1102685Sakolb #include <ctype.h> 1112685Sakolb #include <fcntl.h> 1122685Sakolb #include <string.h> 1132685Sakolb #include <dirent.h> 1142685Sakolb #include <limits.h> 1152685Sakolb #include <link.h> 1162685Sakolb #include <libelf.h> 1172685Sakolb #include <locale.h> 1182685Sakolb #include <sys/types.h> 1192685Sakolb #include <sys/mman.h> 1202685Sakolb #include <sys/stat.h> 1212685Sakolb #include <sys/mkdev.h> 1222685Sakolb #include <assert.h> 1232685Sakolb #include <libproc.h> 1242685Sakolb #include <libgen.h> 1252685Sakolb #include <signal.h> 1262685Sakolb 1272685Sakolb #ifndef TEXT_DOMAIN /* should be defined by cc -D */ 1282685Sakolb #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */ 1292685Sakolb #endif 1302685Sakolb 1312685Sakolb #define KILOBYTE 1024 1322685Sakolb 1332685Sakolb /* 1342685Sakolb * Round up the value to the nearest kilobyte 1352685Sakolb */ 1362685Sakolb #define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE) 1372685Sakolb 1382685Sakolb #define NO_ADVICE 0 1392685Sakolb 1402685Sakolb /* 1412685Sakolb * The following definitions are used as the third argument in insert_addr() 1422685Sakolb * NODUPS = no duplicates are not allowed, thus if the addr being inserted 1432685Sakolb * already exists in the list, return without inserting again. 1442685Sakolb * 1452685Sakolb * YESDUPS = yes duplicates are allowed, thus always insert the addr 1462685Sakolb * regardless of whether it already exists in the list or not. 1472685Sakolb */ 1482685Sakolb #define NODUPS 1 1492685Sakolb #define YESDUPS 0 1502685Sakolb 1512685Sakolb /* 1522685Sakolb * Advice that can be passed to madvise fit into three groups that each 1532685Sakolb * contain 3 mutually exclusive options. These groups are defined below: 1542685Sakolb * Group 1: normal, random, sequential 1552685Sakolb * Group 2: willneed, dontneed, free 1562685Sakolb * Group 3: default, accesslwp, accessmany 1572685Sakolb * Thus, advice that includes (at most) one from each group is valid. 1582685Sakolb * 1592685Sakolb * The following #define's are used as masks to determine which group(s) a 1602685Sakolb * particular advice fall under. 1612685Sakolb */ 1622685Sakolb 1632685Sakolb #define GRP1_ADV (1 << MADV_NORMAL | 1 << MADV_RANDOM | \ 1642685Sakolb 1 << MADV_SEQUENTIAL) 1652685Sakolb #define GRP2_ADV (1 << MADV_WILLNEED | 1 << MADV_DONTNEED | \ 1662685Sakolb 1 << MADV_FREE) 1672685Sakolb #define GRP3_ADV (1 << MADV_ACCESS_DEFAULT | 1 << MADV_ACCESS_LWP | \ 1682685Sakolb 1 << MADV_ACCESS_MANY) 1692685Sakolb 1702685Sakolb static int create_maplist(void *, const prmap_t *, const char *); 1712685Sakolb static int pr_madvise(struct ps_prochandle *, caddr_t, size_t, int); 1722685Sakolb 1732685Sakolb static char *mflags(uint_t); 1742685Sakolb static char *advtostr(int); 1752685Sakolb 1762685Sakolb static int addr_width, size_width; 1772685Sakolb static char *progname; 1782685Sakolb static struct ps_prochandle *Pr; 1792685Sakolb 1802685Sakolb typedef struct lwpstack { 1812685Sakolb lwpid_t lwps_lwpid; 1822685Sakolb stack_t lwps_stack; 1832685Sakolb } lwpstack_t; 1842685Sakolb 1852685Sakolb static lwpstack_t *stacks; 1862685Sakolb static uint_t nstacks; 1872685Sakolb 1882685Sakolb /* 1892685Sakolb * Used to set the advice type var (at_map) when parsing the arguments to 1902685Sakolb * pmadvise. Later, when creating the map list, at_map is used as a mask 1912685Sakolb * to determine if any generic advice applies to each memory mapping. 1922685Sakolb */ 1932685Sakolb enum atype_enum { 1942685Sakolb AT_PRIVM, 1952685Sakolb AT_SHARED, 1962685Sakolb AT_HEAP, 1972685Sakolb AT_STACK, 1982685Sakolb AT_SEG, 1992685Sakolb AT_NTYPES 2002685Sakolb }; 2012685Sakolb 2022685Sakolb static char *suboptstr[] = { 2032685Sakolb "private", 2042685Sakolb "shared", 2052685Sakolb "heap", 2062685Sakolb "stack", 2072685Sakolb NULL 2082685Sakolb }; 2092685Sakolb 2102685Sakolb 2112685Sakolb int generic_adv[] = {NO_ADVICE, NO_ADVICE, NO_ADVICE, NO_ADVICE}; 2122685Sakolb int at_map = 0; 2132685Sakolb 2142685Sakolb typedef struct saddr_struct { 2152685Sakolb uintptr_t addr; 2162685Sakolb size_t length; 2172685Sakolb int adv; 2182685Sakolb struct saddr_struct *next; 2192685Sakolb } saddr_t; 2202685Sakolb static int apply_advice(saddr_t **); 2212685Sakolb static void set_advice(int *, int); 2222685Sakolb static void create_choplist(saddr_t **, saddr_t *); 2232685Sakolb 2242685Sakolb /* 2252685Sakolb * The segment address advice from the command line 2262685Sakolb */ 2272685Sakolb saddr_t *rawadv_list = NULL; 2282685Sakolb /* 2292685Sakolb * The rawadv_list + list entries for the generic advice (if any). 2302685Sakolb * This must be recreated for each PID as the memory maps might be different. 2312685Sakolb */ 2322685Sakolb saddr_t *merged_list = NULL; 2332685Sakolb /* 2342685Sakolb * The merged_list cut up so as to remove all overlap 2352685Sakolb * e.g. if merged_list contained two entries: 2362685Sakolb * 2372685Sakolb * [0x38000:0x3e000) = adv1 2382685Sakolb * [0x3a000:0x3c000) = adv2 2392685Sakolb * 2402685Sakolb * the chopped list will contain three entries: 2412685Sakolb * 2422685Sakolb * [0x38000:0x3a000) = adv1 2432685Sakolb * [0x3a000:0x3c000) = adv1,adv2 2442685Sakolb * [0x3c000:0x3e000) = adv1 2452685Sakolb * 2462685Sakolb */ 2472685Sakolb saddr_t *chopped_list = NULL; 2482685Sakolb 2492685Sakolb typedef struct mapnode_struct { 2502685Sakolb prmap_t *pmp; 2512685Sakolb char label[PATH_MAX]; 2522685Sakolb int mtypes; 2532685Sakolb struct mapnode_struct *next; 2542685Sakolb } mapnode_t; 2552685Sakolb 2562685Sakolb mapnode_t *maplist_head = NULL; 2572685Sakolb mapnode_t *maplist_tail = NULL; 2582685Sakolb static void print_advice(saddr_t *, mapnode_t *); 2592685Sakolb 2602685Sakolb int opt_verbose; 2612685Sakolb 2622685Sakolb static char *advicestr[] = { 2632685Sakolb "normal", 2642685Sakolb "random", 2652685Sakolb "sequential", 2662685Sakolb "willneed", 2672685Sakolb "dontneed", 2682685Sakolb "free", 2692685Sakolb "access_default", 2702685Sakolb "access_lwp", 2712685Sakolb "access_many" 2722685Sakolb }; 2732685Sakolb 2742685Sakolb /* 2752685Sakolb * How many signals caught from terminal 2762685Sakolb * We bail out as soon as possible when interrupt is set 2772685Sakolb */ 2782685Sakolb static int interrupt = 0; 2792685Sakolb 2802685Sakolb /* 2812685Sakolb * Interrupt handler 2822685Sakolb */ 2832685Sakolb static void intr(int); 2842685Sakolb 2852685Sakolb /* 2862685Sakolb * Iterative function passed to Plwp_iter to 2872685Sakolb * get alt and main stacks for given lwp. 2882685Sakolb */ 2892685Sakolb static int 2902685Sakolb getstack(void *data, const lwpstatus_t *lsp) 2912685Sakolb { 2922685Sakolb int *np = (int *)data; 2932685Sakolb 2942685Sakolb if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 2952685Sakolb stacks[*np].lwps_stack.ss_flags |= SS_ONSTACK; 2962685Sakolb stacks[*np].lwps_lwpid = lsp->pr_lwpid; 2972685Sakolb (*np)++; 2982685Sakolb } 2992685Sakolb 3002685Sakolb if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) { 3012685Sakolb stacks[*np].lwps_lwpid = lsp->pr_lwpid; 3022685Sakolb (*np)++; 3032685Sakolb } 3042685Sakolb 3052685Sakolb return (0); 3062685Sakolb } 3072685Sakolb 3082685Sakolb /* 3092685Sakolb * We compare the high memory addresses since stacks are faulted in from 3102685Sakolb * high memory addresses to low memory addresses, and our prmap_t 3112685Sakolb * structures identify only the range of addresses that have been faulted 3122685Sakolb * in so far. 3132685Sakolb */ 3142685Sakolb static int 3152685Sakolb cmpstacks(const void *ap, const void *bp) 3162685Sakolb { 3172685Sakolb const lwpstack_t *as = ap; 3182685Sakolb const lwpstack_t *bs = bp; 3192685Sakolb uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 3202685Sakolb uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 3212685Sakolb 3222685Sakolb if (a < b) 3232685Sakolb return (1); 3242685Sakolb if (a > b) 3252685Sakolb return (-1); 3262685Sakolb return (0); 3272685Sakolb } 3282685Sakolb 3292685Sakolb /* 3302685Sakolb * Prints usage and exits 3312685Sakolb */ 3322685Sakolb static void 3332685Sakolb usage() 3342685Sakolb { 3352685Sakolb (void) fprintf(stderr, 3362685Sakolb gettext("usage:\t%s -o option[,option] [-v] [-F] pid ...\n"), 3372685Sakolb progname); 3382685Sakolb (void) fprintf(stderr, 3392685Sakolb gettext(" (Give \"advice\" about a process's memory)\n" 3402685Sakolb " -o option[,option]: options are\n" 3412685Sakolb " private=<advice>\n" 3422685Sakolb " shared=<advice>\n" 3432685Sakolb " heap=<advice>\n" 3442685Sakolb " stack=<advice>\n" 3452685Sakolb " <segaddr>[:<length>]=<advice>\n" 3462685Sakolb " valid <advice> is one of:\n" 3472685Sakolb " normal, random, sequential, willneed, dontneed,\n" 3482685Sakolb " free, access_lwp, access_many, access_default\n" 3492685Sakolb " -v: verbose output\n" 3502685Sakolb " -F: force grabbing of the target process(es)\n" 3512685Sakolb " pid: process id list\n")); 3522685Sakolb exit(2); 3532685Sakolb } 3542685Sakolb 3552685Sakolb /* 3562685Sakolb * Function to parse advice from options string 3572685Sakolb */ 3582685Sakolb static int 3592685Sakolb get_advice(char *optarg) 3602685Sakolb { 3612685Sakolb /* 3622685Sakolb * Determine which advice is given, we use shifted values as 3632685Sakolb * multiple pieces of advice may apply for a particular region. 3642685Sakolb * (See comment above regarding GRP[1,2,3]_ADV definitions for 3652685Sakolb * breakdown of advice groups). 3662685Sakolb */ 3672685Sakolb if (strcmp(optarg, "access_default") == 0) 3682685Sakolb return (1 << MADV_ACCESS_DEFAULT); 3692685Sakolb else if (strcmp(optarg, "access_many") == 0) 3702685Sakolb return (1 << MADV_ACCESS_MANY); 3712685Sakolb else if (strcmp(optarg, "access_lwp") == 0) 3722685Sakolb return (1 << MADV_ACCESS_LWP); 3732685Sakolb else if (strcmp(optarg, "sequential") == 0) 3742685Sakolb return (1 << MADV_SEQUENTIAL); 3752685Sakolb else if (strcmp(optarg, "willneed") == 0) 3762685Sakolb return (1 << MADV_WILLNEED); 3772685Sakolb else if (strcmp(optarg, "dontneed") == 0) 3782685Sakolb return (1 << MADV_DONTNEED); 3792685Sakolb else if (strcmp(optarg, "random") == 0) 3802685Sakolb return (1 << MADV_RANDOM); 3812685Sakolb else if (strcmp(optarg, "normal") == 0) 3822685Sakolb return (1 << MADV_NORMAL); 3832685Sakolb else if (strcmp(optarg, "free") == 0) 3842685Sakolb return (1 << MADV_FREE); 3852685Sakolb else { 3862685Sakolb (void) fprintf(stderr, gettext("%s: invalid advice: %s\n"), 3872685Sakolb progname, optarg); 3882685Sakolb usage(); 3892685Sakolb return (-1); 3902685Sakolb } 3912685Sakolb } 3922685Sakolb 3932685Sakolb /* 3942685Sakolb * Function to convert character size indicators into actual size 3952685Sakolb * (i.e., 123M => sz = 123 * 1024 * 1024) 3962685Sakolb */ 3972685Sakolb static size_t 3982685Sakolb atosz(char *optarg, char **endptr) 3992685Sakolb { 4002685Sakolb size_t sz = 0; 4012685Sakolb 4022685Sakolb if (optarg == NULL || optarg[0] == '\0') 4032685Sakolb return (0); 4042685Sakolb 4052685Sakolb sz = strtoll(optarg, endptr, 0); 4062685Sakolb 4072685Sakolb switch (**endptr) { 4082685Sakolb case 'E': 4092685Sakolb case 'e': 4102685Sakolb sz *= KILOBYTE; 4112685Sakolb /* FALLTHRU */ 4122685Sakolb case 'P': 4132685Sakolb case 'p': 4142685Sakolb sz *= KILOBYTE; 4152685Sakolb /* FALLTHRU */ 4162685Sakolb case 'T': 4172685Sakolb case 't': 4182685Sakolb sz *= KILOBYTE; 4192685Sakolb /* FALLTHRU */ 4202685Sakolb case 'G': 4212685Sakolb case 'g': 4222685Sakolb sz *= KILOBYTE; 4232685Sakolb /* FALLTHRU */ 4242685Sakolb case 'M': 4252685Sakolb case 'm': 4262685Sakolb sz *= KILOBYTE; 4272685Sakolb /* FALLTHRU */ 4282685Sakolb case 'K': 4292685Sakolb case 'k': 4302685Sakolb sz *= KILOBYTE; 4312685Sakolb /* FALLTHRU */ 4322685Sakolb case 'B': 4332685Sakolb case 'b': 4342685Sakolb (*endptr)++; 4352685Sakolb /* FALLTHRU */ 4362685Sakolb default: 4372685Sakolb break; 4382685Sakolb } 4392685Sakolb return (sz); 4402685Sakolb } 4412685Sakolb 4422685Sakolb /* 4432685Sakolb * Inserts newaddr into list. dups indicates whether we allow duplicate 4442685Sakolb * addr entries in the list (valid values are NODUPS and YESDUPS). 4452685Sakolb */ 4462685Sakolb static void 4472685Sakolb insert_addr(saddr_t **list, saddr_t *newaddr, int dups) 4482685Sakolb { 4492685Sakolb saddr_t *prev = *list; 4502685Sakolb saddr_t *psaddr; 4512685Sakolb 4522685Sakolb if (*list == NULL) { 4532685Sakolb newaddr->next = *list; 4542685Sakolb *list = newaddr; 4552685Sakolb return; 4562685Sakolb } 4572685Sakolb 4582685Sakolb for (psaddr = (*list)->next; psaddr != NULL; psaddr = psaddr->next) { 4592685Sakolb if ((dups == NODUPS) && (psaddr->addr == newaddr->addr)) { 4602685Sakolb free(newaddr); 4612685Sakolb return; 4622685Sakolb } 4632685Sakolb 4642685Sakolb /* 4652685Sakolb * primary level of comparison is by address; smaller addr 1st 4662685Sakolb * secondary level of comparison is by length; bigger length 1st 4672685Sakolb */ 4682685Sakolb if ((psaddr->addr > newaddr->addr) || 4692685Sakolb (psaddr->addr == newaddr->addr && 4702685Sakolb psaddr->length < newaddr->length)) 4712685Sakolb break; 4722685Sakolb 4732685Sakolb prev = psaddr; 4742685Sakolb } 4752685Sakolb 4762685Sakolb prev->next = newaddr; 4772685Sakolb newaddr->next = psaddr; 4782685Sakolb } 4792685Sakolb 4802685Sakolb /* 4812685Sakolb * Deletes given element from list 4822685Sakolb */ 4832685Sakolb static void 4842685Sakolb delete_addr(saddr_t **list, saddr_t *delme) 4852685Sakolb { 4862685Sakolb saddr_t *prev = *list; 4872685Sakolb 4882685Sakolb if (delme == *list) { 4892685Sakolb *list = delme->next; 4902685Sakolb free(delme); 4912685Sakolb return; 4922685Sakolb } 4932685Sakolb 4942685Sakolb while (prev != NULL && prev->next != delme) { 4952685Sakolb prev = prev->next; 4962685Sakolb } 4972685Sakolb 4982685Sakolb if (prev) { 4992685Sakolb prev->next = delme->next; 5002685Sakolb free(delme); 5012685Sakolb } 5022685Sakolb } 5032685Sakolb 5042685Sakolb /* 5052685Sakolb * Delete entire list 5062685Sakolb */ 5072685Sakolb static void 5082685Sakolb delete_list(saddr_t **list) 5092685Sakolb { 5102685Sakolb saddr_t *psaddr = *list; 5112685Sakolb 5122685Sakolb while (psaddr != NULL) { 5132685Sakolb saddr_t *temp = psaddr; 5142685Sakolb 5152685Sakolb psaddr = psaddr->next; 5162685Sakolb free(temp); 5172685Sakolb } 5182685Sakolb *list = NULL; 5192685Sakolb } 5202685Sakolb 5212685Sakolb static saddr_t * 5222685Sakolb parse_suboptions(char *value) 5232685Sakolb { 5242685Sakolb char *endptr; 5252685Sakolb saddr_t *psaddr = malloc(sizeof (saddr_t)); 5262685Sakolb 5272685Sakolb /* 5282685Sakolb * This must (better) be a segment addr 5292685Sakolb */ 5302685Sakolb psaddr->addr = 5312685Sakolb strtoull(value, &endptr, 16); 5322685Sakolb 5332685Sakolb /* 5342685Sakolb * Check to make sure strtoul worked correctly (a properly formatted 5352685Sakolb * string will terminate in a ':' (if size is given) or an '=' (if size 5362685Sakolb * is not specified). Also check to make sure a 0 addr wasn't returned 5372685Sakolb * indicating strtoll was unable to convert). 5382685Sakolb */ 5392685Sakolb if ((psaddr->addr == 0) || (*endptr != ':' && *endptr != '=')) { 5402685Sakolb free(psaddr); 5412685Sakolb (void) fprintf(stderr, 5422685Sakolb gettext("%s: invalid option %s\n"), 5432685Sakolb progname, value); 5442685Sakolb usage(); 5452685Sakolb } else { 5462685Sakolb /* init other fields */ 5472685Sakolb psaddr->length = 0; 5482685Sakolb psaddr->adv = NO_ADVICE; 5492685Sakolb psaddr->next = NULL; 5502685Sakolb 5512685Sakolb /* skip past address */ 5522685Sakolb value = endptr; 5532685Sakolb 5542685Sakolb /* check for length */ 5552685Sakolb if (*value == ':') { 5562685Sakolb /* skip the ":" */ 5572685Sakolb value++; 5582685Sakolb psaddr->length = atosz(value, &endptr); 5592685Sakolb } 5602685Sakolb 5612685Sakolb if (*endptr != '=') { 5622685Sakolb (void) fprintf(stderr, 5632685Sakolb gettext("%s: invalid option %s\n"), 5642685Sakolb progname, value); 5652685Sakolb /* 5662685Sakolb * if improperly formatted, free mem, print usage, and 5672685Sakolb * exit Note: usage ends with a call to exit() 5682685Sakolb */ 5692685Sakolb free(psaddr); 5702685Sakolb usage(); 5712685Sakolb } 5722685Sakolb /* skip the "=" */ 5732685Sakolb value = endptr + 1; 5742685Sakolb at_map |= (1 << AT_SEG); 5752685Sakolb psaddr->adv = 5762685Sakolb get_advice(value); 5772685Sakolb } 5782685Sakolb 5792685Sakolb return (psaddr); 5802685Sakolb } 5812685Sakolb 5822685Sakolb /* 5832685Sakolb * Create labels for non-anon, non-heap mappings 5842685Sakolb */ 5852685Sakolb static char * 5862685Sakolb make_name(struct ps_prochandle *Pr, uintptr_t addr, const char *mapname, 5872685Sakolb char *buf, size_t bufsz) 5882685Sakolb { 5892685Sakolb const pstatus_t *Psp = Pstatus(Pr); 5902685Sakolb char fname[100]; 5912685Sakolb struct stat statb; 5922685Sakolb int len; 5932685Sakolb 5942685Sakolb if (strcmp(mapname, "a.out") == 0 && 5952685Sakolb Pexecname(Pr, buf, bufsz) != NULL) 5962685Sakolb return (buf); 5972685Sakolb 5982685Sakolb if (Pobjname(Pr, addr, buf, bufsz) != NULL) { 5992685Sakolb if ((len = resolvepath(buf, buf, bufsz)) > 0) { 6002685Sakolb buf[len] = '\0'; 6012685Sakolb return (buf); 6022685Sakolb } 6032685Sakolb } 6042685Sakolb 6052685Sakolb if (*mapname != '\0') { 6062685Sakolb (void) snprintf(fname, sizeof (fname), "/proc/%d/object/%s", 6072685Sakolb (int)Psp->pr_pid, mapname); 6082685Sakolb if (stat(fname, &statb) == 0) { 6092685Sakolb dev_t dev = statb.st_dev; 6102685Sakolb ino_t ino = statb.st_ino; 6112685Sakolb (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", 6122685Sakolb (ulong_t)major(dev), (ulong_t)minor(dev), ino); 6132685Sakolb return (buf); 6142685Sakolb } 6152685Sakolb } 6162685Sakolb 6172685Sakolb return (NULL); 6182685Sakolb } 6192685Sakolb 6202685Sakolb /* 6212685Sakolb * Create label for anon mappings 6222685Sakolb */ 6232685Sakolb static char * 6242685Sakolb anon_name(char *name, const pstatus_t *Psp, 6252685Sakolb uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypes) 6262685Sakolb { 6272685Sakolb if (mflags & MA_ISM) { 6282685Sakolb if (shmid == -1) 6292685Sakolb (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 6302685Sakolb (mflags & MA_NORESERVE) ? "ism" : "dism"); 6312685Sakolb else 6322685Sakolb (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 6332685Sakolb (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 6342685Sakolb *mtypes |= (1 << AT_SHARED); 6352685Sakolb } else if (mflags & MA_SHM) { 6362685Sakolb if (shmid == -1) 6372685Sakolb (void) sprintf(name, " [ shmid=null ]"); 6382685Sakolb else 6392685Sakolb (void) sprintf(name, " [ shmid=0x%x ]", shmid); 6402685Sakolb *mtypes |= (1 << AT_SHARED); 6412685Sakolb 6422685Sakolb } else if (vaddr + size > Psp->pr_stkbase && 6432685Sakolb vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 6442685Sakolb (void) strcpy(name, " [ stack ]"); 6452685Sakolb *mtypes |= (1 << AT_STACK); 6462685Sakolb 6472685Sakolb } else if ((mflags & MA_ANON) && 6482685Sakolb vaddr + size > Psp->pr_brkbase && 6492685Sakolb vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 6502685Sakolb (void) strcpy(name, " [ heap ]"); 6512685Sakolb *mtypes |= (1 << AT_HEAP); 6522685Sakolb 6532685Sakolb } else { 6542685Sakolb lwpstack_t key, *stk; 6552685Sakolb 6562685Sakolb key.lwps_stack.ss_sp = (void *)vaddr; 6572685Sakolb key.lwps_stack.ss_size = size; 6582685Sakolb if (nstacks > 0 && 6592685Sakolb (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 6602685Sakolb cmpstacks)) != NULL) { 6612685Sakolb (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 6622685Sakolb (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 6632685Sakolb "altstack" : "stack", 6642685Sakolb stk->lwps_lwpid); 6652685Sakolb *mtypes |= (1 << AT_STACK); 6662685Sakolb } else { 6672685Sakolb (void) strcpy(name, " [ anon ]"); 6682685Sakolb *mtypes |= (1 << AT_PRIVM); 6692685Sakolb } 6702685Sakolb } 6712685Sakolb 6722685Sakolb return (name); 6732685Sakolb } 6742685Sakolb 6752685Sakolb /* 6762685Sakolb * Create linked list of mappings for current process 6772685Sakolb * In addition, add generic advice and raw advice 6782685Sakolb * entries to merged_list. 6792685Sakolb */ 6802685Sakolb /* ARGSUSED */ 6812685Sakolb static int 6822685Sakolb create_maplist(void *arg, const prmap_t *pmp, const char *object_name) 6832685Sakolb { 6842685Sakolb const pstatus_t *Psp = Pstatus(Pr); 6852685Sakolb mapnode_t *newmap = malloc(sizeof (mapnode_t)); 6862685Sakolb saddr_t *newaddr; 6872685Sakolb saddr_t *psaddr; 6882685Sakolb char *lname = NULL; 6892685Sakolb int i; 6902685Sakolb 6912685Sakolb if (interrupt) 6922685Sakolb return (0); 6932685Sakolb 6942685Sakolb newmap->pmp = malloc(sizeof (prmap_t)); 6952685Sakolb newmap->label[0] = '\0'; 6962685Sakolb newmap->mtypes = 0; 6972685Sakolb newmap->next = NULL; 6982685Sakolb (void) memcpy(newmap->pmp, pmp, sizeof (prmap_t)); 6992685Sakolb 7002685Sakolb /* 7012685Sakolb * If the mapping is not anon or not part of the heap, make a name 7022685Sakolb * for it. We don't want to report the heap as a.out's data. 7032685Sakolb */ 7042685Sakolb if (!(pmp->pr_mflags & MA_ANON) || 7052685Sakolb (pmp->pr_vaddr + pmp->pr_size <= Psp->pr_brkbase || 7062685Sakolb pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize)) { 7072685Sakolb lname = make_name(Pr, pmp->pr_vaddr, pmp->pr_mapname, 7082685Sakolb newmap->label, sizeof (newmap->label)); 7092685Sakolb if (pmp->pr_mflags & MA_SHARED) 7102685Sakolb newmap->mtypes |= 1 << AT_SHARED; 7112685Sakolb else 7122685Sakolb newmap->mtypes |= 1 << AT_PRIVM; 7132685Sakolb } 7142685Sakolb 7152685Sakolb if (lname == NULL && (pmp->pr_mflags & MA_ANON)) { 7162685Sakolb lname = anon_name(newmap->label, Psp, pmp->pr_vaddr, 7172685Sakolb pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid, 7182685Sakolb &newmap->mtypes); 7192685Sakolb } 7202685Sakolb 7212685Sakolb /* 7222685Sakolb * Add raw advice that applies to this mapping to the merged_list 7232685Sakolb */ 7242685Sakolb psaddr = rawadv_list; 7252685Sakolb /* 7262685Sakolb * Advance to point in rawadv_list that applies to this mapping 7272685Sakolb */ 7282685Sakolb while (psaddr && psaddr->addr < pmp->pr_vaddr) 7292685Sakolb psaddr = psaddr->next; 7302685Sakolb /* 7312685Sakolb * Copy over to merged_list, check to see if size needs to be filled in 7322685Sakolb */ 7332685Sakolb while (psaddr && psaddr->addr < (pmp->pr_vaddr + pmp->pr_size)) { 7342685Sakolb newaddr = malloc(sizeof (saddr_t)); 7352685Sakolb (void) memcpy(newaddr, psaddr, sizeof (saddr_t)); 7362685Sakolb insert_addr(&merged_list, newaddr, YESDUPS); 7372685Sakolb /* 7382685Sakolb * For raw advice that is given without size, try to default 7392685Sakolb * size to size of mapping (only allowed if raw adv addr is 7402685Sakolb * equal to beginning of mapping). Don't change the entry 7412685Sakolb * in rawadv_list, only in the merged_list as the mappings 7422685Sakolb * (and thus the default sizes) will be different for 7432685Sakolb * different processes. 7442685Sakolb */ 7452685Sakolb if ((pmp->pr_vaddr == psaddr->addr) && (psaddr->length == 0)) 7462685Sakolb newaddr->length = pmp->pr_size; 7472685Sakolb psaddr = psaddr->next; 7482685Sakolb } 7492685Sakolb 7502685Sakolb /* 7512685Sakolb * Put mapping into merged list with no advice, then 7522685Sakolb * check to see if any generic advice applies. 7532685Sakolb */ 7542685Sakolb newaddr = malloc(sizeof (saddr_t)); 7552685Sakolb newaddr->addr = pmp->pr_vaddr; 7562685Sakolb newaddr->length = pmp->pr_size; 7572685Sakolb newaddr->adv = NO_ADVICE; 7582685Sakolb insert_addr(&merged_list, newaddr, YESDUPS); 7592685Sakolb 7602685Sakolb newmap->mtypes &= at_map; 7612685Sakolb for (i = AT_STACK; i >= AT_PRIVM; i--) { 7622685Sakolb if (newmap->mtypes & (1 << i)) { 7632685Sakolb assert(generic_adv[i] != NO_ADVICE); 7642685Sakolb newaddr->adv = generic_adv[i]; 7652685Sakolb break; 7662685Sakolb } 7672685Sakolb } 7682685Sakolb 7692685Sakolb /* 7702685Sakolb * Add to linked list of mappings 7712685Sakolb */ 7722685Sakolb if (maplist_tail == NULL) { 7732685Sakolb maplist_head = maplist_tail = newmap; 7742685Sakolb } else { 7752685Sakolb maplist_tail->next = newmap; 7762685Sakolb maplist_tail = newmap; 7772685Sakolb } 7782685Sakolb 7792685Sakolb 7802685Sakolb return (0); 7812685Sakolb } 7822685Sakolb 7832685Sakolb /* 7842685Sakolb * Traverse advice list and apply all applicable advice to each region 7852685Sakolb */ 7862685Sakolb static int 7872685Sakolb apply_advice(saddr_t **advicelist) 7882685Sakolb { 7892685Sakolb saddr_t *psaddr = *advicelist; 7902685Sakolb saddr_t *next; 7912685Sakolb int i; 7922685Sakolb 7932685Sakolb 7942685Sakolb while (!interrupt && psaddr != NULL) { 7952685Sakolb /* 7962685Sakolb * Save next pointer since element may be removed before 7972685Sakolb * we get a chance to advance psaddr. 7982685Sakolb */ 7992685Sakolb next = psaddr->next; 8002685Sakolb 8012685Sakolb /* 8022685Sakolb * Since mappings have been added to the merged list 8032685Sakolb * even if no generic advice was given for the map, 8042685Sakolb * check to make sure advice exists before bothering 8052685Sakolb * with the for loop. 8062685Sakolb */ 8072685Sakolb if (psaddr->adv != NO_ADVICE) { 8082685Sakolb for (i = MADV_NORMAL; i <= MADV_ACCESS_MANY; i++) { 8092685Sakolb if ((psaddr->adv & (1 << i)) && 8102685Sakolb (pr_madvise(Pr, (caddr_t)psaddr->addr, 8112685Sakolb psaddr->length, i) < 0)) { 8122685Sakolb /* 8132685Sakolb * madvise(3C) call failed trying to 8142685Sakolb * apply advice output error and remove 8152685Sakolb * from advice list 8162685Sakolb */ 8172685Sakolb (void) fprintf(stderr, 8182685Sakolb gettext("Error applying " 8192685Sakolb "advice (%s) to memory range " 8202685Sakolb "[%lx, %lx):\n"), 8212685Sakolb advicestr[i], (ulong_t)psaddr->addr, 8222685Sakolb (ulong_t)psaddr->addr + 8232685Sakolb psaddr->length); 8242685Sakolb perror("madvise"); 8252685Sakolb /* 8262685Sakolb * Clear this advice from the advice 8272685Sakolb * mask. If no more advice is given 8282685Sakolb * for this element, remove element 8292685Sakolb * from list. 8302685Sakolb */ 8312685Sakolb psaddr->adv &= ~(1 << i); 8322685Sakolb if (psaddr->adv == 0) { 8332685Sakolb delete_addr(advicelist, psaddr); 8342685Sakolb break; 8352685Sakolb } 8362685Sakolb } 8372685Sakolb } 8382685Sakolb } 8392685Sakolb psaddr = next; 8402685Sakolb } 8412685Sakolb return (0); 8422685Sakolb } 8432685Sakolb 8442685Sakolb /* 8452685Sakolb * Set advice but keep mutual exclusive property of advice groupings 8462685Sakolb */ 8472685Sakolb static void 8482685Sakolb set_advice(int *combined_adv, int new_adv) { 8492685Sakolb /* 8502685Sakolb * Since advice falls in 3 groups of mutually exclusive options, 8512685Sakolb * clear previous value if new advice overwrites that group. 8522685Sakolb */ 8532685Sakolb 8542685Sakolb /* 8552685Sakolb * If this is the first advice to be applied, clear invalid value (-1) 8562685Sakolb */ 8572685Sakolb if (*combined_adv == -1) 8582685Sakolb *combined_adv = 0; 8592685Sakolb 8602685Sakolb if (new_adv & GRP1_ADV) 8612685Sakolb *combined_adv &= ~GRP1_ADV; 8622685Sakolb else if (new_adv & GRP2_ADV) 8632685Sakolb *combined_adv &= ~GRP2_ADV; 8642685Sakolb else 8652685Sakolb *combined_adv &= ~GRP3_ADV; 8662685Sakolb 8672685Sakolb *combined_adv |= new_adv; 8682685Sakolb } 8692685Sakolb 8702685Sakolb /* 8712685Sakolb * Create chopped list from merged list for use with verbose output 8722685Sakolb */ 8732685Sakolb static void 8742685Sakolb create_choplist(saddr_t **choppedlist, saddr_t *mergedlist) 8752685Sakolb { 8762685Sakolb saddr_t *mlptr, *clptr; 8772685Sakolb 8782685Sakolb for (mlptr = mergedlist; mlptr != NULL; mlptr = mlptr->next) { 8792685Sakolb clptr = malloc(sizeof (saddr_t)); 8802685Sakolb clptr->addr = mlptr->addr; 8812685Sakolb clptr->length = 0; 8822685Sakolb /* 8832685Sakolb * Initialize the adv to -1 as an indicator for invalid 8842685Sakolb * elements in the chopped list (created from gaps between 8852685Sakolb * memory maps). 8862685Sakolb */ 8872685Sakolb clptr->adv = -1; 8882685Sakolb clptr->next = NULL; 8892685Sakolb insert_addr(choppedlist, clptr, NODUPS); 8902685Sakolb 8912685Sakolb clptr = malloc(sizeof (saddr_t)); 8922685Sakolb clptr->addr = mlptr->addr + mlptr->length; 8932685Sakolb clptr->length = 0; 8942685Sakolb /* 8952685Sakolb * Again, initialize to -1 as an indicatorfor invalid elements 8962685Sakolb */ 8972685Sakolb clptr->adv = -1; 8982685Sakolb clptr->next = NULL; 8992685Sakolb insert_addr(choppedlist, clptr, NODUPS); 9002685Sakolb } 9012685Sakolb 9022685Sakolb for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) { 9032685Sakolb if (clptr->next) 9042685Sakolb clptr->length = clptr->next->addr - clptr->addr; 9052685Sakolb else { 9062685Sakolb /* 9072685Sakolb * must be last element, now that we've calculated 9082685Sakolb * all segment lengths, we can remove this node 9092685Sakolb */ 9102685Sakolb delete_addr(choppedlist, clptr); 9112685Sakolb } 9122685Sakolb } 9132685Sakolb 9142685Sakolb for (mlptr = mergedlist; mlptr != NULL; mlptr = mlptr->next) { 9152685Sakolb for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) { 9162685Sakolb if (mlptr->addr <= clptr->addr && 9172685Sakolb mlptr->addr + mlptr->length >= 9182685Sakolb clptr->addr + clptr->length) 9192685Sakolb /* 9202685Sakolb * set_advice() will take care of conflicting 9212685Sakolb * advice by taking only the last advice 9222685Sakolb * applied for each of the 3 groups of advice. 9232685Sakolb */ 9242685Sakolb set_advice(&clptr->adv, mlptr->adv); 9252685Sakolb if (mlptr->addr + mlptr->length < 9262685Sakolb clptr->addr) 9272685Sakolb break; 9282685Sakolb } 9292685Sakolb } 9302685Sakolb } 9312685Sakolb 9322685Sakolb /* 9332685Sakolb * Print advice in pmap style for verbose output 9342685Sakolb */ 9352685Sakolb static void 9362685Sakolb print_advice(saddr_t *advlist, mapnode_t *maplist) 9372685Sakolb { 9382685Sakolb saddr_t *psaddr = advlist; 9392685Sakolb mapnode_t *pmapnode; 9402685Sakolb char *advice; 9412685Sakolb 9422685Sakolb pmapnode = maplist; 9432685Sakolb 9442685Sakolb while (psaddr) { 9452685Sakolb /* 9462685Sakolb * Using indicator flag from create_choppedlist, we know 9472685Sakolb * which entries in the chopped_list are gaps and should 9482685Sakolb * not be printed. 9492685Sakolb */ 9502685Sakolb if (psaddr->adv == -1) { 9512685Sakolb psaddr = psaddr->next; 9522685Sakolb continue; 9532685Sakolb } 9542685Sakolb 9552685Sakolb while (pmapnode && (pmapnode->pmp->pr_vaddr + 9562685Sakolb pmapnode->pmp->pr_size <= psaddr->addr)) 9572685Sakolb pmapnode = pmapnode->next; 9582685Sakolb 9592685Sakolb advice = advtostr(psaddr->adv); 9602685Sakolb 9612685Sakolb /* 9622685Sakolb * Print segment mapping and advice if there is any, or just a 9632685Sakolb * segment mapping. 9642685Sakolb */ 9652685Sakolb if (strlen(advice) > 0) { 9662685Sakolb (void) printf("%.*lX %*uK %6s %s\t%s\n", 9672685Sakolb addr_width, (ulong_t)psaddr->addr, size_width - 1, 9682685Sakolb (int)ROUNDUP_KB(psaddr->length), 9692685Sakolb mflags(pmapnode->pmp->pr_mflags), pmapnode->label, 9702685Sakolb advice); 9712685Sakolb } else { 9722685Sakolb (void) printf("%.*lX %*uK %6s %s\n", 9732685Sakolb addr_width, (ulong_t)psaddr->addr, size_width - 1, 9742685Sakolb (int)ROUNDUP_KB(psaddr->length), 9752685Sakolb mflags(pmapnode->pmp->pr_mflags), pmapnode->label); 9762685Sakolb } 9772685Sakolb psaddr = psaddr->next; 9782685Sakolb 9792685Sakolb } 9802685Sakolb } 9812685Sakolb 9822685Sakolb /* 9832685Sakolb * Call madvise(3c) in the context of the target process 9842685Sakolb */ 9852685Sakolb static int 9862685Sakolb pr_madvise(struct ps_prochandle *Pr, caddr_t addr, size_t len, int advice) 9872685Sakolb { 9882685Sakolb return (pr_memcntl(Pr, addr, len, MC_ADVISE, 9892685Sakolb (caddr_t)(uintptr_t)advice, 0, 0)); 9902685Sakolb } 9912685Sakolb 9922685Sakolb static char * 9932685Sakolb mflags(uint_t arg) 9942685Sakolb { 9952685Sakolb static char code_buf[80]; 9962685Sakolb 9972685Sakolb /* 9982685Sakolb * rwxsR 9992685Sakolb * 10002685Sakolb * r - segment is readable 10012685Sakolb * w - segment is writable 10022685Sakolb * x - segment is executable 10032685Sakolb * s - segment is shared 10042685Sakolb * R - segment is mapped MAP_NORESERVE 10052685Sakolb * 10062685Sakolb */ 10072685Sakolb (void) snprintf(code_buf, sizeof (code_buf), "%c%c%c%c%c ", 10082685Sakolb arg & MA_READ ? 'r' : '-', 10092685Sakolb arg & MA_WRITE ? 'w' : '-', 10102685Sakolb arg & MA_EXEC ? 'x' : '-', 10112685Sakolb arg & MA_SHARED ? 's' : '-', 10122685Sakolb arg & MA_NORESERVE ? 'R' : '-'); 10132685Sakolb 10142685Sakolb return (code_buf); 10152685Sakolb } 10162685Sakolb 10172685Sakolb /* 10182685Sakolb * Convert advice to a string containing a commented list of applicable advice 10192685Sakolb */ 10202685Sakolb static char * 10212685Sakolb advtostr(int adv) 10222685Sakolb { 10232685Sakolb static char buf[50]; 10242685Sakolb int i; 10252685Sakolb 10262685Sakolb *buf = '\0'; 10272685Sakolb 10282685Sakolb if (adv != NO_ADVICE) { 10292685Sakolb for (i = MADV_NORMAL; i <= MADV_ACCESS_MANY; i++) { 10302685Sakolb if (adv & (1 << i)) { 10312685Sakolb /* 10322685Sakolb * check if it's the first advice entry 10332685Sakolb */ 10342685Sakolb if (*buf == '\0') 10352685Sakolb (void) snprintf(buf, sizeof (buf) - 1, 10362685Sakolb "<= %s", advicestr[i]); 10372685Sakolb else 10382685Sakolb (void) snprintf(buf, sizeof (buf) - 1, 10392685Sakolb "%s,%s", buf, advicestr[i]); 10402685Sakolb } 10412685Sakolb } 10422685Sakolb } 10432685Sakolb 10442685Sakolb return (buf); 10452685Sakolb } 10462685Sakolb 10472685Sakolb /* 10482685Sakolb * Handler for catching signals from terminal 10492685Sakolb */ 10502685Sakolb /* ARGSUSED */ 10512685Sakolb static void 10522685Sakolb intr(int sig) 10532685Sakolb { 10542685Sakolb interrupt++; 10552685Sakolb } 10562685Sakolb 10572685Sakolb int 10582685Sakolb main(int argc, char **argv) 10592685Sakolb { 10602685Sakolb int Fflag = 0; 10612685Sakolb int rc = 0; 10622685Sakolb int opt, subopt; 10632685Sakolb int tmpadv; 10642685Sakolb char *options, *value; 10652685Sakolb saddr_t *psaddr; 10662685Sakolb mapnode_t *pmapnode, *tempmapnode; 10672685Sakolb 10682685Sakolb (void) setlocale(LC_ALL, ""); 10692685Sakolb (void) textdomain(TEXT_DOMAIN); 10702685Sakolb 10712685Sakolb /* 10722685Sakolb * Get name of program for error messages 10732685Sakolb */ 10742685Sakolb progname = basename(argv[0]); 10752685Sakolb 10762685Sakolb /* 10772685Sakolb * Not much to do when only name of program given 10782685Sakolb */ 10792685Sakolb if (argc == 1) 10802685Sakolb usage(); 10812685Sakolb 10822685Sakolb /* 10832685Sakolb * Catch signals from terminal, so they can be handled asynchronously 10842685Sakolb * when we're ready instead of when we're not (;-) 10852685Sakolb */ 10862685Sakolb if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 10872685Sakolb (void) sigset(SIGHUP, intr); 10882685Sakolb if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 10892685Sakolb (void) sigset(SIGINT, intr); 10902685Sakolb if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 10912685Sakolb (void) sigset(SIGQUIT, intr); 10922685Sakolb (void) sigset(SIGPIPE, intr); 10932685Sakolb (void) sigset(SIGTERM, intr); 10942685Sakolb 10952685Sakolb /* 10962685Sakolb * Parse options, record generic advice if any and create 10972685Sakolb * rawadv_list from specific address advice. 10982685Sakolb */ 10992685Sakolb 11002685Sakolb while ((opt = getopt(argc, argv, "Fo:v")) != EOF) { 11012685Sakolb switch (opt) { 11022685Sakolb case 'o': 11032685Sakolb options = optarg; 11042685Sakolb while (*options != '\0') { 11052685Sakolb subopt = getsubopt(&options, suboptstr, 11062685Sakolb &value); 11072685Sakolb switch (subopt) { 11082685Sakolb case AT_PRIVM: 11092685Sakolb case AT_HEAP: 11102685Sakolb case AT_SHARED: 11112685Sakolb case AT_STACK: 11122685Sakolb at_map |= (1 << subopt); 11132685Sakolb tmpadv = get_advice(value); 11142685Sakolb set_advice(&generic_adv[subopt], 11152685Sakolb tmpadv); 11162685Sakolb break; 11172685Sakolb default: 11182685Sakolb at_map |= (1 << AT_SEG); 11192685Sakolb psaddr = parse_suboptions(value); 11202685Sakolb if (psaddr == NULL) { 11212685Sakolb usage(); 11222685Sakolb } else { 11232685Sakolb insert_addr(&rawadv_list, 11242685Sakolb psaddr, YESDUPS); 11252685Sakolb } 11262685Sakolb break; 11272685Sakolb } 11282685Sakolb } 11292685Sakolb break; 11302685Sakolb case 'v': 11312685Sakolb opt_verbose = 1; 11322685Sakolb break; 11332685Sakolb case 'F': /* force grabbing (no O_EXCL) */ 11342685Sakolb Fflag = PGRAB_FORCE; 11352685Sakolb break; 11362685Sakolb default: 11372685Sakolb usage(); 11382685Sakolb break; 11392685Sakolb } 11402685Sakolb } 11412685Sakolb 11422685Sakolb argc -= optind; 11432685Sakolb argv += optind; 11442685Sakolb 11452685Sakolb if (argc <= 0) { 11462685Sakolb usage(); 11472685Sakolb } 11482685Sakolb 1149*7032Sakolb (void) proc_initstdio(); 1150*7032Sakolb 11512685Sakolb /* 11522685Sakolb * Iterate through all pid arguments, create new merged_list, maplist, 11532685Sakolb * (and chopped_list if using verbose output) based on each process' 11542685Sakolb * memory map. 11552685Sakolb */ 11562685Sakolb 11572685Sakolb while (!interrupt && argc-- > 0) { 11582685Sakolb char *arg; 11592685Sakolb int gcode; 11602685Sakolb psinfo_t psinfo; 11612685Sakolb 1162*7032Sakolb (void) proc_flushstdio(); 1163*7032Sakolb 11642685Sakolb if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_PIDS, 11652685Sakolb PGRAB_RETAIN | Fflag, &gcode)) == NULL) { 11662685Sakolb (void) fprintf(stderr, 11672685Sakolb gettext("%s: cannot examine %s: %s\n"), 11682685Sakolb progname, arg, Pgrab_error(gcode)); 11692685Sakolb rc++; 11702685Sakolb continue; 11712685Sakolb } 11722685Sakolb 11732685Sakolb 11742685Sakolb addr_width = 11752685Sakolb (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 16 : 8; 11762685Sakolb size_width = 11772685Sakolb (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) ? 11 : 8; 11782685Sakolb (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t)); 11792685Sakolb 11802685Sakolb if (opt_verbose) { 11812685Sakolb proc_unctrl_psinfo(&psinfo); 11822685Sakolb (void) printf("%d:\t%.70s\n", 11832685Sakolb (int)psinfo.pr_pid, psinfo.pr_psargs); 11842685Sakolb } 11852685Sakolb 11862685Sakolb /* 11872685Sakolb * Get mappings for a process unless it is a system process. 11882685Sakolb */ 11892685Sakolb if (!(Pstatus(Pr)->pr_flags & PR_ISSYS)) { 11902685Sakolb nstacks = psinfo.pr_nlwp * 2; 11912685Sakolb stacks = calloc(nstacks, sizeof (stacks[0])); 11922685Sakolb if (stacks != NULL) { 11932685Sakolb int n = 0; 11942685Sakolb (void) Plwp_iter(Pr, getstack, &n); 11952685Sakolb qsort(stacks, nstacks, sizeof (stacks[0]), 11962685Sakolb cmpstacks); 11972685Sakolb } 11982685Sakolb 11992685Sakolb if (Pgetauxval(Pr, AT_BASE) != -1L && 12002685Sakolb Prd_agent(Pr) == NULL) { 12012685Sakolb (void) fprintf(stderr, 12022685Sakolb gettext("%s: warning: " 12032685Sakolb "librtld_db failed to initialize; " 12042685Sakolb "shared library information will not " 12052685Sakolb "be available\n"), 12062685Sakolb progname); 12072685Sakolb } 12082685Sakolb 12092685Sakolb /* 12102685Sakolb * Create linked list of mappings for current process 12112685Sakolb * In addition, add generic advice and raw advice 12122685Sakolb * entries to merged_list. 12132685Sakolb * e.g. if rawadv_list contains: 12142685Sakolb * [0x38000,0x3a000) = adv1 12152685Sakolb * [0x3a000,0x3c000) = adv2 12162685Sakolb * and there is generic advice: 12172685Sakolb * heap = adv3 12182685Sakolb * where heap corresponds to 0x38000, then merged_list 12192685Sakolb * will contain: 12202685Sakolb * ... (include all other mappings from process) 12212685Sakolb * [0x38000,0x3c000) = adv3 12222685Sakolb * [0x38000,0x3a000) = adv1 12232685Sakolb * [0x3a000,0x3c000) = adv2 12242685Sakolb * ... (include all other mappings from process) 12252685Sakolb */ 12262685Sakolb assert(merged_list == NULL); 12272685Sakolb maplist_head = maplist_tail = NULL; 12282685Sakolb rc += Pmapping_iter(Pr, (proc_map_f *)create_maplist, 12292685Sakolb NULL); 12302685Sakolb 12312685Sakolb /* 12322685Sakolb * Apply advice by iterating through merged list 12332685Sakolb */ 12342685Sakolb (void) apply_advice(&merged_list); 12352685Sakolb 12362685Sakolb if (opt_verbose) { 12372685Sakolb assert(chopped_list == NULL); 12382685Sakolb /* 12392685Sakolb * Create chopped_list from merged_list 12402685Sakolb */ 12412685Sakolb create_choplist(&chopped_list, merged_list); 12422685Sakolb 12432685Sakolb /* 12442685Sakolb * Iterate through maplist and output as 12452685Sakolb * given by chopped_list 12462685Sakolb */ 12472685Sakolb print_advice(chopped_list, maplist_head); 12482685Sakolb delete_list(&chopped_list); 12492685Sakolb } 12502685Sakolb 12512685Sakolb delete_list(&merged_list); 12522685Sakolb 12532685Sakolb /* 12542685Sakolb * Clear maplist 12552685Sakolb */ 12562685Sakolb pmapnode = maplist_head; 12572685Sakolb while (pmapnode) { 12582685Sakolb tempmapnode = pmapnode; 12592685Sakolb pmapnode = pmapnode->next; 12602685Sakolb free(tempmapnode); 12612685Sakolb } 12622685Sakolb 12632685Sakolb if (stacks != NULL) { 12642685Sakolb free(stacks); 12652685Sakolb stacks = NULL; 12662685Sakolb } 12672685Sakolb } 12682685Sakolb 12692685Sakolb Prelease(Pr, 0); 12702685Sakolb } 12712685Sakolb 1272*7032Sakolb (void) proc_finistdio(); 1273*7032Sakolb 12742685Sakolb return (rc); 12752685Sakolb } 1276