#include <sys/param.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <machine/elf.h>
#include <machine/vmparam.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
static void killed(int);
static void restart_target(void);
static void usage(void) __dead2;
kvm_t *kd;
static pid_t pid;
ssize_t gcore_seg_limit = -1;
int gcore_verbose;
int
main(int argc, char **argv)
{
void *exec;
int ch, cnt, efd, fd, sflag;
char *binfile, *corefile;
char *eptr;
char fname[MAXPATHLEN + 1];
sflag = 0;
corefile = NULL;
while ((ch = getopt(argc, argv, "c:l:sv")) != -1) {
switch (ch) {
case 'c':
corefile = optarg;
break;
case 'l':
gcore_seg_limit = strtol(optarg, &eptr, 0);
switch(*eptr) {
case 0:
break;
case 't':
case 'T':
gcore_seg_limit *= 1024;
case 'g':
case 'G':
gcore_seg_limit *= 1024;
case 'm':
case 'M':
gcore_seg_limit *= 1024;
case 'k':
case 'K':
gcore_seg_limit *= 1024;
break;
default:
usage();
break;
}
break;
case 's':
sflag = 1;
break;
case 'v':
gcore_verbose = 1;
break;
default:
usage();
break;
}
}
argv += optind;
argc -= optind;
switch (argc) {
case 1:
pid = atoi(argv[0]);
asprintf(&binfile, "/proc/%d/file", pid);
if (binfile == NULL)
errx(1, "allocation failure");
break;
case 2:
pid = atoi(argv[1]);
binfile = argv[0];
break;
default:
usage();
}
efd = open(binfile, O_RDONLY, 0);
if (efd < 0)
err(1, "%s", binfile);
cnt = read(efd, &exec, sizeof(Elf_Ehdr));
if (cnt != sizeof(Elf_Ehdr))
errx(1, "%s exec header: %s",
binfile, cnt > 0 ? strerror(EIO) : strerror(errno));
if (IS_ELF(*(Elf_Ehdr *)&exec)) {
close(efd);
} else
errx(1, "Invalid executable file");
if (corefile == NULL) {
snprintf(fname, sizeof(fname), "core.%d", pid);
corefile = fname;
}
fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
if (fd < 0)
err(1, "%s", corefile);
if (sflag) {
signal(SIGHUP, killed);
signal(SIGINT, killed);
signal(SIGTERM, killed);
if (kill(pid, SIGSTOP) == -1)
err(1, "%d: stop signal", pid);
atexit(restart_target);
}
elf_coredump(fd, pid);
close(fd);
exit(0);
}
static void
killed(int sig)
{
restart_target();
signal(sig, SIG_DFL);
kill(getpid(), sig);
}
static void
restart_target(void)
{
kill(pid, SIGCONT);
}
void
usage(void)
{
fprintf(stderr,
"usage: gcore [-sv] [-c core] [-l seglimit] [executable] pid\n");
exit(1);
}