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