root/usr/src/cmd/ptools/pmap/pmap_common.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
/*
 * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
 */

#include <fcntl.h>
#include <libproc.h>
#include <limits.h>
#include <stdio.h>
#include <strings.h>
#include <sys/mkdev.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "pmap_common.h"

/*
 * We compare the high memory addresses since stacks are faulted in from
 * high memory addresses to low memory addresses, and our prmap_t
 * structures identify only the range of addresses that have been faulted
 * in so far.
 */
int
cmpstacks(const void *ap, const void *bp)
{
        const lwpstack_t *as = ap;
        const lwpstack_t *bs = bp;
        uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size;
        uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size;

        if (a < b)
                return (1);
        if (a > b)
                return (-1);
        return (0);
}

/*
 * Create labels for non-anon, non-heap mappings
 */
char *
make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr,
    const char *mapname, char *buf, size_t bufsz)
{
        const pstatus_t         *Psp = Pstatus(Pr);
        struct stat             statb;
        char                    path[PATH_MAX];
        int                     len;

        if (lflag || Pstate(Pr) == PS_DEAD) {
                if (Pobjname(Pr, addr, buf, bufsz) != NULL)
                        return (buf);
        } else {
                if (Pobjname_resolved(Pr, addr, buf, bufsz) != NULL) {
                        /* Verify that the path exists */
                        if ((len = resolvepath(buf, buf, bufsz)) > 0) {
                                buf[len] = '\0';
                                return (buf);
                        }
                }
        }

        if (Pstate(Pr) == PS_DEAD || *mapname == '\0')
                return (NULL);

        /* first see if we can find a path via /proc */
        (void) snprintf(path, sizeof (path), "/proc/%d/path/%s",
            (int)Psp->pr_pid, mapname);
        len = readlink(path, buf, bufsz - 1);
        if (len >= 0) {
                buf[len] = '\0';
                return (buf);
        }

        /* fall back to object information reported by /proc */
        (void) snprintf(path, sizeof (path),
            "/proc/%d/object/%s", (int)Psp->pr_pid, mapname);
        if (stat(path, &statb) == 0) {
                dev_t dev = statb.st_dev;
                ino_t ino = statb.st_ino;
                (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu",
                    (ulong_t)major(dev), (ulong_t)minor(dev), ino);
                return (buf);
        }

        return (NULL);
}

/*
 * Create label for anon mappings
 */
char *
anon_name(char *name, const pstatus_t *Psp, lwpstack_t *stacks, uint_t nstacks,
    uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypesp)
{
        int mtypes = 0;

        if (mflags & MA_ISM) {
                if (shmid == -1)
                        (void) snprintf(name, PATH_MAX, "  [ %s shmid=null ]",
                            (mflags & MA_NORESERVE) ? "ism" : "dism");
                else
                        (void) snprintf(name, PATH_MAX, "  [ %s shmid=0x%x ]",
                            (mflags & MA_NORESERVE) ? "ism" : "dism", shmid);
                mtypes |= (1 << AT_SHARED);
        } else if (mflags & MA_SHM) {
                if (shmid == -1)
                        (void) sprintf(name, "  [ shmid=null ]");
                else
                        (void) sprintf(name, "  [ shmid=0x%x ]", shmid);
                mtypes |= (1 << AT_SHARED);
        } else if (vaddr + size > Psp->pr_stkbase &&
            vaddr < Psp->pr_stkbase + Psp->pr_stksize) {
                (void) strcpy(name, "  [ stack ]");
                mtypes |= (1 << AT_STACK);
        } else if ((mflags & MA_ANON) &&
            vaddr + size > Psp->pr_brkbase &&
            vaddr < Psp->pr_brkbase + Psp->pr_brksize) {
                (void) strcpy(name, "  [ heap ]");
                mtypes |= (1 << AT_HEAP);
        } else {
                lwpstack_t key, *stk;

                key.lwps_stack.ss_sp = (void *)vaddr;
                key.lwps_stack.ss_size = size;
                if (nstacks > 0 &&
                    (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]),
                    cmpstacks)) != NULL) {
                        (void) snprintf(name, PATH_MAX, "  [ %s tid=%d ]",
                            (stk->lwps_stack.ss_flags & SS_ONSTACK) ?
                            "altstack" : "stack",
                            stk->lwps_lwpid);
                        mtypes |= (1 << AT_STACK);
                } else {
                        (void) strcpy(name, "  [ anon ]");
                        mtypes |= (1 << AT_PRIVM);
                }
        }

        if (mtypesp)
                *mtypesp = mtypes;
        return (name);
}