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