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