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 }