proc_sym.c revision 269885
155682Smarkm/*-
2233294Sstas * Copyright (c) 2010 The FreeBSD Foundation
3233294Sstas * Copyright (c) 2008 John Birrell (jb@freebsd.org)
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Portions of this software were developed by Rui Paulo under sponsorship
7233294Sstas * from the FreeBSD Foundation.
8233294Sstas *
955682Smarkm * Redistribution and use in source and binary forms, with or without
10233294Sstas * modification, are permitted provided that the following conditions
11233294Sstas * are met:
1255682Smarkm * 1. Redistributions of source code must retain the above copyright
13233294Sstas *    notice, this list of conditions and the following disclaimer.
14233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
15233294Sstas *    notice, this list of conditions and the following disclaimer in the
1655682Smarkm *    documentation and/or other materials provided with the distribution.
17233294Sstas *
18233294Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2055682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28233294Sstas * SUCH DAMAGE.
29233294Sstas *
30233294Sstas * $FreeBSD: stable/10/lib/libproc/proc_sym.c 269885 2014-08-12 17:56:48Z dim $
31233294Sstas */
3255682Smarkm
3355682Smarkm#include <sys/types.h>
3455682Smarkm#include <sys/user.h>
3555682Smarkm
3655682Smarkm#include <assert.h>
3755682Smarkm#include <err.h>
3855682Smarkm#include <stdio.h>
39178825Sdfr#include <libgen.h>
4055682Smarkm#include <string.h>
4155682Smarkm#include <stdlib.h>
4255682Smarkm#include <fcntl.h>
4355682Smarkm#include <string.h>
4455682Smarkm#include <unistd.h>
4555682Smarkm#include <libutil.h>
4655682Smarkm
4755682Smarkm#include "_libproc.h"
4855682Smarkm
4955682Smarkm#ifndef NO_CXA_DEMANGLE
5055682Smarkmextern char *__cxa_demangle(const char *, char *, size_t *, int *);
5155682Smarkm#endif /* NO_CXA_DEMANGLE */
5255682Smarkm
5355682Smarkmstatic void	proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
5455682Smarkm
5555682Smarkmstatic void
5655682Smarkmdemangle(const char *symbol, char *buf, size_t len)
5755682Smarkm{
5855682Smarkm#ifndef NO_CXA_DEMANGLE
5955682Smarkm	char *dembuf;
6055682Smarkm
6155682Smarkm	if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) {
6255682Smarkm		dembuf = __cxa_demangle(symbol, NULL, NULL, NULL);
6355682Smarkm		if (!dembuf)
6455682Smarkm			goto fail;
6555682Smarkm		strlcpy(buf, dembuf, len);
6655682Smarkm		free(dembuf);
6755682Smarkm		return;
6855682Smarkm	}
6955682Smarkmfail:
7055682Smarkm#endif /* NO_CXA_DEMANGLE */
7155682Smarkm	strlcpy(buf, symbol, len);
7255682Smarkm}
73233294Sstas
7455682Smarkmstatic void
7555682Smarkmproc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
7655682Smarkm{
7755682Smarkm	map->pr_vaddr = rdl->rdl_saddr;
7855682Smarkm	map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
7955682Smarkm	map->pr_offset = rdl->rdl_offset;
8055682Smarkm	map->pr_mflags = 0;
8155682Smarkm	if (rdl->rdl_prot & RD_RDL_R)
8255682Smarkm		map->pr_mflags |= MA_READ;
83233294Sstas	if (rdl->rdl_prot & RD_RDL_W)
8478527Sassar		map->pr_mflags |= MA_WRITE;
8578527Sassar	if (rdl->rdl_prot & RD_RDL_X)
8655682Smarkm		map->pr_mflags |= MA_EXEC;
8755682Smarkm	strlcpy(map->pr_mapname, rdl->rdl_path,
8855682Smarkm	    sizeof(map->pr_mapname));
8955682Smarkm}
9055682Smarkm
9155682Smarkmchar *
9255682Smarkmproc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
9355682Smarkm    size_t objnamesz)
9455682Smarkm{
9555682Smarkm	size_t i;
9655682Smarkm	rd_loadobj_t *rdl;
9755682Smarkm
9855682Smarkm	for (i = 0; i < p->nobjs; i++) {
9955682Smarkm		rdl = &p->rdobjs[i];
10055682Smarkm		if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
10155682Smarkm			strlcpy(objname, rdl->rdl_path, objnamesz);
10255682Smarkm			return (objname);
10355682Smarkm		}
10455682Smarkm	}
10555682Smarkm	return (NULL);
10655682Smarkm}
10755682Smarkm
10855682Smarkmprmap_t *
10955682Smarkmproc_obj2map(struct proc_handle *p, const char *objname)
11055682Smarkm{
11155682Smarkm	size_t i;
11255682Smarkm	prmap_t *map;
11355682Smarkm	rd_loadobj_t *rdl;
11455682Smarkm	char path[MAXPATHLEN];
11555682Smarkm
11655682Smarkm	for (i = 0; i < p->nobjs; i++) {
11755682Smarkm		rdl = &p->rdobjs[i];
11855682Smarkm		basename_r(rdl->rdl_path, path);
11955682Smarkm		if (strcmp(path, objname) == 0) {
12055682Smarkm			if ((map = malloc(sizeof(*map))) == NULL)
12155682Smarkm				return (NULL);
12255682Smarkm			proc_rdl2prmap(rdl, map);
12355682Smarkm			return (map);
12455682Smarkm		}
12555682Smarkm	}
12655682Smarkm	return (NULL);
12755682Smarkm}
12855682Smarkm
12955682Smarkmint
13055682Smarkmproc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
13155682Smarkm{
13255682Smarkm	size_t i;
13355682Smarkm	rd_loadobj_t *rdl;
13455682Smarkm	prmap_t map;
13555682Smarkm	char path[MAXPATHLEN];
13655682Smarkm	char last[MAXPATHLEN];
13755682Smarkm
13855682Smarkm	if (p->nobjs == 0)
13955682Smarkm		return (-1);
14055682Smarkm	memset(last, 0, sizeof(last));
14155682Smarkm	for (i = 0; i < p->nobjs; i++) {
14255682Smarkm		rdl = &p->rdobjs[i];
14355682Smarkm		proc_rdl2prmap(rdl, &map);
14455682Smarkm		basename_r(rdl->rdl_path, path);
14555682Smarkm		/*
14655682Smarkm		 * We shouldn't call the callback twice with the same object.
14755682Smarkm		 * To do that we are assuming the fact that if there are
14855682Smarkm		 * repeated object names (i.e. different mappings for the
14955682Smarkm		 * same object) they occur next to each other.
15055682Smarkm		 */
15155682Smarkm		if (strcmp(path, last) == 0)
152233294Sstas			continue;
15355682Smarkm		(*func)(cd, &map, path);
15455682Smarkm		strlcpy(last, path, sizeof(last));
15555682Smarkm	}
15655682Smarkm
15755682Smarkm	return (0);
15855682Smarkm}
15955682Smarkm
16055682Smarkmprmap_t *
16155682Smarkmproc_addr2map(struct proc_handle *p, uintptr_t addr)
16255682Smarkm{
16355682Smarkm	size_t i;
16455682Smarkm	int cnt, lastvn = 0;
16555682Smarkm	prmap_t *map;
16655682Smarkm	rd_loadobj_t *rdl;
16755682Smarkm	struct kinfo_vmentry *kves, *kve;
16855682Smarkm
16955682Smarkm	/*
17055682Smarkm	 * If we don't have a cache of listed objects, we need to query
17155682Smarkm	 * it ourselves.
17255682Smarkm	 */
17355682Smarkm	if (p->nobjs == 0) {
17455682Smarkm		if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
17555682Smarkm			return (NULL);
17655682Smarkm		for (i = 0; i < (size_t)cnt; i++) {
17755682Smarkm			kve = kves + i;
178233294Sstas			if (kve->kve_type == KVME_TYPE_VNODE)
17955682Smarkm				lastvn = i;
18055682Smarkm			if (addr >= kve->kve_start && addr < kve->kve_end) {
18155682Smarkm				if ((map = malloc(sizeof(*map))) == NULL) {
18255682Smarkm					free(kves);
18355682Smarkm					return (NULL);
18455682Smarkm				}
18555682Smarkm				map->pr_vaddr = kve->kve_start;
18655682Smarkm				map->pr_size = kve->kve_end - kve->kve_start;
18755682Smarkm				map->pr_offset = kve->kve_offset;
18855682Smarkm				map->pr_mflags = 0;
18955682Smarkm				if (kve->kve_protection & KVME_PROT_READ)
19090926Snectar					map->pr_mflags |= MA_READ;
19155682Smarkm				if (kve->kve_protection & KVME_PROT_WRITE)
192178825Sdfr					map->pr_mflags |= MA_WRITE;
193178825Sdfr				if (kve->kve_protection & KVME_PROT_EXEC)
19455682Smarkm					map->pr_mflags |= MA_EXEC;
19555682Smarkm				if (kve->kve_flags & KVME_FLAG_COW)
19655682Smarkm					map->pr_mflags |= MA_COW;
19790926Snectar				if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
19855682Smarkm					map->pr_mflags |= MA_NEEDS_COPY;
19955682Smarkm				if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
20055682Smarkm					map->pr_mflags |= MA_NOCOREDUMP;
20155682Smarkm				strlcpy(map->pr_mapname, kves[lastvn].kve_path,
20255682Smarkm				    sizeof(map->pr_mapname));
203178825Sdfr				free(kves);
20455682Smarkm				return (map);
205178825Sdfr			}
206178825Sdfr		}
20755682Smarkm		free(kves);
208178825Sdfr		return (NULL);
20990926Snectar	}
21090926Snectar
211233294Sstas	for (i = 0; i < p->nobjs; i++) {
212178825Sdfr		rdl = &p->rdobjs[i];
213178825Sdfr		if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) {
214178825Sdfr			if ((map = malloc(sizeof(*map))) == NULL)
215178825Sdfr				return (NULL);
216178825Sdfr			proc_rdl2prmap(rdl, map);
217178825Sdfr			return (map);
21855682Smarkm		}
21955682Smarkm	}
22055682Smarkm	return (NULL);
22155682Smarkm}
22255682Smarkm
22355682Smarkmint
22455682Smarkmproc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
225178825Sdfr    size_t namesz, GElf_Sym *symcopy)
22655682Smarkm{
22755682Smarkm	Elf *e;
228178825Sdfr	Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
229178825Sdfr	Elf_Data *data;
23055682Smarkm	GElf_Shdr shdr;
23155682Smarkm	GElf_Sym sym;
23255682Smarkm	GElf_Ehdr ehdr;
23355682Smarkm	int fd, error = -1;
23455682Smarkm	size_t i;
23555682Smarkm	uint64_t rsym;
23655682Smarkm	prmap_t *map;
23755682Smarkm	char *s;
23855682Smarkm	unsigned long symtabstridx = 0, dynsymstridx = 0;
23955682Smarkm
24055682Smarkm	if ((map = proc_addr2map(p, addr)) == NULL)
24155682Smarkm		return (-1);
24255682Smarkm	if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
24355682Smarkm		DPRINTF("ERROR: open %s failed", map->pr_mapname);
24455682Smarkm		goto err0;
24555682Smarkm	}
24655682Smarkm	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
24755682Smarkm		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
248233294Sstas		goto err1;
24955682Smarkm	}
25055682Smarkm	if (gelf_getehdr(e, &ehdr) == NULL) {
25155682Smarkm		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
25255682Smarkm		goto err2;
25355682Smarkm	}
25455682Smarkm	/*
25555682Smarkm	 * Find the index of the STRTAB and SYMTAB sections to locate
25655682Smarkm	 * symbol names.
257233294Sstas	 */
25855682Smarkm	scn = NULL;
25955682Smarkm	while ((scn = elf_nextscn(e, scn)) != NULL) {
26055682Smarkm		gelf_getshdr(scn, &shdr);
26155682Smarkm		switch (shdr.sh_type) {
26255682Smarkm		case SHT_SYMTAB:
26355682Smarkm			symtabscn = scn;
26455682Smarkm			symtabstridx = shdr.sh_link;
26555682Smarkm			break;
266233294Sstas		case SHT_DYNSYM:
26755682Smarkm			dynsymscn = scn;
26855682Smarkm			dynsymstridx = shdr.sh_link;
26955682Smarkm			break;
270233294Sstas		default:
27155682Smarkm			break;
27255682Smarkm		}
27355682Smarkm	}
27455682Smarkm	/*
27555682Smarkm	 * Iterate over the Dynamic Symbols table to find the symbol.
27655682Smarkm	 * Then look up the string name in STRTAB (.dynstr)
27755682Smarkm	 */
27855682Smarkm	if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
27955682Smarkm		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
28055682Smarkm		goto symtab;
28155682Smarkm	}
28255682Smarkm	i = 0;
28355682Smarkm	while (gelf_getsym(data, i++, &sym) != NULL) {
28455682Smarkm		/*
28555682Smarkm		 * Calculate the address mapped to the virtual memory
28655682Smarkm		 * by rtld.
28755682Smarkm		 */
28855682Smarkm		if (ehdr.e_type != ET_EXEC)
28955682Smarkm			rsym = map->pr_vaddr + sym.st_value;
29055682Smarkm		else
291233294Sstas			rsym = sym.st_value;
29255682Smarkm		if (addr >= rsym && addr < rsym + sym.st_size) {
29355682Smarkm			s = elf_strptr(e, dynsymstridx, sym.st_name);
29455682Smarkm			if (s) {
29555682Smarkm				demangle(s, name, namesz);
29655682Smarkm				memcpy(symcopy, &sym, sizeof(sym));
29755682Smarkm				/*
29855682Smarkm				 * DTrace expects the st_value to contain
29955682Smarkm				 * only the address relative to the start of
300178825Sdfr				 * the function.
30155682Smarkm				 */
30255682Smarkm				symcopy->st_value = rsym;
30355682Smarkm				error = 0;
30455682Smarkm				goto out;
30555682Smarkm			}
30655682Smarkm		}
30755682Smarkm	}
30855682Smarkmsymtab:
30955682Smarkm	/*
31055682Smarkm	 * Iterate over the Symbols Table to find the symbol.
311233294Sstas	 * Then look up the string name in STRTAB (.dynstr)
31255682Smarkm	 */
31355682Smarkm	if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
31455682Smarkm		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
31555682Smarkm		goto err2;
31655682Smarkm	}
31755682Smarkm	i = 0;
31855682Smarkm	while (gelf_getsym(data, i++, &sym) != NULL) {
31955682Smarkm		/*
320233294Sstas		 * Calculate the address mapped to the virtual memory
32155682Smarkm		 * by rtld.
32255682Smarkm		 */
32355682Smarkm		if (ehdr.e_type != ET_EXEC)
32455682Smarkm			rsym = map->pr_vaddr + sym.st_value;
32555682Smarkm		else
32655682Smarkm			rsym = sym.st_value;
32755682Smarkm		if (addr >= rsym && addr < rsym + sym.st_size) {
328			s = elf_strptr(e, symtabstridx, sym.st_name);
329			if (s) {
330				demangle(s, name, namesz);
331				memcpy(symcopy, &sym, sizeof(sym));
332				/*
333				 * DTrace expects the st_value to contain
334				 * only the address relative to the start of
335				 * the function.
336				 */
337				symcopy->st_value = rsym;
338				error = 0;
339				goto out;
340			}
341		}
342	}
343out:
344err2:
345	elf_end(e);
346err1:
347	close(fd);
348err0:
349	free(map);
350	return (error);
351}
352
353prmap_t *
354proc_name2map(struct proc_handle *p, const char *name)
355{
356	size_t i;
357	int cnt;
358	prmap_t *map;
359	char tmppath[MAXPATHLEN];
360	struct kinfo_vmentry *kves, *kve;
361	rd_loadobj_t *rdl;
362
363	/*
364	 * If we haven't iterated over the list of loaded objects,
365	 * librtld_db isn't yet initialized and it's very likely
366	 * that librtld_db called us. We need to do the heavy
367	 * lifting here to find the symbol librtld_db is looking for.
368	 */
369	if (p->nobjs == 0) {
370		if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
371			return (NULL);
372		for (i = 0; i < (size_t)cnt; i++) {
373			kve = kves + i;
374			basename_r(kve->kve_path, tmppath);
375			if (strcmp(tmppath, name) == 0) {
376				map = proc_addr2map(p, kve->kve_start);
377				free(kves);
378				return (map);
379			}
380		}
381		free(kves);
382		return (NULL);
383	}
384	if (name == NULL || strcmp(name, "a.out") == 0) {
385		map = proc_addr2map(p, p->rdobjs[0].rdl_saddr);
386		return (map);
387	}
388	for (i = 0; i < p->nobjs; i++) {
389		rdl = &p->rdobjs[i];
390		basename_r(rdl->rdl_path, tmppath);
391		if (strcmp(tmppath, name) == 0) {
392			if ((map = malloc(sizeof(*map))) == NULL)
393				return (NULL);
394			proc_rdl2prmap(rdl, map);
395			return (map);
396		}
397	}
398
399	return (NULL);
400}
401
402int
403proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
404    GElf_Sym *symcopy)
405{
406	Elf *e;
407	Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
408	Elf_Data *data;
409	GElf_Shdr shdr;
410	GElf_Sym sym;
411	GElf_Ehdr ehdr;
412	int fd, error = -1;
413	size_t i;
414	prmap_t *map;
415	char *s;
416	unsigned long symtabstridx = 0, dynsymstridx = 0;
417
418	if ((map = proc_name2map(p, object)) == NULL) {
419		DPRINTFX("ERROR: couldn't find object %s", object);
420		goto err0;
421	}
422	if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
423		DPRINTF("ERROR: open %s failed", map->pr_mapname);
424		goto err0;
425	}
426	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
427		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
428		goto err1;
429	}
430	if (gelf_getehdr(e, &ehdr) == NULL) {
431		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
432		goto err2;
433	}
434	/*
435	 * Find the index of the STRTAB and SYMTAB sections to locate
436	 * symbol names.
437	 */
438	scn = NULL;
439	while ((scn = elf_nextscn(e, scn)) != NULL) {
440		gelf_getshdr(scn, &shdr);
441		switch (shdr.sh_type) {
442		case SHT_SYMTAB:
443			symtabscn = scn;
444			symtabstridx = shdr.sh_link;
445			break;
446		case SHT_DYNSYM:
447			dynsymscn = scn;
448			dynsymstridx = shdr.sh_link;
449			break;
450		default:
451			break;
452		}
453	}
454	/*
455	 * Iterate over the Dynamic Symbols table to find the symbol.
456	 * Then look up the string name in STRTAB (.dynstr)
457	 */
458	if ((data = elf_getdata(dynsymscn, NULL))) {
459		i = 0;
460		while (gelf_getsym(data, i++, &sym) != NULL) {
461			s = elf_strptr(e, dynsymstridx, sym.st_name);
462			if (s && strcmp(s, symbol) == 0) {
463				memcpy(symcopy, &sym, sizeof(sym));
464				if (ehdr.e_type != ET_EXEC)
465					symcopy->st_value += map->pr_vaddr;
466				error = 0;
467				goto out;
468			}
469		}
470	}
471	/*
472	 * Iterate over the Symbols Table to find the symbol.
473	 * Then look up the string name in STRTAB (.dynstr)
474	 */
475	if ((data = elf_getdata(symtabscn, NULL))) {
476		i = 0;
477		while (gelf_getsym(data, i++, &sym) != NULL) {
478			s = elf_strptr(e, symtabstridx, sym.st_name);
479			if (s && strcmp(s, symbol) == 0) {
480				memcpy(symcopy, &sym, sizeof(sym));
481				if (ehdr.e_type != ET_EXEC)
482					symcopy->st_value += map->pr_vaddr;
483				error = 0;
484				goto out;
485			}
486		}
487	}
488out:
489	DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol);
490err2:
491	elf_end(e);
492err1:
493	close(fd);
494err0:
495	free(map);
496
497	return (error);
498}
499
500
501int
502proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
503    int mask, proc_sym_f *func, void *cd)
504{
505	Elf *e;
506	int i, fd;
507	prmap_t *map;
508	Elf_Scn *scn, *foundscn = NULL;
509	Elf_Data *data;
510	GElf_Ehdr ehdr;
511	GElf_Shdr shdr;
512	GElf_Sym sym;
513	unsigned long stridx = -1;
514	char *s;
515	int error = -1;
516
517	if ((map = proc_name2map(p, object)) == NULL)
518		return (-1);
519	if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) {
520		DPRINTF("ERROR: open %s failed", map->pr_mapname);
521		goto err0;
522	}
523	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
524		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
525		goto err1;
526	}
527	if (gelf_getehdr(e, &ehdr) == NULL) {
528		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
529		goto err2;
530	}
531	/*
532	 * Find the section we are looking for.
533	 */
534	scn = NULL;
535	while ((scn = elf_nextscn(e, scn)) != NULL) {
536		gelf_getshdr(scn, &shdr);
537		if (which == PR_SYMTAB &&
538		    shdr.sh_type == SHT_SYMTAB) {
539			foundscn = scn;
540			break;
541		} else if (which == PR_DYNSYM &&
542		    shdr.sh_type == SHT_DYNSYM) {
543			foundscn = scn;
544			break;
545		}
546	}
547	if (!foundscn)
548		return (-1);
549	stridx = shdr.sh_link;
550	if ((data = elf_getdata(foundscn, NULL)) == NULL) {
551		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
552		goto err2;
553	}
554	i = 0;
555	while (gelf_getsym(data, i++, &sym) != NULL) {
556		if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
557		    (mask & BIND_LOCAL) == 0)
558			continue;
559		if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
560		    (mask & BIND_GLOBAL) == 0)
561			continue;
562		if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
563		    (mask & BIND_WEAK) == 0)
564			continue;
565		if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
566		    (mask & TYPE_NOTYPE) == 0)
567			continue;
568		if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
569		    (mask & TYPE_OBJECT) == 0)
570			continue;
571		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
572		    (mask & TYPE_FUNC) == 0)
573			continue;
574		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
575		    (mask & TYPE_SECTION) == 0)
576			continue;
577		if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
578		    (mask & TYPE_FILE) == 0)
579			continue;
580		s = elf_strptr(e, stridx, sym.st_name);
581		if (ehdr.e_type != ET_EXEC)
582			sym.st_value += map->pr_vaddr;
583		(*func)(cd, &sym, s);
584	}
585	error = 0;
586err2:
587	elf_end(e);
588err1:
589	close(fd);
590err0:
591	free(map);
592	return (error);
593}
594