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$ 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 49 #ifndef NO_CXA_DEMANGLE 50 extern char *__cxa_demangle(const char *, char *, size_t *, int *); 51 #endif /* NO_CXA_DEMANGLE */ 52 53 static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *); 54 55 static void 56 demangle(const char *symbol, char *buf, size_t len) 57 { 58 #ifndef NO_CXA_DEMANGLE 59 char *dembuf; 60 61 if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) { 62 dembuf = __cxa_demangle(symbol, NULL, NULL, NULL); 63 if (!dembuf) 64 goto fail; 65 strlcpy(buf, dembuf, len); 66 free(dembuf); 67 return; 68 } 69 fail: 70 #endif /* NO_CXA_DEMANGLE */ 71 strlcpy(buf, symbol, len); 72 } 73 74 static void 75 proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map) 76 { 77 map->pr_vaddr = rdl->rdl_saddr; 78 map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr; 79 map->pr_offset = rdl->rdl_offset; 80 map->pr_mflags = 0; 81 if (rdl->rdl_prot & RD_RDL_R) 82 map->pr_mflags |= MA_READ; 83 if (rdl->rdl_prot & RD_RDL_W) 84 map->pr_mflags |= MA_WRITE; 85 if (rdl->rdl_prot & RD_RDL_X) 86 map->pr_mflags |= MA_EXEC; 87 strlcpy(map->pr_mapname, rdl->rdl_path, 88 sizeof(map->pr_mapname)); 89 } 90 91 char * 92 proc_objname(struct proc_handle *p, uintptr_t addr, char *objname, 93 size_t objnamesz) 94 { 95 size_t i; 96 rd_loadobj_t *rdl; 97 98 for (i = 0; i < p->nobjs; i++) { 99 rdl = &p->rdobjs[i]; 100 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 101 strlcpy(objname, rdl->rdl_path, objnamesz); 102 return (objname); 103 } 104 } 105 return (NULL); 106 } 107 108 prmap_t * 109 proc_obj2map(struct proc_handle *p, const char *objname) 110 { 111 size_t i; 112 prmap_t *map; 113 rd_loadobj_t *rdl; 114 char path[MAXPATHLEN]; 115 116 rdl = NULL; 117 for (i = 0; i < p->nobjs; i++) { 118 basename_r(p->rdobjs[i].rdl_path, path); 119 if (strcmp(path, objname) == 0) { 120 rdl = &p->rdobjs[i]; 121 break; 122 } 123 } 124 if (rdl == NULL) { 125 if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL) 126 rdl = p->rdexec; 127 else 128 return (NULL); 129 } 130 131 if ((map = malloc(sizeof(*map))) == NULL) 132 return (NULL); 133 proc_rdl2prmap(rdl, map); 134 return (map); 135 } 136 137 int 138 proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd) 139 { 140 size_t i; 141 rd_loadobj_t *rdl; 142 prmap_t map; 143 char path[MAXPATHLEN]; 144 char last[MAXPATHLEN]; 145 146 if (p->nobjs == 0) 147 return (-1); 148 memset(last, 0, sizeof(last)); 149 for (i = 0; i < p->nobjs; i++) { 150 rdl = &p->rdobjs[i]; 151 proc_rdl2prmap(rdl, &map); 152 basename_r(rdl->rdl_path, path); 153 /* 154 * We shouldn't call the callback twice with the same object. 155 * To do that we are assuming the fact that if there are 156 * repeated object names (i.e. different mappings for the 157 * same object) they occur next to each other. 158 */ 159 if (strcmp(path, last) == 0) 160 continue; 161 (*func)(cd, &map, path); 162 strlcpy(last, path, sizeof(last)); 163 } 164 165 return (0); 166 } 167 168 prmap_t * 169 proc_addr2map(struct proc_handle *p, uintptr_t addr) 170 { 171 size_t i; 172 int cnt, lastvn = 0; 173 prmap_t *map; 174 rd_loadobj_t *rdl; 175 struct kinfo_vmentry *kves, *kve; 176 177 /* 178 * If we don't have a cache of listed objects, we need to query 179 * it ourselves. 180 */ 181 if (p->nobjs == 0) { 182 if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL) 183 return (NULL); 184 for (i = 0; i < (size_t)cnt; i++) { 185 kve = kves + i; 186 if (kve->kve_type == KVME_TYPE_VNODE) 187 lastvn = i; 188 if (addr >= kve->kve_start && addr < kve->kve_end) { 189 if ((map = malloc(sizeof(*map))) == NULL) { 190 free(kves); 191 return (NULL); 192 } 193 map->pr_vaddr = kve->kve_start; 194 map->pr_size = kve->kve_end - kve->kve_start; 195 map->pr_offset = kve->kve_offset; 196 map->pr_mflags = 0; 197 if (kve->kve_protection & KVME_PROT_READ) 198 map->pr_mflags |= MA_READ; 199 if (kve->kve_protection & KVME_PROT_WRITE) 200 map->pr_mflags |= MA_WRITE; 201 if (kve->kve_protection & KVME_PROT_EXEC) 202 map->pr_mflags |= MA_EXEC; 203 if (kve->kve_flags & KVME_FLAG_COW) 204 map->pr_mflags |= MA_COW; 205 if (kve->kve_flags & KVME_FLAG_NEEDS_COPY) 206 map->pr_mflags |= MA_NEEDS_COPY; 207 if (kve->kve_flags & KVME_FLAG_NOCOREDUMP) 208 map->pr_mflags |= MA_NOCOREDUMP; 209 strlcpy(map->pr_mapname, kves[lastvn].kve_path, 210 sizeof(map->pr_mapname)); 211 free(kves); 212 return (map); 213 } 214 } 215 free(kves); 216 return (NULL); 217 } 218 219 for (i = 0; i < p->nobjs; i++) { 220 rdl = &p->rdobjs[i]; 221 if (addr >= rdl->rdl_saddr && addr < rdl->rdl_eaddr) { 222 if ((map = malloc(sizeof(*map))) == NULL) 223 return (NULL); 224 proc_rdl2prmap(rdl, map); 225 return (map); 226 } 227 } 228 return (NULL); 229 } 230 231 int 232 proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 233 size_t namesz, GElf_Sym *symcopy) 234 { 235 Elf *e; 236 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 237 Elf_Data *data; 238 GElf_Shdr shdr; 239 GElf_Sym sym; 240 GElf_Ehdr ehdr; 241 int fd, error = -1; 242 size_t i; 243 uint64_t rsym; 244 prmap_t *map; 245 char *s; 246 unsigned long symtabstridx = 0, dynsymstridx = 0; 247 248 if ((map = proc_addr2map(p, addr)) == NULL) 249 return (-1); 250 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 251 DPRINTF("ERROR: open %s failed", map->pr_mapname); 252 goto err0; 253 } 254 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 255 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 256 goto err1; 257 } 258 if (gelf_getehdr(e, &ehdr) == NULL) { 259 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 260 goto err2; 261 } 262 /* 263 * Find the index of the STRTAB and SYMTAB sections to locate 264 * symbol names. 265 */ 266 scn = NULL; 267 while ((scn = elf_nextscn(e, scn)) != NULL) { 268 gelf_getshdr(scn, &shdr); 269 switch (shdr.sh_type) { 270 case SHT_SYMTAB: 271 symtabscn = scn; 272 symtabstridx = shdr.sh_link; 273 break; 274 case SHT_DYNSYM: 275 dynsymscn = scn; 276 dynsymstridx = shdr.sh_link; 277 break; 278 default: 279 break; 280 } 281 } 282 /* 283 * Iterate over the Dynamic Symbols table to find the symbol. 284 * Then look up the string name in STRTAB (.dynstr) 285 */ 286 if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { 287 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 288 goto symtab; 289 } 290 i = 0; 291 while (gelf_getsym(data, i++, &sym) != NULL) { 292 /* 293 * Calculate the address mapped to the virtual memory 294 * by rtld. 295 */ 296 if (ehdr.e_type != ET_EXEC) 297 rsym = map->pr_vaddr + sym.st_value; 298 else 299 rsym = sym.st_value; 300 if (addr >= rsym && addr < rsym + sym.st_size) { 301 s = elf_strptr(e, dynsymstridx, sym.st_name); 302 if (s) { 303 demangle(s, name, namesz); 304 memcpy(symcopy, &sym, sizeof(sym)); 305 /* 306 * DTrace expects the st_value to contain 307 * only the address relative to the start of 308 * the function. 309 */ 310 symcopy->st_value = rsym; 311 error = 0; 312 goto out; 313 } 314 } 315 } 316 symtab: 317 /* 318 * Iterate over the Symbols Table to find the symbol. 319 * Then look up the string name in STRTAB (.dynstr) 320 */ 321 if ((data = elf_getdata(symtabscn, NULL)) == NULL) { 322 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 323 goto err2; 324 } 325 i = 0; 326 while (gelf_getsym(data, i++, &sym) != NULL) { 327 /* 328 * Calculate the address mapped to the virtual memory 329 * by rtld. 330 */ 331 if (ehdr.e_type != ET_EXEC) 332 rsym = map->pr_vaddr + sym.st_value; 333 else 334 rsym = sym.st_value; 335 if (addr >= rsym && addr < rsym + sym.st_size) { 336 s = elf_strptr(e, symtabstridx, sym.st_name); 337 if (s) { 338 demangle(s, name, namesz); 339 memcpy(symcopy, &sym, sizeof(sym)); 340 /* 341 * DTrace expects the st_value to contain 342 * only the address relative to the start of 343 * the function. 344 */ 345 symcopy->st_value = rsym; 346 error = 0; 347 goto out; 348 } 349 } 350 } 351 out: 352 err2: 353 elf_end(e); 354 err1: 355 close(fd); 356 err0: 357 free(map); 358 return (error); 359 } 360 361 prmap_t * 362 proc_name2map(struct proc_handle *p, const char *name) 363 { 364 size_t i; 365 int cnt; 366 prmap_t *map; 367 char tmppath[MAXPATHLEN]; 368 struct kinfo_vmentry *kves, *kve; 369 rd_loadobj_t *rdl; 370 371 /* 372 * If we haven't iterated over the list of loaded objects, 373 * librtld_db isn't yet initialized and it's very likely 374 * that librtld_db called us. We need to do the heavy 375 * lifting here to find the symbol librtld_db is looking for. 376 */ 377 if (p->nobjs == 0) { 378 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 379 return (NULL); 380 for (i = 0; i < (size_t)cnt; i++) { 381 kve = kves + i; 382 basename_r(kve->kve_path, tmppath); 383 if (strcmp(tmppath, name) == 0) { 384 map = proc_addr2map(p, kve->kve_start); 385 free(kves); 386 return (map); 387 } 388 } 389 free(kves); 390 return (NULL); 391 } 392 if ((name == NULL || strcmp(name, "a.out") == 0) && 393 p->rdexec != NULL) { 394 map = proc_addr2map(p, p->rdexec->rdl_saddr); 395 return (map); 396 } 397 for (i = 0; i < p->nobjs; i++) { 398 rdl = &p->rdobjs[i]; 399 basename_r(rdl->rdl_path, tmppath); 400 if (strcmp(tmppath, name) == 0) { 401 if ((map = malloc(sizeof(*map))) == NULL) 402 return (NULL); 403 proc_rdl2prmap(rdl, map); 404 return (map); 405 } 406 } 407 408 return (NULL); 409 } 410 411 int 412 proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 413 GElf_Sym *symcopy) 414 { 415 Elf *e; 416 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 417 Elf_Data *data; 418 GElf_Shdr shdr; 419 GElf_Sym sym; 420 GElf_Ehdr ehdr; 421 int fd, error = -1; 422 size_t i; 423 prmap_t *map; 424 char *s; 425 unsigned long symtabstridx = 0, dynsymstridx = 0; 426 427 if ((map = proc_name2map(p, object)) == NULL) { 428 DPRINTFX("ERROR: couldn't find object %s", object); 429 goto err0; 430 } 431 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 432 DPRINTF("ERROR: open %s failed", map->pr_mapname); 433 goto err0; 434 } 435 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 436 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 437 goto err1; 438 } 439 if (gelf_getehdr(e, &ehdr) == NULL) { 440 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 441 goto err2; 442 } 443 /* 444 * Find the index of the STRTAB and SYMTAB sections to locate 445 * symbol names. 446 */ 447 scn = NULL; 448 while ((scn = elf_nextscn(e, scn)) != NULL) { 449 gelf_getshdr(scn, &shdr); 450 switch (shdr.sh_type) { 451 case SHT_SYMTAB: 452 symtabscn = scn; 453 symtabstridx = shdr.sh_link; 454 break; 455 case SHT_DYNSYM: 456 dynsymscn = scn; 457 dynsymstridx = shdr.sh_link; 458 break; 459 default: 460 break; 461 } 462 } 463 /* 464 * Iterate over the Dynamic Symbols table to find the symbol. 465 * Then look up the string name in STRTAB (.dynstr) 466 */ 467 if ((data = elf_getdata(dynsymscn, NULL))) { 468 i = 0; 469 while (gelf_getsym(data, i++, &sym) != NULL) { 470 s = elf_strptr(e, dynsymstridx, sym.st_name); 471 if (s && strcmp(s, symbol) == 0) { 472 memcpy(symcopy, &sym, sizeof(sym)); 473 if (ehdr.e_type != ET_EXEC) 474 symcopy->st_value += map->pr_vaddr; 475 error = 0; 476 goto out; 477 } 478 } 479 } 480 /* 481 * Iterate over the Symbols Table to find the symbol. 482 * Then look up the string name in STRTAB (.dynstr) 483 */ 484 if ((data = elf_getdata(symtabscn, NULL))) { 485 i = 0; 486 while (gelf_getsym(data, i++, &sym) != NULL) { 487 s = elf_strptr(e, symtabstridx, sym.st_name); 488 if (s && strcmp(s, symbol) == 0) { 489 memcpy(symcopy, &sym, sizeof(sym)); 490 if (ehdr.e_type != ET_EXEC) 491 symcopy->st_value += map->pr_vaddr; 492 error = 0; 493 goto out; 494 } 495 } 496 } 497 out: 498 DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol); 499 err2: 500 elf_end(e); 501 err1: 502 close(fd); 503 err0: 504 free(map); 505 506 return (error); 507 } 508 509 510 int 511 proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 512 int mask, proc_sym_f *func, void *cd) 513 { 514 Elf *e; 515 int i, fd; 516 prmap_t *map; 517 Elf_Scn *scn, *foundscn = NULL; 518 Elf_Data *data; 519 GElf_Ehdr ehdr; 520 GElf_Shdr shdr; 521 GElf_Sym sym; 522 unsigned long stridx = -1; 523 char *s; 524 int error = -1; 525 526 if ((map = proc_name2map(p, object)) == NULL) 527 return (-1); 528 if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 529 DPRINTF("ERROR: open %s failed", map->pr_mapname); 530 goto err0; 531 } 532 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 533 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 534 goto err1; 535 } 536 if (gelf_getehdr(e, &ehdr) == NULL) { 537 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 538 goto err2; 539 } 540 /* 541 * Find the section we are looking for. 542 */ 543 scn = NULL; 544 while ((scn = elf_nextscn(e, scn)) != NULL) { 545 gelf_getshdr(scn, &shdr); 546 if (which == PR_SYMTAB && 547 shdr.sh_type == SHT_SYMTAB) { 548 foundscn = scn; 549 break; 550 } else if (which == PR_DYNSYM && 551 shdr.sh_type == SHT_DYNSYM) { 552 foundscn = scn; 553 break; 554 } 555 } 556 if (!foundscn) 557 return (-1); 558 stridx = shdr.sh_link; 559 if ((data = elf_getdata(foundscn, NULL)) == NULL) { 560 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 561 goto err2; 562 } 563 i = 0; 564 while (gelf_getsym(data, i++, &sym) != NULL) { 565 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 566 (mask & BIND_LOCAL) == 0) 567 continue; 568 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 569 (mask & BIND_GLOBAL) == 0) 570 continue; 571 if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 572 (mask & BIND_WEAK) == 0) 573 continue; 574 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 575 (mask & TYPE_NOTYPE) == 0) 576 continue; 577 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 578 (mask & TYPE_OBJECT) == 0) 579 continue; 580 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 581 (mask & TYPE_FUNC) == 0) 582 continue; 583 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 584 (mask & TYPE_SECTION) == 0) 585 continue; 586 if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 587 (mask & TYPE_FILE) == 0) 588 continue; 589 s = elf_strptr(e, stridx, sym.st_name); 590 if (ehdr.e_type != ET_EXEC) 591 sym.st_value += map->pr_vaddr; 592 (*func)(cd, &sym, s); 593 } 594 error = 0; 595 err2: 596 elf_end(e); 597 err1: 598 close(fd); 599 err0: 600 free(map); 601 return (error); 602 } 603