📄 psymtab.c
字号:
if (P->rap == NULL && P->state != PS_DEAD && P->state != PS_IDLE) { Pupdate_maps(P); if (P->num_files == 0) load_static_maps(P); rd_log(_libproc_debug); if ((P->rap = rd_new(P)) != NULL) (void) rd_loadobj_iter(P->rap, map_iter, P); } return (P->rap);}/* * Return the prmap_t structure containing 'addr', but only if it * is in the dynamic linker's link map and is the text section. */const prmap_t *Paddr_to_text_map(struct ps_prochandle *P, uintptr_t addr){ map_info_t *mptr; if (!P->info_valid) Pupdate_maps(P); if ((mptr = Paddr2mptr(P, addr)) != NULL) { file_info_t *fptr = build_map_symtab(P, mptr); const prmap_t *pmp = &mptr->map_pmap; if (fptr != NULL && fptr->file_lo != NULL && fptr->file_lo->rl_base >= pmp->pr_vaddr && fptr->file_lo->rl_base < pmp->pr_vaddr + pmp->pr_size) return (pmp); } return (NULL);}/* * Return the prmap_t structure containing 'addr' (no restrictions on * the type of mapping). */const prmap_t *Paddr_to_map(struct ps_prochandle *P, uintptr_t addr){ map_info_t *mptr; if (!P->info_valid) Pupdate_maps(P); if ((mptr = Paddr2mptr(P, addr)) != NULL) return (&mptr->map_pmap); return (NULL);}/* * Convert a full or partial load object name to the prmap_t for its * corresponding primary text mapping. */const prmap_t *Plmid_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name){ map_info_t *mptr; if (name == PR_OBJ_EVERY) return (NULL); /* A reasonable mistake */ if ((mptr = object_name_to_map(P, lmid, name)) != NULL) return (&mptr->map_pmap); return (NULL);}const prmap_t *Pname_to_map(struct ps_prochandle *P, const char *name){ return (Plmid_to_map(P, PR_LMID_EVERY, name));}const rd_loadobj_t *Paddr_to_loadobj(struct ps_prochandle *P, uintptr_t addr){ map_info_t *mptr; if (!P->info_valid) Pupdate_maps(P); if ((mptr = Paddr2mptr(P, addr)) == NULL) return (NULL); /* * By building the symbol table, we implicitly bring the PLT * information up to date in the load object. */ (void) build_map_symtab(P, mptr); return (mptr->map_file->file_lo);}const rd_loadobj_t *Plmid_to_loadobj(struct ps_prochandle *P, Lmid_t lmid, const char *name){ map_info_t *mptr; if (name == PR_OBJ_EVERY) return (NULL); if ((mptr = object_name_to_map(P, lmid, name)) == NULL) return (NULL); /* * By building the symbol table, we implicitly bring the PLT * information up to date in the load object. */ (void) build_map_symtab(P, mptr); return (mptr->map_file->file_lo);}const rd_loadobj_t *Pname_to_loadobj(struct ps_prochandle *P, const char *name){ return (Plmid_to_loadobj(P, PR_LMID_EVERY, name));}ctf_file_t *Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr){ ctf_sect_t ctdata, symtab, strtab; sym_tbl_t *symp; int err; if (fptr->file_ctfp != NULL) return (fptr->file_ctfp); Pbuild_file_symtab(P, fptr); if (fptr->file_ctf_size == 0) return (NULL); symp = fptr->file_ctf_dyn ? &fptr->file_dynsym : &fptr->file_symtab; if (symp->sym_data == NULL) return (NULL); /* * The buffer may alread be allocated if this is a core file that * contained CTF data for this file. */ if (fptr->file_ctf_buf == NULL) { fptr->file_ctf_buf = malloc(fptr->file_ctf_size); if (fptr->file_ctf_buf == NULL) { dprintf("failed to allocate ctf buffer\n"); return (NULL); } if (pread(fptr->file_fd, fptr->file_ctf_buf, fptr->file_ctf_size, fptr->file_ctf_off) != fptr->file_ctf_size) { free(fptr->file_ctf_buf); fptr->file_ctf_buf = NULL; dprintf("failed to read ctf data\n"); return (NULL); } } ctdata.cts_name = ".SUNW_ctf"; ctdata.cts_type = SHT_PROGBITS; ctdata.cts_flags = 0; ctdata.cts_data = fptr->file_ctf_buf; ctdata.cts_size = fptr->file_ctf_size; ctdata.cts_entsize = 1; ctdata.cts_offset = 0; symtab.cts_name = fptr->file_ctf_dyn ? ".dynsym" : ".symtab"; symtab.cts_type = symp->sym_hdr.sh_type; symtab.cts_flags = symp->sym_hdr.sh_flags; symtab.cts_data = symp->sym_data->d_buf; symtab.cts_size = symp->sym_hdr.sh_size; symtab.cts_entsize = symp->sym_hdr.sh_entsize; symtab.cts_offset = symp->sym_hdr.sh_offset; strtab.cts_name = fptr->file_ctf_dyn ? ".dynstr" : ".strtab"; strtab.cts_type = symp->sym_strhdr.sh_type; strtab.cts_flags = symp->sym_strhdr.sh_flags; strtab.cts_data = symp->sym_strs; strtab.cts_size = symp->sym_strhdr.sh_size; strtab.cts_entsize = symp->sym_strhdr.sh_entsize; strtab.cts_offset = symp->sym_strhdr.sh_offset; fptr->file_ctfp = ctf_bufopen(&ctdata, &symtab, &strtab, &err); if (fptr->file_ctfp == NULL) { free(fptr->file_ctf_buf); fptr->file_ctf_buf = NULL; return (NULL); } dprintf("loaded %lu bytes of CTF data for %s\n", (ulong_t)fptr->file_ctf_size, fptr->file_pname); return (fptr->file_ctfp);}ctf_file_t *Paddr_to_ctf(struct ps_prochandle *P, uintptr_t addr){ map_info_t *mptr; file_info_t *fptr; if (!P->info_valid) Pupdate_maps(P); if ((mptr = Paddr2mptr(P, addr)) == NULL || (fptr = mptr->map_file) == NULL) return (NULL); return (Pbuild_file_ctf(P, fptr));}ctf_file_t *Plmid_to_ctf(struct ps_prochandle *P, Lmid_t lmid, const char *name){ map_info_t *mptr; file_info_t *fptr; if (name == PR_OBJ_EVERY) return (NULL); if ((mptr = object_name_to_map(P, lmid, name)) == NULL || (fptr = mptr->map_file) == NULL) return (NULL); return (Pbuild_file_ctf(P, fptr));}ctf_file_t *Pname_to_ctf(struct ps_prochandle *P, const char *name){ return (Plmid_to_ctf(P, PR_LMID_EVERY, name));}/* * If we're not a core file, re-read the /proc/<pid>/auxv file and store * its contents in P->auxv. In the case of a core file, we either * initialized P->auxv in Pcore() from the NT_AUXV, or we don't have an * auxv because the note was missing. */voidPreadauxvec(struct ps_prochandle *P){ char auxfile[64]; struct stat statb; ssize_t naux; int fd; if (P->state == PS_DEAD) return; /* Already read during Pgrab_core() */ if (P->state == PS_IDLE) return; /* No aux vec for Pgrab_file() */ if (P->auxv != NULL) { free(P->auxv); P->auxv = NULL; P->nauxv = 0; } (void) sprintf(auxfile, "/proc/%d/auxv", (int)P->pid); if ((fd = open(auxfile, O_RDONLY)) < 0) return; if (fstat(fd, &statb) == 0 && statb.st_size >= sizeof (auxv_t) && (P->auxv = malloc(statb.st_size + sizeof (auxv_t))) != NULL) { if ((naux = read(fd, P->auxv, statb.st_size)) < 0 || (naux /= sizeof (auxv_t)) < 1) { free(P->auxv); P->auxv = NULL; } else { P->auxv[naux].a_type = AT_NULL; P->auxv[naux].a_un.a_val = 0L; P->nauxv = (int)naux; } } (void) close(fd);}/* * Return a requested element from the process's aux vector. * Return -1 on failure (this is adequate for our purposes). */longPgetauxval(struct ps_prochandle *P, int type){ auxv_t *auxv; if (P->auxv == NULL) Preadauxvec(P); if (P->auxv == NULL) return (-1); for (auxv = P->auxv; auxv->a_type != AT_NULL; auxv++) { if (auxv->a_type == type) return (auxv->a_un.a_val); } return (-1);}/* * Return a pointer to our internal copy of the process's aux vector. * The caller should not hold on to this pointer across any libproc calls. */const auxv_t *Pgetauxvec(struct ps_prochandle *P){ static const auxv_t empty = { AT_NULL, 0L }; if (P->auxv == NULL) Preadauxvec(P); if (P->auxv == NULL) return (&empty); return (P->auxv);}/* * Find or build the symbol table for the given mapping. */static file_info_t *build_map_symtab(struct ps_prochandle *P, map_info_t *mptr){ prmap_t *pmap = &mptr->map_pmap; file_info_t *fptr; rd_loadobj_t *lop; uint_t i; if ((fptr = mptr->map_file) != NULL) { Pbuild_file_symtab(P, fptr); return (fptr); } if (pmap->pr_mapname[0] == '\0') return (NULL); /* * Attempt to find a matching file. * (A file can be mapped at several different addresses.) */ for (i = 0, fptr = list_next(&P->file_head); i < P->num_files; i++, fptr = list_next(fptr)) { if (strcmp(fptr->file_pname, pmap->pr_mapname) == 0 && (lop = fptr->file_lo) != NULL && ((pmap->pr_vaddr <= lop->rl_base && lop->rl_base < pmap->pr_vaddr + pmap->pr_size) || (pmap->pr_vaddr <= lop->rl_data_base && lop->rl_data_base < pmap->pr_vaddr + pmap->pr_size))) { mptr->map_file = fptr; fptr->file_ref++; Pbuild_file_symtab(P, fptr); return (fptr); } } /* * If we need to create a new file_info structure, iterate * through the load objects in order to attempt to connect * this new file with its primary text mapping. We again * need to handle ld.so as a special case because we need * to be able to bootstrap librtld_db. */ if ((fptr = file_info_new(P, mptr)) == NULL) return (NULL); if (P->map_ldso != mptr) { if (P->rap != NULL) (void) rd_loadobj_iter(P->rap, map_iter, P); else (void) Prd_agent(P); } else { fptr->file_map = mptr; } /* * If librtld_db wasn't able to help us connect the file to a primary * text mapping, set file_map to the current mapping because we require * fptr->file_map to be set in Pbuild_file_symtab. librtld_db may be * unaware of what's going on in the rare case that a legitimate ELF * file has been mmap(2)ed into the process address space *without* * the use of dlopen(3x). Why would this happen? See pwdx ... :) */ if (fptr->file_map == NULL) fptr->file_map = mptr; Pbuild_file_symtab(P, fptr); return (fptr);}static intread_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uintptr_t addr){ if (Pread(P, ehdr, sizeof (*ehdr), addr) != sizeof (*ehdr)) return (-1); if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 || ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3 || ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||#ifdef _BIG_ENDIAN ehdr->e_ident[EI_DATA] != ELFDATA2MSB ||#else ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||#endif ehdr->e_ident[EI_VERSION] != EV_CURRENT) return (-1); return (0);}static intread_dynamic_phdr32(struct ps_prochandle *P, const Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, uintptr_t addr){ uint_t i; for (i = 0; i < ehdr->e_phnum; i++) { uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize; if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr)) return (-1); if (phdr->p_type == PT_DYNAMIC) return (0); } return (-1);}#ifdef _LP64static intread_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uintptr_t addr){ if (Pread(P, ehdr, sizeof (Elf64_Ehdr), addr) != sizeof (Elf64_Ehdr)) return (-1); if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || ehdr->e_ident[EI_MAG1] != ELFMAG1 || ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3 || ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||#ifdef _BIG_ENDIAN ehdr->e_ident[EI_DATA] != ELFDATA2MSB ||#else ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||#endif ehdr->e_ident[EI_VERSION] != EV_CURRENT) return (-1); return (0);}static intread_dynamic_phdr64(struct ps_prochandle *P, const Elf64_Ehdr *ehdr, Elf64_Phdr *phdr, uintptr_t addr){ uint_t i; for (i = 0; i < ehdr->e_phnum; i++) { uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize; if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr)) return (-1); if (phdr->p_type == PT_DYNAMIC) return (0); } return (-1);}#endif /* _LP64 *//* * The text segment for each load object contains the elf header and * program headers. We can use this information to determine if the * file that corresponds to the load object is the same file that * was loaded into the process's address space. There can be a discrepency * if a file is recompiled after the process is started or if the target * represents a core file from a differently configured system -- two * common examples. The DT_CHECKSUM entry in the dynamic section * provides an easy method of comparison. It is important to note that * the dynamic section usually lives in the data segment, but the meta * data we use to find the dynamic section lives in the text segment so * if either of those segments is absent we can't proceed. * * We're looking through the elf file for several items: the symbol tables * (both dynsym and symtab), the procedure linkage table (PLT) base, * size, and relocation base, and the CTF information. Most of this can * be recovered from the loaded image of the file itself, the exceptions * being the symtab and CTF data. * * First we try to open the file that we think corresponds to the load * object, if the DT_CHECKSUM values match, we're all set, and can simply * recover all the information we need from the file. If the values of * DT_CHECKSUM don't match, or if we can't access the file for whatever * reasaon, we fake up a elf file to use in its stead. If we can't read * the elf data in the process's address space, we fall back to using * the file even though it may give inaccurate information. * * The elf file that we fake up has to consist of sections for the * dynsym, the PLT and the dynamic section. Note that in the case of a * core file, we'll get the CTF data in the file_info_t later on from * a section embedded the core file (if it's present). * * file_differs() conservatively looks for mismatched files, identifying * a match when there is any ambiguity (since that's the legacy behavior).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -