1179185Sjb/*- 2210688Srpaulo * Copyright (c) 2010 The FreeBSD Foundation 3179185Sjb * Copyright (c) 2008 John Birrell (jb@freebsd.org) 4179185Sjb * All rights reserved. 5179185Sjb * 6210688Srpaulo * Portions of this software were developed by Rui Paulo under sponsorship 7210688Srpaulo * from the FreeBSD Foundation. 8210688Srpaulo * 9179185Sjb * Redistribution and use in source and binary forms, with or without 10179185Sjb * modification, are permitted provided that the following conditions 11179185Sjb * are met: 12179185Sjb * 1. Redistributions of source code must retain the above copyright 13179185Sjb * notice, this list of conditions and the following disclaimer. 14179185Sjb * 2. Redistributions in binary form must reproduce the above copyright 15179185Sjb * notice, this list of conditions and the following disclaimer in the 16179185Sjb * documentation and/or other materials provided with the distribution. 17179185Sjb * 18179185Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19179185Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20179185Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21179185Sjb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22179185Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23179185Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24179185Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25179185Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26179185Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27179185Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28179185Sjb * SUCH DAMAGE. 29179185Sjb * 30179185Sjb * $FreeBSD$ 31179185Sjb */ 32179185Sjb 33210688Srpaulo#include <sys/types.h> 34210688Srpaulo#include <sys/user.h> 35210688Srpaulo 36210688Srpaulo#include <assert.h> 37210688Srpaulo#include <err.h> 38179185Sjb#include <stdio.h> 39210688Srpaulo#include <libgen.h> 40210688Srpaulo#include <string.h> 41210688Srpaulo#include <stdlib.h> 42210688Srpaulo#include <fcntl.h> 43210688Srpaulo#include <string.h> 44210688Srpaulo#include <unistd.h> 45210688Srpaulo#include <libutil.h> 46179185Sjb 47210688Srpaulo#include "_libproc.h" 48210688Srpaulo 49268775Sdim#ifndef NO_CXA_DEMANGLE 50240156Srpauloextern char *__cxa_demangle(const char *, char *, size_t *, int *); 51268775Sdim#endif /* NO_CXA_DEMANGLE */ 52240156Srpaulo 53210688Srpaulostatic void proc_rdl2prmap(rd_loadobj_t *, prmap_t *); 54210688Srpaulo 55210688Srpaulostatic void 56240182Srpaulodemangle(const char *symbol, char *buf, size_t len) 57240182Srpaulo{ 58268775Sdim#ifndef NO_CXA_DEMANGLE 59240182Srpaulo char *dembuf; 60240182Srpaulo 61268775Sdim if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) { 62269885Sdim dembuf = __cxa_demangle(symbol, NULL, NULL, NULL); 63268775Sdim if (!dembuf) 64268775Sdim goto fail; 65268775Sdim strlcpy(buf, dembuf, len); 66268775Sdim free(dembuf); 67269885Sdim return; 68268775Sdim } 69240182Srpaulofail: 70268775Sdim#endif /* NO_CXA_DEMANGLE */ 71240182Srpaulo strlcpy(buf, symbol, len); 72240182Srpaulo} 73240182Srpaulo 74240182Srpaulostatic void 75210688Srpauloproc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 76210688Srpaulo{ 77210688Srpaulo map->pr_vaddr = rdl->rdl_saddr; 78210688Srpaulo map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 79210688Srpaulo map->pr_offset = rdl->rdl_offset; 80210688Srpaulo map->pr_mflags = 0; 81210688Srpaulo if (rdl->rdl_prot & RD_RDL_R) 82210688Srpaulo map->pr_mflags |= MA_READ; 83210688Srpaulo if (rdl->rdl_prot & RD_RDL_W) 84210688Srpaulo map->pr_mflags |= MA_WRITE; 85210688Srpaulo if (rdl->rdl_prot & RD_RDL_X) 86210688Srpaulo map->pr_mflags |= MA_EXEC; 87210688Srpaulo strlcpy(map->pr_mapname, rdl->rdl_path, 88210688Srpaulo sizeof(map->pr_mapname)); 89210688Srpaulo} 90210688Srpaulo 91179185Sjbchar * 92179185Sjbproc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 93179185Sjb size_t objnamesz) 94179185Sjb{ 95210688Srpaulo size_t i; 96210688Srpaulo rd_loadobj_t *rdl; 97210688Srpaulo 98210688Srpaulo for (i = 0; i < p->nobjs; i++) { 99210688Srpaulo rdl = &p->rdobjs[i]; 100265073Smarkj if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 101210688Srpaulo strlcpy(objname, rdl->rdl_path, objnamesz); 102210688Srpaulo return (objname); 103210688Srpaulo } 104210688Srpaulo } 105179185Sjb return (NULL); 106179185Sjb} 107179185Sjb 108210688Srpauloprmap_t * 109210688Srpauloproc_obj2map(struct proc_handle *p, const char *objname) 110210688Srpaulo{ 111210688Srpaulo size_t i; 112210688Srpaulo prmap_t *map; 113210688Srpaulo rd_loadobj_t *rdl; 114210688Srpaulo char path[MAXPATHLEN]; 115210688Srpaulo 116270731Smarkj rdl = NULL; 117210688Srpaulo for (i = 0; i < p->nobjs; i++) { 118270731Smarkj basename_r(p->rdobjs[i].rdl_path, path); 119210688Srpaulo if (strcmp(path, objname) == 0) { 120270731Smarkj rdl = &p->rdobjs[i]; 121270731Smarkj break; 122210688Srpaulo } 123210688Srpaulo } 124270731Smarkj if (rdl == NULL) { 125270731Smarkj if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL) 126270731Smarkj rdl = p->rdexec; 127270731Smarkj else 128270731Smarkj return (NULL); 129270731Smarkj } 130270731Smarkj 131270731Smarkj if ((map = malloc(sizeof(*map))) == NULL) 132270731Smarkj return (NULL); 133270731Smarkj proc_rdl2prmap(rdl, map); 134270731Smarkj return (map); 135210688Srpaulo} 136210688Srpaulo 137210688Srpauloint 138210688Srpauloproc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 139210688Srpaulo{ 140210688Srpaulo size_t i; 141210688Srpaulo rd_loadobj_t *rdl; 142210688Srpaulo prmap_t map; 143210688Srpaulo char path[MAXPATHLEN]; 144211184Srpaulo char last[MAXPATHLEN]; 145210688Srpaulo 146210688Srpaulo if (p->nobjs == 0) 147210688Srpaulo return (-1); 148211184Srpaulo memset(last, 0, sizeof(last)); 149210688Srpaulo for (i = 0; i < p->nobjs; i++) { 150210688Srpaulo rdl = &p->rdobjs[i]; 151210688Srpaulo proc_rdl2prmap(rdl, &map); 152210688Srpaulo basename_r(rdl->rdl_path, path); 153211184Srpaulo /* 154211184Srpaulo * We shouldn't call the callback twice with the same object. 155211184Srpaulo * To do that we are assuming the fact that if there are 156211184Srpaulo * repeated object names (i.e. different mappings for the 157211184Srpaulo * same object) they occur next to each other. 158211184Srpaulo */ 159211184Srpaulo if (strcmp(path, last) == 0) 160211184Srpaulo continue; 161210688Srpaulo (*func)(cd, &map, path); 162211184Srpaulo strlcpy(last, path, sizeof(last)); 163210688Srpaulo } 164210688Srpaulo 165210688Srpaulo return (0); 166210688Srpaulo} 167210688Srpaulo 168210688Srpauloprmap_t * 169179185Sjbproc_addr2map(struct proc_handle *p, uintptr_t addr) 170179185Sjb{ 171210688Srpaulo size_t i; 172210688Srpaulo int cnt, lastvn = 0; 173210688Srpaulo prmap_t *map; 174210688Srpaulo rd_loadobj_t *rdl; 175210688Srpaulo struct kinfo_vmentry *kves, *kve; 176210688Srpaulo 177210688Srpaulo /* 178210688Srpaulo * If we don't have a cache of listed objects, we need to query 179210688Srpaulo * it ourselves. 180210688Srpaulo */ 181210688Srpaulo if (p->nobjs == 0) { 182210688Srpaulo if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 183210688Srpaulo return (NULL); 184210688Srpaulo for (i = 0; i < (size_t)cnt; i++) { 185210688Srpaulo kve = kves + i; 186210688Srpaulo if (kve->kve_type == KVME_TYPE_VNODE) 187210688Srpaulo lastvn = i; 188265073Smarkj if (addr >= kve->kve_start && addr < kve->kve_end) { 189210688Srpaulo if ((map = malloc(sizeof(*map))) == NULL) { 190210688Srpaulo free(kves); 191210688Srpaulo return (NULL); 192210688Srpaulo } 193210688Srpaulo map->pr_vaddr = kve->kve_start; 194210688Srpaulo map->pr_size = kve->kve_end - kve->kve_start; 195210688Srpaulo map->pr_offset = kve->kve_offset; 196210688Srpaulo map->pr_mflags = 0; 197210688Srpaulo if (kve->kve_protection & KVME_PROT_READ) 198210688Srpaulo map->pr_mflags |= MA_READ; 199210688Srpaulo if (kve->kve_protection & KVME_PROT_WRITE) 200210688Srpaulo map->pr_mflags |= MA_WRITE; 201210688Srpaulo if (kve->kve_protection & KVME_PROT_EXEC) 202210688Srpaulo map->pr_mflags |= MA_EXEC; 203210688Srpaulo if (kve->kve_flags & KVME_FLAG_COW) 204210688Srpaulo map->pr_mflags |= MA_COW; 205210688Srpaulo if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 206210688Srpaulo map->pr_mflags |= MA_NEEDS_COPY; 207210688Srpaulo if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 208210688Srpaulo map->pr_mflags |= MA_NOCOREDUMP; 209210688Srpaulo strlcpy(map->pr_mapname, kves[lastvn].kve_path, 210210688Srpaulo sizeof(map->pr_mapname)); 211210688Srpaulo free(kves); 212210688Srpaulo return (map); 213210688Srpaulo } 214210688Srpaulo } 215210688Srpaulo free(kves); 216210688Srpaulo return (NULL); 217210688Srpaulo } 218210688Srpaulo 219210688Srpaulo for (i = 0; i < p->nobjs; i++) { 220210688Srpaulo rdl = &p->rdobjs[i]; 221265073Smarkj if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 222210688Srpaulo if ((map = malloc(sizeof(*map))) == NULL) 223210688Srpaulo return (NULL); 224210688Srpaulo proc_rdl2prmap(rdl, map); 225210688Srpaulo return (map); 226210688Srpaulo } 227210688Srpaulo } 228179185Sjb return (NULL); 229179185Sjb} 230179185Sjb 231179185Sjbint 232179185Sjbproc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 233210688Srpaulo size_t namesz, GElf_Sym *symcopy) 234179185Sjb{ 235210688Srpaulo Elf *e; 236210688Srpaulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 237210688Srpaulo Elf_Data *data; 238210688Srpaulo GElf_Shdr shdr; 239210688Srpaulo GElf_Sym sym; 240210688Srpaulo GElf_Ehdr ehdr; 241210688Srpaulo int fd, error = -1; 242210688Srpaulo size_t i; 243210688Srpaulo uint64_t rsym; 244210688Srpaulo prmap_t *map; 245210688Srpaulo char *s; 246210688Srpaulo unsigned long symtabstridx = 0, dynsymstridx = 0; 247210688Srpaulo 248210688Srpaulo if ((map = proc_addr2map(p, addr)) == NULL) 249210688Srpaulo return (-1); 250259895Smarkj if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 251259895Smarkj DPRINTF("ERROR: open %s failed", map->pr_mapname); 252210688Srpaulo goto err0; 253210688Srpaulo } 254210688Srpaulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 255259895Smarkj DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 256210688Srpaulo goto err1; 257210688Srpaulo } 258210688Srpaulo if (gelf_getehdr(e, &ehdr) == NULL) { 259259895Smarkj DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 260210688Srpaulo goto err2; 261210688Srpaulo } 262210688Srpaulo /* 263210688Srpaulo * Find the index of the STRTAB and SYMTAB sections to locate 264210688Srpaulo * symbol names. 265210688Srpaulo */ 266210688Srpaulo scn = NULL; 267210688Srpaulo while ((scn = elf_nextscn(e, scn)) != NULL) { 268210688Srpaulo gelf_getshdr(scn, &shdr); 269210688Srpaulo switch (shdr.sh_type) { 270210688Srpaulo case SHT_SYMTAB: 271210688Srpaulo symtabscn = scn; 272210688Srpaulo symtabstridx = shdr.sh_link; 273210688Srpaulo break; 274210688Srpaulo case SHT_DYNSYM: 275210688Srpaulo dynsymscn = scn; 276210688Srpaulo dynsymstridx = shdr.sh_link; 277210688Srpaulo break; 278210688Srpaulo default: 279210688Srpaulo break; 280210688Srpaulo } 281210688Srpaulo } 282210688Srpaulo /* 283210688Srpaulo * Iterate over the Dynamic Symbols table to find the symbol. 284210688Srpaulo * Then look up the string name in STRTAB (.dynstr) 285210688Srpaulo */ 286210688Srpaulo if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { 287259895Smarkj DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 288240040Srpaulo goto symtab; 289210688Srpaulo } 290210688Srpaulo i = 0; 291210688Srpaulo while (gelf_getsym(data, i++, &sym) != NULL) { 292210688Srpaulo /* 293210688Srpaulo * Calculate the address mapped to the virtual memory 294210688Srpaulo * by rtld. 295210688Srpaulo */ 296259972Smarkj if (ehdr.e_type != ET_EXEC) 297259972Smarkj rsym = map->pr_vaddr + sym.st_value; 298259972Smarkj else 299259972Smarkj rsym = sym.st_value; 300259965Smarkj if (addr >= rsym && addr < rsym + sym.st_size) { 301210688Srpaulo s = elf_strptr(e, dynsymstridx, sym.st_name); 302210688Srpaulo if (s) { 303268775Sdim demangle(s, name, namesz); 304210688Srpaulo memcpy(symcopy, &sym, sizeof(sym)); 305210688Srpaulo /* 306210688Srpaulo * DTrace expects the st_value to contain 307210688Srpaulo * only the address relative to the start of 308210688Srpaulo * the function. 309210688Srpaulo */ 310210688Srpaulo symcopy->st_value = rsym; 311254177Srpaulo error = 0; 312210688Srpaulo goto out; 313210688Srpaulo } 314210688Srpaulo } 315210688Srpaulo } 316240040Srpaulosymtab: 317210688Srpaulo /* 318210688Srpaulo * Iterate over the Symbols Table to find the symbol. 319210688Srpaulo * Then look up the string name in STRTAB (.dynstr) 320210688Srpaulo */ 321210688Srpaulo if ((data = elf_getdata(symtabscn, NULL)) == NULL) { 322259895Smarkj DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 323210688Srpaulo goto err2; 324210688Srpaulo } 325210688Srpaulo i = 0; 326210688Srpaulo while (gelf_getsym(data, i++, &sym) != NULL) { 327210688Srpaulo /* 328210688Srpaulo * Calculate the address mapped to the virtual memory 329210688Srpaulo * by rtld. 330210688Srpaulo */ 331210688Srpaulo if (ehdr.e_type != ET_EXEC) 332210688Srpaulo rsym = map->pr_vaddr + sym.st_value; 333210688Srpaulo else 334210688Srpaulo rsym = sym.st_value; 335259965Smarkj if (addr >= rsym && addr < rsym + sym.st_size) { 336210688Srpaulo s = elf_strptr(e, symtabstridx, sym.st_name); 337210688Srpaulo if (s) { 338268775Sdim demangle(s, name, namesz); 339210688Srpaulo memcpy(symcopy, &sym, sizeof(sym)); 340210688Srpaulo /* 341210688Srpaulo * DTrace expects the st_value to contain 342210688Srpaulo * only the address relative to the start of 343210688Srpaulo * the function. 344210688Srpaulo */ 345210688Srpaulo symcopy->st_value = rsym; 346210688Srpaulo error = 0; 347210688Srpaulo goto out; 348210688Srpaulo } 349210688Srpaulo } 350210688Srpaulo } 351210688Srpauloout: 352210688Srpauloerr2: 353210688Srpaulo elf_end(e); 354210688Srpauloerr1: 355210688Srpaulo close(fd); 356210688Srpauloerr0: 357210688Srpaulo free(map); 358210688Srpaulo return (error); 359179185Sjb} 360179185Sjb 361210688Srpauloprmap_t * 362179185Sjbproc_name2map(struct proc_handle *p, const char *name) 363179185Sjb{ 364210688Srpaulo size_t i; 365210688Srpaulo int cnt; 366210688Srpaulo prmap_t *map; 367210688Srpaulo char tmppath[MAXPATHLEN]; 368210688Srpaulo struct kinfo_vmentry *kves, *kve; 369210688Srpaulo rd_loadobj_t *rdl; 370210688Srpaulo 371210688Srpaulo /* 372210688Srpaulo * If we haven't iterated over the list of loaded objects, 373210688Srpaulo * librtld_db isn't yet initialized and it's very likely 374210688Srpaulo * that librtld_db called us. We need to do the heavy 375210688Srpaulo * lifting here to find the symbol librtld_db is looking for. 376210688Srpaulo */ 377210688Srpaulo if (p->nobjs == 0) { 378210688Srpaulo if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 379210688Srpaulo return (NULL); 380210688Srpaulo for (i = 0; i < (size_t)cnt; i++) { 381210688Srpaulo kve = kves + i; 382210688Srpaulo basename_r(kve->kve_path, tmppath); 383210688Srpaulo if (strcmp(tmppath, name) == 0) { 384210688Srpaulo map = proc_addr2map(p, kve->kve_start); 385210688Srpaulo free(kves); 386210688Srpaulo return (map); 387210688Srpaulo } 388210688Srpaulo } 389210688Srpaulo free(kves); 390210688Srpaulo return (NULL); 391210688Srpaulo } 392270731Smarkj if ((name == NULL || strcmp(name, "a.out") == 0) && 393270731Smarkj p->rdexec != NULL) { 394270731Smarkj map = proc_addr2map(p, p->rdexec->rdl_saddr); 395210688Srpaulo return (map); 396210688Srpaulo } 397210688Srpaulo for (i = 0; i < p->nobjs; i++) { 398210688Srpaulo rdl = &p->rdobjs[i]; 399210688Srpaulo basename_r(rdl->rdl_path, tmppath); 400210688Srpaulo if (strcmp(tmppath, name) == 0) { 401210688Srpaulo if ((map = malloc(sizeof(*map))) == NULL) 402210688Srpaulo return (NULL); 403210688Srpaulo proc_rdl2prmap(rdl, map); 404210688Srpaulo return (map); 405210688Srpaulo } 406210688Srpaulo } 407210688Srpaulo 408179185Sjb return (NULL); 409179185Sjb} 410179185Sjb 411179185Sjbint 412179185Sjbproc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 413210688Srpaulo GElf_Sym *symcopy) 414179185Sjb{ 415210688Srpaulo Elf *e; 416210688Srpaulo Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 417210688Srpaulo Elf_Data *data; 418210688Srpaulo GElf_Shdr shdr; 419210688Srpaulo GElf_Sym sym; 420210688Srpaulo GElf_Ehdr ehdr; 421210688Srpaulo int fd, error = -1; 422210688Srpaulo size_t i; 423210688Srpaulo prmap_t *map; 424210688Srpaulo char *s; 425210688Srpaulo unsigned long symtabstridx = 0, dynsymstridx = 0; 426210688Srpaulo 427210688Srpaulo if ((map = proc_name2map(p, object)) == NULL) { 428259895Smarkj DPRINTFX("ERROR: couldn't find object %s", object); 429210688Srpaulo goto err0; 430210688Srpaulo } 431210688Srpaulo if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 432210688Srpaulo DPRINTF("ERROR: open %s failed", map->pr_mapname); 433210688Srpaulo goto err0; 434210688Srpaulo } 435210688Srpaulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 436259895Smarkj DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 437210688Srpaulo goto err1; 438210688Srpaulo } 439210688Srpaulo if (gelf_getehdr(e, &ehdr) == NULL) { 440259895Smarkj DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 441210688Srpaulo goto err2; 442210688Srpaulo } 443210688Srpaulo /* 444210688Srpaulo * Find the index of the STRTAB and SYMTAB sections to locate 445210688Srpaulo * symbol names. 446210688Srpaulo */ 447210688Srpaulo scn = NULL; 448210688Srpaulo while ((scn = elf_nextscn(e, scn)) != NULL) { 449210688Srpaulo gelf_getshdr(scn, &shdr); 450210688Srpaulo switch (shdr.sh_type) { 451210688Srpaulo case SHT_SYMTAB: 452210688Srpaulo symtabscn = scn; 453210688Srpaulo symtabstridx = shdr.sh_link; 454210688Srpaulo break; 455210688Srpaulo case SHT_DYNSYM: 456210688Srpaulo dynsymscn = scn; 457210688Srpaulo dynsymstridx = shdr.sh_link; 458210688Srpaulo break; 459210688Srpaulo default: 460210688Srpaulo break; 461210688Srpaulo } 462210688Srpaulo } 463210688Srpaulo /* 464210688Srpaulo * Iterate over the Dynamic Symbols table to find the symbol. 465210688Srpaulo * Then look up the string name in STRTAB (.dynstr) 466210688Srpaulo */ 467240040Srpaulo if ((data = elf_getdata(dynsymscn, NULL))) { 468240040Srpaulo i = 0; 469240040Srpaulo while (gelf_getsym(data, i++, &sym) != NULL) { 470240040Srpaulo s = elf_strptr(e, dynsymstridx, sym.st_name); 471240040Srpaulo if (s && strcmp(s, symbol) == 0) { 472240040Srpaulo memcpy(symcopy, &sym, sizeof(sym)); 473259972Smarkj if (ehdr.e_type != ET_EXEC) 474259972Smarkj symcopy->st_value += map->pr_vaddr; 475240040Srpaulo error = 0; 476240040Srpaulo goto out; 477240040Srpaulo } 478210688Srpaulo } 479210688Srpaulo } 480210688Srpaulo /* 481210688Srpaulo * Iterate over the Symbols Table to find the symbol. 482210688Srpaulo * Then look up the string name in STRTAB (.dynstr) 483210688Srpaulo */ 484240040Srpaulo if ((data = elf_getdata(symtabscn, NULL))) { 485240040Srpaulo i = 0; 486240040Srpaulo while (gelf_getsym(data, i++, &sym) != NULL) { 487240040Srpaulo s = elf_strptr(e, symtabstridx, sym.st_name); 488240040Srpaulo if (s && strcmp(s, symbol) == 0) { 489240040Srpaulo memcpy(symcopy, &sym, sizeof(sym)); 490259972Smarkj if (ehdr.e_type != ET_EXEC) 491259972Smarkj symcopy->st_value += map->pr_vaddr; 492240040Srpaulo error = 0; 493240040Srpaulo goto out; 494240040Srpaulo } 495210688Srpaulo } 496210688Srpaulo } 497210688Srpauloout: 498259972Smarkj DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol); 499210688Srpauloerr2: 500210688Srpaulo elf_end(e); 501210688Srpauloerr1: 502210688Srpaulo close(fd); 503210688Srpauloerr0: 504210688Srpaulo free(map); 505210688Srpaulo 506210688Srpaulo return (error); 507179185Sjb} 508210688Srpaulo 509210688Srpaulo 510210688Srpauloint 511210688Srpauloproc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 512210688Srpaulo int mask, proc_sym_f *func, void *cd) 513210688Srpaulo{ 514210688Srpaulo Elf *e; 515210688Srpaulo int i, fd; 516210688Srpaulo prmap_t *map; 517210688Srpaulo Elf_Scn *scn, *foundscn = NULL; 518210688Srpaulo Elf_Data *data; 519259972Smarkj GElf_Ehdr ehdr; 520210688Srpaulo GElf_Shdr shdr; 521210688Srpaulo GElf_Sym sym; 522210688Srpaulo unsigned long stridx = -1; 523210688Srpaulo char *s; 524210688Srpaulo int error = -1; 525210688Srpaulo 526210688Srpaulo if ((map = proc_name2map(p, object)) == NULL) 527210688Srpaulo return (-1); 528210688Srpaulo if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 529259895Smarkj DPRINTF("ERROR: open %s failed", map->pr_mapname); 530210688Srpaulo goto err0; 531210688Srpaulo } 532210688Srpaulo if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 533259895Smarkj DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 534210688Srpaulo goto err1; 535210688Srpaulo } 536259972Smarkj if (gelf_getehdr(e, &ehdr) == NULL) { 537259972Smarkj DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 538259972Smarkj goto err2; 539259972Smarkj } 540210688Srpaulo /* 541210688Srpaulo * Find the section we are looking for. 542210688Srpaulo */ 543210688Srpaulo scn = NULL; 544210688Srpaulo while ((scn = elf_nextscn(e, scn)) != NULL) { 545210688Srpaulo gelf_getshdr(scn, &shdr); 546210688Srpaulo if (which == PR_SYMTAB && 547210688Srpaulo shdr.sh_type == SHT_SYMTAB) { 548210688Srpaulo foundscn = scn; 549210688Srpaulo break; 550210688Srpaulo } else if (which == PR_DYNSYM && 551210688Srpaulo shdr.sh_type == SHT_DYNSYM) { 552210688Srpaulo foundscn = scn; 553210688Srpaulo break; 554210688Srpaulo } 555210688Srpaulo } 556210688Srpaulo if (!foundscn) 557210688Srpaulo return (-1); 558210688Srpaulo stridx = shdr.sh_link; 559210688Srpaulo if ((data = elf_getdata(foundscn, NULL)) == NULL) { 560259895Smarkj DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 561210688Srpaulo goto err2; 562210688Srpaulo } 563210688Srpaulo i = 0; 564210688Srpaulo while (gelf_getsym(data, i++, &sym) != NULL) { 565210688Srpaulo if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 566210688Srpaulo (mask & BIND_LOCAL) == 0) 567210688Srpaulo continue; 568210688Srpaulo if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 569210688Srpaulo (mask & BIND_GLOBAL) == 0) 570210688Srpaulo continue; 571210688Srpaulo if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 572210688Srpaulo (mask & BIND_WEAK) == 0) 573210688Srpaulo continue; 574210688Srpaulo if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 575210688Srpaulo (mask & TYPE_NOTYPE) == 0) 576210688Srpaulo continue; 577210688Srpaulo if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 578210688Srpaulo (mask & TYPE_OBJECT) == 0) 579210688Srpaulo continue; 580210688Srpaulo if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 581210688Srpaulo (mask & TYPE_FUNC) == 0) 582210688Srpaulo continue; 583210688Srpaulo if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 584210688Srpaulo (mask & TYPE_SECTION) == 0) 585210688Srpaulo continue; 586210688Srpaulo if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 587210688Srpaulo (mask & TYPE_FILE) == 0) 588210688Srpaulo continue; 589210688Srpaulo s = elf_strptr(e, stridx, sym.st_name); 590259972Smarkj if (ehdr.e_type != ET_EXEC) 591259972Smarkj sym.st_value += map->pr_vaddr; 592210688Srpaulo (*func)(cd, &sym, s); 593210688Srpaulo } 594210688Srpaulo error = 0; 595210688Srpauloerr2: 596210688Srpaulo elf_end(e); 597210688Srpauloerr1: 598210688Srpaulo close(fd); 599210688Srpauloerr0: 600210688Srpaulo free(map); 601210688Srpaulo return (error); 602210688Srpaulo} 603