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