1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /*
  27  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
  28  */
  29 
  30 #include <fcntl.h>
  31 #include <libproc.h>
  32 #include <limits.h>
  33 #include <stdio.h>
  34 #include <strings.h>
  35 #include <sys/mkdev.h>
  36 #include <sys/stat.h>
  37 #include <sys/types.h>
  38 
  39 #include "pmap_common.h"
  40 #include "ptools_common.h"
  41 
  42 /*
  43  * We compare the high memory addresses since stacks are faulted in from
  44  * high memory addresses to low memory addresses, and our prmap_t
  45  * structures identify only the range of addresses that have been faulted
  46  * in so far.
  47  */
  48 int
  49 cmpstacks(const void *ap, const void *bp)
  50 {
  51         const lwpstack_t *as = ap;
  52         const lwpstack_t *bs = bp;
  53         uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size;
  54         uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size;
  55 
  56         if (a < b)
  57                 return (1);
  58         if (a > b)
  59                 return (-1);
  60         return (0);
  61 }
  62 
  63 /*
  64  * Create labels for non-anon, non-heap mappings
  65  */
  66 char *
  67 make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr,
  68     const char *mapname, char *buf, size_t bufsz)
  69 {
  70         const pstatus_t         *Psp = Pstatus(Pr);
  71         struct stat             statb;
  72         char                    path[PATH_MAX];
  73         int                     len;
  74 
  75         if (lflag || Pstate(Pr) == PS_DEAD) {
  76                 if (Pobjname(Pr, addr, buf, bufsz) != NULL)
  77                         return (buf);
  78         } else {
  79                 if (Pobjname_resolved(Pr, addr, buf, bufsz) != NULL) {
  80                         /* Verify that the path exists */
  81                         if ((len = resolvepath(buf, buf, bufsz)) > 0) {
  82                                 buf[len] = '\0';
  83                                 return (buf);
  84                         }
  85                 }
  86         }
  87 
  88         if (Pstate(Pr) == PS_DEAD || *mapname == '\0')
  89                 return (NULL);
  90 
  91         /* first see if we can find a path via /proc */
  92         (void) proc_snprintf(path, sizeof (path), "/proc/%d/path/%s",
  93             (int)Psp->pr_pid, mapname);
  94         len = readlink(path, buf, bufsz - 1);
  95         if (len >= 0) {
  96                 buf[len] = '\0';
  97                 return (buf);
  98         }
  99 
 100         /* fall back to object information reported by /proc */
 101         (void) proc_snprintf(path, sizeof (path),
 102             "/proc/%d/object/%s", (int)Psp->pr_pid, mapname);
 103         if (stat(path, &statb) == 0) {
 104                 dev_t dev = statb.st_dev;
 105                 ino_t ino = statb.st_ino;
 106                 (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu",
 107                     (ulong_t)major(dev), (ulong_t)minor(dev), ino);
 108                 return (buf);
 109         }
 110 
 111         return (NULL);
 112 }
 113 
 114 /*
 115  * Create label for anon mappings
 116  */
 117 char *
 118 anon_name(char *name, const pstatus_t *Psp, lwpstack_t *stacks, uint_t nstacks,
 119     uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypesp)
 120 {
 121         int mtypes = 0;
 122 
 123         if (mflags & MA_ISM) {
 124                 if (shmid == -1)
 125                         (void) snprintf(name, PATH_MAX, "  [ %s shmid=null ]",
 126                             (mflags & MA_NORESERVE) ? "ism" : "dism");
 127                 else
 128                         (void) snprintf(name, PATH_MAX, "  [ %s shmid=0x%x ]",
 129                             (mflags & MA_NORESERVE) ? "ism" : "dism", shmid);
 130                 mtypes |= (1 << AT_SHARED);
 131         } else if (mflags & MA_SHM) {
 132                 if (shmid == -1)
 133                         (void) sprintf(name, "  [ shmid=null ]");
 134                 else
 135                         (void) sprintf(name, "  [ shmid=0x%x ]", shmid);
 136                 mtypes |= (1 << AT_SHARED);
 137         } else if (vaddr + size > Psp->pr_stkbase &&
 138             vaddr < Psp->pr_stkbase + Psp->pr_stksize) {
 139                 (void) strcpy(name, "  [ stack ]");
 140                 mtypes |= (1 << AT_STACK);
 141         } else if ((mflags & MA_ANON) &&
 142             vaddr + size > Psp->pr_brkbase &&
 143             vaddr < Psp->pr_brkbase + Psp->pr_brksize) {
 144                 (void) strcpy(name, "  [ heap ]");
 145                 mtypes |= (1 << AT_HEAP);
 146         } else {
 147                 lwpstack_t key, *stk;
 148 
 149                 key.lwps_stack.ss_sp = (void *)vaddr;
 150                 key.lwps_stack.ss_size = size;
 151                 if (nstacks > 0 &&
 152                     (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]),
 153                     cmpstacks)) != NULL) {
 154                         (void) snprintf(name, PATH_MAX, "  [ %s tid=%d ]",
 155                             (stk->lwps_stack.ss_flags & SS_ONSTACK) ?
 156                             "altstack" : "stack",
 157                             stk->lwps_lwpid);
 158                         mtypes |= (1 << AT_STACK);
 159                 } else {
 160                         (void) strcpy(name, "  [ anon ]");
 161                         mtypes |= (1 << AT_PRIVM);
 162                 }
 163         }
 164 
 165         if (mtypesp)
 166                 *mtypesp = mtypes;
 167         return (name);
 168 }