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
|
.\" @(#)gcore.1 8.2 (Berkeley) 4/18/94
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd July 13, 2016
|
.Dd April 24, 2021
|
||||||
.Dt GCORE 1
|
.Dt GCORE 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -37,6 +37,7 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
.Op Fl f
|
.Op Fl f
|
||||||
|
.Op Fl k
|
||||||
.Op Fl c Ar core
|
.Op Fl c Ar core
|
||||||
.Op Ar executable
|
.Op Ar executable
|
||||||
.Ar pid
|
.Ar pid
|
||||||
@ -58,13 +59,24 @@ The following options are available:
|
|||||||
Write the core file to the specified file instead of
|
Write the core file to the specified file instead of
|
||||||
.Dq Pa core.<pid> .
|
.Dq Pa core.<pid> .
|
||||||
.It Fl f
|
.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
|
Unlike the default invocation, this flag dumps mappings of devices which
|
||||||
may invalidate the state of device transactions or trigger other unexpected
|
may invalidate the state of device transactions or trigger other unexpected
|
||||||
behavior.
|
behavior.
|
||||||
As a result, this flag should only be used when the behavior of the
|
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
|
application and any devices it has mapped is fully understood and any side
|
||||||
effects can be controlled or tolerated.
|
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
|
.El
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width /var/log/messages -compact
|
.Bl -tag -width /var/log/messages -compact
|
||||||
|
@ -56,13 +56,16 @@ __FBSDID("$FreeBSD$");
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/linker_set.h>
|
#include <sys/linker_set.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -75,6 +78,7 @@ static void killed(int);
|
|||||||
static void usage(void) __dead2;
|
static void usage(void) __dead2;
|
||||||
|
|
||||||
static pid_t pid;
|
static pid_t pid;
|
||||||
|
static bool kflag = false;
|
||||||
|
|
||||||
SET_DECLARE(dumpset, struct dumpers);
|
SET_DECLARE(dumpset, struct dumpers);
|
||||||
|
|
||||||
@ -82,6 +86,7 @@ static int
|
|||||||
open_corefile(char *corefile)
|
open_corefile(char *corefile)
|
||||||
{
|
{
|
||||||
char fname[MAXPATHLEN];
|
char fname[MAXPATHLEN];
|
||||||
|
int fd;
|
||||||
|
|
||||||
if (corefile == NULL) {
|
if (corefile == NULL) {
|
||||||
(void)snprintf(fname, sizeof(fname), "core.%d", pid);
|
(void)snprintf(fname, sizeof(fname), "core.%d", pid);
|
||||||
@ -93,6 +98,45 @@ open_corefile(char *corefile)
|
|||||||
return (fd);
|
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
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -104,7 +148,7 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
pflags = 0;
|
pflags = 0;
|
||||||
corefile = NULL;
|
corefile = NULL;
|
||||||
while ((ch = getopt(argc, argv, "c:f")) != -1) {
|
while ((ch = getopt(argc, argv, "c:fk")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'c':
|
case 'c':
|
||||||
corefile = optarg;
|
corefile = optarg;
|
||||||
@ -112,6 +156,9 @@ main(int argc, char *argv[])
|
|||||||
case 'f':
|
case 'f':
|
||||||
pflags |= PFLAGS_FULL;
|
pflags |= PFLAGS_FULL;
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
kflag = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
@ -119,10 +166,26 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
argv += optind;
|
argv += optind;
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
|
|
||||||
/* XXX we should check that the pid argument is really a number */
|
/* XXX we should check that the pid argument is really a number */
|
||||||
switch (argc) {
|
switch (argc) {
|
||||||
case 1:
|
case 1:
|
||||||
pid = atoi(argv[0]);
|
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[0] = CTL_KERN;
|
||||||
name[1] = KERN_PROC;
|
name[1] = KERN_PROC;
|
||||||
name[2] = KERN_PROC_PATHNAME;
|
name[2] = KERN_PROC_PATHNAME;
|
||||||
@ -131,13 +194,6 @@ main(int argc, char *argv[])
|
|||||||
if (sysctl(name, 4, passpath, &len, NULL, 0) == -1)
|
if (sysctl(name, 4, passpath, &len, NULL, 0) == -1)
|
||||||
errx(1, "kern.proc.pathname failure");
|
errx(1, "kern.proc.pathname failure");
|
||||||
binfile = passpath;
|
binfile = passpath;
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
pid = atoi(argv[1]);
|
|
||||||
binfile = argv[0];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
}
|
}
|
||||||
efd = open(binfile, O_RDONLY, 0);
|
efd = open(binfile, O_RDONLY, 0);
|
||||||
if (efd < 0)
|
if (efd < 0)
|
||||||
@ -165,6 +221,7 @@ void
|
|||||||
usage(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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user