prmap_t * proc_name2map(struct proc_handle *p, const char *name) { size_t i; int cnt; prmap_t *map; char tmppath[MAXPATHLEN]; struct kinfo_vmentry *kves, *kve; rd_loadobj_t *rdl; /* * If we haven't iterated over the list of loaded objects, * librtld_db isn't yet initialized and it's very likely * that librtld_db called us. We need to do the heavy * lifting here to find the symbol librtld_db is looking for. */ if (p->nobjs == 0) { if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL) return (NULL); for (i = 0; i < (size_t)cnt; i++) { kve = kves + i; basename_r(kve->kve_path, tmppath); if (strcmp(tmppath, name) == 0) { map = proc_addr2map(p, kve->kve_start); free(kves); return (map); } } free(kves); return (NULL); } if (name == NULL || strcmp(name, "a.out") == 0) { map = proc_addr2map(p, p->rdobjs[0].rdl_saddr); return (map); } for (i = 0; i < p->nobjs; i++) { rdl = &p->rdobjs[i]; basename_r(rdl->rdl_path, tmppath); if (strcmp(tmppath, name) == 0) { if ((map = malloc(sizeof(*map))) == NULL) return (NULL); proc_rdl2prmap(rdl, map); return (map); } } return (NULL); }
/* * Wait for the specified process to hit a breakpoint at the specified symbol. */ static void verify_bkpt(struct proc_handle *phdl, GElf_Sym *sym, const char *symname, const char *mapname) { char mapbname[MAXPATHLEN], *name; GElf_Sym tsym; prmap_t *map; size_t namesz; u_long addr; int error, state; state = proc_wstatus(phdl); ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has state %d", state); /* Get the program counter and decrement it. */ error = proc_regget(phdl, REG_PC, &addr); ATF_REQUIRE_EQ_MSG(error, 0, "failed to obtain PC for '%s'", target_prog_file); proc_bkptregadj(&addr); /* * Make sure the PC matches the expected value obtained from the symbol * definition we looked up earlier. */ ATF_CHECK_EQ_MSG(addr, sym->st_value, "program counter 0x%lx doesn't match expected value 0x%jx", addr, (uintmax_t)sym->st_value); /* * Ensure we can look up the r_debug_state symbol using its starting * address and that the resulting symbol matches the one we found using * a name lookup. */ namesz = strlen(symname) + 1; name = malloc(namesz); ATF_REQUIRE(name != NULL); error = proc_addr2sym(phdl, addr, name, namesz, &tsym); ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up symbol at 0x%lx", addr); ATF_REQUIRE_EQ(memcmp(sym, &tsym, sizeof(*sym)), 0); ATF_REQUIRE_EQ_MSG(strcmp(symname, name), 0, "expected symbol name '%s' doesn't match '%s'", symname, name); free(name); map = proc_addr2map(phdl, addr); ATF_REQUIRE_MSG(map != NULL, "failed to look up map for address 0x%lx", addr); basename_r(map->pr_mapname, mapbname); ATF_REQUIRE_EQ_MSG(strcmp(mapname, mapbname), 0, "expected map name '%s' doesn't match '%s'", mapname, mapbname); }
int proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, size_t namesz, GElf_Sym *symcopy) { Elf *e; Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; Elf_Data *data; GElf_Shdr shdr; GElf_Sym sym; GElf_Ehdr ehdr; int fd, error = -1; size_t i; uint64_t rsym; prmap_t *map; char *s; unsigned long symtabstridx = 0, dynsymstridx = 0; if ((map = proc_addr2map(p, addr)) == NULL) return (-1); if (!map->pr_mapname || (fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) { warn("ERROR: open %s failed", map->pr_mapname); goto err0; } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { warn("ERROR: elf_begin() failed"); goto err1; } if (gelf_getehdr(e, &ehdr) == NULL) { warn("ERROR: gelf_getehdr() failed"); goto err2; } /* * Find the index of the STRTAB and SYMTAB sections to locate * symbol names. */ scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); switch (shdr.sh_type) { case SHT_SYMTAB: symtabscn = scn; symtabstridx = shdr.sh_link; break; case SHT_DYNSYM: dynsymscn = scn; dynsymstridx = shdr.sh_link; break; default: break; } } /* * Iterate over the Dynamic Symbols table to find the symbol. * Then look up the string name in STRTAB (.dynstr) */ if ((data = elf_getdata(dynsymscn, NULL)) == NULL) { DPRINTF("ERROR: elf_getdata() failed"); goto symtab; } i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { /* * Calculate the address mapped to the virtual memory * by rtld. */ rsym = map->pr_vaddr + sym.st_value; if (addr >= rsym && addr <= (rsym + sym.st_size)) { s = elf_strptr(e, dynsymstridx, sym.st_name); if (s) { if (s[0] == '_' && s[1] == 'Z' && s[2]) demangle(s, name, namesz); else strlcpy(name, s, namesz); memcpy(symcopy, &sym, sizeof(sym)); /* * DTrace expects the st_value to contain * only the address relative to the start of * the function. */ symcopy->st_value = rsym; error = 0; goto out; } } } symtab: /* * Iterate over the Symbols Table to find the symbol. * Then look up the string name in STRTAB (.dynstr) */ if (symtabscn == NULL) goto err2; if ((data = elf_getdata(symtabscn, NULL)) == NULL) { DPRINTF("ERROR: elf_getdata() failed"); goto err2; } i = 0; while (gelf_getsym(data, i++, &sym) != NULL) { /* * Calculate the address mapped to the virtual memory * by rtld. */ if (ehdr.e_type != ET_EXEC) rsym = map->pr_vaddr + sym.st_value; else rsym = sym.st_value; if (addr >= rsym && addr <= (rsym + sym.st_size)) { s = elf_strptr(e, symtabstridx, sym.st_name); if (s) { if (s[0] == '_' && s[1] == 'Z' && s[2]) demangle(s, name, namesz); else strlcpy(name, s, namesz); memcpy(symcopy, &sym, sizeof(sym)); /* * DTrace expects the st_value to contain * only the address relative to the start of * the function. */ symcopy->st_value = rsym; error = 0; goto out; } } } out: err2: elf_end(e); err1: close(fd); err0: free(map); return (error); }
int proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name, size_t namesz, GElf_Sym *symcopy) { GElf_Ehdr ehdr; GElf_Shdr shdr; Elf *e; Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL; prmap_t *map; const char *s; uintptr_t off; u_long symtabstridx = 0, dynsymstridx = 0; int fd, error = -1; if ((map = proc_addr2map(p, addr)) == NULL) return (-1); if ((fd = find_dbg_obj(map->pr_mapname)) < 0) { DPRINTF("ERROR: open %s failed", map->pr_mapname); goto err0; } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1)); goto err1; } if (gelf_getehdr(e, &ehdr) == NULL) { DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1)); goto err2; } /* * Find the index of the STRTAB and SYMTAB sections to locate * symbol names. */ scn = NULL; while ((scn = elf_nextscn(e, scn)) != NULL) { gelf_getshdr(scn, &shdr); switch (shdr.sh_type) { case SHT_SYMTAB: symtabscn = scn; symtabstridx = shdr.sh_link; break; case SHT_DYNSYM: dynsymscn = scn; dynsymstridx = shdr.sh_link; break; } } off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr; /* * First look up the symbol in the dynsymtab, and fall back to the * symtab if the lookup fails. */ error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy); if (error == 0) goto out; error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy); if (error != 0) goto err2; out: demangle(s, name, namesz); err2: elf_end(e); err1: close(fd); err0: free(map); return (error); }