⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elfcore.c

📁 能把所有线程的数据和环境记录到文件,方便调试.
💻 C
📖 第 1 页 / 共 4 页
字号:
            #endif          }        }        /* Align all following segments to multiples of page size            */        if (note_align) {          char scratch[note_align];          memset(scratch, 0, sizeof(scratch));          if (writer(handle, scratch, sizeof(scratch)) != sizeof(scratch)) {            goto done;          }        }        /* Write all memory segments                                         */        for (i = 0; i < num_mappings; i++) {          if (mappings[i].flags & (PF_ANONYMOUS|PF_W) &&              writer(handle, (void *)mappings[i].start_address,                     mappings[i].end_address - mappings[i].start_address) !=                     mappings[i].end_address - mappings[i].start_address) {            goto done;          }        }        rc = 0;      }    }  }done:  if (is_done(handle)) {    rc = 0;  }  if (loopback[0] >= 0)    NO_INTR(sys_close(loopback[0]));  if (loopback[1] >= 0)    NO_INTR(sys_close(loopback[1]));  return rc;}struct CreateArgs {  int *fds;  int openmax;  const char *PATH;  const struct CoredumperCompressor* compressors;  int zip_in[2];  int zip_out[2];};static int CreatePipelineChild(void *void_arg) {  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"      struct CreateArgs *args = (struct CreateArgs *)void_arg;    int i;        /* Use pipe to tell parent about the compressor that we chose.     * Make sure the file handle for the write-end of the pipe is     * bigger than 2, so that it does not interfere with the     * stdin/stdout/stderr file handles which must be 0-2.     */    MY_NO_INTR(sys0_close(args->fds[0]));    while (args->fds[1] <= 2) {      MY_NO_INTR(args->fds[1] = sys0_dup(args->fds[1]));    }    sys0_fcntl(args->fds[1], F_SETFD, FD_CLOEXEC);        /* Move the filehandles for stdin/stdout/stderr, so that they     * map to handles 0-2. stdin/stdout are connected to pipes, and     * stderr points to "/dev/null".     */    while (args->zip_in[0]  <= 2) {      MY_NO_INTR(args->zip_in[0]  = sys0_dup(args->zip_in[0]));    }    while (args->zip_out[1] <= 2) {      MY_NO_INTR(args->zip_out[1] = sys0_dup(args->zip_out[1]));    }    MY_NO_INTR(sys0_dup2(args->zip_in[0],  0));    MY_NO_INTR(sys0_dup2(args->zip_out[1], 1));    MY_NO_INTR(sys0_close(2));    MY_NO_INTR(sys0_dup2(sys0_open("/dev/null", O_WRONLY, 0), 2));      /* Close all handles other than stdin/stdout/stderr and the     * pipe to the parent. This also takes care of all the filehandles     * that we temporarily created by calling sys_dup().     */    for (i = 3; i < args->openmax; i++)      if (i != args->fds[1])        MY_NO_INTR(sys0_close(i));      while (args->compressors->compressor != NULL &&           *args->compressors->compressor) {      extern char **environ;            const char        *compressor = args->compressors->compressor;      const char *const *cmd_args   = args->compressors->args;            /* Try next compressor description. If the compressor exists,       * the fds[1] file handle will get closed on exec(). The       * parent detects this, and eventually updates       * selected_compressor with the compressor that is now running.       *       * Please note, the caller does not need to call wait() for any       * compressor that gets launched, because our parent process is       * going to die soon; thus, the compressor will be reaped by "init".       */      c_write(args->fds[1], &args->compressors, sizeof(&args->compressors),              &my_errno);      if (strchr(compressor, '/')) {        /* Absolute or relative path precedes name of executable             */        sys0_execve(compressor, cmd_args, (const char * const *)environ);      } else {        /* Search for executable along PATH variable                         */        const char *ptr = args->PATH;        if (ptr != NULL) {          for (;;) {            const char *end = ptr;            while (*end && *end != ':') end++;            if (ptr == end) {              /* Found current directory in PATH                             */              sys0_execve(compressor, cmd_args, (const char * const *)environ);            } else {              /* Compute new file name                                       */              char executable[strlen(compressor) + (end - ptr) + 2];              memcpy(executable, ptr, end-ptr);              executable[end - ptr] = '/';              strcpy(executable + (end - ptr + 1), compressor);              sys0_execve(executable, cmd_args, (const char * const *)environ);            }            if (!*end)              break;            ptr = end + 1;          }        }      }      ++args->compressors;    }      /* No suitable compressor found. Tell parent about it.                   */    c_write(args->fds[1], &args->compressors, sizeof(&args->compressors),            &my_errno);    MY_NO_INTR(sys0_close(args->fds[1]));    sys__exit(0);    return 0;  }}/* Create a pipeline for sending the core file from the child process back to * the caller. Optionally include a compressor program in the loop. The * "compressors" variable will be updated to point to the compressor that was * actually used. */static int CreatePipeline(int *fds, int openmax, const char *PATH,                          const struct CoredumperCompressor** compressors) {  /* Create a pipe for communicating between processes                       */  if (sys_pipe(fds) < 0)    return -1;  /* Find a suitable compressor program, if necessary                        */  if (*compressors != NULL && (*compressors)->compressor != NULL) {    char stack[4096];    struct CreateArgs args;    pid_t comp_pid;    args.fds         = fds;    args.openmax     = openmax;    args.PATH        = PATH;    args.compressors = *compressors;    if (sys_pipe(args.zip_in) < 0) {   fail0: {        int saved_errno = errno;        NO_INTR(sys_close(fds[0]));        NO_INTR(sys_close(fds[1]));        errno = saved_errno;        return -1;      }    } else if (sys_pipe(args.zip_out) < 0) {   fail1: {        int saved_errno = errno;        NO_INTR(sys_close(args.zip_in[0]));        NO_INTR(sys_close(args.zip_in[1]));        errno = saved_errno;        goto fail0;      }    }    /* We use clone() here, instead of the more common fork(). This ensures     * that the WriteCoreDump() code path never results in making a COW     * instance of the processes' address space. This increases the likelihood     * that we can dump core files even if we are using a lot of memory and     * the kernel disallows overcomitting of memory.     * After cloning, both the parent and the child share the same instance     * of errno. We must make sure that at least one of these processes     * (in our case, the child) uses modified syscall macros that update     * a local copy of errno, instead.     */    comp_pid = sys_clone(CreatePipelineChild, stack + sizeof(stack) - 16,                         CLONE_VM|CLONE_UNTRACED|SIGCHLD, &args, 0, 0, 0);    if (comp_pid < 0) {      int clone_errno = errno;      NO_INTR(sys_close(args.zip_out[0]));      NO_INTR(sys_close(args.zip_out[1]));      errno = clone_errno;      goto fail1;    }    /* Close write-end of pipe, and read from read-end until child closes     * its reference to the pipe.     */    NO_INTR(sys_close(fds[1]));    *compressors = NULL;    while (c_read(fds[0], compressors, sizeof(*compressors), &errno)) {    }    NO_INTR(sys_close(fds[0]));        /* Fail if either the child never even executed (unlikely), or     * did not find any compressor that could be executed.     */    if (*compressors == NULL || (*compressors)->compressor == NULL) {      int saved_errno1 = errno;      NO_INTR(sys_close(args.zip_out[0]));      NO_INTR(sys_close(args.zip_out[1]));      errno = saved_errno1;   fail2: {        int saved_errno2 = errno;        NO_INTR(sys_close(args.zip_in[0]));        NO_INTR(sys_close(args.zip_in[1]));        errno = saved_errno2;        return -1;      }    }        if (*(*compressors)->compressor) {      /* Found a good compressor program, which is now connected to       * zip_in/zip_out.       */      fds[0] = args.zip_out[0];      fds[1] = args.zip_in[1];      NO_INTR(sys_close(args.zip_in[0]));      NO_INTR(sys_close(args.zip_out[1]));    } else {      /* No suitable compressor found, but the caller allowed       * uncompressed core files. So, just close unneeded file handles,       * and reap the child's exit code.       */      int status;      fds[0] = -1;      fds[1] = -1;      NO_INTR(sys_close(args.zip_in[0]));NO_INTR(sys_close(args.zip_out[0]));      NO_INTR(sys_close(args.zip_in[1]));NO_INTR(sys_close(args.zip_out[1]));      while (sys_waitpid(comp_pid, &status, 0) < 0) {        if (errno != EINTR) {          goto fail2;        }      }    }  }  return 0;}/* If this code is being built without support for multi-threaded core files, * some of our basic assumptions are not quite right. Most noticably, the * fake thread lister ends up calling InternalGetCoreDump() from the main * (i.e. only) thread in the application, which cannot be ptrace()'d at this * time. This prevents us from retrieving CPU registers. * * We work around this problem by delaying the call to ptrace() until we * have forked. We also need to double-fork here, in order to make sure that * the core writer process can get reaped by "init" after it reaches EOF. */static inline int GetParentRegs(void *frame, regs *cpu, fpregs *fp,                                fpxregs *fpx, int *hasSSE) {#ifdef THREADS  return 1;#else  int rc = 0;  char scratch[4096];  pid_t pid = getppid();  if (sys_ptrace(PTRACE_ATTACH, pid, (void *)0, (void *)0) == 0 &&      waitpid(pid, (void *)0, __WALL) >= 0) {    memset(scratch, 0xFF, sizeof(scratch));    if (sys_ptrace(PTRACE_GETREGS, pid, scratch, scratch) == 0) {      memcpy(cpu, scratch, sizeof(struct regs));      SET_FRAME(*(Frame *)frame, *cpu);      memset(scratch, 0xFF, sizeof(scratch));      if (sys_ptrace(PTRACE_GETFPREGS, pid, scratch, scratch) == 0) {        memcpy(fp, scratch, sizeof(struct fpregs));        memset(scratch, 0xFF, sizeof(scratch));        #if defined(__i386__) && !defined( __x86_64__)        /* Linux on x86-64 stores all FPU registers in the SSE structure     */        if (sys_ptrace(PTRACE_GETFPXREGS, pid, scratch, scratch) == 0) {          memcpy(fpx, scratch, sizeof(struct fpxregs));        } else {          *hasSSE = 0;        }        #else        *hasSSE = 0;        #endif        rc = 1;      }    }  }  sys_ptrace_detach(pid);  /* Need to double-fork, so that "init" can reap the core writer upon EOF.  */  switch (sys_fork()) {    case -1:      return 0;    case 0:      return rc;    default:      sys__exit(0);  }#endif}/* Internal function for generating a core file. This function works for * both single- and multi-threaded core files. It assumes that all threads * are already suspended, and will resume them before returning. * * The caller must make sure that prctl(PR_SET_DUMPABLE, 1) has been called, * or this function might fail. */int InternalGetCoreDump(void *frame, int num_threads, pid_t *pids,                        va_list ap                     /* const char *file_name, size_t max_length,                        const char *PATH,                        const struct CoredumperCompressor *compressors,                        const struct CoredumperCompressor **selected_comp */) {  long          i;  int           rc = -1, fd = -1, threads = num_threads, hasSSE = 1;  user          user;  prpsinfo      prpsinfo;  prstatus      prstatus;  regs          thread_regs[threads];  fpregs        thread_fpregs[threads];  fpxregs       thread_fpxregs[threads];  int           pair[2];  int           main_pid = ((Frame *)frame)->tid;  /* Get thread status                                                       */  memset(thread_regs,    0, threads * sizeof(struct regs));  memset(thread_fpregs,  0, threads * sizeof(struct fpregs));  memset(thread_fpxregs, 0, threads * sizeof(struct fpxregs));  /* Threads are already attached, read their registers now                  */#ifdef THREADS  for (i = 0; i < threads; i++) {    char scratch[4096];    memset(scratch, 0xFF, sizeof(scratch));    if (sys_ptrace(PTRACE_GETREGS, pids[i], scratch, scratch) == 0) {      memcpy(thread_regs + i, scratch, sizeof(struct regs));      if (main_pid == pids[i])        SET_FRAME(*(Frame *)frame, thread_regs[i]);      memset(scratch, 0xFF, sizeof(scratch));      if (sys_ptrace(PTRACE_GETFPREGS, pids[i], scratch, scratch) == 0) {        memcpy(thread_fpregs + i, scratch, sizeof(struct fpregs));        memset(scratch, 0xFF, sizeof(scratch));        #if defined(__i386__) && !defined( __x86_64__)        /* Linux on x86-64 stores all FPU registers in the SSE structure     */        if (sys_ptrace(PTRACE_GETFPXREGS, pids[i], scratch, scratch) == 0) {          memcpy(thread_fpxregs + i, scratch, sizeof(struct fpxregs));        } else {          hasSSE = 0;        }        #else        hasSSE = 0;        #endif      } else        goto ptrace;    } else {   ptrace: /* Oh, well, undo everything and get out of here                  */      ResumeAllProcessThreads(threads, pids);      goto error;    }  }  /* Get parent's CPU registers, and user data structure                 */  for (i = 0; i < sizeof(struct user); i += sizeof(int))    sys_ptrace(PTRACE_PEEKUSER, pids[0], (void *)i,               ((int *)&user) + i/sizeof(int));  memcpy(&user.regs, thread_regs, sizeof(struct regs));#endif  /* Build the PRPSINFO data structure                                       */  memset(&prpsinfo, 0, sizeof(struct prpsinfo));  prpsinfo.pr_sname = 'R';  prpsinfo.pr_nice  = sys_getpriority(PRIO_PROCESS, 0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -