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