proc_sym.c revision 259964
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: stable/9/lib/libproc/proc_sym.c 259964 2013-12-27 22:14:03Z 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 err2; 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 rsym = map->pr_vaddr + sym.st_value; 266 if (addr >= rsym && addr < rsym + sym.st_size) { 267 s = elf_strptr(e, dynsymstridx, sym.st_name); 268 if (s) { 269 strlcpy(name, s, namesz); 270 memcpy(symcopy, &sym, sizeof(sym)); 271 /* 272 * DTrace expects the st_value to contain 273 * only the address relative to the start of 274 * the function. 275 */ 276 symcopy->st_value = rsym; 277 error = 0; 278 goto out; 279 } 280 } 281 } 282 /* 283 * Iterate over the Symbols Table to find the symbol. 284 * Then look up the string name in STRTAB (.dynstr) 285 */ 286 if (symtabscn == NULL) 287 goto err2; 288 if ((data = elf_getdata(symtabscn, NULL)) == NULL) { 289 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 290 goto err2; 291 } 292 i = 0; 293 while (gelf_getsym(data, i++, &sym) != NULL) { 294 /* 295 * Calculate the address mapped to the virtual memory 296 * by rtld. 297 */ 298 if (ehdr.e_type != ET_EXEC) 299 rsym = map->pr_vaddr + sym.st_value; 300 else 301 rsym = sym.st_value; 302 if (addr >= rsym && addr < rsym + sym.st_size) { 303 s = elf_strptr(e, symtabstridx, sym.st_name); 304 if (s) { 305 strlcpy(name, s, namesz); 306 memcpy(symcopy, &sym, sizeof(sym)); 307 /* 308 * DTrace expects the st_value to contain 309 * only the address relative to the start of 310 * the function. 311 */ 312 symcopy->st_value = rsym; 313 error = 0; 314 goto out; 315 } 316 } 317 } 318out: 319err2: 320 elf_end(e); 321err1: 322 close(fd); 323err0: 324 free(map); 325 return (error); 326} 327 328prmap_t * 329proc_name2map(struct proc_handle *p, const char *name) 330{ 331 size_t i; 332 int cnt; 333 prmap_t *map; 334 char tmppath[MAXPATHLEN]; 335 struct kinfo_vmentry *kves, *kve; 336 rd_loadobj_t *rdl; 337 338 /* 339 * If we haven't iterated over the list of loaded objects, 340 * librtld_db isn't yet initialized and it's very likely 341 * that librtld_db called us. We need to do the heavy 342 * lifting here to find the symbol librtld_db is looking for. 343 */ 344 if (p->nobjs == 0) { 345 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 346 return (NULL); 347 for (i = 0; i < (size_t)cnt; i++) { 348 kve = kves + i; 349 basename_r(kve->kve_path, tmppath); 350 if (strcmp(tmppath, name) == 0) { 351 map = proc_addr2map(p, kve->kve_start); 352 free(kves); 353 return (map); 354 } 355 } 356 free(kves); 357 return (NULL); 358 } 359 if (name == NULL || strcmp(name, "a.out") == 0) { 360 map = proc_addr2map(p, p->rdobjs[0].rdl_saddr); 361 return (map); 362 } 363 for (i = 0; i < p->nobjs; i++) { 364 rdl = &p->rdobjs[i]; 365 basename_r(rdl->rdl_path, tmppath); 366 if (strcmp(tmppath, name) == 0) { 367 if ((map = malloc(sizeof(*map))) == NULL) 368 return (NULL); 369 proc_rdl2prmap(rdl, map); 370 return (map); 371 } 372 } 373 374 return (NULL); 375} 376 377int 378proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 379 GElf_Sym *symcopy) 380{ 381 Elf *e; 382 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 383 Elf_Data *data; 384 GElf_Shdr shdr; 385 GElf_Sym sym; 386 GElf_Ehdr ehdr; 387 int fd, error = -1; 388 size_t i; 389 prmap_t *map; 390 char *s; 391 unsigned long symtabstridx = 0, dynsymstridx = 0; 392 393 if ((map = proc_name2map(p, object)) == NULL) { 394 DPRINTFX("ERROR: couldn't find object %s", object); 395 goto err0; 396 } 397 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 398 DPRINTF("ERROR: open %s failed", map->pr_mapname); 399 goto err0; 400 } 401 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 402 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 403 goto err1; 404 } 405 if (gelf_getehdr(e, &ehdr) == NULL) { 406 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 407 goto err2; 408 } 409 /* 410 * Find the index of the STRTAB and SYMTAB sections to locate 411 * symbol names. 412 */ 413 scn = NULL; 414 while ((scn = elf_nextscn(e, scn)) != NULL) { 415 gelf_getshdr(scn, &shdr); 416 switch (shdr.sh_type) { 417 case SHT_SYMTAB: 418 symtabscn = scn; 419 symtabstridx = shdr.sh_link; 420 break; 421 case SHT_DYNSYM: 422 dynsymscn = scn; 423 dynsymstridx = shdr.sh_link; 424 break; 425 default: 426 break; 427 } 428 } 429 /* 430 * Iterate over the Dynamic Symbols table to find the symbol. 431 * Then look up the string name in STRTAB (.dynstr) 432 */ 433 if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { 434 goto err2; 435 } 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 symcopy->st_value = map->pr_vaddr + sym.st_value; 442 error = 0; 443 goto out; 444 } 445 } 446 /* 447 * Iterate over the Symbols Table to find the symbol. 448 * Then look up the string name in STRTAB (.dynstr) 449 */ 450 if (symtabscn == NULL) 451 goto err2; 452 if ((data = elf_getdata(symtabscn, NULL)) == NULL) { 453 DPRINTF("ERROR: elf_getdata() failed"); 454 goto err2; 455 } 456 i = 0; 457 while (gelf_getsym(data, i++, &sym) != NULL) { 458 s = elf_strptr(e, symtabstridx, sym.st_name); 459 if (s && strcmp(s, symbol) == 0) { 460 memcpy(symcopy, &sym, sizeof(sym)); 461 error = 0; 462 goto out; 463 } 464 } 465out: 466err2: 467 elf_end(e); 468err1: 469 close(fd); 470err0: 471 free(map); 472 473 return (error); 474} 475 476 477int 478proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 479 int mask, proc_sym_f *func, void *cd) 480{ 481 Elf *e; 482 int i, fd; 483 prmap_t *map; 484 Elf_Scn *scn, *foundscn = NULL; 485 Elf_Data *data; 486 GElf_Shdr shdr; 487 GElf_Sym sym; 488 unsigned long stridx = -1; 489 char *s; 490 int error = -1; 491 492 if ((map = proc_name2map(p, object)) == NULL) 493 return (-1); 494 if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 495 DPRINTF("ERROR: open %s failed", map->pr_mapname); 496 goto err0; 497 } 498 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 499 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 500 goto err1; 501 } 502 /* 503 * Find the section we are looking for. 504 */ 505 scn = NULL; 506 while ((scn = elf_nextscn(e, scn)) != NULL) { 507 gelf_getshdr(scn, &shdr); 508 if (which == PR_SYMTAB && 509 shdr.sh_type == SHT_SYMTAB) { 510 foundscn = scn; 511 break; 512 } else if (which == PR_DYNSYM && 513 shdr.sh_type == SHT_DYNSYM) { 514 foundscn = scn; 515 break; 516 } 517 } 518 if (!foundscn) 519 return (-1); 520 stridx = shdr.sh_link; 521 if ((data = elf_getdata(foundscn, NULL)) == NULL) { 522 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 523 goto err2; 524 } 525 i = 0; 526 while (gelf_getsym(data, i++, &sym) != NULL) { 527 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 528 (mask & BIND_LOCAL) == 0) 529 continue; 530 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 531 (mask & BIND_GLOBAL) == 0) 532 continue; 533 if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 534 (mask & BIND_WEAK) == 0) 535 continue; 536 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 537 (mask & TYPE_NOTYPE) == 0) 538 continue; 539 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 540 (mask & TYPE_OBJECT) == 0) 541 continue; 542 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 543 (mask & TYPE_FUNC) == 0) 544 continue; 545 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 546 (mask & TYPE_SECTION) == 0) 547 continue; 548 if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 549 (mask & TYPE_FILE) == 0) 550 continue; 551 s = elf_strptr(e, stridx, sym.st_name); 552 sym.st_value += map->pr_vaddr; 553 (*func)(cd, &sym, s); 554 } 555 error = 0; 556err2: 557 elf_end(e); 558err1: 559 close(fd); 560err0: 561 free(map); 562 return (error); 563} 564