xref: /illumos-gate/usr/src/cmd/ptools/pmap/pmap_common.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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 *
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 *
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