c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * CDDL HEADER START
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * The contents of this file are subject to the terms of the
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Common Development and Distribution License (the "License").
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * You may not use this file except in compliance with the License.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * See the License for the specific language governing permissions
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * and limitations under the License.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * When distributing Covered Code, include this CDDL HEADER in each
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * If applicable, add the following below this CDDL HEADER, with the
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * fields enclosed by brackets "[]" replaced with your own identifying
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * information: Portions Copyright [yyyy] [name of copyright owner]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * CDDL HEADER END
7595fad9bab86562dbe8d6580c4b310bbad949b7akolb * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Use is subject to license terms.
8905f42caceb9f470ffaa19e5f6c9fb6184d12c0Bryan Cantrill * Copyright (c) 2015, Joyent, Inc. All rights reserved.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * ptool wrapper for madvise(3C) to apply memory advice to running processes
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * usage: pmadvise -o option[,option] [-v] [-F] pid ...
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * (Give "advice" about a process's memory)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * -o option[,option]: options are
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * private=<advice>
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * shared=<advice>
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * heap=<advice>
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * stack=<advice>
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * <segaddr>[:<length>]=<advice>
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * valid <advice> is one of:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * normal, random, sequential, willneed, dontneed,
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * free, access_lwp, access_many, access_default
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * -v: verbose output
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * -F: force grabbing of the target process(es)
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz * -l: show unresolved dynamic linker map names
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * pid: process id list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Advice passed to this tool are organized into various lists described here:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * rawadv_list: includes all specific advice from command line (specific
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * advice being those given to a particular address range rather
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * than a type like "heap" or "stack". In contrast, these
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * types are referred to as generic advice). Duplicates allowed.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * List ordered by addr, then by size (largest size first).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Created once per run.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * merged_list: includes all specific advice from the rawadv_list as well as
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * all generic advice. This must be recreated for each process
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * as the generic advice will apply to different regions for
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * different processes. Duplicates allowed. List ordered by addr,
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * then by size (largest size first). Created once per pid.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * chopped_list: used for verbose output only. This list parses the merged
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * list such that it eliminates any overlap and combines the
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * advice. Easiest to think of this visually: if you take all
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * the advice in the merged list and lay them down on a memory
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * range of the entire process (laying on top of each other when
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * necessary), then flatten them into one layer, combining advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * in the case of overlap, you get the chopped_list of advice.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Duplicate entries not allowed (since there is no overlap by
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * definition in this list). List ordered by addr. Created once
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * merged_list: |-----adv1----|---------adv3---------|
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * |--adv2--|--adv4--|-----adv5----|
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * chopped_list: |adv1|-adv1,2-|-adv3,4-|----adv3,5---|
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * maplist: list of memory mappings for a particular process. Used to create
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * generic advice entries for merged_list and for pmap like verbose
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * output. Created once per pid.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Multiple lists are necessary because the actual advice applied given a set
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * of generic and specific advice changes from process to process, so for each
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * pid pmadvise is passed, it must create a new merged_list from which to apply
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * advice (and a new chopped_list if verbose output is requested).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Pseudo-code:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * I. Input advice from command line
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * II. Create [raw advice list] of specific advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * III. Iterate through PIDs:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * A. Create [map list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * B. Merge generic advice and [raw advice list] into [merged list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * C. Apply advice from [merged list]; upon error:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * i. output madvise error message
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * ii. remove element from [merged list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * D. If verbose output:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * i. Create [chopped list] from [merged list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * ii. Iterate through [map list]:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * a. output advice as given by [merged list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * iii. Delete [chopped list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * E. Delete [merged list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * F. Delete [map list]
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb#define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Round up the value to the nearest kilobyte
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb#define ROUNDUP_KB(x) (((x) + (KILOBYTE - 1)) / KILOBYTE)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * The following definitions are used as the third argument in insert_addr()
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * NODUPS = no duplicates are not allowed, thus if the addr being inserted
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * already exists in the list, return without inserting again.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * YESDUPS = yes duplicates are allowed, thus always insert the addr
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * regardless of whether it already exists in the list or not.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Advice that can be passed to madvise fit into three groups that each
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * contain 3 mutually exclusive options. These groups are defined below:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Group 1: normal, random, sequential
8905f42caceb9f470ffaa19e5f6c9fb6184d12c0Bryan Cantrill * Group 2: willneed, dontneed, free, purge
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Group 3: default, accesslwp, accessmany
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Thus, advice that includes (at most) one from each group is valid.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * The following #define's are used as masks to determine which group(s) a
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * particular advice fall under.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb#define GRP1_ADV (1 << MADV_NORMAL | 1 << MADV_RANDOM | \
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb#define GRP2_ADV (1 << MADV_WILLNEED | 1 << MADV_DONTNEED | \
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb#define GRP3_ADV (1 << MADV_ACCESS_DEFAULT | 1 << MADV_ACCESS_LWP | \
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic int create_maplist(void *, const prmap_t *, const char *);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic int pr_madvise(struct ps_prochandle *, caddr_t, size_t, int);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic char *advtostr(int);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbint generic_adv[] = {NO_ADVICE, NO_ADVICE, NO_ADVICE, NO_ADVICE};
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic void set_advice(int *, int);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * The segment address advice from the command line
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * The rawadv_list + list entries for the generic advice (if any).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * This must be recreated for each PID as the memory maps might be different.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * The merged_list cut up so as to remove all overlap
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * e.g. if merged_list contained two entries:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x38000:0x3e000) = adv1
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x3a000:0x3c000) = adv2
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * the chopped list will contain three entries:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x38000:0x3a000) = adv1
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x3a000:0x3c000) = adv1,adv2
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x3c000:0x3e000) = adv1
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb "sequential",
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb "willneed",
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb "dontneed",
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb "access_default",
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb "access_lwp",
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb "access_many"
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * How many signals caught from terminal
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * We bail out as soon as possible when interrupt is set
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Interrupt handler
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic void intr(int);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Iterative function passed to Plwp_iter to
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * get alt and main stacks for given lwp.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb if (Plwp_alt_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb if (Plwp_main_stack(Pr, lsp->pr_lwpid, &stacks[*np].lwps_stack) == 0) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb return (0);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Prints usage and exits
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz gettext("usage:\t%s [-o option[,option]] [-Flv] pid ...\n"),
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb gettext(" (Give \"advice\" about a process's memory)\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " -o option[,option]: options are\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " private=<advice>\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " shared=<advice>\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " heap=<advice>\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " stack=<advice>\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " <segaddr>[:<length>]=<advice>\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " valid <advice> is one of:\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " normal, random, sequential, willneed, dontneed,\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " free, access_lwp, access_many, access_default\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " -v: verbose output\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " -F: force grabbing of the target process(es)\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " -l: show unresolved dynamic linker map names\n"
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz " pid: process id list\n"));
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Function to parse advice from options string
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Determine which advice is given, we use shifted values as
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * multiple pieces of advice may apply for a particular region.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * (See comment above regarding GRP[1,2,3]_ADV definitions for
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * breakdown of advice groups).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb (void) fprintf(stderr, gettext("%s: invalid advice: %s\n"),
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb return (-1);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Function to convert character size indicators into actual size
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * (i.e., 123M => sz = 123 * 1024 * 1024)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb return (0);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb switch (**endptr) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* FALLTHRU */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Inserts newaddr into list. dups indicates whether we allow duplicate
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * addr entries in the list (valid values are NODUPS and YESDUPS).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbinsert_addr(saddr_t **list, saddr_t *newaddr, int dups)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb for (psaddr = (*list)->next; psaddr != NULL; psaddr = psaddr->next) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb if ((dups == NODUPS) && (psaddr->addr == newaddr->addr)) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * primary level of comparison is by address; smaller addr 1st
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * secondary level of comparison is by length; bigger length 1st
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Deletes given element from list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Delete entire list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * This must (better) be a segment addr
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Check to make sure strtoul worked correctly (a properly formatted
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * string will terminate in a ':' (if size is given) or an '=' (if size
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * is not specified). Also check to make sure a 0 addr wasn't returned
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * indicating strtoll was unable to convert).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb if ((psaddr->addr == 0) || (*endptr != ':' && *endptr != '=')) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* init other fields */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* skip past address */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* check for length */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* skip the ":" */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * if improperly formatted, free mem, print usage, and
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * exit Note: usage ends with a call to exit()
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb /* skip the "=" */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Create linked list of mappings for current process
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * In addition, add generic advice and raw advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * entries to merged_list.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb/* ARGSUSED */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbcreate_maplist(void *arg, const prmap_t *pmp, const char *object_name)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb return (0);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * If the mapping is not anon or not part of the heap, make a name
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * for it. We don't want to report the heap as a.out's data.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb pmp->pr_vaddr >= Psp->pr_brkbase + Psp->pr_brksize)) {
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz lname = make_name(Pr, lflag, pmp->pr_vaddr, pmp->pr_mapname,
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz lname = anon_name(newmap->label, Psp, stacks, nstacks,
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz pmp->pr_vaddr, pmp->pr_size, pmp->pr_mflags, pmp->pr_shmid,
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Add raw advice that applies to this mapping to the merged_list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Advance to point in rawadv_list that applies to this mapping
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Copy over to merged_list, check to see if size needs to be filled in
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb while (psaddr && psaddr->addr < (pmp->pr_vaddr + pmp->pr_size)) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * For raw advice that is given without size, try to default
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * size to size of mapping (only allowed if raw adv addr is
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * equal to beginning of mapping). Don't change the entry
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * in rawadv_list, only in the merged_list as the mappings
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * (and thus the default sizes) will be different for
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * different processes.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb if ((pmp->pr_vaddr == psaddr->addr) && (psaddr->length == 0))
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Put mapping into merged list with no advice, then
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * check to see if any generic advice applies.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Add to linked list of mappings
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb return (0);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Traverse advice list and apply all applicable advice to each region
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Save next pointer since element may be removed before
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * we get a chance to advance psaddr.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Since mappings have been added to the merged list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * even if no generic advice was given for the map,
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * check to make sure advice exists before bothering
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * with the for loop.
8905f42caceb9f470ffaa19e5f6c9fb6184d12c0Bryan Cantrill for (i = MADV_NORMAL; i <= MADV_PURGE; i++) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * madvise(3C) call failed trying to
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * apply advice output error and remove
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * from advice list
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz "advice (%s) to memory range "
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz "[%lx, %lx):\n"),
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Clear this advice from the advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * mask. If no more advice is given
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * for this element, remove element
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * from list.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb return (0);
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Set advice but keep mutual exclusive property of advice groupings
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Since advice falls in 3 groups of mutually exclusive options,
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * clear previous value if new advice overwrites that group.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * If this is the first advice to be applied, clear invalid value (-1)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Create chopped list from merged list for use with verbose output
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbcreate_choplist(saddr_t **choppedlist, saddr_t *mergedlist)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb for (mlptr = mergedlist; mlptr != NULL; mlptr = mlptr->next) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Initialize the adv to -1 as an indicator for invalid
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * elements in the chopped list (created from gaps between
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * memory maps).
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Again, initialize to -1 as an indicatorfor invalid elements
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * must be last element, now that we've calculated
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * all segment lengths, we can remove this node
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb for (mlptr = mergedlist; mlptr != NULL; mlptr = mlptr->next) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb for (clptr = *choppedlist; clptr != NULL; clptr = clptr->next) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * set_advice() will take care of conflicting
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * advice by taking only the last advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * applied for each of the 3 groups of advice.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Print advice in pmap style for verbose output
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Using indicator flag from create_choppedlist, we know
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * which entries in the chopped_list are gaps and should
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * not be printed.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Print segment mapping and advice if there is any, or just a
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * segment mapping.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Call madvise(3c) in the context of the target process
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbpr_madvise(struct ps_prochandle *Pr, caddr_t addr, size_t len, int advice)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic char *
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * r - segment is readable
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * w - segment is writable
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * x - segment is executable
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * s - segment is shared
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * R - segment is mapped MAP_NORESERVE
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb (void) snprintf(code_buf, sizeof (code_buf), "%c%c%c%c%c ",
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Convert advice to a string containing a commented list of applicable advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolbstatic char *
8905f42caceb9f470ffaa19e5f6c9fb6184d12c0Bryan Cantrill for (i = MADV_NORMAL; i <= MADV_PURGE; i++) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * check if it's the first advice entry
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Handler for catching signals from terminal
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb/* ARGSUSED */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Get name of program for error messages
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Not much to do when only name of program given
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Catch signals from terminal, so they can be handled asynchronously
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * when we're ready instead of when we're not (;-)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Parse options, record generic advice if any and create
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * rawadv_list from specific address advice.
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz while ((opt = getopt(argc, argv, "Flo:v")) != EOF) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb switch (opt) {
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz case 'l': /* show unresolved link map names */
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb if (argc <= 0) {
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Iterate through all pid arguments, create new merged_list, maplist,
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * (and chopped_list if using verbose output) based on each process'
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * memory map.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Get mappings for a process unless it is a system process.
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz "librtld_db failed to initialize; "
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz "shared library information will not "
186f7fbf5e07d046b50e4e15c32b21f109b76c80Edward Pilatowicz "be available\n"),
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Create linked list of mappings for current process
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * In addition, add generic advice and raw advice
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * entries to merged_list.
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * e.g. if rawadv_list contains:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x38000,0x3a000) = adv1
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x3a000,0x3c000) = adv2
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * and there is generic advice:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * heap = adv3
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * where heap corresponds to 0x38000, then merged_list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * will contain:
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * ... (include all other mappings from process)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x38000,0x3c000) = adv3
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x38000,0x3a000) = adv1
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * [0x3a000,0x3c000) = adv2
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * ... (include all other mappings from process)
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Apply advice by iterating through merged list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Create chopped_list from merged_list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Iterate through maplist and output as
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * given by chopped_list
c64027834c5ffc60c557c2b12555e0cd4d30320cakolb * Clear maplist