proc_sym.c revision 267654
1/*- 2 * Copyright (c) 2010 The FreeBSD Foundation 3 * Copyright (c) 2008 John Birrell (jb@freebsd.org) 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Rui Paulo under sponsorship 7 * from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: releng/9.3/lib/libproc/proc_sym.c 265074 2014-04-29 03:37:30Z markj $ 31 */ 32 33#include <sys/types.h> 34#include <sys/user.h> 35 36#include <assert.h> 37#include <err.h> 38#include <stdio.h> 39#include <libgen.h> 40#include <string.h> 41#include <stdlib.h> 42#include <fcntl.h> 43#include <string.h> 44#include <unistd.h> 45#include <libutil.h> 46 47#include "_libproc.h" 48 49static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *); 50 51static void 52proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 53{ 54 map->pr_vaddr = rdl->rdl_saddr; 55 map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 56 map->pr_offset = rdl->rdl_offset; 57 map->pr_mflags = 0; 58 if (rdl->rdl_prot & RD_RDL_R) 59 map->pr_mflags |= MA_READ; 60 if (rdl->rdl_prot & RD_RDL_W) 61 map->pr_mflags |= MA_WRITE; 62 if (rdl->rdl_prot & RD_RDL_X) 63 map->pr_mflags |= MA_EXEC; 64 strlcpy(map->pr_mapname, rdl->rdl_path, 65 sizeof(map->pr_mapname)); 66} 67 68char * 69proc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 70 size_t objnamesz) 71{ 72 size_t i; 73 rd_loadobj_t *rdl; 74 75 for (i = 0; i < p->nobjs; i++) { 76 rdl = &p->rdobjs[i]; 77 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 78 strlcpy(objname, rdl->rdl_path, objnamesz); 79 return (objname); 80 } 81 } 82 return (NULL); 83} 84 85prmap_t * 86proc_obj2map(struct proc_handle *p, const char *objname) 87{ 88 size_t i; 89 prmap_t *map; 90 rd_loadobj_t *rdl; 91 char path[MAXPATHLEN]; 92 93 for (i = 0; i < p->nobjs; i++) { 94 rdl = &p->rdobjs[i]; 95 basename_r(rdl->rdl_path, path); 96 if (strcmp(path, objname) == 0) { 97 if ((map = malloc(sizeof(*map))) == NULL) 98 return (NULL); 99 proc_rdl2prmap(rdl, map); 100 return (map); 101 } 102 } 103 return (NULL); 104} 105 106int 107proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 108{ 109 size_t i; 110 rd_loadobj_t *rdl; 111 prmap_t map; 112 char path[MAXPATHLEN]; 113 char last[MAXPATHLEN]; 114 115 if (p->nobjs == 0) 116 return (-1); 117 memset(last, 0, sizeof(last)); 118 for (i = 0; i < p->nobjs; i++) { 119 rdl = &p->rdobjs[i]; 120 proc_rdl2prmap(rdl, &map); 121 basename_r(rdl->rdl_path, path); 122 /* 123 * We shouldn't call the callback twice with the same object. 124 * To do that we are assuming the fact that if there are 125 * repeated object names (i.e. different mappings for the 126 * same object) they occur next to each other. 127 */ 128 if (strcmp(path, last) == 0) 129 continue; 130 (*func)(cd, &map, path); 131 strlcpy(last, path, sizeof(last)); 132 } 133 134 return (0); 135} 136 137prmap_t * 138proc_addr2map(struct proc_handle *p, uintptr_t addr) 139{ 140 size_t i; 141 int cnt, lastvn = 0; 142 prmap_t *map; 143 rd_loadobj_t *rdl; 144 struct kinfo_vmentry *kves, *kve; 145 146 /* 147 * If we don't have a cache of listed objects, we need to query 148 * it ourselves. 149 */ 150 if (p->nobjs == 0) { 151 if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 152 return (NULL); 153 for (i = 0; i < (size_t)cnt; i++) { 154 kve = kves + i; 155 if (kve->kve_type == KVME_TYPE_VNODE) 156 lastvn = i; 157 if (addr >= kve->kve_start && addr < kve->kve_end) { 158 if ((map = malloc(sizeof(*map))) == NULL) { 159 free(kves); 160 return (NULL); 161 } 162 map->pr_vaddr = kve->kve_start; 163 map->pr_size = kve->kve_end - kve->kve_start; 164 map->pr_offset = kve->kve_offset; 165 map->pr_mflags = 0; 166 if (kve->kve_protection & KVME_PROT_READ) 167 map->pr_mflags |= MA_READ; 168 if (kve->kve_protection & KVME_PROT_WRITE) 169 map->pr_mflags |= MA_WRITE; 170 if (kve->kve_protection & KVME_PROT_EXEC) 171 map->pr_mflags |= MA_EXEC; 172 if (kve->kve_flags & KVME_FLAG_COW) 173 map->pr_mflags |= MA_COW; 174 if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 175 map->pr_mflags |= MA_NEEDS_COPY; 176 if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 177 map->pr_mflags |= MA_NOCOREDUMP; 178 strlcpy(map->pr_mapname, kves[lastvn].kve_path, 179 sizeof(map->pr_mapname)); 180 free(kves); 181 return (map); 182 } 183 } 184 free(kves); 185 return (NULL); 186 } 187 188 for (i = 0; i < p->nobjs; i++) { 189 rdl = &p->rdobjs[i]; 190 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 191 if ((map = malloc(sizeof(*map))) == NULL) 192 return (NULL); 193 proc_rdl2prmap(rdl, map); 194 return (map); 195 } 196 } 197 return (NULL); 198} 199 200int 201proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 202 size_t namesz, GElf_Sym *symcopy) 203{ 204 Elf *e; 205 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 206 Elf_Data *data; 207 GElf_Shdr shdr; 208 GElf_Sym sym; 209 GElf_Ehdr ehdr; 210 int fd, error = -1; 211 size_t i; 212 uint64_t rsym; 213 prmap_t *map; 214 char *s; 215 unsigned long symtabstridx = 0, dynsymstridx = 0; 216 217 if ((map = proc_addr2map(p, addr)) == NULL) 218 return (-1); 219 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 220 DPRINTF("ERROR: open %s failed", map->pr_mapname); 221 goto err0; 222 } 223 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 224 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 225 goto err1; 226 } 227 if (gelf_getehdr(e, &ehdr) == NULL) { 228 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 229 goto err2; 230 } 231 /* 232 * Find the index of the STRTAB and SYMTAB sections to locate 233 * symbol names. 234 */ 235 scn = NULL; 236 while ((scn = elf_nextscn(e, scn)) != NULL) { 237 gelf_getshdr(scn, &shdr); 238 switch (shdr.sh_type) { 239 case SHT_SYMTAB: 240 symtabscn = scn; 241 symtabstridx = shdr.sh_link; 242 break; 243 case SHT_DYNSYM: 244 dynsymscn = scn; 245 dynsymstridx = shdr.sh_link; 246 break; 247 default: 248 break; 249 } 250 } 251 /* 252 * Iterate over the Dynamic Symbols table to find the symbol. 253 * Then look up the string name in STRTAB (.dynstr) 254 */ 255 if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { 256 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 257 goto symtab; 258 } 259 i = 0; 260 while (gelf_getsym(data, i++, &sym) != NULL) { 261 /* 262 * Calculate the address mapped to the virtual memory 263 * by rtld. 264 */ 265 if (ehdr.e_type != ET_EXEC) 266 rsym = map->pr_vaddr + sym.st_value; 267 else 268 rsym = sym.st_value; 269 if (addr >= rsym && addr < rsym + sym.st_size) { 270 s = elf_strptr(e, dynsymstridx, sym.st_name); 271 if (s) { 272 strlcpy(name, s, namesz); 273 memcpy(symcopy, &sym, sizeof(sym)); 274 /* 275 * DTrace expects the st_value to contain 276 * only the address relative to the start of 277 * the function. 278 */ 279 symcopy->st_value = rsym; 280 error = 0; 281 goto out; 282 } 283 } 284 } 285symtab: 286 /* 287 * Iterate over the Symbols Table to find the symbol. 288 * Then look up the string name in STRTAB (.dynstr) 289 */ 290 if ((data = elf_getdata(symtabscn, NULL)) == NULL) { 291 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 292 goto err2; 293 } 294 i = 0; 295 while (gelf_getsym(data, i++, &sym) != NULL) { 296 /* 297 * Calculate the address mapped to the virtual memory 298 * by rtld. 299 */ 300 if (ehdr.e_type != ET_EXEC) 301 rsym = map->pr_vaddr + sym.st_value; 302 else 303 rsym = sym.st_value; 304 if (addr >= rsym && addr < rsym + sym.st_size) { 305 s = elf_strptr(e, symtabstridx, sym.st_name); 306 if (s) { 307 strlcpy(name, s, namesz); 308 memcpy(symcopy, &sym, sizeof(sym)); 309 /* 310 * DTrace expects the st_value to contain 311 * only the address relative to the start of 312 * the function. 313 */ 314 symcopy->st_value = rsym; 315 error = 0; 316 goto out; 317 } 318 } 319 } 320out: 321err2: 322 elf_end(e); 323err1: 324 close(fd); 325err0: 326 free(map); 327 return (error); 328} 329 330prmap_t * 331proc_name2map(struct proc_handle *p, const char *name) 332{ 333 size_t i; 334 int cnt; 335 prmap_t *map; 336 char tmppath[MAXPATHLEN]; 337 struct kinfo_vmentry *kves, *kve; 338 rd_loadobj_t *rdl; 339 340 /* 341 * If we haven't iterated over the list of loaded objects, 342 * librtld_db isn't yet initialized and it's very likely 343 * that librtld_db called us. We need to do the heavy 344 * lifting here to find the symbol librtld_db is looking for. 345 */ 346 if (p->nobjs == 0) { 347 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 348 return (NULL); 349 for (i = 0; i < (size_t)cnt; i++) { 350 kve = kves + i; 351 basename_r(kve->kve_path, tmppath); 352 if (strcmp(tmppath, name) == 0) { 353 map = proc_addr2map(p, kve->kve_start); 354 free(kves); 355 return (map); 356 } 357 } 358 free(kves); 359 return (NULL); 360 } 361 if (name == NULL || strcmp(name, "a.out") == 0) { 362 map = proc_addr2map(p, p->rdobjs[0].rdl_saddr); 363 return (map); 364 } 365 for (i = 0; i < p->nobjs; i++) { 366 rdl = &p->rdobjs[i]; 367 basename_r(rdl->rdl_path, tmppath); 368 if (strcmp(tmppath, name) == 0) { 369 if ((map = malloc(sizeof(*map))) == NULL) 370 return (NULL); 371 proc_rdl2prmap(rdl, map); 372 return (map); 373 } 374 } 375 376 return (NULL); 377} 378 379int 380proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 381 GElf_Sym *symcopy) 382{ 383 Elf *e; 384 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 385 Elf_Data *data; 386 GElf_Shdr shdr; 387 GElf_Sym sym; 388 GElf_Ehdr ehdr; 389 int fd, error = -1; 390 size_t i; 391 prmap_t *map; 392 char *s; 393 unsigned long symtabstridx = 0, dynsymstridx = 0; 394 395 if ((map = proc_name2map(p, object)) == NULL) { 396 DPRINTFX("ERROR: couldn't find object %s", object); 397 goto err0; 398 } 399 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 400 DPRINTF("ERROR: open %s failed", map->pr_mapname); 401 goto err0; 402 } 403 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 404 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 405 goto err1; 406 } 407 if (gelf_getehdr(e, &ehdr) == NULL) { 408 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 409 goto err2; 410 } 411 /* 412 * Find the index of the STRTAB and SYMTAB sections to locate 413 * symbol names. 414 */ 415 scn = NULL; 416 while ((scn = elf_nextscn(e, scn)) != NULL) { 417 gelf_getshdr(scn, &shdr); 418 switch (shdr.sh_type) { 419 case SHT_SYMTAB: 420 symtabscn = scn; 421 symtabstridx = shdr.sh_link; 422 break; 423 case SHT_DYNSYM: 424 dynsymscn = scn; 425 dynsymstridx = shdr.sh_link; 426 break; 427 default: 428 break; 429 } 430 } 431 /* 432 * Iterate over the Dynamic Symbols table to find the symbol. 433 * Then look up the string name in STRTAB (.dynstr) 434 */ 435 if ((data = elf_getdata(dynsymscn, NULL))) { 436 i = 0; 437 while (gelf_getsym(data, i++, &sym) != NULL) { 438 s = elf_strptr(e, dynsymstridx, sym.st_name); 439 if (s && strcmp(s, symbol) == 0) { 440 memcpy(symcopy, &sym, sizeof(sym)); 441 if (ehdr.e_type != ET_EXEC) 442 symcopy->st_value += map->pr_vaddr; 443 error = 0; 444 goto out; 445 } 446 } 447 } 448 /* 449 * Iterate over the Symbols Table to find the symbol. 450 * Then look up the string name in STRTAB (.dynstr) 451 */ 452 if ((data = elf_getdata(symtabscn, NULL))) { 453 i = 0; 454 while (gelf_getsym(data, i++, &sym) != NULL) { 455 s = elf_strptr(e, symtabstridx, sym.st_name); 456 if (s && strcmp(s, symbol) == 0) { 457 memcpy(symcopy, &sym, sizeof(sym)); 458 if (ehdr.e_type != ET_EXEC) 459 symcopy->st_value += map->pr_vaddr; 460 error = 0; 461 goto out; 462 } 463 } 464 } 465out: 466 DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol); 467err2: 468 elf_end(e); 469err1: 470 close(fd); 471err0: 472 free(map); 473 474 return (error); 475} 476 477 478int 479proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 480 int mask, proc_sym_f *func, void *cd) 481{ 482 Elf *e; 483 int i, fd; 484 prmap_t *map; 485 Elf_Scn *scn, *foundscn = NULL; 486 Elf_Data *data; 487 GElf_Ehdr ehdr; 488 GElf_Shdr shdr; 489 GElf_Sym sym; 490 unsigned long stridx = -1; 491 char *s; 492 int error = -1; 493 494 if ((map = proc_name2map(p, object)) == NULL) 495 return (-1); 496 if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 497 DPRINTF("ERROR: open %s failed", map->pr_mapname); 498 goto err0; 499 } 500 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 501 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 502 goto err1; 503 } 504 if (gelf_getehdr(e, &ehdr) == NULL) { 505 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 506 goto err2; 507 } 508 /* 509 * Find the section we are looking for. 510 */ 511 scn = NULL; 512 while ((scn = elf_nextscn(e, scn)) != NULL) { 513 gelf_getshdr(scn, &shdr); 514 if (which == PR_SYMTAB && 515 shdr.sh_type == SHT_SYMTAB) { 516 foundscn = scn; 517 break; 518 } else if (which == PR_DYNSYM && 519 shdr.sh_type == SHT_DYNSYM) { 520 foundscn = scn; 521 break; 522 } 523 } 524 if (!foundscn) 525 return (-1); 526 stridx = shdr.sh_link; 527 if ((data = elf_getdata(foundscn, NULL)) == NULL) { 528 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 529 goto err2; 530 } 531 i = 0; 532 while (gelf_getsym(data, i++, &sym) != NULL) { 533 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 534 (mask & BIND_LOCAL) == 0) 535 continue; 536 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 537 (mask & BIND_GLOBAL) == 0) 538 continue; 539 if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 540 (mask & BIND_WEAK) == 0) 541 continue; 542 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 543 (mask & TYPE_NOTYPE) == 0) 544 continue; 545 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 546 (mask & TYPE_OBJECT) == 0) 547 continue; 548 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 549 (mask & TYPE_FUNC) == 0) 550 continue; 551 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 552 (mask & TYPE_SECTION) == 0) 553 continue; 554 if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 555 (mask & TYPE_FILE) == 0) 556 continue; 557 s = elf_strptr(e, stridx, sym.st_name); 558 if (ehdr.e_type != ET_EXEC) 559 sym.st_value += map->pr_vaddr; 560 (*func)(cd, &sym, s); 561 } 562 error = 0; 563err2: 564 elf_end(e); 565err1: 566 close(fd); 567err0: 568 free(map); 569 return (error); 570} 571