📄 elfcore.c
字号:
NO_INTR(rc = write(fds->write_fd, buf, len)); if (rc < 0 && errno != EAGAIN) { return -1; } buf += rc; len -= rc; } } return bytes - len;}/* Flush the remaining data (if any) from the pipe. */static int FlushPipe(struct WriterFds *fds) { long flags; NO_INTR(flags = sys_fcntl(fds->compressed_fd, F_GETFL, 0)); NO_INTR(sys_fcntl(fds->compressed_fd, F_SETFL, flags & ~O_NONBLOCK)); while (fds->max_length > 0) { char scratch[4096]; size_t l = sizeof(scratch); ssize_t rc; if (l > fds->max_length) { l = fds->max_length; } if (l > 0) { NO_INTR(rc = read(fds->compressed_fd, scratch, l)); if (rc < 0) { return -1; } else if (rc == 0) { break; } if (c_write(fds->out_fd, scratch, rc, &errno) != rc) { return -1; } fds->max_length -= rc; } } return 0;}struct io { int fd; unsigned char *data, *end; unsigned char buf[4096];};/* Reads one character from the "io" file. This function has the same * semantics as fgetc(), but we cannot call any library functions at this * time. */static int GetChar(struct io *io) { unsigned char *ptr = io->data; if (ptr == io->end) { /* Even though we are parsing one character at a time, read in larger * chunks. */ ssize_t n = c_read(io->fd, io->buf, sizeof(io->buf), &errno); if (n <= 0) { if (n == 0) errno = 0; return -1; } ptr = &io->buf[0]; io->end = &io->buf[n]; } io->data = ptr+1; return *ptr;}/* Place the hex number read from "io" into "*hex". The first non-hex * character is returned (or -1 in the case of end-of-file). */static int GetHex(struct io *io, size_t *hex) { int ch; *hex = 0; while (((ch = GetChar(io)) >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9); return ch;}/* Computes the amount of leading zeros in a memory region. */static size_t LeadingZeros(int *loopback, void *mem, size_t len, size_t pagesize) { char buf[pagesize]; size_t count; char *ptr = buf; for (count = 0; count < len; ) { /* Read a page by going through the pipe. Assume that we can write at * least one page without blocking. * * "Normal" kernels do not require this hack. But some of the security * patches (e.g. grsec) can be configured to disallow read access of * executable pages. So, directly scanning the memory range would * result in a segmentation fault. * * If we cannot access a page, we assume that it was all zeros. */ if ((count % pagesize) == 0) { if (c_write(loopback[1], (char *)mem + count, pagesize, &errno) < 0 || c_read(loopback[0], buf, pagesize, &errno) < 0) { count += pagesize; continue; } else { ptr = buf; } } if (*ptr++) { break; } count++; } return count & ~(pagesize-1);}/* Dynamically determines the byte sex of the system. Returns non-zero * for big-endian machines. */static inline int sex() { int probe = 1; return !*(char *)&probe;}/* This function is invoked from a seperate process. It has access to a * copy-on-write copy of the parents address space, and all crucial * information about the parent has been computed by the caller. */static int CreateElfCore(void *handle, ssize_t (*writer)(void *, const void *, size_t), int (*is_done)(void *), prpsinfo *prpsinfo, user *user, prstatus *prstatus, int num_threads, pid_t *pids, regs *regs, fpregs *fpregs, fpxregs *fpxregs, size_t pagesize) { /* Count the number of mappings in "/proc/self/maps". We are guaranteed * that this number is not going to change while this function executes. */ int rc = -1, num_mappings = 0; struct io io; int loopback[2] = { -1, -1 }; if (sys_pipe(loopback) < 0) goto done; io.data = io.end = 0; NO_INTR(io.fd = sys_open("/proc/self/maps", O_RDONLY, 0)); if (io.fd >= 0) { int i, ch; while ((ch = GetChar(&io)) >= 0) { num_mappings += (ch == '\n'); } if (errno != 0) { read_error: NO_INTR(sys_close(io.fd)); goto done; } NO_INTR(sys_close(io.fd)); /* Read all mappings. This requires re-opening "/proc/self/maps" */ /* scope */ { static const int PF_ANONYMOUS = 0x80000000; static const int PF_MASK = 0x00000007; struct { size_t start_address, end_address, offset; int flags; } mappings[num_mappings]; io.data = io.end = 0; NO_INTR(io.fd = sys_open("/proc/self/maps", O_RDONLY, 0)); if (io.fd >= 0) { size_t note_align; /* Parse entries of the form: * "^[0-9A-F]*-[0-9A-F]* [r-][w-][x-][p-] [0-9A-F]*.*$" */ for (i = 0; i < num_mappings;) { static const char * const dev_zero = "/dev/zero"; const char *dev = dev_zero; int j, is_device, is_anonymous; size_t zeros; memset(&mappings[i], 0, sizeof(mappings[i])); /* Read start and end addresses */ if (GetHex(&io, &mappings[i].start_address) != '-' || GetHex(&io, &mappings[i].end_address) != ' ') goto read_error; /* Read flags */ while ((ch = GetChar(&io)) != ' ') { if (ch < 0) goto read_error; mappings[i].flags = (mappings[i].flags << 1) | (ch != '-'); } /* Read offset */ if ((ch = GetHex(&io, &mappings[i].offset)) != ' ') goto read_error; /* Skip over device numbers, and inode number */ for (j = 0; j < 2; j++) { while (ch == ' ') { ch = GetChar(&io); } while (ch != ' ' && ch != '\n') { if (ch < 0) goto read_error; ch = GetChar(&io); } while (ch == ' ') { ch = GetChar(&io); } if (ch < 0) goto read_error; } /* Check whether this is a mapping for a device */ is_anonymous = (ch == '\n' || ch == '['); while (*dev && ch == *dev) { ch = GetChar(&io); dev++; } is_device = dev >= dev_zero + 5 && ((ch != '\n' && ch != ' ') || *dev != '\000'); /* Drop the private/shared bit. This makes the flags compatible with * the ELF access bits */ mappings[i].flags = (mappings[i].flags >> 1) & PF_MASK; if (is_anonymous) { mappings[i].flags |= PF_ANONYMOUS; } /* Skip until end of line */ while (ch != '\n') { if (ch < 0) goto read_error; ch = GetChar(&io); } /* Skip leading zeroed pages (as found in the stack segment) */ if ((mappings[i].flags & PF_R) && !is_device) { zeros = LeadingZeros(loopback, (void *)mappings[i].start_address, mappings[i].end_address - mappings[i].start_address, pagesize); mappings[i].start_address += zeros; } /* Remove mapping, if it was not readable, or completely zero * anyway. The former is usually the case of stack guard pages, and * the latter occasionally happens for unused memory. * Also, be careful not to touch mapped devices. */ if ((mappings[i].flags & PF_R) == 0 || mappings[i].start_address == mappings[i].end_address || is_device) { num_mappings--; } else { i++; } } NO_INTR(sys_close(io.fd)); /* Write out the ELF header */ /* scope */ { Ehdr ehdr; memset(&ehdr, 0, sizeof(Ehdr)); ehdr.e_ident[0] = ELFMAG0; ehdr.e_ident[1] = ELFMAG1; ehdr.e_ident[2] = ELFMAG2; ehdr.e_ident[3] = ELFMAG3; ehdr.e_ident[4] = ELF_CLASS; ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB; ehdr.e_ident[6] = EV_CURRENT; ehdr.e_type = ET_CORE; ehdr.e_machine = ELF_ARCH; ehdr.e_version = EV_CURRENT; ehdr.e_phoff = sizeof(Ehdr); ehdr.e_ehsize = sizeof(Ehdr); ehdr.e_phentsize= sizeof(Phdr); ehdr.e_phnum = num_mappings + 1; ehdr.e_shentsize= sizeof(Shdr); if (writer(handle, &ehdr, sizeof(Ehdr)) != sizeof(Ehdr)) { goto done; } } /* Write program headers, starting with the PT_NOTE entry */ /* scope */ { Phdr phdr; size_t offset = sizeof(Ehdr) + (num_mappings + 1)*sizeof(Phdr); size_t filesz = sizeof(Nhdr) + 4 + sizeof(struct prpsinfo) + sizeof(Nhdr) + 4 + sizeof(struct user) + num_threads*( + sizeof(Nhdr) + 4 + sizeof(struct prstatus) + sizeof(Nhdr) + 4 + sizeof(struct fpregs)); #if defined(__i386__) && !defined(__x86_64__) if (fpxregs) { filesz += num_threads*( sizeof(Nhdr) + 8 + sizeof(struct fpxregs)); } #endif memset(&phdr, 0, sizeof(Phdr)); phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_filesz = filesz; if (writer(handle, &phdr, sizeof(Phdr)) != sizeof(Phdr)) { goto done; } /* Now follow with program headers for each of the memory segments */ phdr.p_type = PT_LOAD; phdr.p_align = pagesize; phdr.p_paddr = 0; note_align = phdr.p_align - ((offset+filesz) % phdr.p_align); if (note_align == phdr.p_align) note_align = 0; offset += note_align; for (i = 0; i < num_mappings; i++) { offset += filesz; filesz = mappings[i].end_address -mappings[i].start_address; phdr.p_offset = offset; phdr.p_vaddr = mappings[i].start_address; phdr.p_memsz = filesz; /* Do not write contents for memory segments that are read-only */ if ((mappings[i].flags & (PF_ANONYMOUS|PF_W)) == 0) { filesz = 0; } phdr.p_filesz = filesz; phdr.p_flags = mappings[i].flags & PF_MASK; if (writer(handle, &phdr, sizeof(Phdr)) != sizeof(Phdr)) { goto done; } } } /* Write note section */ /* scope */ { Nhdr nhdr; memset(&nhdr, 0, sizeof(Nhdr)); nhdr.n_namesz = 4; nhdr.n_descsz = sizeof(struct prpsinfo); nhdr.n_type = NT_PRPSINFO; if (writer(handle, &nhdr, sizeof(Nhdr)) != sizeof(Nhdr) || writer(handle, "CORE", 4) != 4 || writer(handle, prpsinfo, sizeof(struct prpsinfo)) != sizeof(struct prpsinfo)) { goto done; } nhdr.n_descsz = sizeof(struct user); nhdr.n_type = NT_PRXREG; if (writer(handle, &nhdr, sizeof(Nhdr)) != sizeof(Nhdr) || writer(handle, "CORE", 4) != 4 || writer(handle, user, sizeof(struct user)) !=sizeof(struct user)){ goto done; } for (i = num_threads; i-- > 0; ) { /* Process status and integer registers */ nhdr.n_descsz = sizeof(struct prstatus); nhdr.n_type = NT_PRSTATUS; prstatus->pr_pid = pids[i]; prstatus->pr_reg = regs[i]; if (writer(handle, &nhdr, sizeof(Nhdr)) != sizeof(Nhdr) || writer(handle, "CORE", 4) != 4 || writer(handle, prstatus, sizeof(struct prstatus)) != sizeof(struct prstatus)) { goto done; } /* FPU registers */ nhdr.n_descsz = sizeof(struct fpregs); nhdr.n_type = NT_FPREGSET; if (writer(handle, &nhdr, sizeof(Nhdr)) != sizeof(Nhdr) || writer(handle, "CORE", 4) != 4 || writer(handle, fpregs+1, sizeof(struct fpregs)) != sizeof(struct fpregs)) { goto done; } /* SSE registers */ #if defined(__i386__) && !defined( __x86_64__) /* Linux on x86-64 stores all FPU registers in the SSE structure */ if (fpxregs) { nhdr.n_namesz = 8; nhdr.n_descsz = sizeof(struct fpxregs); nhdr.n_type = NT_PRXFPREG; if (writer(handle, &nhdr, sizeof(Nhdr)) != sizeof(Nhdr) || writer(handle, "LINUX\000\000", 8) != 8 || writer(handle, fpxregs+1, sizeof(struct fpxregs)) != sizeof(struct fpxregs)) { goto done; } nhdr.n_namesz = 4; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -