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 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25 /*
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30 #include <elf.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <procfs.h>
36 #include <string.h>
37 #include <sys/stat.h>
38
39 #if defined(__sparcv9) || defined(__amd64)
40
41 #define Elf_Ehdr Elf64_Ehdr
42 #define Elf_Phdr Elf64_Phdr
43 #define Elf_Shdr Elf64_Shdr
44 #define Elf_Sym Elf64_Sym
45 #define ELF_ST_BIND ELF64_ST_BIND
46 #define ELF_ST_TYPE ELF64_ST_TYPE
47
48 #else
49
50 #define Elf_Ehdr Elf32_Ehdr
51 #define Elf_Phdr Elf32_Phdr
52 #define Elf_Shdr Elf32_Shdr
53 #define Elf_Sym Elf32_Sym
54 #define ELF_ST_BIND ELF32_ST_BIND
55 #define ELF_ST_TYPE ELF32_ST_TYPE
56
57 #endif /* __sparcv9 */
58
59 /* semi-permanent data established by __fex_sym_init */
60 static prmap_t *pm = NULL; /* prmap_t array */
61 static int npm = 0; /* number of entries in pm */
62
63 /* transient data modified by __fex_sym */
64 static prmap_t *lpm = NULL; /* prmap_t found in last call */
65 static Elf_Phdr *ph = NULL; /* program header array */
66 static int phsize = 0; /* size of ph */
67 static int nph; /* number of entries in ph */
68 static char *stbuf = NULL; /* symbol and string table buffer */
69 static int stbufsize = 0; /* size of stbuf */
70 static int stoffset; /* offset of string table in stbuf */
71 static int nsyms; /* number of symbols in stbuf */
72
73 /* get a current prmap_t list (must call this before each stack trace) */
74 void
75 __fex_sym_init()
76 {
77 struct stat statbuf;
78 long n;
79 int i;
80
81 /* clear out the previous prmap_t list */
82 if (pm != NULL)
83 free(pm);
84 pm = lpm = NULL;
85 npm = 0;
86
87 /* get the current prmap_t list */
88 if (stat("/proc/self/map", &statbuf) < 0 || statbuf.st_size <= 0 ||
89 (pm = (prmap_t*)malloc(statbuf.st_size)) == NULL)
90 return;
91 if ((i = open("/proc/self/map", O_RDONLY)) < 0)
92 {
93 free(pm);
94 pm = NULL;
95 return;
96 }
97 n = read(i, pm, statbuf.st_size);
98 close(i);
99 if (n != statbuf.st_size)
100 {
101 free(pm);
102 pm = NULL;
103 }
104 else
105 npm = (int) (n / sizeof(prmap_t));
106 }
107
108 /* read ELF program headers and symbols; return -1 on error, 0 otherwise */
109 static int
110 __fex_read_syms(int fd)
111 {
112 Elf_Ehdr h;
113 Elf_Shdr *sh;
114 int i, size;
115
116 /* read the ELF header */
117 if (read(fd, &h, sizeof(h)) != sizeof(h))
118 return -1;
119 if (h.e_ident[EI_MAG0] != ELFMAG0 ||
120 h.e_ident[EI_MAG1] != ELFMAG1 ||
121 h.e_ident[EI_MAG2] != ELFMAG2 ||
122 h.e_ident[EI_MAG3] != ELFMAG3 ||
123 h.e_phentsize != sizeof(Elf_Phdr) ||
124 h.e_shentsize != sizeof(Elf_Shdr))
125 return -1;
126
127 /* get space for the program headers */
128 size = h.e_phnum * h.e_phentsize;
129 if (size > phsize)
130 {
131 if (ph)
132 free(ph);
133 phsize = nph = 0;
134 if ((ph = (Elf_Phdr*)malloc(size)) == NULL)
135 return -1;
136 phsize = size;
137 }
138
139 /* read the program headers */
140 if (lseek(fd, h.e_phoff, SEEK_SET) != h.e_phoff ||
141 read(fd, ph, size) != (ssize_t)size)
142 {
143 nph = 0;
144 return -1;
145 }
146 nph = h.e_phnum;
147
148 /* read the section headers */
149 size = h.e_shnum * h.e_shentsize;
150 if ((sh = (Elf_Shdr*)malloc(size)) == NULL)
151 return -1;
152 if (lseek(fd, h.e_shoff, SEEK_SET) != h.e_shoff ||
153 read(fd, sh, size) != (ssize_t)size)
154 {
155 free(sh);
156 return -1;
157 }
158
159 /* find the symtab section header */
160 for (i = 0; i < h.e_shnum; i++)
161 {
162 if (sh[i].sh_type == SHT_SYMTAB)
163 break; /* assume there is only one */
164 }
165 if (i == h.e_shnum || sh[i].sh_size == 0 ||
166 sh[i].sh_entsize != sizeof(Elf_Sym) ||
167 sh[i].sh_link < 1 || sh[i].sh_link >= h.e_shnum ||
168 sh[sh[i].sh_link].sh_type != SHT_STRTAB ||
169 sh[sh[i].sh_link].sh_size == 0)
170 {
171 free(sh);
172 return -1;
173 }
174
175 /* get space for the symbol and string tables */
176 size = (int) (sh[i].sh_size + sh[sh[i].sh_link].sh_size);
177 if (size > stbufsize)
178 {
179 if (stbuf)
180 free(stbuf);
181 stbufsize = nsyms = 0;
182 if ((stbuf = (char*)malloc(size)) == NULL)
183 {
184 free(sh);
185 return -1;
186 }
187 stbufsize = size;
188 }
189
190 /* read the symbol and string tables */
191 if (lseek(fd, sh[i].sh_offset, SEEK_SET) != sh[i].sh_offset ||
192 read(fd, stbuf, sh[i].sh_size) != sh[i].sh_size ||
193 lseek(fd, sh[sh[i].sh_link].sh_offset, SEEK_SET) !=
194 sh[sh[i].sh_link].sh_offset ||
195 read(fd, stbuf + sh[i].sh_size, sh[sh[i].sh_link].sh_size) !=
196 sh[sh[i].sh_link].sh_size)
197 {
198 free(sh);
199 return (-1);
200 }
201 nsyms = (int) (sh[i].sh_size / sh[i].sh_entsize);
202 stoffset = (int) sh[i].sh_size;
203
204 free(sh);
205 return (0);
206 }
207
208 /* find the symbol corresponding to the given text address;
209 return NULL on error, symbol address otherwise */
210 char *
211 __fex_sym(char *a, char **name)
212 {
213 Elf_Sym *s;
214 unsigned long fo, va, value;
215 int fd, i, j, nm;
216 char fname[PRMAPSZ+20];
217
218 /* see if the last prmap_t found contains the indicated address */
219 if (lpm)
220 {
221 if (a >= (char*)lpm->pr_vaddr && a < (char*)lpm->pr_vaddr +
222 lpm->pr_size)
223 goto cont;
224 }
225
226 /* look for a prmap_t that contains the indicated address */
227 for (i = 0; i < npm; i++)
228 {
229 if (a >= (char*)pm[i].pr_vaddr && a < (char*)pm[i].pr_vaddr +
230 pm[i].pr_size)
231 break;
232 }
233 if (i == npm)
234 return NULL;
235
236 /* get an open file descriptor for the mapped object */
237 if (pm[i].pr_mapname[0] == '\0')
238 return NULL;
239 strcpy(fname, "/proc/self/object/");
240 strncat(fname, pm[i].pr_mapname, PRMAPSZ);
241 fd = open(fname, O_RDONLY);
242 if (fd < 0)
243 return NULL;
244
245 /* read the program headers and symbols */
246 lpm = NULL;
247 j = __fex_read_syms(fd);
248 close(fd);
249 if (j < 0)
250 return NULL;
251 lpm = &pm[i];
252
253 cont:
254 /* compute the file offset corresponding to the mapped address */
255 fo = (a - (char*)lpm->pr_vaddr) + lpm->pr_offset;
256
257 /* find the program header containing the file offset */
258 for (i = 0; i < nph; i++)
259 {
260 if (ph[i].p_type == PT_LOAD && fo >= ph[i].p_offset &&
261 fo < ph[i].p_offset + ph[i].p_filesz)
262 break;
263 }
264 if (i == nph)
265 return NULL;
266
267 /* compute the virtual address corresponding to the file offset */
268 va = (fo - ph[i].p_offset) + ph[i].p_vaddr;
269
270 /* find the symbol in this segment with the highest value
271 less than or equal to the virtual address */
272 s = (Elf_Sym*)stbuf;
273 value = nm = 0;
274 for (j = 0; j < nsyms; j++)
275 {
276 if (s[j].st_name == 0 || s[j].st_shndx == SHN_UNDEF ||
277 (ELF_ST_BIND(s[j].st_info) != STB_LOCAL &&
278 ELF_ST_BIND(s[j].st_info) != STB_GLOBAL &&
279 ELF_ST_BIND(s[j].st_info) != STB_WEAK) ||
280 (ELF_ST_TYPE(s[j].st_info) != STT_NOTYPE &&
281 ELF_ST_TYPE(s[j].st_info) != STT_OBJECT &&
282 ELF_ST_TYPE(s[j].st_info) != STT_FUNC))
283 {
284 continue;
285 }
286
287 if (s[j].st_value < ph[i].p_vaddr || s[j].st_value >= ph[i].p_vaddr
288 + ph[i].p_memsz)
289 {
290 continue;
291 }
292
293 if (s[j].st_value < value || s[j].st_value > va)
294 continue;
295
296 value = s[j].st_value;
297 nm = s[j].st_name;
298 }
299 if (nm == 0)
300 return NULL;
301
302 /* pass back the name and return the mapped address of the symbol */
303 *name = stbuf + stoffset + nm;
304 fo = (value - ph[i].p_vaddr) + ph[i].p_offset;
305 return (char*)lpm->pr_vaddr + (fo - lpm->pr_offset);
306 }
|
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 2011 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 */
30
31 #include <elf.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <procfs.h>
37 #include <string.h>
38 #include <sys/stat.h>
39
40 #if defined(__sparcv9) || defined(__amd64)
41 #define Elf_Ehdr Elf64_Ehdr
42 #define Elf_Phdr Elf64_Phdr
43 #define Elf_Shdr Elf64_Shdr
44 #define Elf_Sym Elf64_Sym
45 #define ELF_ST_BIND ELF64_ST_BIND
46 #define ELF_ST_TYPE ELF64_ST_TYPE
47 #else
48 #define Elf_Ehdr Elf32_Ehdr
49 #define Elf_Phdr Elf32_Phdr
50 #define Elf_Shdr Elf32_Shdr
51 #define Elf_Sym Elf32_Sym
52 #define ELF_ST_BIND ELF32_ST_BIND
53 #define ELF_ST_TYPE ELF32_ST_TYPE
54 #endif /* __sparcv9 */
55
56 /* semi-permanent data established by __fex_sym_init */
57 static prmap_t *pm = NULL; /* prmap_t array */
58 static int npm = 0; /* number of entries in pm */
59
60 /* transient data modified by __fex_sym */
61 static prmap_t *lpm = NULL; /* prmap_t found in last call */
62 static Elf_Phdr *ph = NULL; /* program header array */
63 static int phsize = 0; /* size of ph */
64 static int nph; /* number of entries in ph */
65 static char *stbuf = NULL; /* symbol and string table buffer */
66 static int stbufsize = 0; /* size of stbuf */
67 static int stoffset; /* offset of string table in stbuf */
68 static int nsyms; /* number of symbols in stbuf */
69
70 /* get a current prmap_t list (must call this before each stack trace) */
71 void
72 __fex_sym_init()
73 {
74 struct stat statbuf;
75 long n;
76 int i;
77
78 /* clear out the previous prmap_t list */
79 if (pm != NULL)
80 free(pm);
81
82 pm = lpm = NULL;
83 npm = 0;
84
85 /* get the current prmap_t list */
86 if (stat("/proc/self/map", &statbuf) < 0 || statbuf.st_size <= 0 ||
87 (pm = (prmap_t *)malloc(statbuf.st_size)) == NULL)
88 return;
89
90 if ((i = open("/proc/self/map", O_RDONLY)) < 0) {
91 free(pm);
92 pm = NULL;
93 return;
94 }
95
96 n = read(i, pm, statbuf.st_size);
97 close(i);
98
99 if (n != statbuf.st_size) {
100 free(pm);
101 pm = NULL;
102 } else {
103 npm = (int)(n / sizeof (prmap_t));
104 }
105 }
106
107 /* read ELF program headers and symbols; return -1 on error, 0 otherwise */
108 static int
109 __fex_read_syms(int fd)
110 {
111 Elf_Ehdr h;
112 Elf_Shdr *sh;
113 int i, size;
114
115 /* read the ELF header */
116 if (read(fd, &h, sizeof (h)) != sizeof (h))
117 return (-1);
118
119 if (h.e_ident[EI_MAG0] != ELFMAG0 || h.e_ident[EI_MAG1] != ELFMAG1 ||
120 h.e_ident[EI_MAG2] != ELFMAG2 || h.e_ident[EI_MAG3] != ELFMAG3 ||
121 h.e_phentsize != sizeof (Elf_Phdr) || h.e_shentsize !=
122 sizeof (Elf_Shdr))
123 return (-1);
124
125 /* get space for the program headers */
126 size = h.e_phnum * h.e_phentsize;
127
128 if (size > phsize) {
129 if (ph)
130 free(ph);
131
132 phsize = nph = 0;
133
134 if ((ph = (Elf_Phdr *)malloc(size)) == NULL)
135 return (-1);
136
137 phsize = size;
138 }
139
140 /* read the program headers */
141 if (lseek(fd, h.e_phoff, SEEK_SET) != h.e_phoff || read(fd, ph, size) !=
142 (ssize_t)size) {
143 nph = 0;
144 return (-1);
145 }
146
147 nph = h.e_phnum;
148
149 /* read the section headers */
150 size = h.e_shnum * h.e_shentsize;
151
152 if ((sh = (Elf_Shdr *)malloc(size)) == NULL)
153 return (-1);
154
155 if (lseek(fd, h.e_shoff, SEEK_SET) != h.e_shoff || read(fd, sh, size) !=
156 (ssize_t)size) {
157 free(sh);
158 return (-1);
159 }
160
161 /* find the symtab section header */
162 for (i = 0; i < h.e_shnum; i++) {
163 if (sh[i].sh_type == SHT_SYMTAB)
164 break; /* assume there is only one */
165 }
166
167 if (i == h.e_shnum || sh[i].sh_size == 0 || sh[i].sh_entsize !=
168 sizeof (Elf_Sym) || sh[i].sh_link < 1 || sh[i].sh_link >=
169 h.e_shnum || sh[sh[i].sh_link].sh_type != SHT_STRTAB ||
170 sh[sh[i].sh_link].sh_size == 0) {
171 free(sh);
172 return (-1);
173 }
174
175 /* get space for the symbol and string tables */
176 size = (int)(sh[i].sh_size + sh[sh[i].sh_link].sh_size);
177
178 if (size > stbufsize) {
179 if (stbuf)
180 free(stbuf);
181
182 stbufsize = nsyms = 0;
183
184 if ((stbuf = (char *)malloc(size)) == NULL) {
185 free(sh);
186 return (-1);
187 }
188
189 stbufsize = size;
190 }
191
192 /* read the symbol and string tables */
193 if (lseek(fd, sh[i].sh_offset, SEEK_SET) != sh[i].sh_offset ||
194 read(fd, stbuf, sh[i].sh_size) != sh[i].sh_size ||
195 lseek(fd, sh[sh[i].sh_link].sh_offset, SEEK_SET) !=
196 sh[sh[i].sh_link].sh_offset ||
197 read(fd, stbuf + sh[i].sh_size, sh[sh[i].sh_link].sh_size) !=
198 sh[sh[i].sh_link].sh_size) {
199 free(sh);
200 return (-1);
201 }
202
203 nsyms = (int)(sh[i].sh_size / sh[i].sh_entsize);
204 stoffset = (int)sh[i].sh_size;
205
206 free(sh);
207 return (0);
208 }
209
210 /*
211 * find the symbol corresponding to the given text address;
212 * return NULL on error, symbol address otherwise
213 */
214 char *
215 __fex_sym(char *a, char **name)
216 {
217 Elf_Sym *s;
218 unsigned long fo, va, value;
219 int fd, i, j, nm;
220 char fname[PRMAPSZ + 20];
221
222 /* see if the last prmap_t found contains the indicated address */
223 if (lpm) {
224 if (a >= (char *)lpm->pr_vaddr && a < (char *)lpm->pr_vaddr +
225 lpm->pr_size)
226 goto cont;
227 }
228
229 /* look for a prmap_t that contains the indicated address */
230 for (i = 0; i < npm; i++) {
231 if (a >= (char *)pm[i].pr_vaddr && a < (char *)pm[i].pr_vaddr +
232 pm[i].pr_size)
233 break;
234 }
235
236 if (i == npm)
237 return (NULL);
238
239 /* get an open file descriptor for the mapped object */
240 if (pm[i].pr_mapname[0] == '\0')
241 return (NULL);
242
243 strcpy(fname, "/proc/self/object/");
244 strncat(fname, pm[i].pr_mapname, PRMAPSZ);
245 fd = open(fname, O_RDONLY);
246
247 if (fd < 0)
248 return (NULL);
249
250 /* read the program headers and symbols */
251 lpm = NULL;
252 j = __fex_read_syms(fd);
253 close(fd);
254
255 if (j < 0)
256 return (NULL);
257
258 lpm = &pm[i];
259
260 cont:
261 /* compute the file offset corresponding to the mapped address */
262 fo = (a - (char *)lpm->pr_vaddr) + lpm->pr_offset;
263
264 /* find the program header containing the file offset */
265 for (i = 0; i < nph; i++) {
266 if (ph[i].p_type == PT_LOAD && fo >= ph[i].p_offset && fo <
267 ph[i].p_offset + ph[i].p_filesz)
268 break;
269 }
270
271 if (i == nph)
272 return (NULL);
273
274 /* compute the virtual address corresponding to the file offset */
275 va = (fo - ph[i].p_offset) + ph[i].p_vaddr;
276
277 /*
278 * find the symbol in this segment with the highest value
279 * less than or equal to the virtual address
280 */
281 s = (Elf_Sym *)stbuf;
282 value = nm = 0;
283
284 for (j = 0; j < nsyms; j++) {
285 if (s[j].st_name == 0 || s[j].st_shndx == SHN_UNDEF ||
286 (ELF_ST_BIND(s[j].st_info) != STB_LOCAL && ELF_ST_BIND(
287 s[j].st_info) != STB_GLOBAL && ELF_ST_BIND(s[j].st_info) !=
288 STB_WEAK) || (ELF_ST_TYPE(s[j].st_info) != STT_NOTYPE &&
289 ELF_ST_TYPE(s[j].st_info) != STT_OBJECT && ELF_ST_TYPE(
290 s[j].st_info) != STT_FUNC))
291 continue;
292
293 if (s[j].st_value < ph[i].p_vaddr || s[j].st_value >=
294 ph[i].p_vaddr + ph[i].p_memsz)
295 continue;
296
297 if (s[j].st_value < value || s[j].st_value > va)
298 continue;
299
300 value = s[j].st_value;
301 nm = s[j].st_name;
302 }
303
304 if (nm == 0)
305 return (NULL);
306
307 /* pass back the name and return the mapped address of the symbol */
308 *name = stbuf + stoffset + nm;
309 fo = (value - ph[i].p_vaddr) + ph[i].p_offset;
310 return ((char *)lpm->pr_vaddr + (fo - lpm->pr_offset));
311 }
|