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 41 /* 42 * We compare the high memory addresses since stacks are faulted in from 43 * high memory addresses to low memory addresses, and our prmap_t 44 * structures identify only the range of addresses that have been faulted 45 * in so far. 46 */ 47 int 48 cmpstacks(const void *ap, const void *bp) 49 { 50 const lwpstack_t *as = ap; 51 const lwpstack_t *bs = bp; 52 uintptr_t a = (uintptr_t)as->lwps_stack.ss_sp + as->lwps_stack.ss_size; 53 uintptr_t b = (uintptr_t)bs->lwps_stack.ss_sp + bs->lwps_stack.ss_size; 54 55 if (a < b) 56 return (1); 57 if (a > b) 58 return (-1); 59 return (0); 60 } 61 62 /* 63 * Create labels for non-anon, non-heap mappings 64 */ 65 char * 66 make_name(struct ps_prochandle *Pr, int lflag, uintptr_t addr, 67 const char *mapname, char *buf, size_t bufsz) 68 { 69 const pstatus_t *Psp = Pstatus(Pr); 70 struct stat statb; 71 char path[PATH_MAX]; 72 int len; 73 74 if (lflag || Pstate(Pr) == PS_DEAD) { 75 if (Pobjname(Pr, addr, buf, bufsz) != NULL) 76 return (buf); 77 } else { 78 if (Pobjname_resolved(Pr, addr, buf, bufsz) != NULL) { 79 /* Verify that the path exists */ 80 if ((len = resolvepath(buf, buf, bufsz)) > 0) { 81 buf[len] = '\0'; 82 return (buf); 83 } 84 } 85 } 86 87 if (Pstate(Pr) == PS_DEAD || *mapname == '\0') 88 return (NULL); 89 90 /* first see if we can find a path via /proc */ 91 (void) snprintf(path, sizeof (path), "/proc/%d/path/%s", 92 (int)Psp->pr_pid, mapname); 93 len = readlink(path, buf, bufsz - 1); 94 if (len >= 0) { 95 buf[len] = '\0'; 96 return (buf); 97 } 98 99 /* fall back to object information reported by /proc */ 100 (void) snprintf(path, sizeof (path), 101 "/proc/%d/object/%s", (int)Psp->pr_pid, mapname); 102 if (stat(path, &statb) == 0) { 103 dev_t dev = statb.st_dev; 104 ino_t ino = statb.st_ino; 105 (void) snprintf(buf, bufsz, "dev:%lu,%lu ino:%lu", 106 (ulong_t)major(dev), (ulong_t)minor(dev), ino); 107 return (buf); 108 } 109 110 return (NULL); 111 } 112 113 /* 114 * Create label for anon mappings 115 */ 116 char * 117 anon_name(char *name, const pstatus_t *Psp, lwpstack_t *stacks, uint_t nstacks, 118 uintptr_t vaddr, size_t size, int mflags, int shmid, int *mtypesp) 119 { 120 int mtypes = 0; 121 122 if (mflags & MA_ISM) { 123 if (shmid == -1) 124 (void) snprintf(name, PATH_MAX, " [ %s shmid=null ]", 125 (mflags & MA_NORESERVE) ? "ism" : "dism"); 126 else 127 (void) snprintf(name, PATH_MAX, " [ %s shmid=0x%x ]", 128 (mflags & MA_NORESERVE) ? "ism" : "dism", shmid); 129 mtypes |= (1 << AT_SHARED); 130 } else if (mflags & MA_SHM) { 131 if (shmid == -1) 132 (void) sprintf(name, " [ shmid=null ]"); 133 else 134 (void) sprintf(name, " [ shmid=0x%x ]", shmid); 135 mtypes |= (1 << AT_SHARED); 136 } else if (vaddr + size > Psp->pr_stkbase && 137 vaddr < Psp->pr_stkbase + Psp->pr_stksize) { 138 (void) strcpy(name, " [ stack ]"); 139 mtypes |= (1 << AT_STACK); 140 } else if ((mflags & MA_ANON) && 141 vaddr + size > Psp->pr_brkbase && 142 vaddr < Psp->pr_brkbase + Psp->pr_brksize) { 143 (void) strcpy(name, " [ heap ]"); 144 mtypes |= (1 << AT_HEAP); 145 } else { 146 lwpstack_t key, *stk; 147 148 key.lwps_stack.ss_sp = (void *)vaddr; 149 key.lwps_stack.ss_size = size; 150 if (nstacks > 0 && 151 (stk = bsearch(&key, stacks, nstacks, sizeof (stacks[0]), 152 cmpstacks)) != NULL) { 153 (void) snprintf(name, PATH_MAX, " [ %s tid=%d ]", 154 (stk->lwps_stack.ss_flags & SS_ONSTACK) ? 155 "altstack" : "stack", 156 stk->lwps_lwpid); 157 mtypes |= (1 << AT_STACK); 158 } else { 159 (void) strcpy(name, " [ anon ]"); 160 mtypes |= (1 << AT_PRIVM); 161 } 162 } 163 164 if (mtypesp) 165 *mtypesp = mtypes; 166 return (name); 167 } 168