11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1992, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3127273Scharnierstatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1992, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341590Srgrimes#endif /* not lint */
351590Srgrimes
3699130Sobrien#if 0
371590Srgrimes#ifndef lint
381590Srgrimesstatic char sccsid[] = "@(#)gcore.c	8.2 (Berkeley) 9/23/93";
3999130Sobrien#endif /* not lint */
4027273Scharnier#endif
4194560Scharnier#include <sys/cdefs.h>
4294560Scharnier__FBSDID("$FreeBSD$");
4394560Scharnier
441590Srgrimes/*
451590Srgrimes * Originally written by Eric Cooper in Fall 1981.
461590Srgrimes * Inspired by a version 6 program by Len Levin, 1978.
471590Srgrimes * Several pieces of code lifted from Bill Joy's 4BSD ps.
481590Srgrimes * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne,
491590Srgrimes * Lawrence Berkeley Laboratory.
501590Srgrimes *
511590Srgrimes * Portions of this software were developed by the Computer Systems
521590Srgrimes * Engineering group at Lawrence Berkeley Laboratory under DARPA
531590Srgrimes * contract BG 91-66 and contributed to Berkeley.
541590Srgrimes */
5594560Scharnier
561590Srgrimes#include <sys/param.h>
571590Srgrimes#include <sys/time.h>
581590Srgrimes#include <sys/stat.h>
59103299Speter#include <sys/linker_set.h>
60199805Sattilio#include <sys/sysctl.h>
6176228Sobrien
6227273Scharnier#include <err.h>
631590Srgrimes#include <fcntl.h>
641590Srgrimes#include <stdio.h>
651590Srgrimes#include <stdlib.h>
66200462Sdelphij#include <string.h>
671590Srgrimes#include <unistd.h>
681590Srgrimes
691590Srgrimes#include "extern.h"
70210063Sattilioint pflags;
711590Srgrimes
7292920Simpstatic void	killed(int);
7392920Simpstatic void	usage(void) __dead2;
741590Srgrimes
7540562Sjdpstatic pid_t pid;
761590Srgrimes
77103299SpeterSET_DECLARE(dumpset, struct dumpers);
78103299Speter
791590Srgrimesint
80103299Spetermain(int argc, char *argv[])
811590Srgrimes{
82203532Smjacob	int ch, efd, fd, name[4];
8339164Sdes	char *binfile, *corefile;
84199805Sattilio	char passpath[MAXPATHLEN], fname[MAXPATHLEN];
85103299Speter	struct dumpers **d, *dumper;
86199805Sattilio	size_t len;
871590Srgrimes
88210063Sattilio	pflags = 0;
891590Srgrimes	corefile = NULL;
90210063Sattilio        while ((ch = getopt(argc, argv, "c:fs")) != -1) {
911590Srgrimes                switch (ch) {
921590Srgrimes                case 'c':
931590Srgrimes			corefile = optarg;
941590Srgrimes                        break;
95210063Sattilio		case 'f':
96210063Sattilio			pflags |= PFLAGS_FULL;
97210063Sattilio			break;
981590Srgrimes		case 's':
99210063Sattilio			pflags |= PFLAGS_RESUME;
1001590Srgrimes			break;
1011590Srgrimes		default:
1021590Srgrimes			usage();
1031590Srgrimes			break;
1041590Srgrimes		}
1051590Srgrimes	}
1061590Srgrimes	argv += optind;
1071590Srgrimes	argc -= optind;
10839164Sdes	/* XXX we should check that the pid argument is really a number */
10939164Sdes	switch (argc) {
11039164Sdes	case 1:
11139164Sdes		pid = atoi(argv[0]);
112199805Sattilio		name[0] = CTL_KERN;
113199805Sattilio		name[1] = KERN_PROC;
114199805Sattilio		name[2] = KERN_PROC_PATHNAME;
115199805Sattilio		name[3] = pid;
116199805Sattilio		len = sizeof(passpath);
117199805Sattilio		if (sysctl(name, 4, passpath, &len, NULL, 0) == -1)
118199805Sattilio			errx(1, "kern.proc.pathname failure");
119199805Sattilio		binfile = passpath;
12039164Sdes		break;
12139164Sdes	case 2:
12239164Sdes		pid = atoi(argv[1]);
12339164Sdes		binfile = argv[0];
12439164Sdes		break;
12539164Sdes	default:
1261590Srgrimes		usage();
12739164Sdes	}
12840525Sjdp	efd = open(binfile, O_RDONLY, 0);
12940525Sjdp	if (efd < 0)
13040525Sjdp		err(1, "%s", binfile);
131103299Speter	dumper = NULL;
132103299Speter	SET_FOREACH(d, dumpset) {
133103299Speter		lseek(efd, 0, SEEK_SET);
134103299Speter		if (((*d)->ident)(efd, pid, binfile)) {
135103299Speter			dumper = (*d);
136103299Speter			lseek(efd, 0, SEEK_SET);
137103299Speter			break;
138103299Speter		}
139103299Speter	}
140103299Speter	if (dumper == NULL)
14140525Sjdp		errx(1, "Invalid executable file");
1421590Srgrimes	if (corefile == NULL) {
1431590Srgrimes		(void)snprintf(fname, sizeof(fname), "core.%d", pid);
1441590Srgrimes		corefile = fname;
1451590Srgrimes	}
1461590Srgrimes	fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
1471590Srgrimes	if (fd < 0)
14827273Scharnier		err(1, "%s", corefile);
149203532Smjacob	/*
150203532Smjacob	 * The semantics of the 's' flag is to stop the target process.
151203532Smjacob	 * Previous versions of gcore would manage this by trapping SIGHUP,
152203532Smjacob	 * SIGINT and SIGTERM (to be passed to the target pid), and then
153203532Smjacob	 * signal the child to stop.
154203532Smjacob	 *
155203532Smjacob	 * However, this messes up if the selected dumper uses ptrace calls
156203532Smjacob	 * that leave the child already stopped. The waitpid call in elfcore
157203532Smjacob	 * never returns.
158203532Smjacob	 *
159203532Smjacob	 * The best thing to do here is to externalize the 's' flag and let
160203532Smjacob	 * each dumper dispose of what that means, if anything. For the elfcore
161203532Smjacob	 * dumper, the 's' flag is a no-op since the ptrace attach stops the
162203532Smjacob	 * process in question already.
163203532Smjacob	 */
164203532Smjacob
165103299Speter	dumper->dump(efd, fd, pid);
1661590Srgrimes	(void)close(fd);
167103299Speter	(void)close(efd);
1681590Srgrimes	exit(0);
1691590Srgrimes}
1701590Srgrimes
1711590Srgrimesvoid
172103299Speterusage(void)
1731590Srgrimes{
1741590Srgrimes
17581735Smikeh	(void)fprintf(stderr, "usage: gcore [-s] [-c core] [executable] pid\n");
1761590Srgrimes	exit(1);
1771590Srgrimes}
178