📄 pcore.c
字号:
{#ifdef _BIG_ENDIAN uchar_t order = ELFDATA2MSB;#else uchar_t order = ELFDATA2LSB;#endif Elf32_Ehdr e32; int is_noelf = -1; int isa_err = 0; /* * Because 32-bit libelf cannot deal with large files, we need to read, * check, and convert the file header manually in case type == ET_CORE. */ if (pread64(efp->e_fd, &e32, sizeof (e32), 0) != sizeof (e32)) { if (perr != NULL) *perr = G_FORMAT; goto err; } if ((is_noelf = memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG)) != 0 || e32.e_type != type || (isa_err = (e32.e_ident[EI_DATA] != order)) || e32.e_version != EV_CURRENT) { if (perr != NULL) { if (is_noelf == 0 && isa_err) { *perr = G_ISAINVAL; } else { *perr = G_FORMAT; } } goto err; } /* * If the file is 64-bit and we are 32-bit, fail with G_LP64. If the * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr. * Otherwise, the file is 32-bit, so convert e32 to a GElf_Ehdr. */ if (e32.e_ident[EI_CLASS] == ELFCLASS64) {#ifdef _LP64 if (pread64(efp->e_fd, &efp->e_hdr, sizeof (GElf_Ehdr), 0) != sizeof (GElf_Ehdr)) { if (perr != NULL) *perr = G_FORMAT; goto err; }#else /* _LP64 */ if (perr != NULL) *perr = G_LP64; goto err;#endif /* _LP64 */ } else core_ehdr_to_gelf(&e32, &efp->e_hdr); /* * The libelf implementation was never ported to be large-file aware. * This is typically not a problem for your average executable or * shared library, but a large 32-bit core file can exceed 2GB in size. * So if type is ET_CORE, we don't bother doing elf_begin; the code * in Pfgrab_core() below will do its own i/o and struct conversion. */ if (type == ET_CORE) { efp->e_elf = NULL; return (0); } if ((efp->e_elf = elf_begin(efp->e_fd, ELF_C_READ, NULL)) == NULL) { if (perr != NULL) *perr = G_ELF; goto err; } return (0);err: efp->e_elf = NULL; return (-1);}/* * Open the specified file and then do a core_elf_fdopen on it. */static intcore_elf_open(elf_file_t *efp, const char *path, GElf_Half type, int *perr){ (void) memset(efp, 0, sizeof (elf_file_t)); if ((efp->e_fd = open64(path, O_RDONLY)) >= 0) { if (core_elf_fdopen(efp, type, perr) == 0) return (0); (void) close(efp->e_fd); efp->e_fd = -1; } return (-1);}/* * Close the ELF handle and file descriptor. */static voidcore_elf_close(elf_file_t *efp){ if (efp->e_elf != NULL) { (void) elf_end(efp->e_elf); efp->e_elf = NULL; } if (efp->e_fd != -1) { (void) close(efp->e_fd); efp->e_fd = -1; }}/* * Given an ELF file for a statically linked executable, locate the likely * primary text section and fill in rl_base with its virtual address. */static map_info_t *core_find_text(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp){ GElf_Ehdr ehdr; GElf_Phdr phdr; uint_t i; if (gelf_getehdr(elf, &ehdr) != NULL) { for (i = 0; i < ehdr.e_phnum; i++) { if (gelf_getphdr(elf, i, &phdr) != NULL && phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) { rlp->rl_base = phdr.p_vaddr; return (Paddr2mptr(P, rlp->rl_base)); } } } return (NULL);}/* * Given an ELF file and the librtld_db structure corresponding to its primary * text mapping, deduce where its data segment was loaded and fill in * rl_data_base and prmap_t.pr_offset accordingly. */static map_info_t *core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp){ GElf_Ehdr ehdr; GElf_Phdr phdr; map_info_t *mp; uint_t i, pagemask; rlp->rl_data_base = NULL; /* * Find the first loadable, writeable Phdr and compute rl_data_base * as the virtual address at which is was loaded. */ if (gelf_getehdr(elf, &ehdr) != NULL) { for (i = 0; i < ehdr.e_phnum; i++) { if (gelf_getphdr(elf, i, &phdr) != NULL && phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) { rlp->rl_data_base = phdr.p_vaddr; if (ehdr.e_type == ET_DYN) rlp->rl_data_base += rlp->rl_base; break; } } } /* * If we didn't find an appropriate phdr or if the address we * computed has no mapping, return NULL. */ if (rlp->rl_data_base == NULL || (mp = Paddr2mptr(P, rlp->rl_data_base)) == NULL) return (NULL); /* * It wouldn't be procfs-related code if we didn't make use of * unclean knowledge of segvn, even in userland ... the prmap_t's * pr_offset field will be the segvn offset from mmap(2)ing the * data section, which will be the file offset & PAGEMASK. */ pagemask = ~(mp->map_pmap.pr_pagesize - 1); mp->map_pmap.pr_offset = phdr.p_offset & pagemask; return (mp);}/* * Librtld_db agent callback for iterating over load object mappings. * For each load object, we allocate a new file_info_t, perform naming, * and attempt to construct a symbol table for the load object. */static intcore_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P){ char lname[PATH_MAX]; file_info_t *fp; map_info_t *mp; if (Pread_string(P, lname, PATH_MAX, (off_t)rlp->rl_nameaddr) <= 0) { dprintf("failed to read name %p\n", (void *)rlp->rl_nameaddr); return (1); /* Keep going; forget this if we can't get a name */ } dprintf("rd_loadobj name = \"%s\" rl_base = %p\n", lname, (void *)rlp->rl_base); if ((mp = Paddr2mptr(P, rlp->rl_base)) == NULL) { dprintf("no mapping for %p\n", (void *)rlp->rl_base); return (1); /* No mapping; advance to next mapping */ } if ((fp = mp->map_file) == NULL) { if ((fp = malloc(sizeof (file_info_t))) == NULL) { P->core->core_errno = errno; dprintf("failed to malloc mapping data\n"); return (0); /* Abort */ } (void) memset(fp, 0, sizeof (file_info_t)); list_link(fp, &P->file_head); mp->map_file = fp; P->num_files++; fp->file_ref = 1; fp->file_fd = -1; } if ((fp->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) { P->core->core_errno = errno; dprintf("failed to malloc mapping data\n"); return (0); /* Abort */ } *fp->file_lo = *rlp; if (fp->file_lname == NULL && strcmp(mp->map_pmap.pr_mapname, "a.out") == 0) { /* * Naming dance part 1: if the file_info_t is unnamed and * it represents the main executable, name it after the * execname. */ fp->file_lname = P->execname ? strdup(P->execname) : strdup("a.out"); } if (lname[0] != '\0') { /* * Naming dance part 2: if we got a name from librtld_db, then * copy this name to the prmap_t if it is unnamed. If the * file_info_t is unnamed, name it after the lname. */ if (mp->map_pmap.pr_mapname[0] == '\0') { (void) strncpy(mp->map_pmap.pr_mapname, lname, PRMAPSZ); mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0'; } if (fp->file_lname == NULL) fp->file_lname = strdup(lname); } else if (fp->file_lname == NULL && mp->map_pmap.pr_mapname[0] != '\0') { /* * Naming dance part 3: if the mapping is named and the * file_info_t is not, name the file after the mapping. */ fp->file_lname = strdup(mp->map_pmap.pr_mapname); } if (fp->file_lname != NULL) fp->file_lbase = basename(fp->file_lname); /* * Associate the file and the mapping, and attempt to build * a symbol table for this file. */ (void) strcpy(fp->file_pname, mp->map_pmap.pr_mapname); fp->file_map = mp; Pbuild_file_symtab(P, fp); if (fp->file_elf == NULL) return (1); /* No symbol table; advance to next mapping */ /* * Locate the start of a data segment associated with this file, * name it after the file, and establish the mp->map_file link: */ if ((mp = core_find_data(P, fp->file_elf, fp->file_lo)) != NULL) { dprintf("found data for %s at %p (pr_offset 0x%llx)\n", fp->file_pname, (void *)fp->file_lo->rl_data_base, mp->map_pmap.pr_offset); for (; mp < P->mappings + P->map_count; mp++) { if (mp->map_pmap.pr_vaddr > fp->file_lo->rl_bend) break; if (mp->map_file == NULL) { mp->map_file = fp; fp->file_ref++; } if (!(mp->map_pmap.pr_mflags & MA_BREAK)) (void) strcpy(mp->map_pmap.pr_mapname, fp->file_pname); } } return (1); /* Advance to next mapping */}/* * Callback function for Pfindexec(). In order to confirm a given pathname, * we verify that we can open it as an ELF file of type ET_EXEC. */static intcore_exec_open(const char *path, void *efp){ return (core_elf_open(efp, path, ET_EXEC, NULL) == 0);}/* * Attempt to load any section headers found in the core file. If present, * this will refer to non-loadable data added to the core file by the kernel * based on coreadm(1M) settings, including CTF data and the symbol table. */static voidcore_load_shdrs(struct ps_prochandle *P, elf_file_t *efp){ GElf_Shdr *shp, *shdrs = NULL; char *shstrtab = NULL; ulong_t shstrtabsz; const char *name; map_info_t *mp; size_t nbytes; void *buf; int i; if (efp->e_hdr.e_shstrndx >= efp->e_hdr.e_shnum) { dprintf("corrupt shstrndx (%u) exceeds shnum (%u)\n", (uint_t)efp->e_hdr.e_shstrndx, (uint_t)efp->e_hdr.e_shnum); return; } /* * Read the section header table from the core file and then iterate * over the section headers, converting each to a GElf_Shdr. */ shdrs = malloc(efp->e_hdr.e_shnum * sizeof (GElf_Shdr)); nbytes = efp->e_hdr.e_shnum * efp->e_hdr.e_shentsize; buf = malloc(nbytes); if (shdrs == NULL || buf == NULL) { dprintf("failed to malloc %u section headers: %s\n", (uint_t)efp->e_hdr.e_shnum, strerror(errno)); free(buf); goto out; } if (pread64(efp->e_fd, buf, nbytes, efp->e_hdr.e_shoff) != nbytes) { dprintf("failed to read section headers at off %lld: %s\n", (longlong_t)efp->e_hdr.e_shoff, strerror(errno)); free(buf); goto out; } for (i = 0; i < efp->e_hdr.e_shnum; i++) { void *p = (uchar_t *)buf + efp->e_hdr.e_shentsize * i; if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) core_shdr_to_gelf(p, &shdrs[i]); else (void) memcpy(&shdrs[i], p, sizeof (GElf_Shdr)); } free(buf); buf = NULL; /* * Read the .shstrtab section from the core file, terminating it with * an extra \0 so that a corrupt section will not cause us to die. */ shp = &shdrs[efp->e_hdr.e_shstrndx]; shstrtabsz = shp->sh_size; if ((shstrtab = malloc(shstrtabsz + 1)) == NULL) { dprintf("failed to allocate %lu bytes for shstrtab\n", (ulong_t)shstrtabsz); goto out; } if (pread64(efp->e_fd, shstrtab, shstrtabsz, shp->sh_offset) != shstrtabsz) { dprintf("failed to read %lu bytes of shstrs at off %lld: %s\n", shstrtabsz, (longlong_t)shp->sh_offset, strerror(errno)); goto out; } shstrtab[shstrtabsz] = '\0'; /* * Now iterate over each section in the section header table, locating * sections of interest and initializing more of the ps_prochandle. */ for (i = 0; i < efp->e_hdr.e_shnum; i++) { shp = &shdrs[i]; name = shstrtab + shp->sh_name; if (shp->sh_name >= shstrtabsz) { dprintf("skipping section [%d]: corrupt sh_name\n", i); continue; } if (shp->sh_link >= efp->e_hdr.e_shnum) { dprintf("skipping section [%d]: corrupt sh_link\n", i); continue; } dprintf("found section header %s (sh_addr 0x%llx)\n", name, (u_longlong_t)shp->sh_addr); if (strcmp(name, ".SUNW_ctf") == 0) { if ((mp = Paddr2mptr(P, shp->sh_addr)) == NULL) { dprintf("no map at addr 0x%llx for %s [%d]\n", (u_longlong_t)shp->sh_addr, name, i); continue; } if (mp->map_file == NULL || mp->map_file->file_ctf_buf != NULL) { dprintf("no mapping file or duplicate buffer " "for %s [%d]\n", name, i); continue; } if ((buf = malloc(shp->sh_size)) == NULL || pread64(efp->e_fd, buf, shp->sh_size, shp->sh_offset) != shp->sh_size) { dprintf("skipping section %s [%d]: %s\n", name, i, strerror(errno)); free(buf); continue; } mp->map_file->file_ctf_size = shp->sh_size; mp->map_file->file_ctf_buf = buf; if (shdrs[shp->sh_link].sh_type == SHT_DYNSYM) mp->map_file->file_ctf_dyn = 1; } else if (strcmp(name, ".symtab") == 0) { fake_up_symtab(P, &efp->e_hdr, shp, &shdrs[shp->sh_link]); } }out: free(shstrtab); free(shdrs);}/* * Main engine for core file initialization: given an fd for the core file * and an optional pathname, construct the ps_prochandle. The aout_path can * either be a suggested executable pathname, or a suggested directory to * use as a possible current working directory. */struct ps_prochandle *Pfgrab_core(int core_fd, const char *aout_path, int *perr){ struct ps_prochandle *P; map_info_t *stk_mp, *brk_mp; const char *execname; char *interp; int i, notes, pagesize; uintptr_t addr, base_addr; struct stat64 stbuf; void *phbuf, *php; size_t nbytes; int nmap; elf_file_t aout; elf_file_t core; Elf_Scn *scn, *intp_scn = NULL; Elf_Data *dp; GElf_Phdr phdr, note_phdr; GElf_Shdr shdr; GElf_Xword nleft; if (elf_version(EV_CURRENT) == EV_NONE) { dprintf("libproc ELF version is more recent than libelf\n"); *perr = G_ELF; return (NULL); } aout.e_elf = NULL; aout.e_fd = -1; core.e_elf = NULL; core.e_fd = core_fd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -