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