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
31#include <sys/cdefs.h>
32#ifdef __FBSDID
33__FBSDID("$FreeBSD: head/lib/libproc/proc_sym.c 279946 2015-03-13 04:26:48Z stas $");
34#else
35__RCSID("$NetBSD: proc_sym.c,v 1.4 2017/06/15 23:44:58 kamil Exp $");
36#endif
37
38#include <sys/types.h>
39#ifndef NO_CTF
40#include <sys/ctf.h>
41#include <sys/ctf_api.h>
42#endif
43#if defined(__FreeBSD__)
44#include <sys/user.h>
45#endif
46#include <sys/sysctl.h>
47
48#include <assert.h>
49#include <err.h>
50#include <fcntl.h>
51#include <libgen.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include <unistd.h>
56#ifndef NO_CTF
57#include <libctf.h>
58#endif
59#include <util.h>
60
61#include "_libproc.h"
62
63#define DBG_PATH_FMT "/usr/libdata/debug/%s.debug"
64
65#ifdef NO_CTF
66typedef struct ctf_file ctf_file_t;
67#endif
68
69#ifndef NO_CXA_DEMANGLE
70extern char *__cxa_demangle(const char *, char *, size_t *, int *);
71#endif /* NO_CXA_DEMANGLE */
72
73static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
74
75#ifdef __NetBSD__
76static char *basename_r(const char *path, char *buf)
77{
78 // We "know" this works.
79 if (path[0])
80 strlcpy(buf, strrchr(path, '/') + 1, PATH_MAX);
81 else
82 buf[0] = '\0';
83 return buf;
84}
85#endif
86
87static void
88demangle(const char *symbol, char *buf, size_t len)
89{
90#ifndef NO_CXA_DEMANGLE
91 char *dembuf;
92
93 if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) {
94 dembuf = __cxa_demangle(symbol, NULL, NULL, NULL);
95 if (!dembuf)
96 goto fail;
97 strlcpy(buf, dembuf, len);
98 free(dembuf);
99 return;
100 }
101fail:
102#endif /* NO_CXA_DEMANGLE */
103 strlcpy(buf, symbol, len);
104}
105
106static int
107find_dbg_obj(const char *path)
108{
109 int fd;
110 char dbg_path[PATH_MAX];
111
112 snprintf(dbg_path, sizeof(dbg_path), DBG_PATH_FMT, path);
113 fd = open(dbg_path, O_RDONLY);
114 if (fd >= 0)
115 return (fd);
116 else
117 return (open(path, O_RDONLY));
118}
119
120static void
121proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
122{
123 map->pr_vaddr = rdl->rdl_saddr;
124 map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
125 map->pr_offset = rdl->rdl_offset;
126 map->pr_mflags = 0;
127 if (rdl->rdl_prot & RD_RDL_R)
128 map->pr_mflags |= MA_READ;
129 if (rdl->rdl_prot & RD_RDL_W)
130 map->pr_mflags |= MA_WRITE;
131 if (rdl->rdl_prot & RD_RDL_X)
132 map->pr_mflags |= MA_EXEC;
133 strlcpy(map->pr_mapname, rdl->rdl_path,
134 sizeof(map->pr_mapname));
135}
136
137char *
138proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
139 size_t objnamesz)
140{
141 size_t i;
142 rd_loadobj_t *rdl;
143
144 for (i = 0; i < p->nobjs; i++) {
145 rdl = &p->rdobjs[i];
146 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
147 strlcpy(objname, rdl->rdl_path, objnamesz);
148 return (objname);
149 }
150 }
151 return (NULL);
152}
153
154prmap_t *
155proc_obj2map(struct proc_handle *p, const char *objname)
156{
157 size_t i;
158 prmap_t *map;
159 rd_loadobj_t *rdl;
160 char path[MAXPATHLEN];
161
162 rdl = NULL;
163 for (i = 0; i < p->nobjs; i++) {
164 basename_r(p->rdobjs[i].rdl_path, path);
165 if (strcmp(path, objname) == 0) {
166 rdl = &p->rdobjs[i];
167 break;
168 }
169 }
170 if (rdl == NULL) {
171 if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
172 rdl = p->rdexec;
173 else
174 return (NULL);
175 }
176
177 if ((map = malloc(sizeof(*map))) == NULL)
178 return (NULL);
179 proc_rdl2prmap(rdl, map);
180 return (map);
181}
182
183int
184proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
185{
186 size_t i;
187 rd_loadobj_t *rdl;
188 prmap_t map;
189 char path[MAXPATHLEN];
190 char last[MAXPATHLEN];
191 int error;
192
193 if (p->nobjs == 0)
194 return (-1);
195
196 error = 0;
197 memset(last, 0, sizeof(last));
198 for (i = 0; i < p->nobjs; i++) {
199 rdl = &p->rdobjs[i];
200 proc_rdl2prmap(rdl, &map);
201 basename_r(rdl->rdl_path, path);
202 /*
203 * We shouldn't call the callback twice with the same object.
204 * To do that we are assuming the fact that if there are
205 * repeated object names (i.e. different mappings for the
206 * same object) they occur next to each other.
207 */
208 if (strcmp(path, last) == 0)
209 continue;
210 if ((error = (*func)(cd, &map, path)) != 0)
211 break;
212 strlcpy(last, path, sizeof(last));
213 }
214 return (error);
215}
216
217prmap_t *
218proc_addr2map(struct proc_handle *p, uintptr_t addr)
219{
220 size_t i, cnt, lastvn = 0;
221 prmap_t *map;
222 rd_loadobj_t *rdl;
223 struct kinfo_vmentry *kves, *kve;
224
225 /*
226 * If we don't have a cache of listed objects, we need to query
227 * it ourselves.
228 */
229 if (p->nobjs == 0) {
230 if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
231 return (NULL);
232 for (i = 0; i < (size_t)cnt; i++) {
233 kve = kves + i;
234 if (kve->kve_type == KVME_TYPE_VNODE)
235 lastvn = i;
236 if (addr >= kve->kve_start && addr < kve->kve_end) {
237 if ((map = malloc(sizeof(*map))) == NULL) {
238 free(kves);
239 return (NULL);
240 }
241 map->pr_vaddr = kve->kve_start;
242 map->pr_size = kve->kve_end - kve->kve_start;
243 map->pr_offset = kve->kve_offset;
244 map->pr_mflags = 0;
245 if (kve->kve_protection & KVME_PROT_READ)
246 map->pr_mflags |= MA_READ;
247 if (kve->kve_protection & KVME_PROT_WRITE)
248 map->pr_mflags |= MA_WRITE;
249 if (kve->kve_protection & KVME_PROT_EXEC)
250 map->pr_mflags |= MA_EXEC;
251 if (kve->kve_flags & KVME_FLAG_COW)
252 map->pr_mflags |= MA_COW;
253 if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
254 map->pr_mflags |= MA_NEEDS_COPY;
255 if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
256 map->pr_mflags |= MA_NOCOREDUMP;
257 strlcpy(map->pr_mapname, kves[lastvn].kve_path,
258 sizeof(map->pr_mapname));
259 free(kves);
260 return (map);
261 }
262 }
263 free(kves);
264 return (NULL);
265 }
266
267 for (i = 0; i < p->nobjs; i++) {
268 rdl = &p->rdobjs[i];
269 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
270 if ((map = malloc(sizeof(*map))) == NULL)
271 return (NULL);
272 proc_rdl2prmap(rdl, map);
273 return (map);
274 }
275 }
276 return (NULL);
277}
278
279/*
280 * Look up the symbol at addr, returning a copy of the symbol and its name.
281 */
282static int
283lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr,
284 const char **name, GElf_Sym *symcopy)
285{
286 GElf_Sym sym;
287 Elf_Data *data;
288 const char *s;
289 uint64_t rsym;
290 int i;
291
292 if ((data = elf_getdata(scn, NULL)) == NULL) {
293 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
294 return (1);
295 }
296 for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
297 rsym = off + sym.st_value;
298 if (addr >= rsym && addr < rsym + sym.st_size) {
299 s = elf_strptr(e, stridx, sym.st_name);
300 if (s != NULL) {
301 *name = s;
302 memcpy(symcopy, &sym, sizeof(*symcopy));
303 /*
304 * DTrace expects the st_value to contain
305 * only the address relative to the start of
306 * the function.
307 */
308 symcopy->st_value = rsym;
309 return (0);
310 }
311 }
312 }
313 return (1);
314}
315
316int
317proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
318 size_t namesz, GElf_Sym *symcopy)
319{
320 GElf_Ehdr ehdr;
321 GElf_Shdr shdr;
322 Elf *e;
323 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
324 prmap_t *map;
325 const char *s;
326 uintptr_t off;
327 u_long symtabstridx = 0, dynsymstridx = 0;
328 int fd, error = -1;
329
330 if ((map = proc_addr2map(p, addr)) == NULL)
331 return (-1);
332 if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
333 DPRINTF("ERROR: open %s failed", map->pr_mapname);
334 goto err0;
335 }
336 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
337 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
338 goto err1;
339 }
340 if (gelf_getehdr(e, &ehdr) == NULL) {
341 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
342 goto err2;
343 }
344
345 /*
346 * Find the index of the STRTAB and SYMTAB sections to locate
347 * symbol names.
348 */
349 scn = NULL;
350 while ((scn = elf_nextscn(e, scn)) != NULL) {
351 gelf_getshdr(scn, &shdr);
352 switch (shdr.sh_type) {
353 case SHT_SYMTAB:
354 symtabscn = scn;
355 symtabstridx = shdr.sh_link;
356 break;
357 case SHT_DYNSYM:
358 dynsymscn = scn;
359 dynsymstridx = shdr.sh_link;
360 break;
361 }
362 }
363
364 off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
365
366 /*
367 * First look up the symbol in the dynsymtab, and fall back to the
368 * symtab if the lookup fails.
369 */
370 if (dynsymscn) {
371 error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy);
372 if (error == 0)
373 goto out;
374 }
375
376 error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy);
377 if (error != 0)
378 goto err2;
379
380out:
381 demangle(s, name, namesz);
382err2:
383 elf_end(e);
384err1:
385 close(fd);
386err0:
387 free(map);
388 return (error);
389}
390
391prmap_t *
392proc_name2map(struct proc_handle *p, const char *name)
393{
394 size_t i, cnt;
395 prmap_t *map = NULL;
396 char tmppath[MAXPATHLEN];
397 struct kinfo_vmentry *kves, *kve;
398 rd_loadobj_t *rdl;
399
400 /*
401 * If we haven't iterated over the list of loaded objects,
402 * librtld_db isn't yet initialized and it's very likely
403 * that librtld_db called us. We need to do the heavy
404 * lifting here to find the symbol librtld_db is looking for.
405 */
406 if (p->nobjs == 0) {
407 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
408 return (NULL);
409 for (i = 0; i < (size_t)cnt; i++) {
410 kve = kves + i;
411 basename_r(kve->kve_path, tmppath);
412 if (strcmp(tmppath, name) == 0) {
413 map = proc_addr2map(p, kve->kve_start);
414 break;
415 }
416 }
417 free(kves);
418 } else
419 for (i = 0; i < p->nobjs; i++) {
420 rdl = &p->rdobjs[i];
421 basename_r(rdl->rdl_path, tmppath);
422 if (strcmp(tmppath, name) == 0) {
423 if ((map = malloc(sizeof(*map))) == NULL)
424 return (NULL);
425 proc_rdl2prmap(rdl, map);
426 break;
427 }
428 }
429
430 if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL)
431 map = proc_addr2map(p, p->rdexec->rdl_saddr);
432
433 return (map);
434}
435
436/*
437 * Look up the symbol with the given name and return a copy of it.
438 */
439static int
440lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
441 GElf_Sym *symcopy, prsyminfo_t *si)
442{
443 GElf_Sym sym;
444 Elf_Data *data;
445 char *s;
446 int i;
447
448 if ((data = elf_getdata(scn, NULL)) == NULL) {
449 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
450 return (1);
451 }
452 for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
453 s = elf_strptr(e, stridx, sym.st_name);
454 if (s != NULL && strcmp(s, symbol) == 0) {
455 memcpy(symcopy, &sym, sizeof(*symcopy));
456 if (si != NULL)
457 si->prs_id = i;
458 return (0);
459 }
460 }
461 return (1);
462}
463
464int
465proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
466 GElf_Sym *symcopy, prsyminfo_t *si)
467{
468 Elf *e;
469 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
470 GElf_Shdr shdr;
471 GElf_Ehdr ehdr;
472 prmap_t *map;
473 uintptr_t off;
474 u_long symtabstridx = 0, dynsymstridx = 0;
475 int fd, error = -1;
476
477 if ((map = proc_name2map(p, object)) == NULL) {
478 DPRINTFX("ERROR: couldn't find object %s", object);
479 goto err0;
480 }
481 if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
482 DPRINTF("ERROR: open %s failed", map->pr_mapname);
483 goto err0;
484 }
485 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
486 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
487 goto err1;
488 }
489 if (gelf_getehdr(e, &ehdr) == NULL) {
490 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
491 goto err2;
492 }
493 /*
494 * Find the index of the STRTAB and SYMTAB sections to locate
495 * symbol names.
496 */
497 scn = NULL;
498 while ((scn = elf_nextscn(e, scn)) != NULL) {
499 gelf_getshdr(scn, &shdr);
500 switch (shdr.sh_type) {
501 case SHT_SYMTAB:
502 symtabscn = scn;
503 symtabstridx = shdr.sh_link;
504 break;
505 case SHT_DYNSYM:
506 dynsymscn = scn;
507 dynsymstridx = shdr.sh_link;
508 break;
509 }
510 }
511
512 /*
513 * First look up the symbol in the dynsymtab, and fall back to the
514 * symtab if the lookup fails.
515 */
516 if (dynsymscn) {
517 error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
518 if (error == 0)
519 goto out;
520 }
521
522 error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
523 if (error == 0)
524 goto out;
525
526out:
527 off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
528 symcopy->st_value += off;
529
530err2:
531 elf_end(e);
532err1:
533 close(fd);
534err0:
535 free(map);
536
537 return (error);
538}
539
540ctf_file_t *
541proc_name2ctf(struct proc_handle *p, const char *name)
542{
543#ifndef NO_CTF
544 ctf_file_t *ctf;
545 prmap_t *map;
546 int error;
547
548 if ((map = proc_name2map(p, name)) == NULL)
549 return (NULL);
550
551 ctf = ctf_open(map->pr_mapname, &error);
552 free(map);
553 return (ctf);
554#else
555 (void)p;
556 (void)name;
557 return (NULL);
558#endif
559}
560
561int
562proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
563 int mask, proc_sym_f *func, void *cd)
564{
565 Elf *e;
566 int i, fd;
567 prmap_t *map;
568 Elf_Scn *scn, *foundscn = NULL;
569 Elf_Data *data;
570 GElf_Ehdr ehdr;
571 GElf_Shdr shdr;
572 GElf_Sym sym;
573 unsigned long stridx = -1;
574 char *s;
575 int error = -1;
576
577 if ((map = proc_name2map(p, object)) == NULL)
578 return (-1);
579 if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
580 DPRINTF("ERROR: open %s failed", map->pr_mapname);
581 goto err0;
582 }
583 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
584 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
585 goto err1;
586 }
587 if (gelf_getehdr(e, &ehdr) == NULL) {
588 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
589 goto err2;
590 }
591 /*
592 * Find the section we are looking for.
593 */
594 scn = NULL;
595 while ((scn = elf_nextscn(e, scn)) != NULL) {
596 gelf_getshdr(scn, &shdr);
597 if (which == PR_SYMTAB &&
598 shdr.sh_type == SHT_SYMTAB) {
599 foundscn = scn;
600 break;
601 } else if (which == PR_DYNSYM &&
602 shdr.sh_type == SHT_DYNSYM) {
603 foundscn = scn;
604 break;
605 }
606 }
607 if (!foundscn)
608 return (-1);
609 stridx = shdr.sh_link;
610 if ((data = elf_getdata(foundscn, NULL)) == NULL) {
611 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
612 goto err2;
613 }
614 for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
615 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
616 (mask & BIND_LOCAL) == 0)
617 continue;
618 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
619 (mask & BIND_GLOBAL) == 0)
620 continue;
621 if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
622 (mask & BIND_WEAK) == 0)
623 continue;
624 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
625 (mask & TYPE_NOTYPE) == 0)
626 continue;
627 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
628 (mask & TYPE_OBJECT) == 0)
629 continue;
630 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
631 (mask & TYPE_FUNC) == 0)
632 continue;
633 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
634 (mask & TYPE_SECTION) == 0)
635 continue;
636 if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
637 (mask & TYPE_FILE) == 0)
638 continue;
639 s = elf_strptr(e, stridx, sym.st_name);
640 if (ehdr.e_type != ET_EXEC)
641 sym.st_value += map->pr_vaddr;
642 if ((error = (*func)(cd, &sym, s)) != 0)
643 goto err2;
644 }
645 error = 0;
646err2:
647 elf_end(e);
648err1:
649 close(fd);
650err0:
651 free(map);
652 return (error);
653}
654