1 /*-
2 * Copyright (c) 2010 The FreeBSD Foundation
3 * Copyright (c) 2008 John Birrell (jb@freebsd.org)
4 * All rights reserved.
5 *
6 * Portions of this software were developed by Rui Paulo under sponsorship
7 * from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD: stable/9/lib/libproc/proc_sym.c 270730 2014-08-27 19:51:07Z markj $
31 */
32
33 #include <sys/types.h>
34 #include <sys/user.h>
35
36 #include <assert.h>
37 #include <err.h>
38 #include <stdio.h>
39 #include <libgen.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <libutil.h>
46
47 #include "_libproc.h"
48
49 static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
50
51 static void
proc_rdl2prmap(rd_loadobj_t * rdl,prmap_t * map)52 proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
53 {
54 map->pr_vaddr = rdl->rdl_saddr;
55 map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
56 map->pr_offset = rdl->rdl_offset;
57 map->pr_mflags = 0;
58 if (rdl->rdl_prot & RD_RDL_R)
59 map->pr_mflags |= MA_READ;
60 if (rdl->rdl_prot & RD_RDL_W)
61 map->pr_mflags |= MA_WRITE;
62 if (rdl->rdl_prot & RD_RDL_X)
63 map->pr_mflags |= MA_EXEC;
64 strlcpy(map->pr_mapname, rdl->rdl_path,
65 sizeof(map->pr_mapname));
66 }
67
68 char *
proc_objname(struct proc_handle * p,uintptr_t addr,char * objname,size_t objnamesz)69 proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
70 size_t objnamesz)
71 {
72 size_t i;
73 rd_loadobj_t *rdl;
74
75 for (i = 0; i < p->nobjs; i++) {
76 rdl = &p->rdobjs[i];
77 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
78 strlcpy(objname, rdl->rdl_path, objnamesz);
79 return (objname);
80 }
81 }
82 return (NULL);
83 }
84
85 prmap_t *
proc_obj2map(struct proc_handle * p,const char * objname)86 proc_obj2map(struct proc_handle *p, const char *objname)
87 {
88 size_t i;
89 prmap_t *map;
90 rd_loadobj_t *rdl;
91 char path[MAXPATHLEN];
92
93 rdl = NULL;
94 for (i = 0; i < p->nobjs; i++) {
95 basename_r(p->rdobjs[i].rdl_path, path);
96 if (strcmp(path, objname) == 0) {
97 rdl = &p->rdobjs[i];
98 break;
99 }
100 }
101 if (rdl == NULL) {
102 if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
103 rdl = p->rdexec;
104 else
105 return (NULL);
106 }
107
108 if ((map = malloc(sizeof(*map))) == NULL)
109 return (NULL);
110 proc_rdl2prmap(rdl, map);
111 return (map);
112 }
113
114 int
proc_iter_objs(struct proc_handle * p,proc_map_f * func,void * cd)115 proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
116 {
117 size_t i;
118 rd_loadobj_t *rdl;
119 prmap_t map;
120 char path[MAXPATHLEN];
121 char last[MAXPATHLEN];
122
123 if (p->nobjs == 0)
124 return (-1);
125 memset(last, 0, sizeof(last));
126 for (i = 0; i < p->nobjs; i++) {
127 rdl = &p->rdobjs[i];
128 proc_rdl2prmap(rdl, &map);
129 basename_r(rdl->rdl_path, path);
130 /*
131 * We shouldn't call the callback twice with the same object.
132 * To do that we are assuming the fact that if there are
133 * repeated object names (i.e. different mappings for the
134 * same object) they occur next to each other.
135 */
136 if (strcmp(path, last) == 0)
137 continue;
138 (*func)(cd, &map, path);
139 strlcpy(last, path, sizeof(last));
140 }
141
142 return (0);
143 }
144
145 prmap_t *
proc_addr2map(struct proc_handle * p,uintptr_t addr)146 proc_addr2map(struct proc_handle *p, uintptr_t addr)
147 {
148 size_t i;
149 int cnt, lastvn = 0;
150 prmap_t *map;
151 rd_loadobj_t *rdl;
152 struct kinfo_vmentry *kves, *kve;
153
154 /*
155 * If we don't have a cache of listed objects, we need to query
156 * it ourselves.
157 */
158 if (p->nobjs == 0) {
159 if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
160 return (NULL);
161 for (i = 0; i < (size_t)cnt; i++) {
162 kve = kves + i;
163 if (kve->kve_type == KVME_TYPE_VNODE)
164 lastvn = i;
165 if (addr >= kve->kve_start && addr < kve->kve_end) {
166 if ((map = malloc(sizeof(*map))) == NULL) {
167 free(kves);
168 return (NULL);
169 }
170 map->pr_vaddr = kve->kve_start;
171 map->pr_size = kve->kve_end - kve->kve_start;
172 map->pr_offset = kve->kve_offset;
173 map->pr_mflags = 0;
174 if (kve->kve_protection & KVME_PROT_READ)
175 map->pr_mflags |= MA_READ;
176 if (kve->kve_protection & KVME_PROT_WRITE)
177 map->pr_mflags |= MA_WRITE;
178 if (kve->kve_protection & KVME_PROT_EXEC)
179 map->pr_mflags |= MA_EXEC;
180 if (kve->kve_flags & KVME_FLAG_COW)
181 map->pr_mflags |= MA_COW;
182 if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
183 map->pr_mflags |= MA_NEEDS_COPY;
184 if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
185 map->pr_mflags |= MA_NOCOREDUMP;
186 strlcpy(map->pr_mapname, kves[lastvn].kve_path,
187 sizeof(map->pr_mapname));
188 free(kves);
189 return (map);
190 }
191 }
192 free(kves);
193 return (NULL);
194 }
195
196 for (i = 0; i < p->nobjs; i++) {
197 rdl = &p->rdobjs[i];
198 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
199 if ((map = malloc(sizeof(*map))) == NULL)
200 return (NULL);
201 proc_rdl2prmap(rdl, map);
202 return (map);
203 }
204 }
205 return (NULL);
206 }
207
208 int
proc_addr2sym(struct proc_handle * p,uintptr_t addr,char * name,size_t namesz,GElf_Sym * symcopy)209 proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
210 size_t namesz, GElf_Sym *symcopy)
211 {
212 Elf *e;
213 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
214 Elf_Data *data;
215 GElf_Shdr shdr;
216 GElf_Sym sym;
217 GElf_Ehdr ehdr;
218 int fd, error = -1;
219 size_t i;
220 uint64_t rsym;
221 prmap_t *map;
222 char *s;
223 unsigned long symtabstridx = 0, dynsymstridx = 0;
224
225 if ((map = proc_addr2map(p, addr)) == NULL)
226 return (-1);
227 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
228 DPRINTF("ERROR: open %s failed", map->pr_mapname);
229 goto err0;
230 }
231 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
232 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
233 goto err1;
234 }
235 if (gelf_getehdr(e, &ehdr) == NULL) {
236 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
237 goto err2;
238 }
239 /*
240 * Find the index of the STRTAB and SYMTAB sections to locate
241 * symbol names.
242 */
243 scn = NULL;
244 while ((scn = elf_nextscn(e, scn)) != NULL) {
245 gelf_getshdr(scn, &shdr);
246 switch (shdr.sh_type) {
247 case SHT_SYMTAB:
248 symtabscn = scn;
249 symtabstridx = shdr.sh_link;
250 break;
251 case SHT_DYNSYM:
252 dynsymscn = scn;
253 dynsymstridx = shdr.sh_link;
254 break;
255 default:
256 break;
257 }
258 }
259 /*
260 * Iterate over the Dynamic Symbols table to find the symbol.
261 * Then look up the string name in STRTAB (.dynstr)
262 */
263 if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
264 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
265 goto symtab;
266 }
267 i = 0;
268 while (gelf_getsym(data, i++, &sym) != NULL) {
269 /*
270 * Calculate the address mapped to the virtual memory
271 * by rtld.
272 */
273 if (ehdr.e_type != ET_EXEC)
274 rsym = map->pr_vaddr + sym.st_value;
275 else
276 rsym = sym.st_value;
277 if (addr >= rsym && addr < rsym + sym.st_size) {
278 s = elf_strptr(e, dynsymstridx, sym.st_name);
279 if (s) {
280 strlcpy(name, s, namesz);
281 memcpy(symcopy, &sym, sizeof(sym));
282 /*
283 * DTrace expects the st_value to contain
284 * only the address relative to the start of
285 * the function.
286 */
287 symcopy->st_value = rsym;
288 error = 0;
289 goto out;
290 }
291 }
292 }
293 symtab:
294 /*
295 * Iterate over the Symbols Table to find the symbol.
296 * Then look up the string name in STRTAB (.dynstr)
297 */
298 if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
299 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
300 goto err2;
301 }
302 i = 0;
303 while (gelf_getsym(data, i++, &sym) != NULL) {
304 /*
305 * Calculate the address mapped to the virtual memory
306 * by rtld.
307 */
308 if (ehdr.e_type != ET_EXEC)
309 rsym = map->pr_vaddr + sym.st_value;
310 else
311 rsym = sym.st_value;
312 if (addr >= rsym && addr < rsym + sym.st_size) {
313 s = elf_strptr(e, symtabstridx, sym.st_name);
314 if (s) {
315 strlcpy(name, s, namesz);
316 memcpy(symcopy, &sym, sizeof(sym));
317 /*
318 * DTrace expects the st_value to contain
319 * only the address relative to the start of
320 * the function.
321 */
322 symcopy->st_value = rsym;
323 error = 0;
324 goto out;
325 }
326 }
327 }
328 out:
329 err2:
330 elf_end(e);
331 err1:
332 close(fd);
333 err0:
334 free(map);
335 return (error);
336 }
337
338 prmap_t *
proc_name2map(struct proc_handle * p,const char * name)339 proc_name2map(struct proc_handle *p, const char *name)
340 {
341 size_t i;
342 int cnt;
343 prmap_t *map;
344 char tmppath[MAXPATHLEN];
345 struct kinfo_vmentry *kves, *kve;
346 rd_loadobj_t *rdl;
347
348 /*
349 * If we haven't iterated over the list of loaded objects,
350 * librtld_db isn't yet initialized and it's very likely
351 * that librtld_db called us. We need to do the heavy
352 * lifting here to find the symbol librtld_db is looking for.
353 */
354 if (p->nobjs == 0) {
355 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
356 return (NULL);
357 for (i = 0; i < (size_t)cnt; i++) {
358 kve = kves + i;
359 basename_r(kve->kve_path, tmppath);
360 if (strcmp(tmppath, name) == 0) {
361 map = proc_addr2map(p, kve->kve_start);
362 free(kves);
363 return (map);
364 }
365 }
366 free(kves);
367 return (NULL);
368 }
369 if ((name == NULL || strcmp(name, "a.out") == 0) &&
370 p->rdexec != NULL) {
371 map = proc_addr2map(p, p->rdexec->rdl_saddr);
372 return (map);
373 }
374 for (i = 0; i < p->nobjs; i++) {
375 rdl = &p->rdobjs[i];
376 basename_r(rdl->rdl_path, tmppath);
377 if (strcmp(tmppath, name) == 0) {
378 if ((map = malloc(sizeof(*map))) == NULL)
379 return (NULL);
380 proc_rdl2prmap(rdl, map);
381 return (map);
382 }
383 }
384
385 return (NULL);
386 }
387
388 int
proc_name2sym(struct proc_handle * p,const char * object,const char * symbol,GElf_Sym * symcopy)389 proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
390 GElf_Sym *symcopy)
391 {
392 Elf *e;
393 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
394 Elf_Data *data;
395 GElf_Shdr shdr;
396 GElf_Sym sym;
397 GElf_Ehdr ehdr;
398 int fd, error = -1;
399 size_t i;
400 prmap_t *map;
401 char *s;
402 unsigned long symtabstridx = 0, dynsymstridx = 0;
403
404 if ((map = proc_name2map(p, object)) == NULL) {
405 DPRINTFX("ERROR: couldn't find object %s", object);
406 goto err0;
407 }
408 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
409 DPRINTF("ERROR: open %s failed", map->pr_mapname);
410 goto err0;
411 }
412 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
413 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
414 goto err1;
415 }
416 if (gelf_getehdr(e, &ehdr) == NULL) {
417 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
418 goto err2;
419 }
420 /*
421 * Find the index of the STRTAB and SYMTAB sections to locate
422 * symbol names.
423 */
424 scn = NULL;
425 while ((scn = elf_nextscn(e, scn)) != NULL) {
426 gelf_getshdr(scn, &shdr);
427 switch (shdr.sh_type) {
428 case SHT_SYMTAB:
429 symtabscn = scn;
430 symtabstridx = shdr.sh_link;
431 break;
432 case SHT_DYNSYM:
433 dynsymscn = scn;
434 dynsymstridx = shdr.sh_link;
435 break;
436 default:
437 break;
438 }
439 }
440 /*
441 * Iterate over the Dynamic Symbols table to find the symbol.
442 * Then look up the string name in STRTAB (.dynstr)
443 */
444 if ((data = elf_getdata(dynsymscn, NULL))) {
445 i = 0;
446 while (gelf_getsym(data, i++, &sym) != NULL) {
447 s = elf_strptr(e, dynsymstridx, sym.st_name);
448 if (s && strcmp(s, symbol) == 0) {
449 memcpy(symcopy, &sym, sizeof(sym));
450 if (ehdr.e_type != ET_EXEC)
451 symcopy->st_value += map->pr_vaddr;
452 error = 0;
453 goto out;
454 }
455 }
456 }
457 /*
458 * Iterate over the Symbols Table to find the symbol.
459 * Then look up the string name in STRTAB (.dynstr)
460 */
461 if ((data = elf_getdata(symtabscn, NULL))) {
462 i = 0;
463 while (gelf_getsym(data, i++, &sym) != NULL) {
464 s = elf_strptr(e, symtabstridx, sym.st_name);
465 if (s && strcmp(s, symbol) == 0) {
466 memcpy(symcopy, &sym, sizeof(sym));
467 if (ehdr.e_type != ET_EXEC)
468 symcopy->st_value += map->pr_vaddr;
469 error = 0;
470 goto out;
471 }
472 }
473 }
474 out:
475 DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol);
476 err2:
477 elf_end(e);
478 err1:
479 close(fd);
480 err0:
481 free(map);
482
483 return (error);
484 }
485
486
487 int
proc_iter_symbyaddr(struct proc_handle * p,const char * object,int which,int mask,proc_sym_f * func,void * cd)488 proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
489 int mask, proc_sym_f *func, void *cd)
490 {
491 Elf *e;
492 int i, fd;
493 prmap_t *map;
494 Elf_Scn *scn, *foundscn = NULL;
495 Elf_Data *data;
496 GElf_Ehdr ehdr;
497 GElf_Shdr shdr;
498 GElf_Sym sym;
499 unsigned long stridx = -1;
500 char *s;
501 int error = -1;
502
503 if ((map = proc_name2map(p, object)) == NULL)
504 return (-1);
505 if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) {
506 DPRINTF("ERROR: open %s failed", map->pr_mapname);
507 goto err0;
508 }
509 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
510 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
511 goto err1;
512 }
513 if (gelf_getehdr(e, &ehdr) == NULL) {
514 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
515 goto err2;
516 }
517 /*
518 * Find the section we are looking for.
519 */
520 scn = NULL;
521 while ((scn = elf_nextscn(e, scn)) != NULL) {
522 gelf_getshdr(scn, &shdr);
523 if (which == PR_SYMTAB &&
524 shdr.sh_type == SHT_SYMTAB) {
525 foundscn = scn;
526 break;
527 } else if (which == PR_DYNSYM &&
528 shdr.sh_type == SHT_DYNSYM) {
529 foundscn = scn;
530 break;
531 }
532 }
533 if (!foundscn)
534 return (-1);
535 stridx = shdr.sh_link;
536 if ((data = elf_getdata(foundscn, NULL)) == NULL) {
537 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
538 goto err2;
539 }
540 i = 0;
541 while (gelf_getsym(data, i++, &sym) != NULL) {
542 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
543 (mask & BIND_LOCAL) == 0)
544 continue;
545 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
546 (mask & BIND_GLOBAL) == 0)
547 continue;
548 if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
549 (mask & BIND_WEAK) == 0)
550 continue;
551 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
552 (mask & TYPE_NOTYPE) == 0)
553 continue;
554 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
555 (mask & TYPE_OBJECT) == 0)
556 continue;
557 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
558 (mask & TYPE_FUNC) == 0)
559 continue;
560 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
561 (mask & TYPE_SECTION) == 0)
562 continue;
563 if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
564 (mask & TYPE_FILE) == 0)
565 continue;
566 s = elf_strptr(e, stridx, sym.st_name);
567 if (ehdr.e_type != ET_EXEC)
568 sym.st_value += map->pr_vaddr;
569 (*func)(cd, &sym, s);
570 }
571 error = 0;
572 err2:
573 elf_end(e);
574 err1:
575 close(fd);
576 err0:
577 free(map);
578 return (error);
579 }
580