📄 elfcore.c
字号:
prpsinfo.pr_uid = sys_geteuid(); prpsinfo.pr_gid = sys_getegid(); prpsinfo.pr_pid = main_pid; prpsinfo.pr_ppid = sys_getppid(); prpsinfo.pr_pgrp = sys_getpgrp(); prpsinfo.pr_sid = sys_getsid(0); /* scope */ { char scratch[4096], *cmd = scratch, *ptr; ssize_t size, len; int cmd_fd; memset(&scratch, 0, sizeof(scratch)); size = sys_readlink("/proc/self/exe", scratch, sizeof(scratch)); len = 0; for (ptr = cmd; *ptr != '\000' && size-- > 0; ptr++) { if (*ptr == '/') { cmd = ptr+1; len = 0; } else len++; } memcpy(prpsinfo.pr_fname, cmd, len > sizeof(prpsinfo.pr_fname) ? sizeof(prpsinfo.pr_fname) : len); NO_INTR(cmd_fd = sys_open("/proc/self/cmdline", O_RDONLY, 0)); if (cmd_fd >= 0) { char *ptr; ssize_t size = c_read(cmd_fd, &prpsinfo.pr_psargs, sizeof(prpsinfo.pr_psargs), &errno); for (ptr = prpsinfo.pr_psargs; size-- > 0; ptr++) if (*ptr == '\000') *ptr = ' '; NO_INTR(sys_close(cmd_fd)); } } /* Build the PRSTATUS data structure */ /* scope */ { int stat_fd; 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); sigset_t old_signals, blocked_signals; const char *file_name = va_arg(ap, const char *); size_t max_length = va_arg(ap, size_t); const char *PATH = va_arg(ap, const char *); const struct CoredumperCompressor *compressors = va_arg(ap, const struct CoredumperCompressor *); const struct CoredumperCompressor **selected_compressor = va_arg(ap, const struct CoredumperCompressor **); 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. */ 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 iovec iov; struct 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. */ if (!GetParentRegs(frame, thread_regs, thread_fpregs, thread_fpxregs, &hasSSE)) { sys__exit(1); } CreateElfCore(&fds[1], SimpleWriter, SimpleDone, &prpsinfo, &user, &prstatus, threads, pids, thread_regs, thread_fpregs, hasSSE ? thread_fpxregs : NULL, pagesize); NO_INTR(sys_close(fds[1])); sys__exit(0); /* Make the compiler happy. We never actually get here. */ return 0; } else if (rc > 0) { #ifndef THREADS /* Child will double-fork, so reap the process, now. */ sys_waitpid(rc, (void *)0, __WALL); #endif } /* In the parent */ sys_sigprocmask(SIG_SETMASK, &old_signals, (void *)0); NO_INTR(sys_close(pair[1])); /* Get pipe file handle from child */ /* scope */ { void *buffer[1]; char cmsg_buf[CMSG_SPACE(sizeof(int))]; struct iovec iov; struct msghdr msg; for (;;) { int nbytes; memset(&iov, 0, sizeof(iov)); memset(&msg, 0, sizeof(msg)); iov.iov_base = buffer; iov.iov_len = sizeof(void *); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &cmsg_buf; msg.msg_controllen = sizeof(cmsg_buf); if ((nbytes = sys_recvmsg(pair[0], &msg, 0)) > 0) { struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); if (cmsg != NULL && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) fd = *(int *)CMSG_DATA(cmsg); if (nbytes == sizeof(void *) && *buffer != NULL && selected_compressor != NULL) *selected_compressor = *buffer; break; } else if (nbytes == 0 || errno != EINTR) { break; } } } sys_shutdown(pair[0], SHUT_RDWR); NO_INTR(sys_close(pair[0])); } } else { /* Synchronously write the core to a file. If necessary, compress the * data on the fly. All other threads are suspended during this time. * In principle, we could use the same code that we used earlier for * building a core file on the fly. But that results in creating a COW * copy of the address space (as a result of the call to fork()), and * some accounting applications are sensitive to the sudden spike in * memory usage. * So, instead, we run a single thread and make use of callback * functions that internally invoke poll() for managing the I/O. */ int fds[2] = { -1, -1 }; int saved_errno, rc; const char *suffix = ""; struct WriterFds writer_fds; ssize_t (*writer)(void *, const void *, size_t); /* 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. */ if (!GetParentRegs(frame, thread_regs, thread_fpregs, thread_fpxregs, &hasSSE)) { goto error; } /* Create a pipe for communicating between processes. If * necessary, add a compressor to the pipeline. */ if (compressors != NULL && compressors->compressor != NULL) { if (CreatePipeline(fds, openmax, PATH, &compressors) < 0) { goto error; } } if (selected_compressor) { *selected_compressor = compressors; } writer_fds.out_fd = -1; if (max_length > 0) { /* Open the output file. If necessary, pick a filename suffix that * matches the selected compression type. */ if (compressors != NULL && compressors->compressor != NULL && compressors->suffix != NULL) { suffix = compressors->suffix; } /* scope */ { char extended_file_name[strlen(file_name) + strlen(suffix) + 1]; strcat(strcpy(extended_file_name, file_name), suffix); NO_INTR(writer_fds.out_fd = sys_open(extended_file_name, O_WRONLY|O_CREAT|O_TRUNC, 0600)); if (writer_fds.out_fd < 0) { saved_errno = errno; if (fds[0] >= 0) NO_INTR(sys_close(fds[0])); if (fds[1] >= 0) NO_INTR(sys_close(fds[1])); errno = saved_errno; goto error; } } /* Set up a suitable writer funtion. */ writer_fds.max_length = max_length; if (fds[0] >= 0) { /* The PipeWriter() can deal with multi I/O requests on the * compression pipeline. */ long flags; NO_INTR(flags = sys_fcntl(fds[0], F_GETFL, 0)); NO_INTR(sys_fcntl(fds[0], F_SETFL, flags | O_NONBLOCK)); NO_INTR(flags = sys_fcntl(fds[1], F_GETFL, 0)); NO_INTR(sys_fcntl(fds[1], F_SETFL, flags | O_NONBLOCK)); writer_fds.write_fd = fds[1]; writer_fds.compressed_fd = fds[0]; writer = PipeWriter; } else { /* If no compression is needed, then we can directly write to the * file. This avoids quite a bit of unnecessary overhead. */ writer = LimitWriter; } rc = CreateElfCore(&writer_fds, writer, PipeDone, &prpsinfo, &user, &prstatus, threads, pids, thread_regs, thread_fpregs, hasSSE ? thread_fpxregs : NULL, pagesize); if (fds[0] >= 0) { saved_errno = errno; /* Close the input side of the compression pipeline, and flush * the remaining compressed data bytes out to the file. */ if (fds[1] >= 0) { NO_INTR(sys_close(fds[1])); fds[1] = -1; } if (FlushPipe(&writer_fds) < 0) { rc = -1; } else { errno = saved_errno; } } } else { rc = 0; } /* Close all remaining open file handles. */ saved_errno = errno; if (writer_fds.out_fd >= 0) NO_INTR(sys_close(writer_fds.out_fd)); if (fds[0] >= 0) NO_INTR(sys_close(fds[0])); if (fds[1] >= 0) NO_INTR(sys_close(fds[1])); errno = saved_errno; if (rc < 0) { goto error; } /* If called with a filename, we do not actually return a file handle, * but instead just signal whether the core file has been written * successfully. */ fd = 0; } } ResumeAllProcessThreads(threads, pids); return fd;error: /* scope */ { int saved_errno = errno; if (fd > 0) NO_INTR(sys_close(fd)); errno = saved_errno; } ResumeAllProcessThreads(threads, pids); return -1;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -