aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-04-24 11:20:24 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-05-03 16:18:26 +0000
commit73e8f06ac523ee4b530e17d50cc580dc366f7ad8 (patch)
tree1765c183ebb2fc9d0afa10009694ef9a029de67d
parentc192228b7398df72e472128605338555e5aa2db9 (diff)
downloadsrc-73e8f06ac523ee4b530e17d50cc580dc366f7ad8.tar.gz
src-73e8f06ac523ee4b530e17d50cc580dc366f7ad8.zip
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
-rw-r--r--usr.bin/gcore/gcore.116
-rw-r--r--usr.bin/gcore/gcore.c75
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.<pid> .
.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 <sys/param.h>
+#include <sys/ptrace.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/linker_set.h>
#include <sys/sysctl.h>
+#include <sys/wait.h>
#include <err.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -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);
}