📄 pcore.c
字号:
/* * Allocate and initialize a ps_prochandle structure for the core. * There are several key pieces of initialization here: * * 1. The PS_DEAD state flag marks this prochandle as a core file. * PS_DEAD also thus prevents all operations which require state * to be PS_STOP from operating on this handle. * * 2. We keep the core file fd in P->asfd since the core file contains * the remnants of the process address space. * * 3. We set the P->info_valid bit because all information about the * core is determined by the end of this function; there is no need * for proc_update_maps() to reload mappings at any later point. * * 4. The read/write ops vector uses our core_rw() function defined * above to handle i/o requests. */ if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) { *perr = G_STRANGE; return (NULL); } (void) memset(P, 0, sizeof (struct ps_prochandle)); (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL); P->state = PS_DEAD; P->pid = (pid_t)-1; P->asfd = core.e_fd; P->ctlfd = -1; P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; P->info_valid = 1; P->ops = &P_core_ops; Pinitsym(P); /* * Fstat and open the core file and make sure it is a valid ELF core. */ if (fstat64(P->asfd, &stbuf) == -1) { *perr = G_STRANGE; goto err; } if (core_elf_fdopen(&core, ET_CORE, perr) == -1) goto err; /* * Allocate and initialize a core_info_t to hang off the ps_prochandle * structure. We keep all core-specific information in this structure. */ if ((P->core = malloc(sizeof (core_info_t))) == NULL) { *perr = G_STRANGE; goto err; } list_link(&P->core->core_lwp_head, NULL); P->core->core_errno = 0; P->core->core_lwp = NULL; P->core->core_nlwp = 0; P->core->core_size = stbuf.st_size; P->core->core_platform = NULL; P->core->core_uts = NULL; P->core->core_cred = NULL; /* * In the days before adjustable core file content, this was the * default core file content. For new core files, this value will * be overwritten by the NT_CONTENT note section. */ P->core->core_content = CC_CONTENT_STACK | CC_CONTENT_HEAP | CC_CONTENT_DATA | CC_CONTENT_RODATA | CC_CONTENT_ANON | CC_CONTENT_SHANON; P->core->core_priv = NULL; P->core->core_priv_size = 0; P->core->core_privinfo = NULL; P->core->core_zonename = NULL; P->core->core_ppii = NULL;#if defined(__i386) || defined(__amd64) P->core->core_ldt = NULL; P->core->core_nldt = 0;#endif switch (core.e_hdr.e_ident[EI_CLASS]) { case ELFCLASS32: P->core->core_dmodel = PR_MODEL_ILP32; break; case ELFCLASS64: P->core->core_dmodel = PR_MODEL_LP64; break; default: *perr = G_FORMAT; goto err; } /* * Because the core file may be a large file, we can't use libelf to * read the Phdrs. We use e_phnum and e_phentsize to simplify things. */ nbytes = core.e_hdr.e_phnum * core.e_hdr.e_phentsize; if ((phbuf = malloc(nbytes)) == NULL) { *perr = G_STRANGE; goto err; } if (pread64(core_fd, phbuf, nbytes, core.e_hdr.e_phoff) != nbytes) { *perr = G_STRANGE; free(phbuf); goto err; } /* * First, determine the number of mappings in the corefile */ nmap = 0; for (php = phbuf, notes = 0, i = 0; i < core.e_hdr.e_phnum; i++) { if (core.e_hdr.e_ident[EI_CLASS] == ELFCLASS64) (void) memcpy(&phdr, php, sizeof (GElf_Phdr)); else core_phdr_to_gelf(php, &phdr); if (phdr.p_type == PT_LOAD) nmap++; php = (char *)php + core.e_hdr.e_phentsize; } if (nmap != 0) P->mappings = malloc(nmap * sizeof (map_info_t)); /* * Now iterate through the program headers in the core file. * We're interested in two types of Phdrs: PT_NOTE (which * contains a set of saved /proc structures), and PT_LOAD (which * represents a memory mapping from the process's address space). * In the case of PT_NOTE, we're interested in the last PT_NOTE * in the core file; currently the first PT_NOTE (if present) * contains /proc structs in the pre-2.6 unstructured /proc format. */ for (php = phbuf, notes = 0, i = 0; i < core.e_hdr.e_phnum; i++) { if (core.e_hdr.e_ident[EI_CLASS] == ELFCLASS64) (void) memcpy(&phdr, php, sizeof (GElf_Phdr)); else core_phdr_to_gelf(php, &phdr); switch (phdr.p_type) { case PT_NOTE: note_phdr = phdr; notes++; break; case PT_LOAD: if (core_add_mapping(P, &phdr) == -1) { *perr = G_STRANGE; free(phbuf); goto err; } break; } php = (char *)php + core.e_hdr.e_phentsize; } free(phbuf); /* * If we couldn't find anything of type PT_NOTE, or only one PT_NOTE * was present, abort. The core file is either corrupt or too old. */ if (notes == 0 || notes == 1) { *perr = G_NOTE; goto err; } /* * Advance the seek pointer to the start of the PT_NOTE data */ if (lseek64(P->asfd, note_phdr.p_offset, SEEK_SET) == (off64_t)-1) { dprintf("Pgrab_core: failed to lseek to PT_NOTE data\n"); *perr = G_STRANGE; goto err; } /* * Now process the PT_NOTE structures. Each one is preceded by * an Elf{32/64}_Nhdr structure describing its type and size. * * +--------+ * | header | * +--------+ * | name | * | ... | * +--------+ * | desc | * | ... | * +--------+ */ for (nleft = note_phdr.p_filesz; nleft > 0; ) { Elf64_Nhdr nhdr; off64_t off, namesz; /* * Although <sys/elf.h> defines both Elf32_Nhdr and Elf64_Nhdr * as different types, they are both of the same content and * size, so we don't need to worry about 32/64 conversion here. */ if (read(P->asfd, &nhdr, sizeof (nhdr)) != sizeof (nhdr)) { dprintf("Pgrab_core: failed to read ELF note header\n"); *perr = G_NOTE; goto err; } /* * According to the System V ABI, the amount of padding * following the name field should align the description * field on a 4 byte boundary for 32-bit binaries or on an 8 * byte boundary for 64-bit binaries. However, this change * was not made correctly during the 64-bit port so all * descriptions can assume only 4-byte alignment. We ignore * the name field and the padding to 4-byte alignment. */ namesz = P2ROUNDUP((off64_t)nhdr.n_namesz, (off64_t)4); if (lseek64(P->asfd, namesz, SEEK_CUR) == (off64_t)-1) { dprintf("failed to seek past name and padding\n"); *perr = G_STRANGE; goto err; } dprintf("Note hdr n_type=%u n_namesz=%u n_descsz=%u\n", nhdr.n_type, nhdr.n_namesz, nhdr.n_descsz); off = lseek64(P->asfd, (off64_t)0L, SEEK_CUR); /* * Invoke the note handler function from our table */ if (nhdr.n_type < sizeof (nhdlrs) / sizeof (nhdlrs[0])) { if (nhdlrs[nhdr.n_type](P, nhdr.n_descsz) < 0) { *perr = G_NOTE; goto err; } } else (void) note_notsup(P, nhdr.n_descsz); /* * Seek past the current note data to the next Elf_Nhdr */ if (lseek64(P->asfd, off + nhdr.n_descsz, SEEK_SET) == (off64_t)-1) { dprintf("Pgrab_core: failed to seek to next nhdr\n"); *perr = G_STRANGE; goto err; } /* * Subtract the size of the header and its data from what * we have left to process. */ nleft -= sizeof (nhdr) + namesz + nhdr.n_descsz; } if (nleft != 0) { dprintf("Pgrab_core: note section malformed\n"); *perr = G_STRANGE; goto err; } if ((pagesize = Pgetauxval(P, AT_PAGESZ)) == -1) { pagesize = getpagesize(); dprintf("AT_PAGESZ missing; defaulting to %d\n", pagesize); } qsort(P->mappings, P->map_count, sizeof (map_info_t), core_cmp_mapping); /* * Locate and label the mappings corresponding to the end of the * heap (MA_BREAK) and the base of the stack (MA_STACK). */ if ((P->status.pr_brkbase != 0 || P->status.pr_brksize != 0) && (brk_mp = Paddr2mptr(P, P->status.pr_brkbase + P->status.pr_brksize - 1)) != NULL) brk_mp->map_pmap.pr_mflags |= MA_BREAK; else brk_mp = NULL; if ((stk_mp = Paddr2mptr(P, P->status.pr_stkbase)) != NULL) stk_mp->map_pmap.pr_mflags |= MA_STACK; /* * At this point, we have enough information to look for the * executable and open it: we have access to the auxv, a psinfo_t, * and the ability to read from mappings provided by the core file. */ (void) Pfindexec(P, aout_path, core_exec_open, &aout); dprintf("P->execname = \"%s\"\n", P->execname ? P->execname : "NULL"); execname = P->execname ? P->execname : "a.out"; /* * Iterate through the sections, looking for the .dynamic and .interp * sections. If we encounter them, remember their section pointers. */ for (scn = NULL; (scn = elf_nextscn(aout.e_elf, scn)) != NULL; ) { char *sname; if ((gelf_getshdr(scn, &shdr) == NULL) || (sname = elf_strptr(aout.e_elf, aout.e_hdr.e_shstrndx, (size_t)shdr.sh_name)) == NULL) continue; if (strcmp(sname, ".interp") == 0) intp_scn = scn; } /* * Get the AT_BASE auxv element. If this is missing (-1), then * we assume this is a statically-linked executable. */ base_addr = Pgetauxval(P, AT_BASE); /* * In order to get librtld_db initialized, we'll need to identify * and name the mapping corresponding to the run-time linker. The * AT_BASE auxv element tells us the address where it was mapped, * and the .interp section of the executable tells us its path. * If for some reason that doesn't pan out, just use ld.so.1. */ if (intp_scn != NULL && (dp = elf_getdata(intp_scn, NULL)) != NULL && dp->d_size != 0) { dprintf(".interp = <%s>\n", (char *)dp->d_buf); interp = dp->d_buf; } else if (base_addr != (uintptr_t)-1L) { if (P->core->core_dmodel == PR_MODEL_LP64) interp = "/usr/lib/64/ld.so.1"; else interp = "/usr/lib/ld.so.1"; dprintf(".interp section is missing or could not be read; " "defaulting to %s\n", interp); } else dprintf("detected statically linked executable\n"); /* * If we have an AT_BASE element, name the mapping at that address * using the interpreter pathname. Name the corresponding data * mapping after the interpreter as well. */ if (base_addr != (uintptr_t)-1L) { elf_file_t intf; P->map_ldso = core_name_mapping(P, base_addr, interp); if (core_elf_open(&intf, interp, ET_DYN, NULL) == 0) { rd_loadobj_t rl; map_info_t *dmp; rl.rl_base = base_addr; dmp = core_find_data(P, intf.e_elf, &rl); if (dmp != NULL) { dprintf("renamed data at %p to %s\n", (void *)rl.rl_data_base, interp); (void) strncpy(dmp->map_pmap.pr_mapname, interp, PRMAPSZ); dmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0'; } } core_elf_close(&intf); } /* * If we have an AT_ENTRY element, name the mapping at that address * using the special name "a.out" just like /proc does. */ if ((addr = Pgetauxval(P, AT_ENTRY)) != (uintptr_t)-1L) P->map_exec = core_name_mapping(P, addr, "a.out"); /* * If we're a statically linked executable, then just locate the * executable's text and data and name them after the executable. */ if (base_addr == (uintptr_t)-1L) { map_info_t *tmp, *dmp; file_info_t *fp; rd_loadobj_t rl; if ((tmp = core_find_text(P, aout.e_elf, &rl)) != NULL && (dmp = core_find_data(P, aout.e_elf, &rl)) != NULL) { (void) strncpy(tmp->map_pmap.pr_mapname, execname, PRMAPSZ); tmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0'; (void) strncpy(dmp->map_pmap.pr_mapname, execname, PRMAPSZ); dmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0'; } if ((P->map_exec = tmp) != NULL && (fp = malloc(sizeof (file_info_t))) != NULL) { (void) memset(fp, 0, sizeof (file_info_t)); list_link(fp, &P->file_head); tmp->map_file = fp; P->num_files++; fp->file_ref = 1; fp->file_fd = -1; fp->file_lo = malloc(sizeof (rd_loadobj_t)); fp->file_lname = strdup(execname); if (fp->file_lo) *fp->file_lo = rl; if (fp->file_lname) fp->file_lbase = basename(fp->file_lname); (void) strcpy(fp->file_pname, P->mappings[0].map_pmap.pr_mapname); fp->file_map = tmp; Pbuild_file_symtab(P, fp); if (dmp != NULL) { dmp->map_file = fp; fp->file_ref++; } } } core_elf_close(&aout); /* * We now have enough information to initialize librtld_db. * After it warms up, we can iterate through the load object chain * in the core, which will allow us to construct the file info * we need to provide symbol information for the other shared * libraries, and also to fill in the missing mapping names. */ rd_log(_libproc_debug); if ((P->rap = rd_new(P)) != NULL) { (void) rd_loadobj_iter(P->rap, (rl_iter_f *) core_iter_mapping, P); if (P->core->core_errno != 0) { errno = P->core->core_errno; *perr = G_STRANGE; goto err; } } else dprintf("failed to initialize rtld_db agent\n"); /* * If there are sections, load them and process the data from any * sections that we can use to annotate the file_info_t's. */ core_load_shdrs(P, &core); /* * If we previously located a stack or break mapping, and they are * still anonymous, we now assume that they were MAP_ANON mappings. * If brk_mp turns out to now have a name, then the heap is still * sitting at the end of the executable's data+bss mapping: remove * the previous MA_BREAK setting to be consistent with /proc. */ if (stk_mp != NULL && stk_mp->map_pmap.pr_mapname[0] == '\0') stk_mp->map_pmap.pr_mflags |= MA_ANON; if (brk_mp != NULL && brk_mp->map_pmap.pr_mapname[0] == '\0') brk_mp->map_pmap.pr_mflags |= MA_ANON; else if (brk_mp != NULL) brk_mp->map_pmap.pr_mflags &= ~MA_BREAK; *perr = 0; return (P);err: Pfree(P); core_elf_close(&aout); return (NULL);}/* * Grab a core file using a pathname. We just open it and call Pfgrab_core(). */struct ps_prochandle *Pgrab_core(const char *core, const char *aout, int gflag, int *perr){ int fd, oflag = (gflag & PGRAB_RDONLY) ? O_RDONLY : O_RDWR; if ((fd = open64(core, oflag)) >= 0) return (Pfgrab_core(fd, aout, perr)); if (errno != ENOENT) *perr = G_STRANGE; else *perr = G_NOCORE; return (NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -