proc_sym.c revision 259970
184865Sobrien/*- 2218822Sdim * Copyright (c) 2010 The FreeBSD Foundation 384865Sobrien * Copyright (c) 2008 John Birrell (jb@freebsd.org) 4218822Sdim * All rights reserved. 584865Sobrien * 684865Sobrien * Portions of this software were developed by Rui Paulo under sponsorship 784865Sobrien * from the FreeBSD Foundation. 884865Sobrien * 984865Sobrien * Redistribution and use in source and binary forms, with or without 1084865Sobrien * modification, are permitted provided that the following conditions 1184865Sobrien * are met: 1284865Sobrien * 1. Redistributions of source code must retain the above copyright 1384865Sobrien * notice, this list of conditions and the following disclaimer. 1484865Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1584865Sobrien * notice, this list of conditions and the following disclaimer in the 1684865Sobrien * documentation and/or other materials provided with the distribution. 1784865Sobrien * 1884865Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1984865Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2084865Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2184865Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22218822Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2384865Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2584865Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2689857Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2784865Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2884865Sobrien * SUCH DAMAGE. 2989857Sobrien * 3084865Sobrien * $FreeBSD: stable/9/lib/libproc/proc_sym.c 259970 2013-12-27 22:54:38Z markj $ 3184865Sobrien */ 3289857Sobrien 3384865Sobrien#include <sys/types.h> 34130561Sobrien#include <sys/user.h> 35130561Sobrien 36130561Sobrien#include <assert.h> 37130561Sobrien#include <err.h> 38130561Sobrien#include <stdio.h> 39130561Sobrien#include <libgen.h> 4089857Sobrien#include <string.h> 4189857Sobrien#include <stdlib.h> 42130561Sobrien#include <fcntl.h> 43130561Sobrien#include <string.h> 44130561Sobrien#include <unistd.h> 45130561Sobrien#include <libutil.h> 46130561Sobrien 47130561Sobrien#include "_libproc.h" 48130561Sobrien 49130561Sobrienstatic void proc_rdl2prmap(rd_loadobj_t *, prmap_t *); 50130561Sobrien 51130561Sobrienstatic void 52130561Sobrienproc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 5389857Sobrien{ 54130561Sobrien map->pr_vaddr = rdl->rdl_saddr; 55130561Sobrien map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 56130561Sobrien map->pr_offset = rdl->rdl_offset; 57218822Sdim map->pr_mflags = 0; 58130561Sobrien if (rdl->rdl_prot & RD_RDL_R) 59130561Sobrien map->pr_mflags |= MA_READ; 60130561Sobrien if (rdl->rdl_prot & RD_RDL_W) 61130561Sobrien map->pr_mflags |= MA_WRITE; 62130561Sobrien if (rdl->rdl_prot & RD_RDL_X) 63130561Sobrien map->pr_mflags |= MA_EXEC; 64130561Sobrien strlcpy(map->pr_mapname, rdl->rdl_path, 65130561Sobrien sizeof(map->pr_mapname)); 66130561Sobrien} 67130561Sobrien 68130561Sobrienchar * 69130561Sobrienproc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 7089857Sobrien size_t objnamesz) 71104834Sobrien{ 72130561Sobrien size_t i; 73130561Sobrien rd_loadobj_t *rdl; 7489857Sobrien 7589857Sobrien for (i = 0; i < p->nobjs; i++) { 7689857Sobrien rdl = &p->rdobjs[i]; 7789857Sobrien if (addr >= rdl->rdl_saddr && addr <= rdl->rdl_eaddr) { 7889857Sobrien strlcpy(objname, rdl->rdl_path, objnamesz); 7989857Sobrien return (objname); 8089857Sobrien } 8189857Sobrien } 8289857Sobrien return (NULL); 8389857Sobrien} 8489857Sobrien 8589857Sobrienprmap_t * 8689857Sobrienproc_obj2map(struct proc_handle *p, const char *objname) 8789857Sobrien{ 8889857Sobrien size_t i; 8989857Sobrien prmap_t *map; 9089857Sobrien rd_loadobj_t *rdl; 91104834Sobrien char path[MAXPATHLEN]; 9289857Sobrien 9389857Sobrien for (i = 0; i < p->nobjs; i++) { 9489857Sobrien rdl = &p->rdobjs[i]; 9589857Sobrien basename_r(rdl->rdl_path, path); 96218822Sdim if (strcmp(path, objname) == 0) { 9789857Sobrien if ((map = malloc(sizeof(*map))) == NULL) 98130561Sobrien return (NULL); 99130561Sobrien proc_rdl2prmap(rdl, map); 100130561Sobrien return (map); 101104834Sobrien } 102130561Sobrien } 103130561Sobrien return (NULL); 104130561Sobrien} 105130561Sobrien 10689857Sobrienint 10789857Sobrienproc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 10889857Sobrien{ 10989857Sobrien size_t i; 11089857Sobrien rd_loadobj_t *rdl; 11189857Sobrien prmap_t map; 11289857Sobrien char path[MAXPATHLEN]; 11389857Sobrien char last[MAXPATHLEN]; 11489857Sobrien 11589857Sobrien if (p->nobjs == 0) 11689857Sobrien return (-1); 11789857Sobrien memset(last, 0, sizeof(last)); 11889857Sobrien for (i = 0; i < p->nobjs; i++) { 11989857Sobrien rdl = &p->rdobjs[i]; 12089857Sobrien proc_rdl2prmap(rdl, &map); 12189857Sobrien basename_r(rdl->rdl_path, path); 12289857Sobrien /* 12389857Sobrien * We shouldn't call the callback twice with the same object. 12489857Sobrien * To do that we are assuming the fact that if there are 12589857Sobrien * repeated object names (i.e. different mappings for the 126104834Sobrien * same object) they occur next to each other. 127104834Sobrien */ 128104834Sobrien if (strcmp(path, last) == 0) 12989857Sobrien continue; 13089857Sobrien (*func)(cd, &map, path); 13189857Sobrien strlcpy(last, path, sizeof(last)); 13284865Sobrien } 13384865Sobrien 134130561Sobrien return (0); 135130561Sobrien} 136130561Sobrien 13789857Sobrienprmap_t * 138130561Sobrienproc_addr2map(struct proc_handle *p, uintptr_t addr) 13989857Sobrien{ 140130561Sobrien size_t i; 141130561Sobrien int cnt, lastvn = 0; 142130561Sobrien prmap_t *map; 143130561Sobrien rd_loadobj_t *rdl; 14489857Sobrien struct kinfo_vmentry *kves, *kve; 14589857Sobrien 14689857Sobrien /* 14789857Sobrien * If we don't have a cache of listed objects, we need to query 14889857Sobrien * it ourselves. 14989857Sobrien */ 15089857Sobrien if (p->nobjs == 0) { 15189857Sobrien if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 15289857Sobrien return (NULL); 15389857Sobrien for (i = 0; i < (size_t)cnt; i++) { 15489857Sobrien kve = kves + i; 15589857Sobrien if (kve->kve_type == KVME_TYPE_VNODE) 156130561Sobrien lastvn = i; 15789857Sobrien if (addr >= kve->kve_start && addr <= kve->kve_end) { 15889857Sobrien if ((map = malloc(sizeof(*map))) == NULL) { 159130561Sobrien free(kves); 16089857Sobrien return (NULL); 16189857Sobrien } 16289857Sobrien map->pr_vaddr = kve->kve_start; 16389857Sobrien map->pr_size = kve->kve_end - kve->kve_start; 164130561Sobrien map->pr_offset = kve->kve_offset; 165130561Sobrien map->pr_mflags = 0; 166130561Sobrien if (kve->kve_protection & KVME_PROT_READ) 167130561Sobrien map->pr_mflags |= MA_READ; 16889857Sobrien if (kve->kve_protection & KVME_PROT_WRITE) 16989857Sobrien map->pr_mflags |= MA_WRITE; 17089857Sobrien if (kve->kve_protection & KVME_PROT_EXEC) 17189857Sobrien map->pr_mflags |= MA_EXEC; 172130561Sobrien if (kve->kve_flags & KVME_FLAG_COW) 173130561Sobrien map->pr_mflags |= MA_COW; 174130561Sobrien if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 175130561Sobrien map->pr_mflags |= MA_NEEDS_COPY; 176130561Sobrien if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 177130561Sobrien map->pr_mflags |= MA_NOCOREDUMP; 178130561Sobrien strlcpy(map->pr_mapname, kves[lastvn].kve_path, 179218822Sdim sizeof(map->pr_mapname)); 18084865Sobrien free(kves); 181104834Sobrien return (map); 182130561Sobrien } 183130561Sobrien } 18489857Sobrien free(kves); 185130561Sobrien return (NULL); 186104834Sobrien } 187130561Sobrien 188104834Sobrien for (i = 0; i < p->nobjs; i++) { 189130561Sobrien rdl = &p->rdobjs[i]; 190104834Sobrien if (addr >= rdl->rdl_saddr && addr <= rdl->rdl_eaddr) { 191130561Sobrien if ((map = malloc(sizeof(*map))) == NULL) 192104834Sobrien return (NULL); 193104834Sobrien proc_rdl2prmap(rdl, map); 194130561Sobrien return (map); 195104834Sobrien } 196104834Sobrien } 197130561Sobrien return (NULL); 198130561Sobrien} 199130561Sobrien 200130561Sobrienint 201104834Sobrienproc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 202130561Sobrien size_t namesz, GElf_Sym *symcopy) 203130561Sobrien{ 204130561Sobrien Elf *e; 205130561Sobrien Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 206130561Sobrien Elf_Data *data; 207130561Sobrien GElf_Shdr shdr; 208130561Sobrien GElf_Sym sym; 209130561Sobrien GElf_Ehdr ehdr; 210130561Sobrien int fd, error = -1; 211130561Sobrien size_t i; 212104834Sobrien uint64_t rsym; 213130561Sobrien prmap_t *map; 214130561Sobrien char *s; 215130561Sobrien unsigned long symtabstridx = 0, dynsymstridx = 0; 216130561Sobrien 217104834Sobrien if ((map = proc_addr2map(p, addr)) == NULL) 218104834Sobrien return (-1); 219130561Sobrien if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 220104834Sobrien DPRINTF("ERROR: open %s failed", map->pr_mapname); 221130561Sobrien goto err0; 222130561Sobrien } 223130561Sobrien if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 224130561Sobrien DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 225104834Sobrien goto err1; 226104834Sobrien } 227130561Sobrien if (gelf_getehdr(e, &ehdr) == NULL) { 228104834Sobrien DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 229104834Sobrien goto err2; 230104834Sobrien } 231104834Sobrien /* 232104834Sobrien * Find the index of the STRTAB and SYMTAB sections to locate 233104834Sobrien * symbol names. 234104834Sobrien */ 235104834Sobrien scn = NULL; 23684865Sobrien while ((scn = elf_nextscn(e, scn)) != NULL) { 23784865Sobrien gelf_getshdr(scn, &shdr); 23884865Sobrien switch (shdr.sh_type) { 239130561Sobrien case SHT_SYMTAB: 24084865Sobrien symtabscn = scn; 24184865Sobrien symtabstridx = shdr.sh_link; 24284865Sobrien break; 24384865Sobrien case SHT_DYNSYM: 24489857Sobrien dynsymscn = scn; 24584865Sobrien dynsymstridx = shdr.sh_link; 24689857Sobrien break; 24784865Sobrien default: 248130561Sobrien break; 24984865Sobrien } 25084865Sobrien } 25184865Sobrien /* 25284865Sobrien * Iterate over the Dynamic Symbols table to find the symbol. 25384865Sobrien * Then look up the string name in STRTAB (.dynstr) 25484865Sobrien */ 25584865Sobrien if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { 25684865Sobrien DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 25784865Sobrien goto symtab; 25884865Sobrien } 25984865Sobrien i = 0; 26084865Sobrien while (gelf_getsym(data, i++, &sym) != NULL) { 26184865Sobrien /* 26284865Sobrien * Calculate the address mapped to the virtual memory 26384865Sobrien * by rtld. 26489857Sobrien */ 265104834Sobrien rsym = map->pr_vaddr + sym.st_value; 26689857Sobrien if (addr >= rsym && addr < rsym + sym.st_size) { 267130561Sobrien s = elf_strptr(e, dynsymstridx, sym.st_name); 26884865Sobrien if (s) { 26984865Sobrien strlcpy(name, s, namesz); 27084865Sobrien memcpy(symcopy, &sym, sizeof(sym)); 27184865Sobrien /* 272130561Sobrien * DTrace expects the st_value to contain 27384865Sobrien * only the address relative to the start of 27484865Sobrien * the function. 27584865Sobrien */ 27684865Sobrien symcopy->st_value = rsym; 27784865Sobrien error = 0; 27884865Sobrien goto out; 27984865Sobrien } 28084865Sobrien } 281130561Sobrien } 28284865Sobriensymtab: 28384865Sobrien /* 28484865Sobrien * Iterate over the Symbols Table to find the symbol. 28584865Sobrien * Then look up the string name in STRTAB (.dynstr) 28684865Sobrien */ 28784865Sobrien if (symtabscn == NULL) 28884865Sobrien goto err2; 28984865Sobrien if ((data = elf_getdata(symtabscn, NULL)) == NULL) { 29084865Sobrien DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 29184865Sobrien goto err2; 29284865Sobrien } 29384865Sobrien i = 0; 29484865Sobrien while (gelf_getsym(data, i++, &sym) != NULL) { 29584865Sobrien /* 29684865Sobrien * Calculate the address mapped to the virtual memory 29784865Sobrien * by rtld. 29884865Sobrien */ 29984865Sobrien if (ehdr.e_type != ET_EXEC) 30084865Sobrien rsym = map->pr_vaddr + sym.st_value; 30184865Sobrien else 30284865Sobrien rsym = sym.st_value; 30384865Sobrien if (addr >= rsym && addr < rsym + sym.st_size) { 30484865Sobrien s = elf_strptr(e, symtabstridx, sym.st_name); 30584865Sobrien if (s) { 306104834Sobrien strlcpy(name, s, namesz); 307104834Sobrien memcpy(symcopy, &sym, sizeof(sym)); 30884865Sobrien /* 30984865Sobrien * DTrace expects the st_value to contain 31084865Sobrien * only the address relative to the start of 31184865Sobrien * the function. 312130561Sobrien */ 31384865Sobrien symcopy->st_value = rsym; 31484865Sobrien error = 0; 31584865Sobrien goto out; 31684865Sobrien } 31784865Sobrien } 31884865Sobrien } 31984865Sobrienout: 320130561Sobrienerr2: 32184865Sobrien elf_end(e); 32284865Sobrienerr1: 32384865Sobrien close(fd); 32484865Sobrienerr0: 325130561Sobrien free(map); 32684865Sobrien return (error); 32784865Sobrien} 32884865Sobrien 32984865Sobrienprmap_t * 330130561Sobrienproc_name2map(struct proc_handle *p, const char *name) 33184865Sobrien{ 33284865Sobrien size_t i; 33384865Sobrien int cnt; 33484865Sobrien prmap_t *map; 33589857Sobrien char tmppath[MAXPATHLEN]; 33684865Sobrien struct kinfo_vmentry *kves, *kve; 33784865Sobrien rd_loadobj_t *rdl; 33884865Sobrien 339130561Sobrien /* 34084865Sobrien * If we haven't iterated over the list of loaded objects, 34184865Sobrien * librtld_db isn't yet initialized and it's very likely 34284865Sobrien * that librtld_db called us. We need to do the heavy 34384865Sobrien * lifting here to find the symbol librtld_db is looking for. 34489857Sobrien */ 34584865Sobrien if (p->nobjs == 0) { 34684865Sobrien if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 34789857Sobrien return (NULL); 34889857Sobrien for (i = 0; i < (size_t)cnt; i++) { 34989857Sobrien kve = kves + i; 35089857Sobrien basename_r(kve->kve_path, tmppath); 35189857Sobrien if (strcmp(tmppath, name) == 0) { 35284865Sobrien map = proc_addr2map(p, kve->kve_start); 35384865Sobrien free(kves); 35484865Sobrien return (map); 35584865Sobrien } 356130561Sobrien } 357130561Sobrien free(kves); 358130561Sobrien return (NULL); 35984865Sobrien } 36084865Sobrien if (name == NULL || strcmp(name, "a.out") == 0) { 36184865Sobrien map = proc_addr2map(p, p->rdobjs[0].rdl_saddr); 36284865Sobrien return (map); 36384865Sobrien } 36484865Sobrien for (i = 0; i < p->nobjs; i++) { 365130561Sobrien rdl = &p->rdobjs[i]; 36684865Sobrien basename_r(rdl->rdl_path, tmppath); 36784865Sobrien if (strcmp(tmppath, name) == 0) { 36884865Sobrien if ((map = malloc(sizeof(*map))) == NULL) 36989857Sobrien return (NULL); 37089857Sobrien proc_rdl2prmap(rdl, map); 37184865Sobrien return (map); 37284865Sobrien } 37389857Sobrien } 37489857Sobrien 37589857Sobrien return (NULL); 37689857Sobrien} 37789857Sobrien 37884865Sobrienint 37984865Sobrienproc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 38084865Sobrien GElf_Sym *symcopy) 38184865Sobrien{ 38284865Sobrien Elf *e; 383130561Sobrien Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 384130561Sobrien Elf_Data *data; 385130561Sobrien GElf_Shdr shdr; 386130561Sobrien GElf_Sym sym; 387130561Sobrien GElf_Ehdr ehdr; 388130561Sobrien int fd, error = -1; 389130561Sobrien size_t i; 39084865Sobrien prmap_t *map; 39189857Sobrien char *s; 39284865Sobrien unsigned long symtabstridx = 0, dynsymstridx = 0; 39384865Sobrien 39489857Sobrien if ((map = proc_name2map(p, object)) == NULL) { 39589857Sobrien DPRINTFX("ERROR: couldn't find object %s", object); 39684865Sobrien goto err0; 39789857Sobrien } 39889857Sobrien if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 39984865Sobrien DPRINTF("ERROR: open %s failed", map->pr_mapname); 40084865Sobrien goto err0; 40189857Sobrien } 40289857Sobrien if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 40389857Sobrien DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 40489857Sobrien goto err1; 40589857Sobrien } 40689857Sobrien if (gelf_getehdr(e, &ehdr) == NULL) { 40789857Sobrien DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 40889857Sobrien goto err2; 40989857Sobrien } 41089857Sobrien /* 41189857Sobrien * Find the index of the STRTAB and SYMTAB sections to locate 41289857Sobrien * symbol names. 41389857Sobrien */ 41489857Sobrien scn = NULL; 41589857Sobrien while ((scn = elf_nextscn(e, scn)) != NULL) { 41684865Sobrien gelf_getshdr(scn, &shdr); 41784865Sobrien switch (shdr.sh_type) { 41884865Sobrien case SHT_SYMTAB: 41984865Sobrien symtabscn = scn; 42084865Sobrien symtabstridx = shdr.sh_link; 42184865Sobrien break; 42284865Sobrien case SHT_DYNSYM: 42389857Sobrien dynsymscn = scn; 42489857Sobrien dynsymstridx = shdr.sh_link; 42589857Sobrien break; 42684865Sobrien default: 42784865Sobrien break; 42884865Sobrien } 42989857Sobrien } 43089857Sobrien /* 43189857Sobrien * Iterate over the Dynamic Symbols table to find the symbol. 43289857Sobrien * Then look up the string name in STRTAB (.dynstr) 43384865Sobrien */ 43484865Sobrien if ((data = elf_getdata(dynsymscn, NULL))) { 43584865Sobrien i = 0; 43684865Sobrien while (gelf_getsym(data, i++, &sym) != NULL) { 43784865Sobrien s = elf_strptr(e, dynsymstridx, sym.st_name); 43884865Sobrien if (s && strcmp(s, symbol) == 0) { 43984865Sobrien memcpy(symcopy, &sym, sizeof(sym)); 44089857Sobrien symcopy->st_value = map->pr_vaddr + sym.st_value; 44189857Sobrien error = 0; 44289857Sobrien goto out; 44389857Sobrien } 44489857Sobrien } 44584865Sobrien } 446130561Sobrien /* 44784865Sobrien * Iterate over the Symbols Table to find the symbol. 44884865Sobrien * Then look up the string name in STRTAB (.dynstr) 44984865Sobrien */ 45084865Sobrien if (symtabscn == NULL) 45184865Sobrien goto err2; 45284865Sobrien if ((data = elf_getdata(symtabscn, NULL))) { 45384865Sobrien i = 0; 45484865Sobrien while (gelf_getsym(data, i++, &sym) != NULL) { 45584865Sobrien s = elf_strptr(e, symtabstridx, sym.st_name); 45689857Sobrien if (s && strcmp(s, symbol) == 0) { 45789857Sobrien memcpy(symcopy, &sym, sizeof(sym)); 45884865Sobrien error = 0; 45984865Sobrien goto out; 46084865Sobrien } 46189857Sobrien } 46289857Sobrien } 46389857Sobrienout: 46489857Sobrienerr2: 46584865Sobrien elf_end(e); 46684865Sobrienerr1: 46784865Sobrien close(fd); 46884865Sobrienerr0: 46989857Sobrien free(map); 47084865Sobrien 47189857Sobrien return (error); 47284865Sobrien} 47389857Sobrien 47484865Sobrien 47589857Sobrienint 47684865Sobrienproc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 47784865Sobrien int mask, proc_sym_f *func, void *cd) 47889857Sobrien{ 47989857Sobrien Elf *e; 48089857Sobrien int i, fd; 48189857Sobrien prmap_t *map; 48289857Sobrien Elf_Scn *scn, *foundscn = NULL; 48389857Sobrien Elf_Data *data; 48489857Sobrien GElf_Shdr shdr; 48589857Sobrien GElf_Sym sym; 48689857Sobrien unsigned long stridx = -1; 48789857Sobrien char *s; 48889857Sobrien int error = -1; 48989857Sobrien 49089857Sobrien if ((map = proc_name2map(p, object)) == NULL) 49189857Sobrien return (-1); 49284865Sobrien if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 49384865Sobrien DPRINTF("ERROR: open %s failed", map->pr_mapname); 49484865Sobrien goto err0; 49589857Sobrien } 496130561Sobrien if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 497130561Sobrien DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 49889857Sobrien goto err1; 49984865Sobrien } 50084865Sobrien /* 50189857Sobrien * Find the section we are looking for. 50289857Sobrien */ 50384865Sobrien scn = NULL; 50484865Sobrien while ((scn = elf_nextscn(e, scn)) != NULL) { 50584865Sobrien gelf_getshdr(scn, &shdr); 50684865Sobrien if (which == PR_SYMTAB && 50789857Sobrien shdr.sh_type == SHT_SYMTAB) { 50884865Sobrien foundscn = scn; 50984865Sobrien break; 51084865Sobrien } else if (which == PR_DYNSYM && 51184865Sobrien shdr.sh_type == SHT_DYNSYM) { 512130561Sobrien foundscn = scn; 51384865Sobrien break; 51484865Sobrien } 51589857Sobrien } 51689857Sobrien if (!foundscn) 51789857Sobrien return (-1); 51889857Sobrien stridx = shdr.sh_link; 51989857Sobrien if ((data = elf_getdata(foundscn, NULL)) == NULL) { 52089857Sobrien DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 52189857Sobrien goto err2; 52289857Sobrien } 52389857Sobrien i = 0; 52489857Sobrien while (gelf_getsym(data, i++, &sym) != NULL) { 52589857Sobrien if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 52684865Sobrien (mask & BIND_LOCAL) == 0) 52789857Sobrien continue; 52889857Sobrien if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 52989857Sobrien (mask & BIND_GLOBAL) == 0) 53089857Sobrien continue; 53189857Sobrien if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 53289857Sobrien (mask & BIND_WEAK) == 0) 53389857Sobrien continue; 53489857Sobrien if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 53589857Sobrien (mask & TYPE_NOTYPE) == 0) 53689857Sobrien continue; 53789857Sobrien if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 53889857Sobrien (mask & TYPE_OBJECT) == 0) 53989857Sobrien continue; 54089857Sobrien if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 54189857Sobrien (mask & TYPE_FUNC) == 0) 54289857Sobrien continue; 54389857Sobrien if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 54489857Sobrien (mask & TYPE_SECTION) == 0) 54584865Sobrien continue; 54689857Sobrien if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 54789857Sobrien (mask & TYPE_FILE) == 0) 54889857Sobrien continue; 54989857Sobrien s = elf_strptr(e, stridx, sym.st_name); 55089857Sobrien sym.st_value += map->pr_vaddr; 55189857Sobrien (*func)(cd, &sym, s); 55289857Sobrien } 55389857Sobrien error = 0; 55489857Sobrienerr2: 55589857Sobrien elf_end(e); 55689857Sobrienerr1: 55784865Sobrien close(fd); 55884865Sobrienerr0: 55989857Sobrien free(map); 56089857Sobrien return (error); 56184865Sobrien} 56284865Sobrien