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 85*eda94c07SRui Paulo static int 86*eda94c07SRui Paulo find_dbg_obj(const char *path) 87*eda94c07SRui Paulo { 88*eda94c07SRui Paulo int fd; 89*eda94c07SRui Paulo char dbg_path[PATH_MAX]; 90*eda94c07SRui Paulo 91*eda94c07SRui Paulo snprintf(dbg_path, sizeof(dbg_path), 92*eda94c07SRui Paulo "/usr/lib/debug/%s.debug", path); 93*eda94c07SRui Paulo fd = open(dbg_path, O_RDONLY); 94*eda94c07SRui Paulo if (fd > 0) 95*eda94c07SRui Paulo return (fd); 96*eda94c07SRui Paulo else 97*eda94c07SRui Paulo return (open(path, O_RDONLY)); 98*eda94c07SRui Paulo } 99*eda94c07SRui Paulo 100404087ccSRui Paulo static void 1018eb20f36SRui Paulo proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 1028eb20f36SRui Paulo { 1038eb20f36SRui Paulo map->pr_vaddr = rdl->rdl_saddr; 1048eb20f36SRui Paulo map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 1058eb20f36SRui Paulo map->pr_offset = rdl->rdl_offset; 1068eb20f36SRui Paulo map->pr_mflags = 0; 1078eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_R) 1088eb20f36SRui Paulo map->pr_mflags |= MA_READ; 1098eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_W) 1108eb20f36SRui Paulo map->pr_mflags |= MA_WRITE; 1118eb20f36SRui Paulo if (rdl->rdl_prot & RD_RDL_X) 1128eb20f36SRui Paulo map->pr_mflags |= MA_EXEC; 1138eb20f36SRui Paulo strlcpy(map->pr_mapname, rdl->rdl_path, 1148eb20f36SRui Paulo sizeof(map->pr_mapname)); 1158eb20f36SRui Paulo } 1162c633af4SJohn Birrell 1172c633af4SJohn Birrell char * 1182c633af4SJohn Birrell proc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 1192c633af4SJohn Birrell size_t objnamesz) 1202c633af4SJohn Birrell { 1218eb20f36SRui Paulo size_t i; 1228eb20f36SRui Paulo rd_loadobj_t *rdl; 1238eb20f36SRui Paulo 1248eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 1258eb20f36SRui Paulo rdl = &p->rdobjs[i]; 1261e6b3858SMark Johnston if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 1278eb20f36SRui Paulo strlcpy(objname, rdl->rdl_path, objnamesz); 1288eb20f36SRui Paulo return (objname); 1298eb20f36SRui Paulo } 1308eb20f36SRui Paulo } 1312c633af4SJohn Birrell return (NULL); 1322c633af4SJohn Birrell } 1332c633af4SJohn Birrell 1348eb20f36SRui Paulo prmap_t * 1358eb20f36SRui Paulo proc_obj2map(struct proc_handle *p, const char *objname) 1368eb20f36SRui Paulo { 1378eb20f36SRui Paulo size_t i; 1388eb20f36SRui Paulo prmap_t *map; 1398eb20f36SRui Paulo rd_loadobj_t *rdl; 1408eb20f36SRui Paulo char path[MAXPATHLEN]; 1418eb20f36SRui Paulo 142acc0eea6SMark Johnston rdl = NULL; 1438eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 144acc0eea6SMark Johnston basename_r(p->rdobjs[i].rdl_path, path); 1458eb20f36SRui Paulo if (strcmp(path, objname) == 0) { 146acc0eea6SMark Johnston rdl = &p->rdobjs[i]; 147acc0eea6SMark Johnston break; 148acc0eea6SMark Johnston } 149acc0eea6SMark Johnston } 15024a08d30SMark Johnston if (rdl == NULL) { 15124a08d30SMark Johnston if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL) 152acc0eea6SMark Johnston rdl = p->rdexec; 153acc0eea6SMark Johnston else 154acc0eea6SMark Johnston return (NULL); 15524a08d30SMark Johnston } 156acc0eea6SMark Johnston 1578eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 1588eb20f36SRui Paulo return (NULL); 1598eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 1608eb20f36SRui Paulo return (map); 1618eb20f36SRui Paulo } 1628eb20f36SRui Paulo 1638eb20f36SRui Paulo int 1648eb20f36SRui Paulo proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 1658eb20f36SRui Paulo { 1668eb20f36SRui Paulo size_t i; 1678eb20f36SRui Paulo rd_loadobj_t *rdl; 1688eb20f36SRui Paulo prmap_t map; 1698eb20f36SRui Paulo char path[MAXPATHLEN]; 1704c74b245SRui Paulo char last[MAXPATHLEN]; 171c7fa6f0bSMark Johnston int error; 1728eb20f36SRui Paulo 1738eb20f36SRui Paulo if (p->nobjs == 0) 1748eb20f36SRui Paulo return (-1); 175c7fa6f0bSMark Johnston 176c7fa6f0bSMark Johnston error = 0; 1774c74b245SRui Paulo memset(last, 0, sizeof(last)); 1788eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 1798eb20f36SRui Paulo rdl = &p->rdobjs[i]; 1808eb20f36SRui Paulo proc_rdl2prmap(rdl, &map); 1818eb20f36SRui Paulo basename_r(rdl->rdl_path, path); 1824c74b245SRui Paulo /* 1834c74b245SRui Paulo * We shouldn't call the callback twice with the same object. 1844c74b245SRui Paulo * To do that we are assuming the fact that if there are 1854c74b245SRui Paulo * repeated object names (i.e. different mappings for the 1864c74b245SRui Paulo * same object) they occur next to each other. 1874c74b245SRui Paulo */ 1884c74b245SRui Paulo if (strcmp(path, last) == 0) 1894c74b245SRui Paulo continue; 190c7fa6f0bSMark Johnston if ((error = (*func)(cd, &map, path)) != 0) 191c7fa6f0bSMark Johnston break; 1924c74b245SRui Paulo strlcpy(last, path, sizeof(last)); 1938eb20f36SRui Paulo } 194c7fa6f0bSMark Johnston return (error); 1958eb20f36SRui Paulo } 1968eb20f36SRui Paulo 1978eb20f36SRui Paulo prmap_t * 1982c633af4SJohn Birrell proc_addr2map(struct proc_handle *p, uintptr_t addr) 1992c633af4SJohn Birrell { 2008eb20f36SRui Paulo size_t i; 2018eb20f36SRui Paulo int cnt, lastvn = 0; 2028eb20f36SRui Paulo prmap_t *map; 2038eb20f36SRui Paulo rd_loadobj_t *rdl; 2048eb20f36SRui Paulo struct kinfo_vmentry *kves, *kve; 2058eb20f36SRui Paulo 2068eb20f36SRui Paulo /* 2078eb20f36SRui Paulo * If we don't have a cache of listed objects, we need to query 2088eb20f36SRui Paulo * it ourselves. 2098eb20f36SRui Paulo */ 2108eb20f36SRui Paulo if (p->nobjs == 0) { 2118eb20f36SRui Paulo if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 2128eb20f36SRui Paulo return (NULL); 2138eb20f36SRui Paulo for (i = 0; i < (size_t)cnt; i++) { 2148eb20f36SRui Paulo kve = kves + i; 2158eb20f36SRui Paulo if (kve->kve_type == KVME_TYPE_VNODE) 2168eb20f36SRui Paulo lastvn = i; 2171e6b3858SMark Johnston if (addr >= kve->kve_start && addr < kve->kve_end) { 2188eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) { 2198eb20f36SRui Paulo free(kves); 2208eb20f36SRui Paulo return (NULL); 2218eb20f36SRui Paulo } 2228eb20f36SRui Paulo map->pr_vaddr = kve->kve_start; 2238eb20f36SRui Paulo map->pr_size = kve->kve_end - kve->kve_start; 2248eb20f36SRui Paulo map->pr_offset = kve->kve_offset; 2258eb20f36SRui Paulo map->pr_mflags = 0; 2268eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_READ) 2278eb20f36SRui Paulo map->pr_mflags |= MA_READ; 2288eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_WRITE) 2298eb20f36SRui Paulo map->pr_mflags |= MA_WRITE; 2308eb20f36SRui Paulo if (kve->kve_protection & KVME_PROT_EXEC) 2318eb20f36SRui Paulo map->pr_mflags |= MA_EXEC; 2328eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_COW) 2338eb20f36SRui Paulo map->pr_mflags |= MA_COW; 2348eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 2358eb20f36SRui Paulo map->pr_mflags |= MA_NEEDS_COPY; 2368eb20f36SRui Paulo if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 2378eb20f36SRui Paulo map->pr_mflags |= MA_NOCOREDUMP; 2388eb20f36SRui Paulo strlcpy(map->pr_mapname, kves[lastvn].kve_path, 2398eb20f36SRui Paulo sizeof(map->pr_mapname)); 2408eb20f36SRui Paulo free(kves); 2418eb20f36SRui Paulo return (map); 2428eb20f36SRui Paulo } 2438eb20f36SRui Paulo } 2448eb20f36SRui Paulo free(kves); 2458eb20f36SRui Paulo return (NULL); 2468eb20f36SRui Paulo } 2478eb20f36SRui Paulo 2488eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 2498eb20f36SRui Paulo rdl = &p->rdobjs[i]; 2501e6b3858SMark Johnston if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 2518eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 2528eb20f36SRui Paulo return (NULL); 2538eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 2548eb20f36SRui Paulo return (map); 2558eb20f36SRui Paulo } 2568eb20f36SRui Paulo } 2572c633af4SJohn Birrell return (NULL); 2582c633af4SJohn Birrell } 2592c633af4SJohn Birrell 260540cc663SMark Johnston /* 261540cc663SMark Johnston * Look up the symbol at addr, returning a copy of the symbol and its name. 262540cc663SMark Johnston */ 263540cc663SMark Johnston static int 264540cc663SMark Johnston lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr, 265540cc663SMark Johnston const char **name, GElf_Sym *symcopy) 266540cc663SMark Johnston { 267540cc663SMark Johnston GElf_Sym sym; 268540cc663SMark Johnston Elf_Data *data; 269540cc663SMark Johnston const char *s; 270540cc663SMark Johnston uint64_t rsym; 271540cc663SMark Johnston int i; 272540cc663SMark Johnston 273540cc663SMark Johnston if ((data = elf_getdata(scn, NULL)) == NULL) { 274540cc663SMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 275540cc663SMark Johnston return (1); 276540cc663SMark Johnston } 277540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 278540cc663SMark Johnston rsym = off + sym.st_value; 279540cc663SMark Johnston if (addr >= rsym && addr < rsym + sym.st_size) { 280540cc663SMark Johnston s = elf_strptr(e, stridx, sym.st_name); 281540cc663SMark Johnston if (s != NULL) { 282540cc663SMark Johnston *name = s; 283540cc663SMark Johnston memcpy(symcopy, &sym, sizeof(*symcopy)); 284540cc663SMark Johnston /* 285540cc663SMark Johnston * DTrace expects the st_value to contain 286540cc663SMark Johnston * only the address relative to the start of 287540cc663SMark Johnston * the function. 288540cc663SMark Johnston */ 289540cc663SMark Johnston symcopy->st_value = rsym; 290540cc663SMark Johnston return (0); 291540cc663SMark Johnston } 292540cc663SMark Johnston } 293540cc663SMark Johnston } 294540cc663SMark Johnston return (1); 295540cc663SMark Johnston } 296540cc663SMark Johnston 2972c633af4SJohn Birrell int 2982c633af4SJohn Birrell proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 2998eb20f36SRui Paulo size_t namesz, GElf_Sym *symcopy) 3002c633af4SJohn Birrell { 301540cc663SMark Johnston GElf_Ehdr ehdr; 302540cc663SMark Johnston GElf_Shdr shdr; 3038eb20f36SRui Paulo Elf *e; 3048eb20f36SRui Paulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 3058eb20f36SRui Paulo prmap_t *map; 306540cc663SMark Johnston const char *s; 307540cc663SMark Johnston uintptr_t off; 308540cc663SMark Johnston u_long symtabstridx = 0, dynsymstridx = 0; 309540cc663SMark Johnston int fd, error = -1; 3108eb20f36SRui Paulo 3118eb20f36SRui Paulo if ((map = proc_addr2map(p, addr)) == NULL) 3128eb20f36SRui Paulo return (-1); 313*eda94c07SRui Paulo if ((fd = find_dbg_obj(map->pr_mapname)) < 0) { 31430e81f7eSMark Johnston DPRINTF("ERROR: open %s failed", map->pr_mapname); 3158eb20f36SRui Paulo goto err0; 3168eb20f36SRui Paulo } 3178eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 31830e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 3198eb20f36SRui Paulo goto err1; 3208eb20f36SRui Paulo } 3218eb20f36SRui Paulo if (gelf_getehdr(e, &ehdr) == NULL) { 32230e81f7eSMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 3238eb20f36SRui Paulo goto err2; 3248eb20f36SRui Paulo } 325540cc663SMark Johnston 3268eb20f36SRui Paulo /* 3278eb20f36SRui Paulo * Find the index of the STRTAB and SYMTAB sections to locate 3288eb20f36SRui Paulo * symbol names. 3298eb20f36SRui Paulo */ 3308eb20f36SRui Paulo scn = NULL; 3318eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 3328eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 3338eb20f36SRui Paulo switch (shdr.sh_type) { 3348eb20f36SRui Paulo case SHT_SYMTAB: 3358eb20f36SRui Paulo symtabscn = scn; 3368eb20f36SRui Paulo symtabstridx = shdr.sh_link; 3378eb20f36SRui Paulo break; 3388eb20f36SRui Paulo case SHT_DYNSYM: 3398eb20f36SRui Paulo dynsymscn = scn; 3408eb20f36SRui Paulo dynsymstridx = shdr.sh_link; 3418eb20f36SRui Paulo break; 3428eb20f36SRui Paulo } 3438eb20f36SRui Paulo } 344540cc663SMark Johnston 345540cc663SMark Johnston off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 346540cc663SMark Johnston 3478eb20f36SRui Paulo /* 348540cc663SMark Johnston * First look up the symbol in the dynsymtab, and fall back to the 349540cc663SMark Johnston * symtab if the lookup fails. 3508eb20f36SRui Paulo */ 351540cc663SMark Johnston error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy); 352540cc663SMark Johnston if (error == 0) 3538eb20f36SRui Paulo goto out; 354540cc663SMark Johnston 355540cc663SMark Johnston error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); 356cd9c9939SMark Johnston if (error != 0) 357cd9c9939SMark Johnston goto err2; 358540cc663SMark Johnston 3598eb20f36SRui Paulo out: 360540cc663SMark Johnston demangle(s, name, namesz); 3618eb20f36SRui Paulo err2: 3628eb20f36SRui Paulo elf_end(e); 3638eb20f36SRui Paulo err1: 3648eb20f36SRui Paulo close(fd); 3658eb20f36SRui Paulo err0: 3668eb20f36SRui Paulo free(map); 3678eb20f36SRui Paulo return (error); 3682c633af4SJohn Birrell } 3692c633af4SJohn Birrell 3708eb20f36SRui Paulo prmap_t * 3712c633af4SJohn Birrell proc_name2map(struct proc_handle *p, const char *name) 3722c633af4SJohn Birrell { 3738eb20f36SRui Paulo size_t i; 3748eb20f36SRui Paulo int cnt; 375540cc663SMark Johnston prmap_t *map = NULL; 3768eb20f36SRui Paulo char tmppath[MAXPATHLEN]; 3778eb20f36SRui Paulo struct kinfo_vmentry *kves, *kve; 3788eb20f36SRui Paulo rd_loadobj_t *rdl; 3798eb20f36SRui Paulo 3808eb20f36SRui Paulo /* 3818eb20f36SRui Paulo * If we haven't iterated over the list of loaded objects, 3828eb20f36SRui Paulo * librtld_db isn't yet initialized and it's very likely 3838eb20f36SRui Paulo * that librtld_db called us. We need to do the heavy 3848eb20f36SRui Paulo * lifting here to find the symbol librtld_db is looking for. 3858eb20f36SRui Paulo */ 3868eb20f36SRui Paulo if (p->nobjs == 0) { 3878eb20f36SRui Paulo if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 3888eb20f36SRui Paulo return (NULL); 3898eb20f36SRui Paulo for (i = 0; i < (size_t)cnt; i++) { 3908eb20f36SRui Paulo kve = kves + i; 3918eb20f36SRui Paulo basename_r(kve->kve_path, tmppath); 3928eb20f36SRui Paulo if (strcmp(tmppath, name) == 0) { 3938eb20f36SRui Paulo map = proc_addr2map(p, kve->kve_start); 394540cc663SMark Johnston break; 3958eb20f36SRui Paulo } 3968eb20f36SRui Paulo } 3978eb20f36SRui Paulo free(kves); 398540cc663SMark Johnston } else 3998eb20f36SRui Paulo for (i = 0; i < p->nobjs; i++) { 4008eb20f36SRui Paulo rdl = &p->rdobjs[i]; 4018eb20f36SRui Paulo basename_r(rdl->rdl_path, tmppath); 4028eb20f36SRui Paulo if (strcmp(tmppath, name) == 0) { 4038eb20f36SRui Paulo if ((map = malloc(sizeof(*map))) == NULL) 4048eb20f36SRui Paulo return (NULL); 4058eb20f36SRui Paulo proc_rdl2prmap(rdl, map); 406540cc663SMark Johnston break; 4078eb20f36SRui Paulo } 4088eb20f36SRui Paulo } 4098eb20f36SRui Paulo 410540cc663SMark Johnston if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL) 411540cc663SMark Johnston map = proc_addr2map(p, p->rdexec->rdl_saddr); 412540cc663SMark Johnston 413540cc663SMark Johnston return (map); 414540cc663SMark Johnston } 415540cc663SMark Johnston 416540cc663SMark Johnston /* 417540cc663SMark Johnston * Look up the symbol with the given name and return a copy of it. 418540cc663SMark Johnston */ 419540cc663SMark Johnston static int 420540cc663SMark Johnston lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol, 42141da933cSMark Johnston GElf_Sym *symcopy, prsyminfo_t *si) 422540cc663SMark Johnston { 423540cc663SMark Johnston GElf_Sym sym; 424540cc663SMark Johnston Elf_Data *data; 425540cc663SMark Johnston char *s; 426540cc663SMark Johnston int i; 427540cc663SMark Johnston 428540cc663SMark Johnston if ((data = elf_getdata(scn, NULL)) == NULL) { 429540cc663SMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 430540cc663SMark Johnston return (1); 431540cc663SMark Johnston } 432540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 433540cc663SMark Johnston s = elf_strptr(e, stridx, sym.st_name); 434540cc663SMark Johnston if (s != NULL && strcmp(s, symbol) == 0) { 435540cc663SMark Johnston memcpy(symcopy, &sym, sizeof(*symcopy)); 43641da933cSMark Johnston if (si != NULL) 43741da933cSMark Johnston si->prs_id = i; 438540cc663SMark Johnston return (0); 439540cc663SMark Johnston } 440540cc663SMark Johnston } 441540cc663SMark Johnston return (1); 4422c633af4SJohn Birrell } 4432c633af4SJohn Birrell 4442c633af4SJohn Birrell int 4452c633af4SJohn Birrell proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 44641da933cSMark Johnston GElf_Sym *symcopy, prsyminfo_t *si) 4472c633af4SJohn Birrell { 4488eb20f36SRui Paulo Elf *e; 4498eb20f36SRui Paulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 4508eb20f36SRui Paulo GElf_Shdr shdr; 4518eb20f36SRui Paulo GElf_Ehdr ehdr; 4528eb20f36SRui Paulo prmap_t *map; 453540cc663SMark Johnston uintptr_t off; 454540cc663SMark Johnston u_long symtabstridx = 0, dynsymstridx = 0; 455540cc663SMark Johnston int fd, error = -1; 4568eb20f36SRui Paulo 4578eb20f36SRui Paulo if ((map = proc_name2map(p, object)) == NULL) { 45830e81f7eSMark Johnston DPRINTFX("ERROR: couldn't find object %s", object); 4598eb20f36SRui Paulo goto err0; 4608eb20f36SRui Paulo } 461*eda94c07SRui Paulo if ((fd = find_dbg_obj(map->pr_mapname)) < 0) { 4628eb20f36SRui Paulo DPRINTF("ERROR: open %s failed", map->pr_mapname); 4638eb20f36SRui Paulo goto err0; 4648eb20f36SRui Paulo } 4658eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 46630e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 4678eb20f36SRui Paulo goto err1; 4688eb20f36SRui Paulo } 4698eb20f36SRui Paulo if (gelf_getehdr(e, &ehdr) == NULL) { 47030e81f7eSMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 4718eb20f36SRui Paulo goto err2; 4728eb20f36SRui Paulo } 4738eb20f36SRui Paulo /* 4748eb20f36SRui Paulo * Find the index of the STRTAB and SYMTAB sections to locate 4758eb20f36SRui Paulo * symbol names. 4768eb20f36SRui Paulo */ 4778eb20f36SRui Paulo scn = NULL; 4788eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 4798eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 4808eb20f36SRui Paulo switch (shdr.sh_type) { 4818eb20f36SRui Paulo case SHT_SYMTAB: 4828eb20f36SRui Paulo symtabscn = scn; 4838eb20f36SRui Paulo symtabstridx = shdr.sh_link; 4848eb20f36SRui Paulo break; 4858eb20f36SRui Paulo case SHT_DYNSYM: 4868eb20f36SRui Paulo dynsymscn = scn; 4878eb20f36SRui Paulo dynsymstridx = shdr.sh_link; 4888eb20f36SRui Paulo break; 4898eb20f36SRui Paulo } 4908eb20f36SRui Paulo } 491540cc663SMark Johnston 4928eb20f36SRui Paulo /* 493540cc663SMark Johnston * First look up the symbol in the dynsymtab, and fall back to the 494540cc663SMark Johnston * symtab if the lookup fails. 4958eb20f36SRui Paulo */ 49641da933cSMark Johnston error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si); 497540cc663SMark Johnston if (error == 0) 4988eb20f36SRui Paulo goto out; 499540cc663SMark Johnston 50041da933cSMark Johnston error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si); 501540cc663SMark Johnston if (error == 0) 5028eb20f36SRui Paulo goto out; 503540cc663SMark Johnston 5048eb20f36SRui Paulo out: 505540cc663SMark Johnston off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 506540cc663SMark Johnston symcopy->st_value += off; 507540cc663SMark Johnston 5088eb20f36SRui Paulo err2: 5098eb20f36SRui Paulo elf_end(e); 5108eb20f36SRui Paulo err1: 5118eb20f36SRui Paulo close(fd); 5128eb20f36SRui Paulo err0: 5138eb20f36SRui Paulo free(map); 5148eb20f36SRui Paulo 5158eb20f36SRui Paulo return (error); 5168eb20f36SRui Paulo } 5178eb20f36SRui Paulo 51841da933cSMark Johnston ctf_file_t * 51941da933cSMark Johnston proc_name2ctf(struct proc_handle *p, const char *name) 52041da933cSMark Johnston { 52141da933cSMark Johnston #ifndef NO_CTF 5223f1cbdbeSMark Johnston ctf_file_t *ctf; 52341da933cSMark Johnston prmap_t *map; 52441da933cSMark Johnston int error; 52541da933cSMark Johnston 526ec045490SMark Johnston if ((map = proc_name2map(p, name)) == NULL) 52741da933cSMark Johnston return (NULL); 52841da933cSMark Johnston 5293f1cbdbeSMark Johnston ctf = ctf_open(map->pr_mapname, &error); 5303f1cbdbeSMark Johnston free(map); 5313f1cbdbeSMark Johnston return (ctf); 53241da933cSMark Johnston #else 53341da933cSMark Johnston (void)p; 53441da933cSMark Johnston (void)name; 53541da933cSMark Johnston return (NULL); 53641da933cSMark Johnston #endif 53741da933cSMark Johnston } 53841da933cSMark Johnston 5398eb20f36SRui Paulo int 5408eb20f36SRui Paulo proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 5418eb20f36SRui Paulo int mask, proc_sym_f *func, void *cd) 5428eb20f36SRui Paulo { 5438eb20f36SRui Paulo Elf *e; 5448eb20f36SRui Paulo int i, fd; 5458eb20f36SRui Paulo prmap_t *map; 5468eb20f36SRui Paulo Elf_Scn *scn, *foundscn = NULL; 5478eb20f36SRui Paulo Elf_Data *data; 548fbce8e16SMark Johnston GElf_Ehdr ehdr; 5498eb20f36SRui Paulo GElf_Shdr shdr; 5508eb20f36SRui Paulo GElf_Sym sym; 5518eb20f36SRui Paulo unsigned long stridx = -1; 5528eb20f36SRui Paulo char *s; 5538eb20f36SRui Paulo int error = -1; 5548eb20f36SRui Paulo 5558eb20f36SRui Paulo if ((map = proc_name2map(p, object)) == NULL) 5568eb20f36SRui Paulo return (-1); 557*eda94c07SRui Paulo if ((fd = find_dbg_obj(map->pr_mapname)) < 0) { 55830e81f7eSMark Johnston DPRINTF("ERROR: open %s failed", map->pr_mapname); 5598eb20f36SRui Paulo goto err0; 5608eb20f36SRui Paulo } 5618eb20f36SRui Paulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 56230e81f7eSMark Johnston DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 5638eb20f36SRui Paulo goto err1; 5648eb20f36SRui Paulo } 565fbce8e16SMark Johnston if (gelf_getehdr(e, &ehdr) == NULL) { 566fbce8e16SMark Johnston DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 567fbce8e16SMark Johnston goto err2; 568fbce8e16SMark Johnston } 5698eb20f36SRui Paulo /* 5708eb20f36SRui Paulo * Find the section we are looking for. 5718eb20f36SRui Paulo */ 5728eb20f36SRui Paulo scn = NULL; 5738eb20f36SRui Paulo while ((scn = elf_nextscn(e, scn)) != NULL) { 5748eb20f36SRui Paulo gelf_getshdr(scn, &shdr); 5758eb20f36SRui Paulo if (which == PR_SYMTAB && 5768eb20f36SRui Paulo shdr.sh_type == SHT_SYMTAB) { 5778eb20f36SRui Paulo foundscn = scn; 5788eb20f36SRui Paulo break; 5798eb20f36SRui Paulo } else if (which == PR_DYNSYM && 5808eb20f36SRui Paulo shdr.sh_type == SHT_DYNSYM) { 5818eb20f36SRui Paulo foundscn = scn; 5828eb20f36SRui Paulo break; 5838eb20f36SRui Paulo } 5848eb20f36SRui Paulo } 5858eb20f36SRui Paulo if (!foundscn) 5868eb20f36SRui Paulo return (-1); 5878eb20f36SRui Paulo stridx = shdr.sh_link; 5888eb20f36SRui Paulo if ((data = elf_getdata(foundscn, NULL)) == NULL) { 58930e81f7eSMark Johnston DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 5908eb20f36SRui Paulo goto err2; 5918eb20f36SRui Paulo } 592540cc663SMark Johnston for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 5938eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 5948eb20f36SRui Paulo (mask & BIND_LOCAL) == 0) 5958eb20f36SRui Paulo continue; 5968eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 5978eb20f36SRui Paulo (mask & BIND_GLOBAL) == 0) 5988eb20f36SRui Paulo continue; 5998eb20f36SRui Paulo if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 6008eb20f36SRui Paulo (mask & BIND_WEAK) == 0) 6018eb20f36SRui Paulo continue; 6028eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 6038eb20f36SRui Paulo (mask & TYPE_NOTYPE) == 0) 6048eb20f36SRui Paulo continue; 6058eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 6068eb20f36SRui Paulo (mask & TYPE_OBJECT) == 0) 6078eb20f36SRui Paulo continue; 6088eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 6098eb20f36SRui Paulo (mask & TYPE_FUNC) == 0) 6108eb20f36SRui Paulo continue; 6118eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 6128eb20f36SRui Paulo (mask & TYPE_SECTION) == 0) 6138eb20f36SRui Paulo continue; 6148eb20f36SRui Paulo if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 6158eb20f36SRui Paulo (mask & TYPE_FILE) == 0) 6168eb20f36SRui Paulo continue; 6178eb20f36SRui Paulo s = elf_strptr(e, stridx, sym.st_name); 618fbce8e16SMark Johnston if (ehdr.e_type != ET_EXEC) 6198eb20f36SRui Paulo sym.st_value += map->pr_vaddr; 620c7fa6f0bSMark Johnston if ((error = (*func)(cd, &sym, s)) != 0) 621c7fa6f0bSMark Johnston goto err2; 6228eb20f36SRui Paulo } 6238eb20f36SRui Paulo error = 0; 6248eb20f36SRui Paulo err2: 6258eb20f36SRui Paulo elf_end(e); 6268eb20f36SRui Paulo err1: 6278eb20f36SRui Paulo close(fd); 6288eb20f36SRui Paulo err0: 6298eb20f36SRui Paulo free(map); 6308eb20f36SRui Paulo return (error); 6312c633af4SJohn Birrell } 632