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
This commit is contained in:
parent
c192228b73
commit
73e8f06ac5
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user