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