📄 elfcore.c
字号:
/* Copyright (c) 2005-2007, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Markus Gutschke */#include "elfcore.h"#if defined DUMPER#include <elf.h>#include <fcntl.h>#include <limits.h>#include <pthread.h>#include <signal.h>#include <stdint.h>#include <stdlib.h>#include <string.h>#include <sys/poll.h>#include <sys/prctl.h>#include <sys/socket.h>#include <sys/sysctl.h>#include <sys/time.h>#include <sys/uio.h>#include <sys/wait.h>#include "google/coredumper.h"#include "linux_syscall_support.h"#include "linuxthreads.h"#include "thread_lister.h"#ifndef CLONE_UNTRACED#define CLONE_UNTRACED 0x00800000#endif/* Data structures found in x86-32/64 and ARM core dumps on Linux; similar * data structures are defined in /usr/include/{linux,asm}/... but those * headers conflict with the rest of the libc headers. So we cannot * include them here. */#if defined(__i386__) || defined(__x86_64__) #if !defined(__x86_64__) typedef struct fpregs { /* FPU registers */ uint32_t cwd; uint32_t swd; uint32_t twd; uint32_t fip; uint32_t fcs; uint32_t foo; uint32_t fos; uint32_t st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ } fpregs; typedef struct fpxregs { /* SSE registers */ #define FPREGS fpxregs #else typedef struct fpxregs { /* x86-64 stores FPU registers in SSE struct */ } fpxregs; typedef struct fpregs { /* FPU registers */ #define FPREGS fpregs #endif uint16_t cwd; uint16_t swd; uint16_t twd; uint16_t fop; uint32_t fip; uint32_t fcs; uint32_t foo; uint32_t fos; uint32_t mxcsr; uint32_t mxcsr_mask; uint32_t st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ uint32_t xmm_space[64]; /* 16*16 bytes for each XMM-reg = 128 bytes */ uint32_t padding[24]; } FPREGS; #undef FPREGS #define regs i386_regs /* General purpose registers */#elif defined(__ARM_ARCH_3__) typedef struct fpxregs { /* No extended FPU registers on ARM */ } fpxregs; typedef struct fpregs { /* FPU registers */ struct fp_reg { unsigned int sign1:1; unsigned int unused:15; unsigned int sign2:1; unsigned int exponent:14; unsigned int j:1; unsigned int mantissa1:31; unsigned int mantissa0:32; } fpregs[8]; unsigned int fpsr:32; unsigned int fpcr:32; unsigned char ftype[8]; unsigned int init_flag; } fpregs; #define regs arm_regs /* General purpose registers */#endiftypedef struct elf_timeval { /* Time value with microsecond resolution */ long tv_sec; /* Seconds */ long tv_usec; /* Microseconds */} elf_timeval;typedef struct elf_siginfo { /* Information about signal (unused) */ int32_t si_signo; /* Signal number */ int32_t si_code; /* Extra code */ int32_t si_errno; /* Errno */} elf_siginfo;typedef struct prstatus { /* Information about thread; includes CPU reg*/ elf_siginfo pr_info; /* Info associated with signal */ uint16_t pr_cursig; /* Current signal */ unsigned long pr_sigpend; /* Set of pending signals */ unsigned long pr_sighold; /* Set of held signals */ pid_t pr_pid; /* Process ID */ pid_t pr_ppid; /* Parent's process ID */ pid_t pr_pgrp; /* Group ID */ pid_t pr_sid; /* Session ID */ elf_timeval pr_utime; /* User time */ elf_timeval pr_stime; /* System time */ elf_timeval pr_cutime; /* Cumulative user time */ elf_timeval pr_cstime; /* Cumulative system time */ regs pr_reg; /* CPU registers */ uint32_t pr_fpvalid; /* True if math co-processor being used */} prstatus;typedef struct prpsinfo { /* Information about process */ unsigned char pr_state; /* Numeric process state */ char pr_sname; /* Char for pr_state */ unsigned char pr_zomb; /* Zombie */ signed char pr_nice; /* Nice val */ unsigned long pr_flag; /* Flags */#ifdef __x86_64__ uint32_t pr_uid; /* User ID */ uint32_t pr_gid; /* Group ID */#else uint16_t pr_uid; /* User ID */ uint16_t pr_gid; /* Group ID */#endif pid_t pr_pid; /* Process ID */ pid_t pr_ppid; /* Parent's process ID */ pid_t pr_pgrp; /* Group ID */ pid_t pr_sid; /* Session ID */ char pr_fname[16]; /* Filename of executable */ char pr_psargs[80]; /* Initial part of arg list */} prpsinfo;typedef struct user { /* Ptrace returns this data for thread state */ regs regs; /* CPU registers */ unsigned long fpvalid; /* True if math co-processor being used */#if defined(__i386__) || defined(__x86_64__) fpregs fpregs; /* FPU registers */#endif unsigned long tsize; /* Text segment size in pages */ unsigned long dsize; /* Data segment size in pages */ unsigned long ssize; /* Stack segment size in pages */ unsigned long start_code; /* Starting virtual address of text */ unsigned long start_stack; /* Starting virtual address of stack area */ unsigned long signal; /* Signal that caused the core dump */ unsigned long reserved; /* No longer used */ regs *regs_ptr; /* Used by gdb to help find the CPU registers*/#if defined(__i386__) || defined(__x86_64__) fpregs *fpregs_ptr; /* Pointer to FPU registers */#endif unsigned long magic; /* Magic for old A.OUT core files */ char comm[32]; /* User command that was responsible */ unsigned long debugreg[8];#if defined(__i386__) || defined(__x86_64__) unsigned long error_code; /* CPU error code or 0 */ unsigned long fault_address; /* CR3 or 0 */#elif defined(__ARM_ARCH_3__) fpregs fpregs; /* FPU registers */ fpregs *fpregs_ptr; /* Pointer to FPU registers */#endif} user;#if __WORDSIZE == 64 #define ELF_CLASS ELFCLASS64 #define Ehdr Elf64_Ehdr #define Phdr Elf64_Phdr #define Shdr Elf64_Shdr #define Nhdr Elf64_Nhdr#else #define ELF_CLASS ELFCLASS32 #define Ehdr Elf32_Ehdr #define Phdr Elf32_Phdr #define Shdr Elf32_Shdr #define Nhdr Elf32_Nhdr#endif#if defined(__x86_64__) #define ELF_ARCH EM_X86_64#elif defined(__i386__) #define ELF_ARCH EM_386#elif defined(__ARM_ARCH_3__) #define ELF_ARCH EM_ARM#endif/* Re-runs fn until it doesn't cause EINTR */#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)#define MY_NO_INTR(fn) do {} while ((fn) < 0 && my_errno == EINTR)/* Wrapper for read() which is guaranteed to never return EINTR. */static ssize_t c_read(int f, void *buf, size_t bytes, int *errno_) { int my_errno; /* scope */ { /* Define a private copy of syscall macros, which does not modify the * global copy of errno. */ #define SYS_ERRNO my_errno #define SYS_INLINE inline #undef SYS_LINUX_SYSCALL_SUPPORT_H #define SYS_PREFIX 0 #include "linux_syscall_support.h" if (bytes > 0) { ssize_t rc; MY_NO_INTR(rc = sys0_read(f, buf, bytes)); if (rc < 0) { *errno_ = my_errno; } return rc; } return 0; }}/* Wrapper for write() which is guaranteed to never return EINTR nor * short writes. */static ssize_t c_write(int f, const void *void_buf, size_t bytes, int *errno_){ int my_errno; /* scope */ { /* Define a private copy of syscall macros, which does not modify the * global copy of errno. */ #define SYS_ERRNO my_errno #define SYS_INLINE inline #undef SYS_LINUX_SYSCALL_SUPPORT_H #define SYS_PREFIX 0 #include "linux_syscall_support.h" const unsigned char *buf = (const unsigned char*)void_buf; size_t len = bytes; while (len > 0) { ssize_t rc; MY_NO_INTR(rc = sys0_write(f, buf, len)); if (rc < 0) { *errno_ = my_errno; return rc; } else if (rc == 0) { break; } buf += rc; len -= rc; } return bytes - len; }}/* The simple synchronous writer is only used when outputting to a pipe * instead of a file. In that case, we do not enforce a pre-determined * maximum output size. */static int SimpleDone(void *f) { return 0;}/* Simple synchronous writer function used by CreateElfCore() when writing * directly to a pipe. */static ssize_t SimpleWriter(void *f, const void *void_buf, size_t bytes) { return c_write(*(int *)f, void_buf, bytes, &errno);}struct WriterFds { size_t max_length; int write_fd; int compressed_fd; int out_fd;};/* Checks whether the maximum number of allowed bytes has been written * to the output file already. */static int PipeDone(void *f) { struct WriterFds *fds = (struct WriterFds *)f; return fds->max_length == 0;}/* Writer function that writes directly to a file and honors size limits. */static ssize_t LimitWriter(void *f, const void *void_buf, size_t bytes) { struct WriterFds *fds = (struct WriterFds *)f; ssize_t rc; if (bytes > fds->max_length) { bytes = fds->max_length; } rc = c_write(fds->out_fd, void_buf, bytes, &errno); if (rc > 0) { fds->max_length -= rc; } return rc;}/* Writer function that can handle writing to one end of a compression * pipeline, reading from the other end of the pipe as compressed data * becomes available, and finally outputting it to a file. */static ssize_t PipeWriter(void *f, const void *void_buf, size_t bytes) { const unsigned char *buf = (const unsigned char *)void_buf; struct WriterFds *fds = (struct WriterFds *)f; size_t len = bytes; while (fds->max_length > 0 && len > 0) { ssize_t rc; struct pollfd pfd[2] = { { fds->compressed_fd, POLLIN, 0 }, { fds->write_fd, POLLOUT, 0 } }; int nfds = sys_poll(pfd, 2, -1); if (nfds < 0) { /* Abort on fatal unexpected I/O errors. */ break; } if (nfds > 0 && (pfd[0].revents & POLLIN)) { /* Some compressed data has become available. Copy to output file. */ char scratch[4096]; for (;;) { size_t l = sizeof(scratch); if (l > fds->max_length) { l = fds->max_length; } NO_INTR(rc = read(fds->compressed_fd, scratch, l)); if (rc < 0) { /* The file handle is set to be non-blocking, so we loop until * read() returns -1. */ if (errno == EAGAIN) { break; } return -1; } else if (rc == 0) { fds->max_length = 0; break; } rc = c_write(fds->out_fd, scratch, rc, &errno); if (rc <= 0) { return -1; } fds->max_length -= rc; } nfds--; } if (nfds > 0 && (pfd[1].revents & POLLOUT)) { /* The compressor has consumed all previous data and is ready to * receive more. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -