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