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 31540cc663SMark Johnston #include <sys/cdefs.h> 32540cc663SMark Johnston __FBSDID("$FreeBSD$"); 33540cc663SMark Johnston 348eb20f36SRui Paulo #include <sys/types.h> 3541da933cSMark Johnston #ifndef NO_CTF 3641da933cSMark Johnston #include <sys/ctf.h> 3741da933cSMark Johnston #include <sys/ctf_api.h> 3841da933cSMark Johnston #endif 398eb20f36SRui Paulo #include <sys/user.h> 408eb20f36SRui Paulo 418eb20f36SRui Paulo #include <assert.h> 428eb20f36SRui Paulo #include <err.h> 438eb20f36SRui Paulo #include <fcntl.h> 44540cc663SMark Johnston #include <libgen.h> 45540cc663SMark Johnston #include <stdio.h> 46540cc663SMark Johnston #include <stdlib.h> 478eb20f36SRui Paulo #include <string.h> 488eb20f36SRui Paulo #include <unistd.h> 4941da933cSMark Johnston #ifndef NO_CTF 5041da933cSMark Johnston #include <libctf.h> 5141da933cSMark Johnston #endif 528eb20f36SRui Paulo #include <libutil.h> 538eb20f36SRui Paulo 548eb20f36SRui Paulo #include "_libproc.h" 558eb20f36SRui Paulo 5641da933cSMark Johnston #ifdef NO_CTF 5741da933cSMark Johnston typedef struct ctf_file ctf_file_t; 5841da933cSMark Johnston #endif 5941da933cSMark Johnston 603d12a343SDimitry Andric #ifndef NO_CXA_DEMANGLE 61cd906041SRui Paulo extern char *__cxa_demangle(const char *, char *, size_t *, int *); 623d12a343SDimitry Andric #endif /* NO_CXA_DEMANGLE */ 63cd906041SRui Paulo 648eb20f36SRui Paulo static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *); 658eb20f36SRui Paulo 668eb20f36SRui Paulo static void 67404087ccSRui Paulo demangle(const char *symbol, char *buf, size_t len) 68404087ccSRui Paulo { 693d12a343SDimitry Andric #ifndef NO_CXA_DEMANGLE 70404087ccSRui Paulo char *dembuf; 71404087ccSRui Paulo 723d12a343SDimitry Andric if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) { 7396ec3cddSDimitry Andric dembuf = __cxa_demangle(symbol, NULL, NULL, NULL); 74404087ccSRui Paulo if (!dembuf) 75404087ccSRui Paulo goto fail; 76404087ccSRui Paulo strlcpy(buf, dembuf, len); 77404087ccSRui Paulo free(dembuf); 78404087ccSRui Paulo return; 7996ec3cddSDimitry Andric } 80404087ccSRui Paulo fail: 813d12a343SDimitry Andric #endif /* NO_CXA_DEMANGLE */ 82404087ccSRui Paulo strlcpy(buf, symbol, len); 83404087ccSRui Paulo } 84404087ccSRui Paulo 85404087ccSRui Paulo static void 868eb20f36SRui Paulo proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 878eb20f36SRui Paulo { 888eb20f36SRui Paulo map->pr_vaddr = rdl->rdl_saddr; 898eb20f36SRui Paulo map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 908eb20f36SRui Paulo map->pr_offset = rdl->rdl_offset; 918eb20f36SRui Paulo map->pr_mflags = 0; 928eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_R) 938eb20f36SRui Paulo map->pr_mflags |= MA_READ; 948eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_W) 958eb20f36SRui Paulo map->pr_mflags |= MA_WRITE; 968eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_X) 978eb20f36SRui Paulo map->pr_mflags |= MA_EXEC; 988eb20f36SRui Paulo strlcpy(map->pr_mapname, rdl->rdl_path, 998eb20f36SRui Paulo sizeof(map->pr_mapname)); 1008eb20f36SRui Paulo } 1012c633af4SJohn Birrell 1022c633af4SJohn Birrell char * 1032c633af4SJohn Birrell proc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 1042c633af4SJohn Birrell size_t objnamesz) 1052c633af4SJohn Birrell { 1068eb20f36SRui Paulo size_t i; 1078eb20f36SRui Paulo rd_loadobj_t *rdl; 1088eb20f36SRui Paulo 1098eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 1108eb20f36SRui Paulo rdl = &p->rdobjs[i]; 1111e6b3858SMark Johnston if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 1128eb20f36SRui Paulo strlcpy(objname, rdl->rdl_path, objnamesz); 1138eb20f36SRui Paulo return (objname); 1148eb20f36SRui Paulo } 1158eb20f36SRui Paulo } 1162c633af4SJohn Birrell return (NULL); 1172c633af4SJohn Birrell } 1182c633af4SJohn Birrell 1198eb20f36SRui Paulo prmap_t * 1208eb20f36SRui Paulo proc_obj2map(struct proc_handle *p, const char *objname) 1218eb20f36SRui Paulo { 1228eb20f36SRui Paulo size_t i; 1238eb20f36SRui Paulo prmap_t *map; 1248eb20f36SRui Paulo rd_loadobj_t *rdl; 1258eb20f36SRui Paulo char path[MAXPATHLEN]; 1268eb20f36SRui Paulo 127acc0eea6SMark Johnston rdl = NULL; 1288eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 129acc0eea6SMark Johnston basename_r(p->rdobjs[i].rdl_path, path); 1308eb20f36SRui Paulo if (strcmp(path, objname) == 0) { 131acc0eea6SMark Johnston rdl = &p->rdobjs[i]; 132acc0eea6SMark Johnston break; 133acc0eea6SMark Johnston } 134acc0eea6SMark Johnston } 13524a08d30SMark Johnston if (rdl == NULL) { 13624a08d30SMark Johnston if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL) 137acc0eea6SMark Johnston rdl = p->rdexec; 138acc0eea6SMark Johnston else 139acc0eea6SMark Johnston return (NULL); 14024a08d30SMark Johnston } 141acc0eea6SMark Johnston 1428eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 1438eb20f36SRui Paulo return (NULL); 1448eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 1458eb20f36SRui Paulo return (map); 1468eb20f36SRui Paulo } 1478eb20f36SRui Paulo 1488eb20f36SRui Paulo int 1498eb20f36SRui Paulo proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 1508eb20f36SRui Paulo { 1518eb20f36SRui Paulo size_t i; 1528eb20f36SRui Paulo rd_loadobj_t *rdl; 1538eb20f36SRui Paulo prmap_t map; 1548eb20f36SRui Paulo char path[MAXPATHLEN]; 1554c74b245SRui Paulo char last[MAXPATHLEN]; 1568eb20f36SRui Paulo 1578eb20f36SRui Paulo if (p->nobjs == 0) 1588eb20f36SRui Paulo return (-1); 1594c74b245SRui Paulo memset(last, 0, sizeof(last)); 1608eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 1618eb20f36SRui Paulo rdl = &p->rdobjs[i]; 1628eb20f36SRui Paulo proc_rdl2prmap(rdl, &map); 1638eb20f36SRui Paulo basename_r(rdl->rdl_path, path); 1644c74b245SRui Paulo /* 1654c74b245SRui Paulo * We shouldn't call the callback twice with the same object. 1664c74b245SRui Paulo * To do that we are assuming the fact that if there are 1674c74b245SRui Paulo * repeated object names (i.e. different mappings for the 1684c74b245SRui Paulo * same object) they occur next to each other. 1694c74b245SRui Paulo */ 1704c74b245SRui Paulo if (strcmp(path, last) == 0) 1714c74b245SRui Paulo continue; 1728eb20f36SRui Paulo (*func)(cd, &map, path); 1734c74b245SRui Paulo strlcpy(last, path, sizeof(last)); 1748eb20f36SRui Paulo } 1758eb20f36SRui Paulo 1768eb20f36SRui Paulo return (0); 1778eb20f36SRui Paulo } 1788eb20f36SRui Paulo 1798eb20f36SRui Paulo prmap_t * 1802c633af4SJohn Birrell proc_addr2map(struct proc_handle *p, uintptr_t addr) 1812c633af4SJohn Birrell { 1828eb20f36SRui Paulo size_t i; 1838eb20f36SRui Paulo int cnt, lastvn = 0; 1848eb20f36SRui Paulo prmap_t *map; 1858eb20f36SRui Paulo rd_loadobj_t *rdl; 1868eb20f36SRui Paulo struct kinfo_vmentry *kves, *kve; 1878eb20f36SRui Paulo 1888eb20f36SRui Paulo /* 1898eb20f36SRui Paulo * If we don't have a cache of listed objects, we need to query 1908eb20f36SRui Paulo * it ourselves. 1918eb20f36SRui Paulo */ 1928eb20f36SRui Paulo if (p->nobjs == 0) { 1938eb20f36SRui Paulo if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 1948eb20f36SRui Paulo return (NULL); 1958eb20f36SRui Paulo for (i = 0; i < (size_t)cnt; i++) { 1968eb20f36SRui Paulo kve = kves + i; 1978eb20f36SRui Paulo if (kve->kve_type == KVME_TYPE_VNODE) 1988eb20f36SRui Paulo lastvn = i; 1991e6b3858SMark Johnston if (addr >= kve->kve_start && addr < kve->kve_end) { 2008eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) { 2018eb20f36SRui Paulo free(kves); 2028eb20f36SRui Paulo return (NULL); 2038eb20f36SRui Paulo } 2048eb20f36SRui Paulo map->pr_vaddr = kve->kve_start; 2058eb20f36SRui Paulo map->pr_size = kve->kve_end - kve->kve_start; 2068eb20f36SRui Paulo map->pr_offset = kve->kve_offset; 2078eb20f36SRui Paulo map->pr_mflags = 0; 2088eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_READ) 2098eb20f36SRui Paulo map->pr_mflags |= MA_READ; 2108eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_WRITE) 2118eb20f36SRui Paulo map->pr_mflags |= MA_WRITE; 2128eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_EXEC) 2138eb20f36SRui Paulo map->pr_mflags |= MA_EXEC; 2148eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_COW) 2158eb20f36SRui Paulo map->pr_mflags |= MA_COW; 2168eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 2178eb20f36SRui Paulo map->pr_mflags |= MA_NEEDS_COPY; 2188eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 2198eb20f36SRui Paulo map->pr_mflags |= MA_NOCOREDUMP; 2208eb20f36SRui Paulo strlcpy(map->pr_mapname, kves[lastvn].kve_path, 2218eb20f36SRui Paulo sizeof(map->pr_mapname)); 2228eb20f36SRui Paulo free(kves); 2238eb20f36SRui Paulo return (map); 2248eb20f36SRui Paulo } 2258eb20f36SRui Paulo } 2268eb20f36SRui Paulo free(kves); 2278eb20f36SRui Paulo return (NULL); 2288eb20f36SRui Paulo } 2298eb20f36SRui Paulo 2308eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 2318eb20f36SRui Paulo rdl = &p->rdobjs[i]; 2321e6b3858SMark Johnston if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 2338eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 2348eb20f36SRui Paulo return (NULL); 2358eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 2368eb20f36SRui Paulo return (map); 2378eb20f36SRui Paulo } 2388eb20f36SRui Paulo } 2392c633af4SJohn Birrell return (NULL); 2402c633af4SJohn Birrell } 2412c633af4SJohn Birrell 242540cc663SMark Johnston /* 243540cc663SMark Johnston * Look up the symbol at addr, returning a copy of the symbol and its name. 244540cc663SMark Johnston */ 245540cc663SMark Johnston static int 246540cc663SMark Johnston lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr, 247540cc663SMark Johnston const char **name, GElf_Sym *symcopy) 248540cc663SMark Johnston { 249540cc663SMark Johnston GElf_Sym sym; 250540cc663SMark Johnston Elf_Data *data; 251540cc663SMark Johnston const char *s; 252540cc663SMark Johnston uint64_t rsym; 253540cc663SMark Johnston int i; 254540cc663SMark Johnston 255540cc663SMark Johnston if ((data = elf_getdata(scn, NULL)) == NULL) { 256540cc663SMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 257540cc663SMark Johnston return (1); 258540cc663SMark Johnston } 259540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 260540cc663SMark Johnston rsym = off + sym.st_value; 261540cc663SMark Johnston if (addr >= rsym && addr < rsym + sym.st_size) { 262540cc663SMark Johnston s = elf_strptr(e, stridx, sym.st_name); 263540cc663SMark Johnston if (s != NULL) { 264540cc663SMark Johnston *name = s; 265540cc663SMark Johnston memcpy(symcopy, &sym, sizeof(*symcopy)); 266540cc663SMark Johnston /* 267540cc663SMark Johnston * DTrace expects the st_value to contain 268540cc663SMark Johnston * only the address relative to the start of 269540cc663SMark Johnston * the function. 270540cc663SMark Johnston */ 271540cc663SMark Johnston symcopy->st_value = rsym; 272540cc663SMark Johnston return (0); 273540cc663SMark Johnston } 274540cc663SMark Johnston } 275540cc663SMark Johnston } 276540cc663SMark Johnston return (1); 277540cc663SMark Johnston } 278540cc663SMark Johnston 2792c633af4SJohn Birrell int 2802c633af4SJohn Birrell proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 2818eb20f36SRui Paulo size_t namesz, GElf_Sym *symcopy) 2822c633af4SJohn Birrell { 283540cc663SMark Johnston GElf_Ehdr ehdr; 284540cc663SMark Johnston GElf_Shdr shdr; 2858eb20f36SRui Paulo Elf *e; 2868eb20f36SRui Paulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 2878eb20f36SRui Paulo prmap_t *map; 288540cc663SMark Johnston const char *s; 289540cc663SMark Johnston uintptr_t off; 290540cc663SMark Johnston u_long symtabstridx = 0, dynsymstridx = 0; 291540cc663SMark Johnston int fd, error = -1; 2928eb20f36SRui Paulo 2938eb20f36SRui Paulo if ((map = proc_addr2map(p, addr)) == NULL) 2948eb20f36SRui Paulo return (-1); 29530e81f7eSMark Johnston if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 29630e81f7eSMark Johnston DPRINTF("ERROR: open %s failed", map->pr_mapname); 2978eb20f36SRui Paulo goto err0; 2988eb20f36SRui Paulo } 2998eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 30030e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 3018eb20f36SRui Paulo goto err1; 3028eb20f36SRui Paulo } 3038eb20f36SRui Paulo if (gelf_getehdr(e, &ehdr) == NULL) { 30430e81f7eSMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 3058eb20f36SRui Paulo goto err2; 3068eb20f36SRui Paulo } 307540cc663SMark Johnston 3088eb20f36SRui Paulo /* 3098eb20f36SRui Paulo * Find the index of the STRTAB and SYMTAB sections to locate 3108eb20f36SRui Paulo * symbol names. 3118eb20f36SRui Paulo */ 3128eb20f36SRui Paulo scn = NULL; 3138eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 3148eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 3158eb20f36SRui Paulo switch (shdr.sh_type) { 3168eb20f36SRui Paulo case SHT_SYMTAB: 3178eb20f36SRui Paulo symtabscn = scn; 3188eb20f36SRui Paulo symtabstridx = shdr.sh_link; 3198eb20f36SRui Paulo break; 3208eb20f36SRui Paulo case SHT_DYNSYM: 3218eb20f36SRui Paulo dynsymscn = scn; 3228eb20f36SRui Paulo dynsymstridx = shdr.sh_link; 3238eb20f36SRui Paulo break; 3248eb20f36SRui Paulo } 3258eb20f36SRui Paulo } 326540cc663SMark Johnston 327540cc663SMark Johnston off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 328540cc663SMark Johnston 3298eb20f36SRui Paulo /* 330540cc663SMark Johnston * First look up the symbol in the dynsymtab, and fall back to the 331540cc663SMark Johnston * symtab if the lookup fails. 3328eb20f36SRui Paulo */ 333540cc663SMark Johnston error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy); 334540cc663SMark Johnston if (error == 0) 3358eb20f36SRui Paulo goto out; 336540cc663SMark Johnston 337540cc663SMark Johnston error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); 338540cc663SMark Johnston if (error == 0) 3398eb20f36SRui Paulo goto out; 340540cc663SMark Johnston 3418eb20f36SRui Paulo out: 342540cc663SMark Johnston demangle(s, name, namesz); 3438eb20f36SRui Paulo err2: 3448eb20f36SRui Paulo elf_end(e); 3458eb20f36SRui Paulo err1: 3468eb20f36SRui Paulo close(fd); 3478eb20f36SRui Paulo err0: 3488eb20f36SRui Paulo free(map); 3498eb20f36SRui Paulo return (error); 3502c633af4SJohn Birrell } 3512c633af4SJohn Birrell 3528eb20f36SRui Paulo prmap_t * 3532c633af4SJohn Birrell proc_name2map(struct proc_handle *p, const char *name) 3542c633af4SJohn Birrell { 3558eb20f36SRui Paulo size_t i; 3568eb20f36SRui Paulo int cnt; 357540cc663SMark Johnston prmap_t *map = NULL; 3588eb20f36SRui Paulo char tmppath[MAXPATHLEN]; 3598eb20f36SRui Paulo struct kinfo_vmentry *kves, *kve; 3608eb20f36SRui Paulo rd_loadobj_t *rdl; 3618eb20f36SRui Paulo 3628eb20f36SRui Paulo /* 3638eb20f36SRui Paulo * If we haven't iterated over the list of loaded objects, 3648eb20f36SRui Paulo * librtld_db isn't yet initialized and it's very likely 3658eb20f36SRui Paulo * that librtld_db called us. We need to do the heavy 3668eb20f36SRui Paulo * lifting here to find the symbol librtld_db is looking for. 3678eb20f36SRui Paulo */ 3688eb20f36SRui Paulo if (p->nobjs == 0) { 3698eb20f36SRui Paulo if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 3708eb20f36SRui Paulo return (NULL); 3718eb20f36SRui Paulo for (i = 0; i < (size_t)cnt; i++) { 3728eb20f36SRui Paulo kve = kves + i; 3738eb20f36SRui Paulo basename_r(kve->kve_path, tmppath); 3748eb20f36SRui Paulo if (strcmp(tmppath, name) == 0) { 3758eb20f36SRui Paulo map = proc_addr2map(p, kve->kve_start); 376540cc663SMark Johnston break; 3778eb20f36SRui Paulo } 3788eb20f36SRui Paulo } 3798eb20f36SRui Paulo free(kves); 380540cc663SMark Johnston } else 3818eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 3828eb20f36SRui Paulo rdl = &p->rdobjs[i]; 3838eb20f36SRui Paulo basename_r(rdl->rdl_path, tmppath); 3848eb20f36SRui Paulo if (strcmp(tmppath, name) == 0) { 3858eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 3868eb20f36SRui Paulo return (NULL); 3878eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 388540cc663SMark Johnston break; 3898eb20f36SRui Paulo } 3908eb20f36SRui Paulo } 3918eb20f36SRui Paulo 392540cc663SMark Johnston if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL) 393540cc663SMark Johnston map = proc_addr2map(p, p->rdexec->rdl_saddr); 394540cc663SMark Johnston 395540cc663SMark Johnston return (map); 396540cc663SMark Johnston } 397540cc663SMark Johnston 398540cc663SMark Johnston /* 399540cc663SMark Johnston * Look up the symbol with the given name and return a copy of it. 400540cc663SMark Johnston */ 401540cc663SMark Johnston static int 402540cc663SMark Johnston lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol, 40341da933cSMark Johnston GElf_Sym *symcopy, prsyminfo_t *si) 404540cc663SMark Johnston { 405540cc663SMark Johnston GElf_Sym sym; 406540cc663SMark Johnston Elf_Data *data; 407540cc663SMark Johnston char *s; 408540cc663SMark Johnston int i; 409540cc663SMark Johnston 410540cc663SMark Johnston if ((data = elf_getdata(scn, NULL)) == NULL) { 411540cc663SMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 412540cc663SMark Johnston return (1); 413540cc663SMark Johnston } 414540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 415540cc663SMark Johnston s = elf_strptr(e, stridx, sym.st_name); 416540cc663SMark Johnston if (s != NULL && strcmp(s, symbol) == 0) { 417540cc663SMark Johnston memcpy(symcopy, &sym, sizeof(*symcopy)); 41841da933cSMark Johnston if (si != NULL) 41941da933cSMark Johnston si->prs_id = i; 420540cc663SMark Johnston return (0); 421540cc663SMark Johnston } 422540cc663SMark Johnston } 423540cc663SMark Johnston return (1); 4242c633af4SJohn Birrell } 4252c633af4SJohn Birrell 4262c633af4SJohn Birrell int 4272c633af4SJohn Birrell proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 42841da933cSMark Johnston GElf_Sym *symcopy, prsyminfo_t *si) 4292c633af4SJohn Birrell { 4308eb20f36SRui Paulo Elf *e; 4318eb20f36SRui Paulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 4328eb20f36SRui Paulo GElf_Shdr shdr; 4338eb20f36SRui Paulo GElf_Ehdr ehdr; 4348eb20f36SRui Paulo prmap_t *map; 435540cc663SMark Johnston uintptr_t off; 436540cc663SMark Johnston u_long symtabstridx = 0, dynsymstridx = 0; 437540cc663SMark Johnston int fd, error = -1; 4388eb20f36SRui Paulo 4398eb20f36SRui Paulo if ((map = proc_name2map(p, object)) == NULL) { 44030e81f7eSMark Johnston DPRINTFX("ERROR: couldn't find object %s", object); 4418eb20f36SRui Paulo goto err0; 4428eb20f36SRui Paulo } 4438eb20f36SRui Paulo if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 4448eb20f36SRui Paulo DPRINTF("ERROR: open %s failed", map->pr_mapname); 4458eb20f36SRui Paulo goto err0; 4468eb20f36SRui Paulo } 4478eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 44830e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 4498eb20f36SRui Paulo goto err1; 4508eb20f36SRui Paulo } 4518eb20f36SRui Paulo if (gelf_getehdr(e, &ehdr) == NULL) { 45230e81f7eSMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 4538eb20f36SRui Paulo goto err2; 4548eb20f36SRui Paulo } 4558eb20f36SRui Paulo /* 4568eb20f36SRui Paulo * Find the index of the STRTAB and SYMTAB sections to locate 4578eb20f36SRui Paulo * symbol names. 4588eb20f36SRui Paulo */ 4598eb20f36SRui Paulo scn = NULL; 4608eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 4618eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 4628eb20f36SRui Paulo switch (shdr.sh_type) { 4638eb20f36SRui Paulo case SHT_SYMTAB: 4648eb20f36SRui Paulo symtabscn = scn; 4658eb20f36SRui Paulo symtabstridx = shdr.sh_link; 4668eb20f36SRui Paulo break; 4678eb20f36SRui Paulo case SHT_DYNSYM: 4688eb20f36SRui Paulo dynsymscn = scn; 4698eb20f36SRui Paulo dynsymstridx = shdr.sh_link; 4708eb20f36SRui Paulo break; 4718eb20f36SRui Paulo } 4728eb20f36SRui Paulo } 473540cc663SMark Johnston 4748eb20f36SRui Paulo /* 475540cc663SMark Johnston * First look up the symbol in the dynsymtab, and fall back to the 476540cc663SMark Johnston * symtab if the lookup fails. 4778eb20f36SRui Paulo */ 47841da933cSMark Johnston error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si); 479540cc663SMark Johnston if (error == 0) 4808eb20f36SRui Paulo goto out; 481540cc663SMark Johnston 48241da933cSMark Johnston error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si); 483540cc663SMark Johnston if (error == 0) 4848eb20f36SRui Paulo goto out; 485540cc663SMark Johnston 4868eb20f36SRui Paulo out: 487540cc663SMark Johnston off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 488540cc663SMark Johnston symcopy->st_value += off; 489540cc663SMark Johnston 4908eb20f36SRui Paulo err2: 4918eb20f36SRui Paulo elf_end(e); 4928eb20f36SRui Paulo err1: 4938eb20f36SRui Paulo close(fd); 4948eb20f36SRui Paulo err0: 4958eb20f36SRui Paulo free(map); 4968eb20f36SRui Paulo 4978eb20f36SRui Paulo return (error); 4988eb20f36SRui Paulo } 4998eb20f36SRui Paulo 50041da933cSMark Johnston ctf_file_t * 50141da933cSMark Johnston proc_name2ctf(struct proc_handle *p, const char *name) 50241da933cSMark Johnston { 50341da933cSMark Johnston #ifndef NO_CTF 504*3f1cbdbeSMark Johnston ctf_file_t *ctf; 50541da933cSMark Johnston prmap_t *map; 50641da933cSMark Johnston int error; 50741da933cSMark Johnston 508ec045490SMark Johnston if ((map = proc_name2map(p, name)) == NULL) 50941da933cSMark Johnston return (NULL); 51041da933cSMark Johnston 511*3f1cbdbeSMark Johnston ctf = ctf_open(map->pr_mapname, &error); 512*3f1cbdbeSMark Johnston free(map); 513*3f1cbdbeSMark Johnston return (ctf); 51441da933cSMark Johnston #else 51541da933cSMark Johnston (void)p; 51641da933cSMark Johnston (void)name; 51741da933cSMark Johnston return (NULL); 51841da933cSMark Johnston #endif 51941da933cSMark Johnston } 52041da933cSMark Johnston 5218eb20f36SRui Paulo int 5228eb20f36SRui Paulo proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 5238eb20f36SRui Paulo int mask, proc_sym_f *func, void *cd) 5248eb20f36SRui Paulo { 5258eb20f36SRui Paulo Elf *e; 5268eb20f36SRui Paulo int i, fd; 5278eb20f36SRui Paulo prmap_t *map; 5288eb20f36SRui Paulo Elf_Scn *scn, *foundscn = NULL; 5298eb20f36SRui Paulo Elf_Data *data; 530fbce8e16SMark Johnston GElf_Ehdr ehdr; 5318eb20f36SRui Paulo GElf_Shdr shdr; 5328eb20f36SRui Paulo GElf_Sym sym; 5338eb20f36SRui Paulo unsigned long stridx = -1; 5348eb20f36SRui Paulo char *s; 5358eb20f36SRui Paulo int error = -1; 5368eb20f36SRui Paulo 5378eb20f36SRui Paulo if ((map = proc_name2map(p, object)) == NULL) 5388eb20f36SRui Paulo return (-1); 5398eb20f36SRui Paulo if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 54030e81f7eSMark Johnston DPRINTF("ERROR: open %s failed", map->pr_mapname); 5418eb20f36SRui Paulo goto err0; 5428eb20f36SRui Paulo } 5438eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 54430e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 5458eb20f36SRui Paulo goto err1; 5468eb20f36SRui Paulo } 547fbce8e16SMark Johnston if (gelf_getehdr(e, &ehdr) == NULL) { 548fbce8e16SMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 549fbce8e16SMark Johnston goto err2; 550fbce8e16SMark Johnston } 5518eb20f36SRui Paulo /* 5528eb20f36SRui Paulo * Find the section we are looking for. 5538eb20f36SRui Paulo */ 5548eb20f36SRui Paulo scn = NULL; 5558eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 5568eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 5578eb20f36SRui Paulo if (which == PR_SYMTAB && 5588eb20f36SRui Paulo shdr.sh_type == SHT_SYMTAB) { 5598eb20f36SRui Paulo foundscn = scn; 5608eb20f36SRui Paulo break; 5618eb20f36SRui Paulo } else if (which == PR_DYNSYM && 5628eb20f36SRui Paulo shdr.sh_type == SHT_DYNSYM) { 5638eb20f36SRui Paulo foundscn = scn; 5648eb20f36SRui Paulo break; 5658eb20f36SRui Paulo } 5668eb20f36SRui Paulo } 5678eb20f36SRui Paulo if (!foundscn) 5688eb20f36SRui Paulo return (-1); 5698eb20f36SRui Paulo stridx = shdr.sh_link; 5708eb20f36SRui Paulo if ((data = elf_getdata(foundscn, NULL)) == NULL) { 57130e81f7eSMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 5728eb20f36SRui Paulo goto err2; 5738eb20f36SRui Paulo } 574540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 5758eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 5768eb20f36SRui Paulo (mask & BIND_LOCAL) == 0) 5778eb20f36SRui Paulo continue; 5788eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 5798eb20f36SRui Paulo (mask & BIND_GLOBAL) == 0) 5808eb20f36SRui Paulo continue; 5818eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 5828eb20f36SRui Paulo (mask & BIND_WEAK) == 0) 5838eb20f36SRui Paulo continue; 5848eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 5858eb20f36SRui Paulo (mask & TYPE_NOTYPE) == 0) 5868eb20f36SRui Paulo continue; 5878eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 5888eb20f36SRui Paulo (mask & TYPE_OBJECT) == 0) 5898eb20f36SRui Paulo continue; 5908eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 5918eb20f36SRui Paulo (mask & TYPE_FUNC) == 0) 5928eb20f36SRui Paulo continue; 5938eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 5948eb20f36SRui Paulo (mask & TYPE_SECTION) == 0) 5958eb20f36SRui Paulo continue; 5968eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 5978eb20f36SRui Paulo (mask & TYPE_FILE) == 0) 5988eb20f36SRui Paulo continue; 5998eb20f36SRui Paulo s = elf_strptr(e, stridx, sym.st_name); 600fbce8e16SMark Johnston if (ehdr.e_type != ET_EXEC) 6018eb20f36SRui Paulo sym.st_value += map->pr_vaddr; 6028eb20f36SRui Paulo (*func)(cd, &sym, s); 6038eb20f36SRui Paulo } 6048eb20f36SRui Paulo error = 0; 6058eb20f36SRui Paulo err2: 6068eb20f36SRui Paulo elf_end(e); 6078eb20f36SRui Paulo err1: 6088eb20f36SRui Paulo close(fd); 6098eb20f36SRui Paulo err0: 6108eb20f36SRui Paulo free(map); 6118eb20f36SRui Paulo return (error); 6122c633af4SJohn Birrell } 613