From 73e8f06ac523ee4b530e17d50cc580dc366f7ad8 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Sat, 24 Apr 2021 14:20:24 +0300 Subject: [PATCH] gcore: add option to dump core using kernel facility -k switch causes gcore to use ptrace(PT_COREDUMP) instead of manually reading process memory and constructing the core. Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D29955 --- usr.bin/gcore/gcore.1 | 16 +++++++-- usr.bin/gcore/gcore.c | 75 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 11 deletions(-) diff --git a/usr.bin/gcore/gcore.1 b/usr.bin/gcore/gcore.1 index 55db2aed3e3a..aa93a5ef1fe0 100644 --- a/usr.bin/gcore/gcore.1 +++ b/usr.bin/gcore/gcore.1 @@ -28,7 +28,7 @@ .\" @(#)gcore.1 8.2 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd July 13, 2016 +.Dd April 24, 2021 .Dt GCORE 1 .Os .Sh NAME @@ -37,6 +37,7 @@ .Sh SYNOPSIS .Nm .Op Fl f +.Op Fl k .Op Fl c Ar core .Op Ar executable .Ar pid @@ -58,13 +59,24 @@ The following options are available: Write the core file to the specified file instead of .Dq Pa core. . .It Fl f -Dumps all available segments, excluding only malformed and undumpable segments. +Dumps all available segments, excluding only malformed and undumpable +segments. Unlike the default invocation, this flag dumps mappings of devices which may invalidate the state of device transactions or trigger other unexpected behavior. As a result, this flag should only be used when the behavior of the application and any devices it has mapped is fully understood and any side effects can be controlled or tolerated. +.It Fl k +Use the +.Xr ptrace 2 +.Dv PT_COREDUMP +kernel facility to write the core dump, instead of reading the process' +memory and constructing the dump file in +.Nm +itself. +This is faster, and the dump is written by the +same kernel code that writes core dumps upon fatal signals. .El .Sh FILES .Bl -tag -width /var/log/messages -compact diff --git a/usr.bin/gcore/gcore.c b/usr.bin/gcore/gcore.c index cbbfea82085b..8055193625f9 100644 --- a/usr.bin/gcore/gcore.c +++ b/usr.bin/gcore/gcore.c @@ -56,13 +56,16 @@ __FBSDID("$FreeBSD$"); */ #include +#include #include #include #include #include +#include #include #include +#include #include #include #include @@ -75,6 +78,7 @@ static void killed(int); static void usage(void) __dead2; static pid_t pid; +static bool kflag = false; SET_DECLARE(dumpset, struct dumpers); @@ -82,6 +86,7 @@ static int open_corefile(char *corefile) { char fname[MAXPATHLEN]; + int fd; if (corefile == NULL) { (void)snprintf(fname, sizeof(fname), "core.%d", pid); @@ -93,6 +98,45 @@ open_corefile(char *corefile) return (fd); } +static void +kcoredump(int fd, pid_t pid) +{ + struct ptrace_coredump pc; + int error, res, ret, waited; + + error = ptrace(PT_ATTACH, pid, NULL, 0); + if (error != 0) + err(1, "attach"); + + waited = waitpid(pid, &res, 0); + if (waited == -1) + err(1, "wait for STOP"); + + ret = 0; + memset(&pc, 0, sizeof(pc)); + pc.pc_fd = fd; + pc.pc_flags = (pflags & PFLAGS_FULL) != 0 ? PC_ALL : 0; + error = ptrace(PT_COREDUMP, pid, (void *)&pc, sizeof(pc)); + if (error == -1) { + warn("coredump"); + ret = 1; + } + + waited = waitpid(pid, &res, WNOHANG); + if (waited == -1) { + warn("wait after coredump"); + ret = 1; + } + + error = ptrace(PT_DETACH, pid, NULL, 0); + if (error == -1) { + warn("detach failed, check process status"); + ret = 1; + } + + exit(ret); +} + int main(int argc, char *argv[]) { @@ -104,7 +148,7 @@ main(int argc, char *argv[]) pflags = 0; corefile = NULL; - while ((ch = getopt(argc, argv, "c:f")) != -1) { + while ((ch = getopt(argc, argv, "c:fk")) != -1) { switch (ch) { case 'c': corefile = optarg; @@ -112,6 +156,9 @@ main(int argc, char *argv[]) case 'f': pflags |= PFLAGS_FULL; break; + case 'k': + kflag = true; + break; default: usage(); break; @@ -119,10 +166,26 @@ main(int argc, char *argv[]) } argv += optind; argc -= optind; + /* XXX we should check that the pid argument is really a number */ switch (argc) { case 1: pid = atoi(argv[0]); + break; + case 2: + binfile = argv[0]; + pid = atoi(argv[1]); + break; + default: + usage(); + } + + if (kflag) { + fd = open_corefile(corefile); + kcoredump(fd, pid); + } + + if (argc == 1) { name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PATHNAME; @@ -131,13 +194,6 @@ main(int argc, char *argv[]) if (sysctl(name, 4, passpath, &len, NULL, 0) == -1) errx(1, "kern.proc.pathname failure"); binfile = passpath; - break; - case 2: - pid = atoi(argv[1]); - binfile = argv[0]; - break; - default: - usage(); } efd = open(binfile, O_RDONLY, 0); if (efd < 0) @@ -165,6 +221,7 @@ void usage(void) { - (void)fprintf(stderr, "usage: gcore [-c core] [executable] pid\n"); + (void)fprintf(stderr, + "usage: gcore [-kf] [-c core] [executable] pid\n"); exit(1); }