12c633af4SJohn Birrell /*- 28eb20f36SRui Paulo * Copyright (c) 2010 The FreeBSD Foundation 32c633af4SJohn Birrell * Copyright (c) 2008 John Birrell (jb@freebsd.org) 42c633af4SJohn Birrell * All rights reserved. 52c633af4SJohn Birrell * 68eb20f36SRui Paulo * Portions of this software were developed by Rui Paulo under sponsorship 78eb20f36SRui Paulo * from the FreeBSD Foundation. 88eb20f36SRui Paulo * 92c633af4SJohn Birrell * Redistribution and use in source and binary forms, with or without 102c633af4SJohn Birrell * modification, are permitted provided that the following conditions 112c633af4SJohn Birrell * are met: 122c633af4SJohn Birrell * 1. Redistributions of source code must retain the above copyright 132c633af4SJohn Birrell * notice, this list of conditions and the following disclaimer. 142c633af4SJohn Birrell * 2. Redistributions in binary form must reproduce the above copyright 152c633af4SJohn Birrell * notice, this list of conditions and the following disclaimer in the 162c633af4SJohn Birrell * documentation and/or other materials provided with the distribution. 172c633af4SJohn Birrell * 182c633af4SJohn Birrell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 192c633af4SJohn Birrell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 202c633af4SJohn Birrell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 212c633af4SJohn Birrell * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 222c633af4SJohn Birrell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 232c633af4SJohn Birrell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 242c633af4SJohn Birrell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 252c633af4SJohn Birrell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 262c633af4SJohn Birrell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 272c633af4SJohn Birrell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 282c633af4SJohn Birrell * SUCH DAMAGE. 292c633af4SJohn Birrell */ 302c633af4SJohn Birrell 31*540cc663SMark Johnston #include <sys/cdefs.h> 32*540cc663SMark Johnston __FBSDID("$FreeBSD$"); 33*540cc663SMark Johnston 348eb20f36SRui Paulo #include <sys/types.h> 358eb20f36SRui Paulo #include <sys/user.h> 368eb20f36SRui Paulo 378eb20f36SRui Paulo #include <assert.h> 388eb20f36SRui Paulo #include <err.h> 398eb20f36SRui Paulo #include <fcntl.h> 40*540cc663SMark Johnston #include <libgen.h> 41*540cc663SMark Johnston #include <stdio.h> 42*540cc663SMark Johnston #include <stdlib.h> 438eb20f36SRui Paulo #include <string.h> 448eb20f36SRui Paulo #include <unistd.h> 458eb20f36SRui Paulo #include <libutil.h> 468eb20f36SRui Paulo 478eb20f36SRui Paulo #include "_libproc.h" 488eb20f36SRui Paulo 493d12a343SDimitry Andric #ifndef NO_CXA_DEMANGLE 50cd906041SRui Paulo extern char *__cxa_demangle(const char *, char *, size_t *, int *); 513d12a343SDimitry Andric #endif /* NO_CXA_DEMANGLE */ 52cd906041SRui Paulo 538eb20f36SRui Paulo static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *); 548eb20f36SRui Paulo 558eb20f36SRui Paulo static void 56404087ccSRui Paulo demangle(const char *symbol, char *buf, size_t len) 57404087ccSRui Paulo { 583d12a343SDimitry Andric #ifndef NO_CXA_DEMANGLE 59404087ccSRui Paulo char *dembuf; 60404087ccSRui Paulo 613d12a343SDimitry Andric if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) { 6296ec3cddSDimitry Andric dembuf = __cxa_demangle(symbol, NULL, NULL, NULL); 63404087ccSRui Paulo if (!dembuf) 64404087ccSRui Paulo goto fail; 65404087ccSRui Paulo strlcpy(buf, dembuf, len); 66404087ccSRui Paulo free(dembuf); 67404087ccSRui Paulo return; 6896ec3cddSDimitry Andric } 69404087ccSRui Paulo fail: 703d12a343SDimitry Andric #endif /* NO_CXA_DEMANGLE */ 71404087ccSRui Paulo strlcpy(buf, symbol, len); 72404087ccSRui Paulo } 73404087ccSRui Paulo 74404087ccSRui Paulo static void 758eb20f36SRui Paulo proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 768eb20f36SRui Paulo { 778eb20f36SRui Paulo map->pr_vaddr = rdl->rdl_saddr; 788eb20f36SRui Paulo map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 798eb20f36SRui Paulo map->pr_offset = rdl->rdl_offset; 808eb20f36SRui Paulo map->pr_mflags = 0; 818eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_R) 828eb20f36SRui Paulo map->pr_mflags |= MA_READ; 838eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_W) 848eb20f36SRui Paulo map->pr_mflags |= MA_WRITE; 858eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_X) 868eb20f36SRui Paulo map->pr_mflags |= MA_EXEC; 878eb20f36SRui Paulo strlcpy(map->pr_mapname, rdl->rdl_path, 888eb20f36SRui Paulo sizeof(map->pr_mapname)); 898eb20f36SRui Paulo } 902c633af4SJohn Birrell 912c633af4SJohn Birrell char * 922c633af4SJohn Birrell proc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 932c633af4SJohn Birrell size_t objnamesz) 942c633af4SJohn Birrell { 958eb20f36SRui Paulo size_t i; 968eb20f36SRui Paulo rd_loadobj_t *rdl; 978eb20f36SRui Paulo 988eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 998eb20f36SRui Paulo rdl = &p->rdobjs[i]; 1001e6b3858SMark Johnston if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 1018eb20f36SRui Paulo strlcpy(objname, rdl->rdl_path, objnamesz); 1028eb20f36SRui Paulo return (objname); 1038eb20f36SRui Paulo } 1048eb20f36SRui Paulo } 1052c633af4SJohn Birrell return (NULL); 1062c633af4SJohn Birrell } 1072c633af4SJohn Birrell 1088eb20f36SRui Paulo prmap_t * 1098eb20f36SRui Paulo proc_obj2map(struct proc_handle *p, const char *objname) 1108eb20f36SRui Paulo { 1118eb20f36SRui Paulo size_t i; 1128eb20f36SRui Paulo prmap_t *map; 1138eb20f36SRui Paulo rd_loadobj_t *rdl; 1148eb20f36SRui Paulo char path[MAXPATHLEN]; 1158eb20f36SRui Paulo 116acc0eea6SMark Johnston rdl = NULL; 1178eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 118acc0eea6SMark Johnston basename_r(p->rdobjs[i].rdl_path, path); 1198eb20f36SRui Paulo if (strcmp(path, objname) == 0) { 120acc0eea6SMark Johnston rdl = &p->rdobjs[i]; 121acc0eea6SMark Johnston break; 122acc0eea6SMark Johnston } 123acc0eea6SMark Johnston } 12424a08d30SMark Johnston if (rdl == NULL) { 12524a08d30SMark Johnston if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL) 126acc0eea6SMark Johnston rdl = p->rdexec; 127acc0eea6SMark Johnston else 128acc0eea6SMark Johnston return (NULL); 12924a08d30SMark Johnston } 130acc0eea6SMark Johnston 1318eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 1328eb20f36SRui Paulo return (NULL); 1338eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 1348eb20f36SRui Paulo return (map); 1358eb20f36SRui Paulo } 1368eb20f36SRui Paulo 1378eb20f36SRui Paulo int 1388eb20f36SRui Paulo proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 1398eb20f36SRui Paulo { 1408eb20f36SRui Paulo size_t i; 1418eb20f36SRui Paulo rd_loadobj_t *rdl; 1428eb20f36SRui Paulo prmap_t map; 1438eb20f36SRui Paulo char path[MAXPATHLEN]; 1444c74b245SRui Paulo char last[MAXPATHLEN]; 1458eb20f36SRui Paulo 1468eb20f36SRui Paulo if (p->nobjs == 0) 1478eb20f36SRui Paulo return (-1); 1484c74b245SRui Paulo memset(last, 0, sizeof(last)); 1498eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 1508eb20f36SRui Paulo rdl = &p->rdobjs[i]; 1518eb20f36SRui Paulo proc_rdl2prmap(rdl, &map); 1528eb20f36SRui Paulo basename_r(rdl->rdl_path, path); 1534c74b245SRui Paulo /* 1544c74b245SRui Paulo * We shouldn't call the callback twice with the same object. 1554c74b245SRui Paulo * To do that we are assuming the fact that if there are 1564c74b245SRui Paulo * repeated object names (i.e. different mappings for the 1574c74b245SRui Paulo * same object) they occur next to each other. 1584c74b245SRui Paulo */ 1594c74b245SRui Paulo if (strcmp(path, last) == 0) 1604c74b245SRui Paulo continue; 1618eb20f36SRui Paulo (*func)(cd, &map, path); 1624c74b245SRui Paulo strlcpy(last, path, sizeof(last)); 1638eb20f36SRui Paulo } 1648eb20f36SRui Paulo 1658eb20f36SRui Paulo return (0); 1668eb20f36SRui Paulo } 1678eb20f36SRui Paulo 1688eb20f36SRui Paulo prmap_t * 1692c633af4SJohn Birrell proc_addr2map(struct proc_handle *p, uintptr_t addr) 1702c633af4SJohn Birrell { 1718eb20f36SRui Paulo size_t i; 1728eb20f36SRui Paulo int cnt, lastvn = 0; 1738eb20f36SRui Paulo prmap_t *map; 1748eb20f36SRui Paulo rd_loadobj_t *rdl; 1758eb20f36SRui Paulo struct kinfo_vmentry *kves, *kve; 1768eb20f36SRui Paulo 1778eb20f36SRui Paulo /* 1788eb20f36SRui Paulo * If we don't have a cache of listed objects, we need to query 1798eb20f36SRui Paulo * it ourselves. 1808eb20f36SRui Paulo */ 1818eb20f36SRui Paulo if (p->nobjs == 0) { 1828eb20f36SRui Paulo if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 1838eb20f36SRui Paulo return (NULL); 1848eb20f36SRui Paulo for (i = 0; i < (size_t)cnt; i++) { 1858eb20f36SRui Paulo kve = kves + i; 1868eb20f36SRui Paulo if (kve->kve_type == KVME_TYPE_VNODE) 1878eb20f36SRui Paulo lastvn = i; 1881e6b3858SMark Johnston if (addr >= kve->kve_start && addr < kve->kve_end) { 1898eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) { 1908eb20f36SRui Paulo free(kves); 1918eb20f36SRui Paulo return (NULL); 1928eb20f36SRui Paulo } 1938eb20f36SRui Paulo map->pr_vaddr = kve->kve_start; 1948eb20f36SRui Paulo map->pr_size = kve->kve_end - kve->kve_start; 1958eb20f36SRui Paulo map->pr_offset = kve->kve_offset; 1968eb20f36SRui Paulo map->pr_mflags = 0; 1978eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_READ) 1988eb20f36SRui Paulo map->pr_mflags |= MA_READ; 1998eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_WRITE) 2008eb20f36SRui Paulo map->pr_mflags |= MA_WRITE; 2018eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_EXEC) 2028eb20f36SRui Paulo map->pr_mflags |= MA_EXEC; 2038eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_COW) 2048eb20f36SRui Paulo map->pr_mflags |= MA_COW; 2058eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 2068eb20f36SRui Paulo map->pr_mflags |= MA_NEEDS_COPY; 2078eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 2088eb20f36SRui Paulo map->pr_mflags |= MA_NOCOREDUMP; 2098eb20f36SRui Paulo strlcpy(map->pr_mapname, kves[lastvn].kve_path, 2108eb20f36SRui Paulo sizeof(map->pr_mapname)); 2118eb20f36SRui Paulo free(kves); 2128eb20f36SRui Paulo return (map); 2138eb20f36SRui Paulo } 2148eb20f36SRui Paulo } 2158eb20f36SRui Paulo free(kves); 2168eb20f36SRui Paulo return (NULL); 2178eb20f36SRui Paulo } 2188eb20f36SRui Paulo 2198eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 2208eb20f36SRui Paulo rdl = &p->rdobjs[i]; 2211e6b3858SMark Johnston if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 2228eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 2238eb20f36SRui Paulo return (NULL); 2248eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 2258eb20f36SRui Paulo return (map); 2268eb20f36SRui Paulo } 2278eb20f36SRui Paulo } 2282c633af4SJohn Birrell return (NULL); 2292c633af4SJohn Birrell } 2302c633af4SJohn Birrell 231*540cc663SMark Johnston /* 232*540cc663SMark Johnston * Look up the symbol at addr, returning a copy of the symbol and its name. 233*540cc663SMark Johnston */ 234*540cc663SMark Johnston static int 235*540cc663SMark Johnston lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr, 236*540cc663SMark Johnston const char **name, GElf_Sym *symcopy) 237*540cc663SMark Johnston { 238*540cc663SMark Johnston GElf_Sym sym; 239*540cc663SMark Johnston Elf_Data *data; 240*540cc663SMark Johnston const char *s; 241*540cc663SMark Johnston uint64_t rsym; 242*540cc663SMark Johnston int i; 243*540cc663SMark Johnston 244*540cc663SMark Johnston if ((data = elf_getdata(scn, NULL)) == NULL) { 245*540cc663SMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 246*540cc663SMark Johnston return (1); 247*540cc663SMark Johnston } 248*540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 249*540cc663SMark Johnston rsym = off + sym.st_value; 250*540cc663SMark Johnston if (addr >= rsym && addr < rsym + sym.st_size) { 251*540cc663SMark Johnston s = elf_strptr(e, stridx, sym.st_name); 252*540cc663SMark Johnston if (s != NULL) { 253*540cc663SMark Johnston *name = s; 254*540cc663SMark Johnston memcpy(symcopy, &sym, sizeof(*symcopy)); 255*540cc663SMark Johnston /* 256*540cc663SMark Johnston * DTrace expects the st_value to contain 257*540cc663SMark Johnston * only the address relative to the start of 258*540cc663SMark Johnston * the function. 259*540cc663SMark Johnston */ 260*540cc663SMark Johnston symcopy->st_value = rsym; 261*540cc663SMark Johnston return (0); 262*540cc663SMark Johnston } 263*540cc663SMark Johnston } 264*540cc663SMark Johnston } 265*540cc663SMark Johnston return (1); 266*540cc663SMark Johnston } 267*540cc663SMark Johnston 2682c633af4SJohn Birrell int 2692c633af4SJohn Birrell proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 2708eb20f36SRui Paulo size_t namesz, GElf_Sym *symcopy) 2712c633af4SJohn Birrell { 272*540cc663SMark Johnston GElf_Ehdr ehdr; 273*540cc663SMark Johnston GElf_Shdr shdr; 2748eb20f36SRui Paulo Elf *e; 2758eb20f36SRui Paulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 2768eb20f36SRui Paulo prmap_t *map; 277*540cc663SMark Johnston const char *s; 278*540cc663SMark Johnston uintptr_t off; 279*540cc663SMark Johnston u_long symtabstridx = 0, dynsymstridx = 0; 280*540cc663SMark Johnston int fd, error = -1; 2818eb20f36SRui Paulo 2828eb20f36SRui Paulo if ((map = proc_addr2map(p, addr)) == NULL) 2838eb20f36SRui Paulo return (-1); 28430e81f7eSMark Johnston if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 28530e81f7eSMark Johnston DPRINTF("ERROR: open %s failed", map->pr_mapname); 2868eb20f36SRui Paulo goto err0; 2878eb20f36SRui Paulo } 2888eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 28930e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 2908eb20f36SRui Paulo goto err1; 2918eb20f36SRui Paulo } 2928eb20f36SRui Paulo if (gelf_getehdr(e, &ehdr) == NULL) { 29330e81f7eSMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 2948eb20f36SRui Paulo goto err2; 2958eb20f36SRui Paulo } 296*540cc663SMark Johnston 2978eb20f36SRui Paulo /* 2988eb20f36SRui Paulo * Find the index of the STRTAB and SYMTAB sections to locate 2998eb20f36SRui Paulo * symbol names. 3008eb20f36SRui Paulo */ 3018eb20f36SRui Paulo scn = NULL; 3028eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 3038eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 3048eb20f36SRui Paulo switch (shdr.sh_type) { 3058eb20f36SRui Paulo case SHT_SYMTAB: 3068eb20f36SRui Paulo symtabscn = scn; 3078eb20f36SRui Paulo symtabstridx = shdr.sh_link; 3088eb20f36SRui Paulo break; 3098eb20f36SRui Paulo case SHT_DYNSYM: 3108eb20f36SRui Paulo dynsymscn = scn; 3118eb20f36SRui Paulo dynsymstridx = shdr.sh_link; 3128eb20f36SRui Paulo break; 3138eb20f36SRui Paulo } 3148eb20f36SRui Paulo } 315*540cc663SMark Johnston 316*540cc663SMark Johnston off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 317*540cc663SMark Johnston 3188eb20f36SRui Paulo /* 319*540cc663SMark Johnston * First look up the symbol in the dynsymtab, and fall back to the 320*540cc663SMark Johnston * symtab if the lookup fails. 3218eb20f36SRui Paulo */ 322*540cc663SMark Johnston error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy); 323*540cc663SMark Johnston if (error == 0) 3248eb20f36SRui Paulo goto out; 325*540cc663SMark Johnston 326*540cc663SMark Johnston error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); 327*540cc663SMark Johnston if (error == 0) 3288eb20f36SRui Paulo goto out; 329*540cc663SMark Johnston 3308eb20f36SRui Paulo out: 331*540cc663SMark Johnston demangle(s, name, namesz); 3328eb20f36SRui Paulo err2: 3338eb20f36SRui Paulo elf_end(e); 3348eb20f36SRui Paulo err1: 3358eb20f36SRui Paulo close(fd); 3368eb20f36SRui Paulo err0: 3378eb20f36SRui Paulo free(map); 3388eb20f36SRui Paulo return (error); 3392c633af4SJohn Birrell } 3402c633af4SJohn Birrell 3418eb20f36SRui Paulo prmap_t * 3422c633af4SJohn Birrell proc_name2map(struct proc_handle *p, const char *name) 3432c633af4SJohn Birrell { 3448eb20f36SRui Paulo size_t i; 3458eb20f36SRui Paulo int cnt; 346*540cc663SMark Johnston prmap_t *map = NULL; 3478eb20f36SRui Paulo char tmppath[MAXPATHLEN]; 3488eb20f36SRui Paulo struct kinfo_vmentry *kves, *kve; 3498eb20f36SRui Paulo rd_loadobj_t *rdl; 3508eb20f36SRui Paulo 3518eb20f36SRui Paulo /* 3528eb20f36SRui Paulo * If we haven't iterated over the list of loaded objects, 3538eb20f36SRui Paulo * librtld_db isn't yet initialized and it's very likely 3548eb20f36SRui Paulo * that librtld_db called us. We need to do the heavy 3558eb20f36SRui Paulo * lifting here to find the symbol librtld_db is looking for. 3568eb20f36SRui Paulo */ 3578eb20f36SRui Paulo if (p->nobjs == 0) { 3588eb20f36SRui Paulo if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 3598eb20f36SRui Paulo return (NULL); 3608eb20f36SRui Paulo for (i = 0; i < (size_t)cnt; i++) { 3618eb20f36SRui Paulo kve = kves + i; 3628eb20f36SRui Paulo basename_r(kve->kve_path, tmppath); 3638eb20f36SRui Paulo if (strcmp(tmppath, name) == 0) { 3648eb20f36SRui Paulo map = proc_addr2map(p, kve->kve_start); 365*540cc663SMark Johnston break; 3668eb20f36SRui Paulo } 3678eb20f36SRui Paulo } 3688eb20f36SRui Paulo free(kves); 369*540cc663SMark Johnston } else 3708eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 3718eb20f36SRui Paulo rdl = &p->rdobjs[i]; 3728eb20f36SRui Paulo basename_r(rdl->rdl_path, tmppath); 3738eb20f36SRui Paulo if (strcmp(tmppath, name) == 0) { 3748eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 3758eb20f36SRui Paulo return (NULL); 3768eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 377*540cc663SMark Johnston break; 3788eb20f36SRui Paulo } 3798eb20f36SRui Paulo } 3808eb20f36SRui Paulo 381*540cc663SMark Johnston if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL) 382*540cc663SMark Johnston map = proc_addr2map(p, p->rdexec->rdl_saddr); 383*540cc663SMark Johnston 384*540cc663SMark Johnston return (map); 385*540cc663SMark Johnston } 386*540cc663SMark Johnston 387*540cc663SMark Johnston /* 388*540cc663SMark Johnston * Look up the symbol with the given name and return a copy of it. 389*540cc663SMark Johnston */ 390*540cc663SMark Johnston static int 391*540cc663SMark Johnston lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol, 392*540cc663SMark Johnston GElf_Sym *symcopy) 393*540cc663SMark Johnston { 394*540cc663SMark Johnston GElf_Sym sym; 395*540cc663SMark Johnston Elf_Data *data; 396*540cc663SMark Johnston char *s; 397*540cc663SMark Johnston int i; 398*540cc663SMark Johnston 399*540cc663SMark Johnston if ((data = elf_getdata(scn, NULL)) == NULL) { 400*540cc663SMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 401*540cc663SMark Johnston return (1); 402*540cc663SMark Johnston } 403*540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 404*540cc663SMark Johnston s = elf_strptr(e, stridx, sym.st_name); 405*540cc663SMark Johnston if (s != NULL && strcmp(s, symbol) == 0) { 406*540cc663SMark Johnston memcpy(symcopy, &sym, sizeof(*symcopy)); 407*540cc663SMark Johnston return (0); 408*540cc663SMark Johnston } 409*540cc663SMark Johnston } 410*540cc663SMark Johnston return (1); 4112c633af4SJohn Birrell } 4122c633af4SJohn Birrell 4132c633af4SJohn Birrell int 4142c633af4SJohn Birrell proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 4158eb20f36SRui Paulo GElf_Sym *symcopy) 4162c633af4SJohn Birrell { 4178eb20f36SRui Paulo Elf *e; 4188eb20f36SRui Paulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 4198eb20f36SRui Paulo GElf_Shdr shdr; 4208eb20f36SRui Paulo GElf_Ehdr ehdr; 4218eb20f36SRui Paulo prmap_t *map; 422*540cc663SMark Johnston uintptr_t off; 423*540cc663SMark Johnston u_long symtabstridx = 0, dynsymstridx = 0; 424*540cc663SMark Johnston int fd, error = -1; 4258eb20f36SRui Paulo 4268eb20f36SRui Paulo if ((map = proc_name2map(p, object)) == NULL) { 42730e81f7eSMark Johnston DPRINTFX("ERROR: couldn't find object %s", object); 4288eb20f36SRui Paulo goto err0; 4298eb20f36SRui Paulo } 4308eb20f36SRui Paulo if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 4318eb20f36SRui Paulo DPRINTF("ERROR: open %s failed", map->pr_mapname); 4328eb20f36SRui Paulo goto err0; 4338eb20f36SRui Paulo } 4348eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 43530e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 4368eb20f36SRui Paulo goto err1; 4378eb20f36SRui Paulo } 4388eb20f36SRui Paulo if (gelf_getehdr(e, &ehdr) == NULL) { 43930e81f7eSMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 4408eb20f36SRui Paulo goto err2; 4418eb20f36SRui Paulo } 4428eb20f36SRui Paulo /* 4438eb20f36SRui Paulo * Find the index of the STRTAB and SYMTAB sections to locate 4448eb20f36SRui Paulo * symbol names. 4458eb20f36SRui Paulo */ 4468eb20f36SRui Paulo scn = NULL; 4478eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 4488eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 4498eb20f36SRui Paulo switch (shdr.sh_type) { 4508eb20f36SRui Paulo case SHT_SYMTAB: 4518eb20f36SRui Paulo symtabscn = scn; 4528eb20f36SRui Paulo symtabstridx = shdr.sh_link; 4538eb20f36SRui Paulo break; 4548eb20f36SRui Paulo case SHT_DYNSYM: 4558eb20f36SRui Paulo dynsymscn = scn; 4568eb20f36SRui Paulo dynsymstridx = shdr.sh_link; 4578eb20f36SRui Paulo break; 4588eb20f36SRui Paulo } 4598eb20f36SRui Paulo } 460*540cc663SMark Johnston 4618eb20f36SRui Paulo /* 462*540cc663SMark Johnston * First look up the symbol in the dynsymtab, and fall back to the 463*540cc663SMark Johnston * symtab if the lookup fails. 4648eb20f36SRui Paulo */ 465*540cc663SMark Johnston error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy); 466*540cc663SMark Johnston if (error == 0) 4678eb20f36SRui Paulo goto out; 468*540cc663SMark Johnston 469*540cc663SMark Johnston error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy); 470*540cc663SMark Johnston if (error == 0) 4718eb20f36SRui Paulo goto out; 472*540cc663SMark Johnston 4738eb20f36SRui Paulo out: 474*540cc663SMark Johnston off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 475*540cc663SMark Johnston symcopy->st_value += off; 476*540cc663SMark Johnston 4778eb20f36SRui Paulo err2: 4788eb20f36SRui Paulo elf_end(e); 4798eb20f36SRui Paulo err1: 4808eb20f36SRui Paulo close(fd); 4818eb20f36SRui Paulo err0: 4828eb20f36SRui Paulo free(map); 4838eb20f36SRui Paulo 4848eb20f36SRui Paulo return (error); 4858eb20f36SRui Paulo } 4868eb20f36SRui Paulo 4878eb20f36SRui Paulo int 4888eb20f36SRui Paulo proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 4898eb20f36SRui Paulo int mask, proc_sym_f *func, void *cd) 4908eb20f36SRui Paulo { 4918eb20f36SRui Paulo Elf *e; 4928eb20f36SRui Paulo int i, fd; 4938eb20f36SRui Paulo prmap_t *map; 4948eb20f36SRui Paulo Elf_Scn *scn, *foundscn = NULL; 4958eb20f36SRui Paulo Elf_Data *data; 496fbce8e16SMark Johnston GElf_Ehdr ehdr; 4978eb20f36SRui Paulo GElf_Shdr shdr; 4988eb20f36SRui Paulo GElf_Sym sym; 4998eb20f36SRui Paulo unsigned long stridx = -1; 5008eb20f36SRui Paulo char *s; 5018eb20f36SRui Paulo int error = -1; 5028eb20f36SRui Paulo 5038eb20f36SRui Paulo if ((map = proc_name2map(p, object)) == NULL) 5048eb20f36SRui Paulo return (-1); 5058eb20f36SRui Paulo if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 50630e81f7eSMark Johnston DPRINTF("ERROR: open %s failed", map->pr_mapname); 5078eb20f36SRui Paulo goto err0; 5088eb20f36SRui Paulo } 5098eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 51030e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 5118eb20f36SRui Paulo goto err1; 5128eb20f36SRui Paulo } 513fbce8e16SMark Johnston if (gelf_getehdr(e, &ehdr) == NULL) { 514fbce8e16SMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 515fbce8e16SMark Johnston goto err2; 516fbce8e16SMark Johnston } 5178eb20f36SRui Paulo /* 5188eb20f36SRui Paulo * Find the section we are looking for. 5198eb20f36SRui Paulo */ 5208eb20f36SRui Paulo scn = NULL; 5218eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 5228eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 5238eb20f36SRui Paulo if (which == PR_SYMTAB && 5248eb20f36SRui Paulo shdr.sh_type == SHT_SYMTAB) { 5258eb20f36SRui Paulo foundscn = scn; 5268eb20f36SRui Paulo break; 5278eb20f36SRui Paulo } else if (which == PR_DYNSYM && 5288eb20f36SRui Paulo shdr.sh_type == SHT_DYNSYM) { 5298eb20f36SRui Paulo foundscn = scn; 5308eb20f36SRui Paulo break; 5318eb20f36SRui Paulo } 5328eb20f36SRui Paulo } 5338eb20f36SRui Paulo if (!foundscn) 5348eb20f36SRui Paulo return (-1); 5358eb20f36SRui Paulo stridx = shdr.sh_link; 5368eb20f36SRui Paulo if ((data = elf_getdata(foundscn, NULL)) == NULL) { 53730e81f7eSMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 5388eb20f36SRui Paulo goto err2; 5398eb20f36SRui Paulo } 540*540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 5418eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 5428eb20f36SRui Paulo (mask & BIND_LOCAL) == 0) 5438eb20f36SRui Paulo continue; 5448eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 5458eb20f36SRui Paulo (mask & BIND_GLOBAL) == 0) 5468eb20f36SRui Paulo continue; 5478eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 5488eb20f36SRui Paulo (mask & BIND_WEAK) == 0) 5498eb20f36SRui Paulo continue; 5508eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 5518eb20f36SRui Paulo (mask & TYPE_NOTYPE) == 0) 5528eb20f36SRui Paulo continue; 5538eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 5548eb20f36SRui Paulo (mask & TYPE_OBJECT) == 0) 5558eb20f36SRui Paulo continue; 5568eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 5578eb20f36SRui Paulo (mask & TYPE_FUNC) == 0) 5588eb20f36SRui Paulo continue; 5598eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 5608eb20f36SRui Paulo (mask & TYPE_SECTION) == 0) 5618eb20f36SRui Paulo continue; 5628eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 5638eb20f36SRui Paulo (mask & TYPE_FILE) == 0) 5648eb20f36SRui Paulo continue; 5658eb20f36SRui Paulo s = elf_strptr(e, stridx, sym.st_name); 566fbce8e16SMark Johnston if (ehdr.e_type != ET_EXEC) 5678eb20f36SRui Paulo sym.st_value += map->pr_vaddr; 5688eb20f36SRui Paulo (*func)(cd, &sym, s); 5698eb20f36SRui Paulo } 5708eb20f36SRui Paulo error = 0; 5718eb20f36SRui Paulo err2: 5728eb20f36SRui Paulo elf_end(e); 5738eb20f36SRui Paulo err1: 5748eb20f36SRui Paulo close(fd); 5758eb20f36SRui Paulo err0: 5768eb20f36SRui Paulo free(map); 5778eb20f36SRui Paulo return (error); 5782c633af4SJohn Birrell } 579