gcore.c revision 76224
1285SN/A/*-
2462SN/A * Copyright (c) 1992, 1993
3285SN/A *	The Regents of the University of California.  All rights reserved.
4285SN/A *
5285SN/A * Redistribution and use in source and binary forms, with or without
6285SN/A * modification, are permitted provided that the following conditions
7285SN/A * are met:
8285SN/A * 1. Redistributions of source code must retain the above copyright
9285SN/A *    notice, this list of conditions and the following disclaimer.
10285SN/A * 2. Redistributions in binary form must reproduce the above copyright
11285SN/A *    notice, this list of conditions and the following disclaimer in the
12285SN/A *    documentation and/or other materials provided with the distribution.
13285SN/A * 3. All advertising materials mentioning features or use of this software
14285SN/A *    must display the following acknowledgement:
15285SN/A *	This product includes software developed by the University of
16285SN/A *	California, Berkeley and its contributors.
17285SN/A * 4. Neither the name of the University nor the names of its contributors
18285SN/A *    may be used to endorse or promote products derived from this software
19285SN/A *    without specific prior written permission.
20285SN/A *
21285SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22285SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23285SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24285SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25285SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26285SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27285SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28285SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29285SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30285SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31285SN/A * SUCH DAMAGE.
32285SN/A */
33285SN/A
34285SN/A#ifndef lint
35285SN/Astatic const char copyright[] =
36285SN/A"@(#) Copyright (c) 1992, 1993\n\
37285SN/A	The Regents of the University of California.  All rights reserved.\n";
38285SN/A#endif /* not lint */
39285SN/A
40285SN/A#ifndef lint
41285SN/A#if 0
42285SN/Astatic char sccsid[] = "@(#)gcore.c	8.2 (Berkeley) 9/23/93";
43285SN/A#endif
44285SN/Astatic const char rcsid[] =
45285SN/A  "$FreeBSD: head/usr.bin/gcore/gcore.c 76224 2001-05-02 23:56:21Z obrien $";
46285SN/A#endif /* not lint */
47285SN/A
48285SN/A/*
49285SN/A * Originally written by Eric Cooper in Fall 1981.
50285SN/A * Inspired by a version 6 program by Len Levin, 1978.
51285SN/A * Several pieces of code lifted from Bill Joy's 4BSD ps.
52285SN/A * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne,
53285SN/A * Lawrence Berkeley Laboratory.
54285SN/A *
55285SN/A * Portions of this software were developed by the Computer Systems
56285SN/A * Engineering group at Lawrence Berkeley Laboratory under DARPA
57285SN/A * contract BG 91-66 and contributed to Berkeley.
58285SN/A */
59285SN/A#include <sys/param.h>
60285SN/A#include <sys/lock.h>
61285SN/A#include <sys/time.h>
62285SN/A#include <sys/stat.h>
63285SN/A#include <sys/proc.h>
64285SN/A#include <sys/user.h>
65285SN/A#include <sys/sysctl.h>
66285SN/A#include <machine/elf.h>
67285SN/A
68285SN/A#include <machine/vmparam.h>
69285SN/A
70285SN/A#include <a.out.h>
71285SN/A#include <err.h>
72285SN/A#include <fcntl.h>
73285SN/A#include <kvm.h>
74285SN/A#include <limits.h>
75285SN/A#include <signal.h>
76285SN/A#include <stdio.h>
77285SN/A#include <stdlib.h>
78285SN/A#include <string.h>
79285SN/A#include <unistd.h>
80285SN/A
81285SN/A#include "extern.h"
82285SN/A
83285SN/Astatic void	core __P((int, int, struct kinfo_proc *));
84285SN/Astatic void	datadump __P((int, int, struct kinfo_proc *, u_long, int));
85285SN/Astatic void	killed __P((int));
86285SN/Astatic void	restart_target __P((void));
87285SN/Astatic void	usage __P((void)) __dead2;
88285SN/Astatic void	userdump __P((int, struct kinfo_proc *, u_long, int));
89285SN/A
90285SN/Akvm_t *kd;
91285SN/A
92285SN/Astatic int data_offset;
93285SN/Astatic pid_t pid;
94285SN/A
95285SN/Aint
96285SN/Amain(argc, argv)
97285SN/A	int argc;
98285SN/A	char *argv[];
99285SN/A{
100285SN/A	struct kinfo_proc *ki = NULL;
101285SN/A	struct exec exec;
102285SN/A	int ch, cnt, efd, fd, sflag, uid;
103285SN/A	char *binfile, *corefile;
104285SN/A	char errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN];
105285SN/A	int is_aout;
106285SN/A
107285SN/A	sflag = 0;
108285SN/A	corefile = NULL;
109285SN/A        while ((ch = getopt(argc, argv, "c:s")) != -1) {
110285SN/A                switch (ch) {
111285SN/A                case 'c':
112285SN/A			corefile = optarg;
113285SN/A                        break;
114285SN/A		case 's':
115285SN/A			sflag = 1;
116285SN/A			break;
117285SN/A		default:
118285SN/A			usage();
119285SN/A			break;
120285SN/A		}
121285SN/A	}
122285SN/A	argv += optind;
123285SN/A	argc -= optind;
124285SN/A
125285SN/A	/* XXX we should check that the pid argument is really a number */
126285SN/A	switch (argc) {
127285SN/A	case 1:
128285SN/A		pid = atoi(argv[0]);
129285SN/A		asprintf(&binfile, "/proc/%d/file", pid);
130285SN/A		if (binfile == NULL)
131285SN/A			errx(1, "allocation failure");
132285SN/A		break;
133285SN/A	case 2:
134285SN/A		pid = atoi(argv[1]);
135285SN/A		binfile = argv[0];
136285SN/A		break;
137285SN/A	default:
138285SN/A		usage();
139285SN/A	}
140285SN/A
141285SN/A	efd = open(binfile, O_RDONLY, 0);
142285SN/A	if (efd < 0)
143285SN/A		err(1, "%s", binfile);
144285SN/A
145285SN/A	cnt = read(efd, &exec, sizeof(exec));
146285SN/A	if (cnt != sizeof(exec))
147285SN/A		errx(1, "%s exec header: %s",
148285SN/A		    binfile, cnt > 0 ? strerror(EIO) : strerror(errno));
149285SN/A	if (!N_BADMAG(exec)) {
150285SN/A		is_aout = 1;
151285SN/A		/*
152285SN/A		 * This legacy a.out support uses the kvm interface instead
153285SN/A		 * of procfs.
154285SN/A		 */
155285SN/A		kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
156285SN/A		if (kd == NULL)
157285SN/A			errx(1, "%s", errbuf);
158285SN/A
159285SN/A		uid = getuid();
160285SN/A
161285SN/A		ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
162285SN/A		if (ki == NULL || cnt != 1)
163285SN/A			errx(1, "%d: not found", pid);
164285SN/A
165285SN/A		if (ki->ki_ruid != uid && uid != 0)
166285SN/A			errx(1, "%d: not owner", pid);
167285SN/A
168285SN/A		if (ki->ki_stat == SZOMB)
169285SN/A			errx(1, "%d: zombie", pid);
170285SN/A
171285SN/A		if (ki->ki_flag & P_WEXIT)
172285SN/A			errx(1, "%d: process exiting", pid);
173285SN/A		if (ki->ki_flag & P_SYSTEM)	/* Swapper or pagedaemon. */
174285SN/A			errx(1, "%d: system process", pid);
175285SN/A		if (exec.a_text != ptoa(ki->ki_tsize))
176285SN/A			errx(1, "The executable %s does not belong to"
177285SN/A			    " process %d!\n"
178285SN/A			    "Text segment size (in bytes): executable %ld,"
179285SN/A			    " process %d", binfile, pid, exec.a_text,
180285SN/A			     ptoa(ki->ki_tsize));
181285SN/A		data_offset = N_DATOFF(exec);
182285SN/A	} else if (IS_ELF(*(Elf_Ehdr *)&exec)) {
183285SN/A		is_aout = 0;
184285SN/A		close(efd);
185285SN/A	} else
186285SN/A		errx(1, "Invalid executable file");
187285SN/A
188285SN/A	if (corefile == NULL) {
189285SN/A		(void)snprintf(fname, sizeof(fname), "core.%d", pid);
190285SN/A		corefile = fname;
191285SN/A	}
192285SN/A	fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
193285SN/A	if (fd < 0)
194285SN/A		err(1, "%s", corefile);
195285SN/A
196285SN/A	if (sflag) {
197285SN/A		signal(SIGHUP, killed);
198285SN/A		signal(SIGINT, killed);
199285SN/A		signal(SIGTERM, killed);
200285SN/A		if (kill(pid, SIGSTOP) == -1)
201285SN/A			err(1, "%d: stop signal", pid);
202285SN/A		atexit(restart_target);
203285SN/A	}
204285SN/A
205285SN/A	if (is_aout)
206285SN/A		core(efd, fd, ki);
207285SN/A	else
208285SN/A		elf_coredump(fd, pid);
209285SN/A
210285SN/A	(void)close(fd);
211285SN/A	exit(0);
212285SN/A}
213285SN/A
214285SN/A/*
215285SN/A * core --
216285SN/A *	Build the core file.
217285SN/A */
218285SN/Avoid
219285SN/Acore(efd, fd, ki)
220285SN/A	int efd;
221285SN/A	int fd;
222285SN/A	struct kinfo_proc *ki;
223285SN/A{
224285SN/A	union {
225285SN/A		struct user user;
226285SN/A		char ubytes[ctob(UPAGES)];
227285SN/A	} uarea;
228285SN/A	int tsize = ki->ki_tsize;
229285SN/A	int dsize = ki->ki_dsize;
230285SN/A	int ssize = ki->ki_ssize;
231285SN/A	int cnt;
232285SN/A
233285SN/A	/* Read in user struct */
234285SN/A	cnt = kvm_read(kd, (u_long)ki->ki_addr, &uarea, sizeof(uarea));
235285SN/A	if (cnt != sizeof(uarea))
236285SN/A		errx(1, "read user structure: %s",
237285SN/A		    cnt > 0 ? strerror(EIO) : strerror(errno));
238285SN/A
239285SN/A	/*
240285SN/A	 * Fill in the eproc vm parameters, since these are garbage unless
241285SN/A	 * the kernel is dumping core or something.
242285SN/A	 */
243285SN/A	uarea.user.u_kproc = *ki;
244285SN/A
245285SN/A	/* Dump user area */
246285SN/A	cnt = write(fd, &uarea, sizeof(uarea));
247285SN/A	if (cnt != sizeof(uarea))
248285SN/A		errx(1, "write user structure: %s",
249285SN/A		    cnt > 0 ? strerror(EIO) : strerror(errno));
250285SN/A
251285SN/A	/* Dump data segment */
252285SN/A	datadump(efd, fd, ki, USRTEXT + ctob(tsize), dsize);
253285SN/A
254285SN/A	/* Dump stack segment */
255285SN/A	userdump(fd, ki, USRSTACK - ctob(ssize), ssize);
256285SN/A
257285SN/A	/* Dump machine dependent portions of the core. */
258285SN/A	md_core(kd, fd, ki);
259285SN/A}
260285SN/A
261285SN/Avoid
262285SN/Adatadump(efd, fd, kp, addr, npage)
263285SN/A	register int efd;
264285SN/A	register int fd;
265285SN/A	struct kinfo_proc *kp;
266285SN/A	register u_long addr;
267285SN/A	register int npage;
268285SN/A{
269285SN/A	register int cc, delta;
270285SN/A	char buffer[PAGE_SIZE];
271367SN/A
272285SN/A	delta = data_offset - addr;
273285SN/A	while (--npage >= 0) {
274285SN/A		cc = kvm_uread(kd, kp, addr, buffer, PAGE_SIZE);
275285SN/A		if (cc != PAGE_SIZE) {
276285SN/A			/* Try to read the page from the executable. */
277285SN/A			if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1)
278285SN/A				err(1, "seek executable: %s", strerror(errno));
279285SN/A			cc = read(efd, buffer, sizeof(buffer));
280285SN/A			if (cc != sizeof(buffer)) {
281285SN/A				if (cc < 0)
282285SN/A					err(1, "read executable");
283285SN/A				else	/* Assume untouched bss page. */
284285SN/A					bzero(buffer, sizeof(buffer));
285285SN/A			}
286285SN/A		}
287285SN/A		cc = write(fd, buffer, PAGE_SIZE);
288285SN/A		if (cc != PAGE_SIZE)
289285SN/A			errx(1, "write data segment: %s",
290285SN/A			    cc > 0 ? strerror(EIO) : strerror(errno));
291285SN/A		addr += PAGE_SIZE;
292285SN/A	}
293285SN/A}
294285SN/A
295285SN/Astatic void
296285SN/Akilled(sig)
297285SN/A	int sig;
298285SN/A{
299285SN/A	restart_target();
300285SN/A	signal(sig, SIG_DFL);
301285SN/A	kill(getpid(), sig);
302285SN/A}
303285SN/A
304285SN/Astatic void
305285SN/Arestart_target()
306285SN/A{
307285SN/A	kill(pid, SIGCONT);
308285SN/A}
309285SN/A
310285SN/Avoid
311285SN/Auserdump(fd, kp, addr, npage)
312285SN/A	register int fd;
313285SN/A	struct kinfo_proc *kp;
314285SN/A	register u_long addr;
315285SN/A	register int npage;
316285SN/A{
317285SN/A	register int cc;
318285SN/A	char buffer[PAGE_SIZE];
319285SN/A
320285SN/A	while (--npage >= 0) {
321285SN/A		cc = kvm_uread(kd, kp, addr, buffer, PAGE_SIZE);
322285SN/A		if (cc != PAGE_SIZE)
323285SN/A			/* Could be an untouched fill-with-zero page. */
324285SN/A			bzero(buffer, PAGE_SIZE);
325285SN/A		cc = write(fd, buffer, PAGE_SIZE);
326285SN/A		if (cc != PAGE_SIZE)
327285SN/A			errx(1, "write stack segment: %s",
328285SN/A			    cc > 0 ? strerror(EIO) : strerror(errno));
329285SN/A		addr += PAGE_SIZE;
330285SN/A	}
331285SN/A}
332285SN/A
333285SN/Avoid
334285SN/Ausage()
335285SN/A{
336285SN/A	(void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n");
337285SN/A	exit(1);
338285SN/A}
339285SN/A