Devel-CoreDump

 view release on metacpan or  search on metacpan

src/elfcore.c  view on Meta::CPAN

    memset(&prstatus, 0, sizeof(struct prstatus));
    prstatus.pr_pid     = prpsinfo.pr_pid;
    prstatus.pr_ppid    = prpsinfo.pr_ppid;
    prstatus.pr_pgrp    = prpsinfo.pr_pgrp;
    prstatus.pr_sid     = prpsinfo.pr_sid;
    prstatus.pr_fpvalid = 1;
    NO_INTR(stat_fd = sys_open("/proc/self/stat", O_RDONLY, 0));
    if (stat_fd >= 0) {
      char scratch[4096];
      ssize_t size = c_read(stat_fd, scratch, sizeof(scratch) - 1, &errno);
      if (size >= 0) {
        unsigned long tms;
        char *ptr = scratch;
        scratch[size] = '\000';

        /* User time                                                         */
        for (i = 13; i && *ptr; ptr++) if (*ptr == ' ') i--;
        tms = 0;
        while (*ptr && *ptr != ' ') tms = 10*tms + *ptr++ - '0';
        prstatus.pr_utime.tv_sec  = tms / 1000;
        prstatus.pr_utime.tv_usec = (tms % 1000) * 1000;

        /* System time                                                       */
        if (*ptr) ptr++;
        tms = 0;
        while (*ptr && *ptr != ' ') tms = 10*tms + *ptr++ - '0';
        prstatus.pr_stime.tv_sec  = tms / 1000;
        prstatus.pr_stime.tv_usec = (tms % 1000) * 1000;

        /* Cumulative user time                                              */
        if (*ptr) ptr++;
        tms = 0;
        while (*ptr && *ptr != ' ') tms = 10*tms + *ptr++ - '0';
        prstatus.pr_cutime.tv_sec  = tms / 1000;
        prstatus.pr_cutime.tv_usec = (tms % 1000) * 1000;

        /* Cumulative system time                                            */
        if (*ptr) ptr++;
        tms = 0;
        while (*ptr && *ptr != ' ') tms = 10*tms + *ptr++ - '0';
        prstatus.pr_cstime.tv_sec  = tms / 1000;
        prstatus.pr_cstime.tv_usec = (tms % 1000) * 1000;

        /* Pending signals                                                   */
        for (i = 14; i && *ptr; ptr++) if (*ptr == ' ') i--;
        while (*ptr && *ptr != ' ')
          prstatus.pr_sigpend = 10*prstatus.pr_sigpend + *ptr++ - '0';

        /* Held signals                                                      */
        if (*ptr) ptr++;
        while (*ptr && *ptr != ' ')
          prstatus.pr_sigpend = 10*prstatus.pr_sigpend + *ptr++ - '0';
      }
      NO_INTR(sys_close(stat_fd));
    }
  }

  /* scope */ {
    int openmax  = sys_sysconf(_SC_OPEN_MAX);
    int pagesize = sys_sysconf(_SC_PAGESIZE);
    struct kernel_sigset_t old_signals, blocked_signals;

    const struct CoreDumpParameters *params =
      va_arg(ap, const struct CoreDumpParameters *);
    const char *file_name =
      va_arg(ap, const char *);
    size_t max_length =
      GetCoreDumpParameter(params, max_length);
    const char *PATH =
      va_arg(ap, const char *);
    const struct CoredumperCompressor *compressors =
      GetCoreDumpParameter(params, compressors);
    const struct CoredumperCompressor **selected_compressor =
      (const struct CoredumperCompressor **)GetCoreDumpParameter(
          params, selected_compressor);
    int prioritize =
      GetCoreDumpParameter(params, flags) & COREDUMPER_FLAG_LIMITED_BY_PRIORITY;
    const struct CoredumperNote *notes =
      GetCoreDumpParameter(params, notes);
    int note_count =
      GetCoreDumpParameter(params, note_count);

    if (selected_compressor != NULL) {
      /* For now, assume that the core dump is uncompressed; we will later
       * override this setting, if we can find a suitable compressor program.
       */
      *selected_compressor = compressors;
      while (*selected_compressor &&
             (*selected_compressor)->compressor != NULL) {
        ++*selected_compressor;
      }
    }

    if (file_name == NULL) {
      /* Create a file descriptor that can be used for reading data from
       * our child process. This is a little complicated because we need
       * to make sure there is no race condition with other threads
       * calling fork() at the same time (this is somewhat mitigated,
       * because our threads are supposedly suspended at this time). We
       * have to avoid other processes holding our file handles open. We
       * can do this by creating the pipe in the child and passing the
       * file handle back to the parent.
       */
      if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) >= 0) {
        /* Block signals prior to forking. Technically, POSIX requires
         * us to call pthread_sigmask(), if this is a threaded
         * application. When using glibc, we are OK calling
         * sigprocmask(), though. We will end up blocking additional
         * signals that libpthread uses internally, but that
         * is actually exactly what we want.
         *
         * Also, POSIX claims that this should not actually be
         * necessarily, but reality says otherwise.
         */
        sys_sigfillset(&blocked_signals);
        sys_sigprocmask(SIG_BLOCK, &blocked_signals, &old_signals);

        /* Create a new core dump in child process; call sys_fork() in order to
         * avoid complications with pthread_atfork() handlers. In the child
         * process, we should only ever call system calls.
         */
        if ((rc = sys_fork()) == 0) {
          int  fds[2];

          /* Create a pipe for communicating between processes. If
           * necessary, add a compressor to the pipeline.
           */
          if (CreatePipeline(fds, openmax, PATH, &compressors) < 0 ||
              (fds[0] < 0 && sys_pipe(fds) < 0)) {
            sys__exit(1);
          }

          /* Pass file handle to parent                                      */
          /* scope */ {
            char cmsg_buf[CMSG_SPACE(sizeof(int))];
            struct kernel_iovec  iov;
            struct kernel_msghdr msg;
            struct cmsghdr       *cmsg;
            memset(&iov, 0, sizeof(iov));
            memset(&msg, 0, sizeof(msg));
            iov.iov_base            = (void *)&compressors;
            iov.iov_len             = sizeof(compressors);
            msg.msg_iov             = &iov;
            msg.msg_iovlen          = 1;
            msg.msg_control         = &cmsg_buf;
            msg.msg_controllen      = sizeof(cmsg_buf);
            cmsg                    = CMSG_FIRSTHDR(&msg);
            if (!cmsg) {
              /* This can't happen, but static analyzers still complain...   */
              sys__exit(1);
            }
            cmsg->cmsg_level        = SOL_SOCKET;
            cmsg->cmsg_type         = SCM_RIGHTS;
            cmsg->cmsg_len          = CMSG_LEN(sizeof(int));
            *(int *)CMSG_DATA(cmsg) = fds[0];
            while (sys_sendmsg(pair[1], &msg, 0) < 0) {
              if (errno != EINTR)
                sys__exit(1);
            }
            while (sys_shutdown(pair[1], SHUT_RDWR) < 0) {
              if (errno != EINTR)
                sys__exit(1);
            }
          }

          /* Close all file handles other than the write end of our pipe     */
          for (i = 0; i < openmax; i++) {
            if (i != fds[1]) {
              NO_INTR(sys_close(i)); }
          }

          /* If compiled without threading support, this is the only
           * place where we can request the parent's CPU
           * registers. This function is a no-op when threading
           * support is available.
           */



( run in 0.666 second using v1.01-cache-2.11-cpan-39bf76dae61 )