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
cmpstacks(const void * ap,const void * bp)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 *
make_name(struct ps_prochandle * Pr,int lflag,uintptr_t addr,const char * mapname,char * buf,size_t bufsz)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 *
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)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