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