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 #include <sys/user.h> 36 37 #include <assert.h> 38 #include <err.h> 39 #include <fcntl.h> 40 #include <libgen.h> 41 #include <stdio.h> 42 #include <stdlib.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 /* 232 * Look up the symbol at addr, returning a copy of the symbol and its name. 233 */ 234 static int 235 lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr, 236 const char **name, GElf_Sym *symcopy) 237 { 238 GElf_Sym sym; 239 Elf_Data *data; 240 const char *s; 241 uint64_t rsym; 242 int i; 243 244 if ((data = elf_getdata(scn, NULL)) == NULL) { 245 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 246 return (1); 247 } 248 for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 249 rsym = off + sym.st_value; 250 if (addr >= rsym && addr < rsym + sym.st_size) { 251 s = elf_strptr(e, stridx, sym.st_name); 252 if (s != NULL) { 253 *name = s; 254 memcpy(symcopy, &sym, sizeof(*symcopy)); 255 /* 256 * DTrace expects the st_value to contain 257 * only the address relative to the start of 258 * the function. 259 */ 260 symcopy->st_value = rsym; 261 return (0); 262 } 263 } 264 } 265 return (1); 266 } 267 268 int 269 proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, 270 size_t namesz, GElf_Sym *symcopy) 271 { 272 GElf_Ehdr ehdr; 273 GElf_Shdr shdr; 274 Elf *e; 275 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 276 prmap_t *map; 277 const char *s; 278 uintptr_t off; 279 u_long symtabstridx = 0, dynsymstridx = 0; 280 int fd, error = -1; 281 282 if ((map = proc_addr2map(p, addr)) == NULL) 283 return (-1); 284 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 285 DPRINTF("ERROR: open %s failed", map->pr_mapname); 286 goto err0; 287 } 288 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 289 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 290 goto err1; 291 } 292 if (gelf_getehdr(e, &ehdr) == NULL) { 293 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 294 goto err2; 295 } 296 297 /* 298 * Find the index of the STRTAB and SYMTAB sections to locate 299 * symbol names. 300 */ 301 scn = NULL; 302 while ((scn = elf_nextscn(e, scn)) != NULL) { 303 gelf_getshdr(scn, &shdr); 304 switch (shdr.sh_type) { 305 case SHT_SYMTAB: 306 symtabscn = scn; 307 symtabstridx = shdr.sh_link; 308 break; 309 case SHT_DYNSYM: 310 dynsymscn = scn; 311 dynsymstridx = shdr.sh_link; 312 break; 313 } 314 } 315 316 off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 317 318 /* 319 * First look up the symbol in the dynsymtab, and fall back to the 320 * symtab if the lookup fails. 321 */ 322 error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy); 323 if (error == 0) 324 goto out; 325 326 error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); 327 if (error == 0) 328 goto out; 329 330 out: 331 demangle(s, name, namesz); 332 err2: 333 elf_end(e); 334 err1: 335 close(fd); 336 err0: 337 free(map); 338 return (error); 339 } 340 341 prmap_t * 342 proc_name2map(struct proc_handle *p, const char *name) 343 { 344 size_t i; 345 int cnt; 346 prmap_t *map = NULL; 347 char tmppath[MAXPATHLEN]; 348 struct kinfo_vmentry *kves, *kve; 349 rd_loadobj_t *rdl; 350 351 /* 352 * If we haven't iterated over the list of loaded objects, 353 * librtld_db isn't yet initialized and it's very likely 354 * that librtld_db called us. We need to do the heavy 355 * lifting here to find the symbol librtld_db is looking for. 356 */ 357 if (p->nobjs == 0) { 358 if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) 359 return (NULL); 360 for (i = 0; i < (size_t)cnt; i++) { 361 kve = kves + i; 362 basename_r(kve->kve_path, tmppath); 363 if (strcmp(tmppath, name) == 0) { 364 map = proc_addr2map(p, kve->kve_start); 365 break; 366 } 367 } 368 free(kves); 369 } else 370 for (i = 0; i < p->nobjs; i++) { 371 rdl = &p->rdobjs[i]; 372 basename_r(rdl->rdl_path, tmppath); 373 if (strcmp(tmppath, name) == 0) { 374 if ((map = malloc(sizeof(*map))) == NULL) 375 return (NULL); 376 proc_rdl2prmap(rdl, map); 377 break; 378 } 379 } 380 381 if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL) 382 map = proc_addr2map(p, p->rdexec->rdl_saddr); 383 384 return (map); 385 } 386 387 /* 388 * Look up the symbol with the given name and return a copy of it. 389 */ 390 static int 391 lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol, 392 GElf_Sym *symcopy) 393 { 394 GElf_Sym sym; 395 Elf_Data *data; 396 char *s; 397 int i; 398 399 if ((data = elf_getdata(scn, NULL)) == NULL) { 400 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 401 return (1); 402 } 403 for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 404 s = elf_strptr(e, stridx, sym.st_name); 405 if (s != NULL && strcmp(s, symbol) == 0) { 406 memcpy(symcopy, &sym, sizeof(*symcopy)); 407 return (0); 408 } 409 } 410 return (1); 411 } 412 413 int 414 proc_name2sym(struct proc_handle *p, const char *object, const char *symbol, 415 GElf_Sym *symcopy) 416 { 417 Elf *e; 418 Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; 419 GElf_Shdr shdr; 420 GElf_Ehdr ehdr; 421 prmap_t *map; 422 uintptr_t off; 423 u_long symtabstridx = 0, dynsymstridx = 0; 424 int fd, error = -1; 425 426 if ((map = proc_name2map(p, object)) == NULL) { 427 DPRINTFX("ERROR: couldn't find object %s", object); 428 goto err0; 429 } 430 if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { 431 DPRINTF("ERROR: open %s failed", map->pr_mapname); 432 goto err0; 433 } 434 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 435 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 436 goto err1; 437 } 438 if (gelf_getehdr(e, &ehdr) == NULL) { 439 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 440 goto err2; 441 } 442 /* 443 * Find the index of the STRTAB and SYMTAB sections to locate 444 * symbol names. 445 */ 446 scn = NULL; 447 while ((scn = elf_nextscn(e, scn)) != NULL) { 448 gelf_getshdr(scn, &shdr); 449 switch (shdr.sh_type) { 450 case SHT_SYMTAB: 451 symtabscn = scn; 452 symtabstridx = shdr.sh_link; 453 break; 454 case SHT_DYNSYM: 455 dynsymscn = scn; 456 dynsymstridx = shdr.sh_link; 457 break; 458 } 459 } 460 461 /* 462 * First look up the symbol in the dynsymtab, and fall back to the 463 * symtab if the lookup fails. 464 */ 465 error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy); 466 if (error == 0) 467 goto out; 468 469 error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy); 470 if (error == 0) 471 goto out; 472 473 out: 474 off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; 475 symcopy->st_value += off; 476 477 err2: 478 elf_end(e); 479 err1: 480 close(fd); 481 err0: 482 free(map); 483 484 return (error); 485 } 486 487 int 488 proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which, 489 int mask, proc_sym_f *func, void *cd) 490 { 491 Elf *e; 492 int i, fd; 493 prmap_t *map; 494 Elf_Scn *scn, *foundscn = NULL; 495 Elf_Data *data; 496 GElf_Ehdr ehdr; 497 GElf_Shdr shdr; 498 GElf_Sym sym; 499 unsigned long stridx = -1; 500 char *s; 501 int error = -1; 502 503 if ((map = proc_name2map(p, object)) == NULL) 504 return (-1); 505 if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) { 506 DPRINTF("ERROR: open %s failed", map->pr_mapname); 507 goto err0; 508 } 509 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 510 DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); 511 goto err1; 512 } 513 if (gelf_getehdr(e, &ehdr) == NULL) { 514 DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); 515 goto err2; 516 } 517 /* 518 * Find the section we are looking for. 519 */ 520 scn = NULL; 521 while ((scn = elf_nextscn(e, scn)) != NULL) { 522 gelf_getshdr(scn, &shdr); 523 if (which == PR_SYMTAB && 524 shdr.sh_type == SHT_SYMTAB) { 525 foundscn = scn; 526 break; 527 } else if (which == PR_DYNSYM && 528 shdr.sh_type == SHT_DYNSYM) { 529 foundscn = scn; 530 break; 531 } 532 } 533 if (!foundscn) 534 return (-1); 535 stridx = shdr.sh_link; 536 if ((data = elf_getdata(foundscn, NULL)) == NULL) { 537 DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1)); 538 goto err2; 539 } 540 for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) { 541 if (GELF_ST_BIND(sym.st_info) == STB_LOCAL && 542 (mask & BIND_LOCAL) == 0) 543 continue; 544 if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL && 545 (mask & BIND_GLOBAL) == 0) 546 continue; 547 if (GELF_ST_BIND(sym.st_info) == STB_WEAK && 548 (mask & BIND_WEAK) == 0) 549 continue; 550 if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE && 551 (mask & TYPE_NOTYPE) == 0) 552 continue; 553 if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT && 554 (mask & TYPE_OBJECT) == 0) 555 continue; 556 if (GELF_ST_TYPE(sym.st_info) == STT_FUNC && 557 (mask & TYPE_FUNC) == 0) 558 continue; 559 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && 560 (mask & TYPE_SECTION) == 0) 561 continue; 562 if (GELF_ST_TYPE(sym.st_info) == STT_FILE && 563 (mask & TYPE_FILE) == 0) 564 continue; 565 s = elf_strptr(e, stridx, sym.st_name); 566 if (ehdr.e_type != ET_EXEC) 567 sym.st_value += map->pr_vaddr; 568 (*func)(cd, &sym, s); 569 } 570 error = 0; 571 err2: 572 elf_end(e); 573 err1: 574 close(fd); 575 err0: 576 free(map); 577 return (error); 578 } 579