xref: /csrg-svn/usr.bin/gcore/gcore.c (revision 64640)
154084Smccanne /*-
262010Sbostic  * Copyright (c) 1992, 1993
362010Sbostic  *	The Regents of the University of California.  All rights reserved.
435512Sbostic  *
554088Smccanne  * %sccs.include.redist.c%
68824Smckusick  */
754084Smccanne 
854565Sbostic #ifndef lint
962010Sbostic static char copyright[] =
1062010Sbostic "@(#) Copyright (c) 1992, 1993\n\
1162010Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1254565Sbostic #endif /* not lint */
1354565Sbostic 
1454565Sbostic #ifndef lint
15*64640Sbostic static char sccsid[] = "@(#)gcore.c	8.2 (Berkeley) 09/23/93";
1654565Sbostic #endif /* not lint */
1754565Sbostic 
1854084Smccanne /*
1954565Sbostic  * Originally written by Eric Cooper in Fall 1981.
2054565Sbostic  * Inspired by a version 6 program by Len Levin, 1978.
2154565Sbostic  * Several pieces of code lifted from Bill Joy's 4BSD ps.
2254565Sbostic  * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne,
2354565Sbostic  * Lawrence Berkeley Laboratory.
2454565Sbostic  *
2554565Sbostic  * Portions of this software were developed by the Computer Systems
2654565Sbostic  * Engineering group at Lawrence Berkeley Laboratory under DARPA
2754565Sbostic  * contract BG 91-66 and contributed to Berkeley.
2854084Smccanne  */
298824Smckusick #include <sys/param.h>
3054084Smccanne #include <sys/time.h>
3154565Sbostic #include <sys/stat.h>
3254084Smccanne #include <sys/proc.h>
3348957Sbostic #include <sys/user.h>
3458905Smckusick #include <sys/sysctl.h>
3559442Sbostic 
3654084Smccanne #include <machine/vmparam.h>
378824Smckusick 
3854565Sbostic #include <a.out.h>
3954565Sbostic #include <fcntl.h>
4054565Sbostic #include <kvm.h>
4154565Sbostic #include <limits.h>
4254565Sbostic #include <signal.h>
4354565Sbostic #include <stdio.h>
4454565Sbostic #include <stdlib.h>
4554565Sbostic #include <string.h>
4654565Sbostic #include <unistd.h>
4759442Sbostic 
4854565Sbostic #include "extern.h"
4954565Sbostic 
5054565Sbostic void	core __P((int, int, struct kinfo_proc *));
5154565Sbostic void	datadump __P((int, int, struct proc *, u_long, int));
5254565Sbostic void	usage __P((void));
5354565Sbostic void	userdump __P((int, struct proc *, u_long, int));
5454565Sbostic 
5554084Smccanne kvm_t *kd;
5654565Sbostic /* XXX undocumented routine, should be in kvm.h? */
5754565Sbostic ssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t));
588824Smckusick 
5954084Smccanne static int data_offset;
608824Smckusick 
6154565Sbostic int
main(argc,argv)628824Smckusick main(argc, argv)
638824Smckusick 	int argc;
6454565Sbostic 	char *argv[];
658824Smckusick {
668824Smckusick 	register struct proc *p;
6754084Smccanne 	struct kinfo_proc *ki;
6854084Smccanne 	struct exec exec;
6954565Sbostic 	int ch, cnt, efd, fd, pid, sflag, uid;
7054565Sbostic 	char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1];
718824Smckusick 
7254565Sbostic 	sflag = 0;
7354565Sbostic 	corefile = NULL;
7454565Sbostic         while ((ch = getopt(argc, argv, "c:s")) != EOF) {
7554565Sbostic                 switch (ch) {
7654084Smccanne                 case 'c':
7754084Smccanne 			corefile = optarg;
7854084Smccanne                         break;
7954084Smccanne 		case 's':
8054565Sbostic 			sflag = 1;
8154084Smccanne 			break;
8254084Smccanne 		default:
8354084Smccanne 			usage();
8454084Smccanne 			break;
858824Smckusick 		}
868824Smckusick 	}
8754084Smccanne 	argv += optind;
8854084Smccanne 	argc -= optind;
8954565Sbostic 
9054084Smccanne 	if (argc != 2)
9154084Smccanne 		usage();
928824Smckusick 
9354084Smccanne 	kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
9454565Sbostic 	if (kd == NULL)
9554565Sbostic 		err(1, "%s", errbuf);
968824Smckusick 
9754084Smccanne 	uid = getuid();
9854084Smccanne 	pid = atoi(argv[1]);
9954084Smccanne 
10058905Smckusick 	ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
10154565Sbostic 	if (ki == NULL || cnt != 1)
10254565Sbostic 		err(1, "%d: not found", pid);
1038824Smckusick 
10454084Smccanne 	p = &ki->kp_proc;
10554084Smccanne 	if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
10654565Sbostic 		err(1, "%d: not owner", pid);
10754084Smccanne 
10854084Smccanne 	if (p->p_stat == SZOMB)
10954565Sbostic 		err(1, "%d: zombie", pid);
11054084Smccanne 
111*64640Sbostic 	if (p->p_flag & P_WEXIT)
11254565Sbostic 		err(0, "process exiting");
113*64640Sbostic 	if (p->p_flag & P_SYSTEM)	/* Swapper or pagedaemon. */
11454565Sbostic 		err(1, "%d: system process");
11554084Smccanne 
11654565Sbostic 	if (corefile == NULL) {
11754565Sbostic 		(void)snprintf(fname, sizeof(fname), "core.%d", pid);
11854084Smccanne 		corefile = fname;
1198824Smckusick 	}
12054565Sbostic 	fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
12154565Sbostic 	if (fd < 0)
12254565Sbostic 		err(1, "%s: %s\n", corefile, strerror(errno));
1238824Smckusick 
12454565Sbostic 	efd = open(argv[0], O_RDONLY, 0);
12554565Sbostic 	if (efd < 0)
12654565Sbostic 		err(1, "%s: %s\n", argv[0], strerror(errno));
12754565Sbostic 
12854565Sbostic 	cnt = read(efd, &exec, sizeof(exec));
12954565Sbostic 	if (cnt != sizeof(exec))
13054565Sbostic 		err(1, "%s exec header: %s",
13154565Sbostic 		    argv[0], cnt > 0 ? strerror(EIO) : strerror(errno));
13254565Sbostic 
13354084Smccanne 	data_offset = N_DATOFF(exec);
1348824Smckusick 
13554565Sbostic 	if (sflag && kill(pid, SIGSTOP) < 0)
13654565Sbostic 		err(0, "%d: stop signal: %s", pid, strerror(errno));
1378824Smckusick 
13854565Sbostic 	core(efd, fd, ki);
1398824Smckusick 
14054084Smccanne 	if (sflag && kill(pid, SIGCONT) < 0)
14154565Sbostic 		err(0, "%d: continue signal: %s", pid, strerror(errno));
14254565Sbostic 	(void)close(fd);
1438824Smckusick 
14454084Smccanne 	exit(0);
1458824Smckusick }
1468824Smckusick 
14754565Sbostic /*
14854565Sbostic  * core --
14954565Sbostic  *	Build the core file.
15054565Sbostic  */
15154565Sbostic void
core(efd,fd,ki)15254565Sbostic core(efd, fd, ki)
15354565Sbostic 	int efd;
15454565Sbostic 	int fd;
15554565Sbostic 	struct kinfo_proc *ki;
15654565Sbostic {
15754565Sbostic 	union {
15854565Sbostic 		struct user user;
15954565Sbostic 		char ubytes[ctob(UPAGES)];
16054565Sbostic 	} uarea;
16154565Sbostic 	struct proc *p = &ki->kp_proc;
16254565Sbostic 	int tsize = ki->kp_eproc.e_vm.vm_tsize;
16354565Sbostic 	int dsize = ki->kp_eproc.e_vm.vm_dsize;
16454565Sbostic 	int ssize = ki->kp_eproc.e_vm.vm_ssize;
16554565Sbostic 	int cnt;
16654565Sbostic 
16754565Sbostic 	/* Read in user struct */
16854565Sbostic 	cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea));
16954565Sbostic 	if (cnt != sizeof(uarea))
17054565Sbostic 		err(1, "read user structure: %s",
17154565Sbostic 		    cnt > 0 ? strerror(EIO) : strerror(errno));
17254565Sbostic 
17354565Sbostic 	/*
17454565Sbostic 	 * Fill in the eproc vm parameters, since these are garbage unless
17554565Sbostic 	 * the kernel is dumping core or something.
17654565Sbostic 	 */
17754565Sbostic 	uarea.user.u_kproc = *ki;
17854565Sbostic 
17954565Sbostic 	/* Dump user area */
18054565Sbostic 	cnt = write(fd, &uarea, sizeof(uarea));
18154565Sbostic 	if (cnt != sizeof(uarea))
18254565Sbostic 		err(1, "write user structure: %s",
18354565Sbostic 		    cnt > 0 ? strerror(EIO) : strerror(errno));
18454565Sbostic 
18554565Sbostic 	/* Dump data segment */
18654565Sbostic 	datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize);
18754565Sbostic 
18854565Sbostic 	/* Dump stack segment */
18954565Sbostic 	userdump(fd, p, USRSTACK - ctob(ssize), ssize);
19054565Sbostic 
19154565Sbostic 	/* Dump machine dependent portions of the core. */
19254565Sbostic 	md_core(kd, fd, ki);
19354565Sbostic }
19454565Sbostic 
19554565Sbostic void
datadump(efd,fd,p,addr,npage)19654565Sbostic datadump(efd, fd, p, addr, npage)
19754565Sbostic 	register int efd;
19854084Smccanne 	register int fd;
19954084Smccanne 	struct proc *p;
20054084Smccanne 	register u_long addr;
20154084Smccanne 	register int npage;
2028824Smckusick {
20354565Sbostic 	register int cc, delta;
20454084Smccanne 	char buffer[NBPG];
20554565Sbostic 
20654565Sbostic 	delta = data_offset - addr;
20754084Smccanne 	while (--npage >= 0) {
20854084Smccanne 		cc = kvm_uread(kd, p, addr, buffer, NBPG);
20954565Sbostic 		if (cc != NBPG) {
21054565Sbostic 			/* Try to read the page from the executable. */
21154565Sbostic 			if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1)
21254565Sbostic 				err(1, "seek executable: %s", strerror(errno));
21354565Sbostic 			cc = read(efd, buffer, sizeof(buffer));
21454565Sbostic 			if (cc != sizeof(buffer))
21554572Sbostic 				if (cc < 0)
21654572Sbostic 					err(1, "read executable: %s",
21754572Sbostic 					    strerror(errno));
21854572Sbostic 				else	/* Assume untouched bss page. */
21954572Sbostic 					bzero(buffer, sizeof(buffer));
22054565Sbostic 		}
22154565Sbostic 		cc = write(fd, buffer, NBPG);
22254084Smccanne 		if (cc != NBPG)
22354565Sbostic 			err(1, "write data segment: %s",
22454565Sbostic 			    cc > 0 ? strerror(EIO) : strerror(errno));
22554084Smccanne 		addr += NBPG;
2268824Smckusick 	}
2278824Smckusick }
2288824Smckusick 
22954565Sbostic void
userdump(fd,p,addr,npage)23054565Sbostic userdump(fd, p, addr, npage)
23154084Smccanne 	register int fd;
23254084Smccanne 	struct proc *p;
23354084Smccanne 	register u_long addr;
23454084Smccanne 	register int npage;
2358824Smckusick {
23654565Sbostic 	register int cc;
23754084Smccanne 	char buffer[NBPG];
23854565Sbostic 
23954084Smccanne 	while (--npage >= 0) {
24054084Smccanne 		cc = kvm_uread(kd, p, addr, buffer, NBPG);
24154565Sbostic 		if (cc != NBPG)
24254565Sbostic 			/* Could be an untouched fill-with-zero page. */
24354565Sbostic 			bzero(buffer, NBPG);
24454565Sbostic 		cc = write(fd, buffer, NBPG);
24554565Sbostic 		if (cc != NBPG)
24654565Sbostic 			err(1, "write stack segment: %s",
24754565Sbostic 			    cc > 0 ? strerror(EIO) : strerror(errno));
24854084Smccanne 		addr += NBPG;
2498824Smckusick 	}
2508824Smckusick }
2518824Smckusick 
25254565Sbostic void
usage()25354565Sbostic usage()
2548824Smckusick {
25554565Sbostic 	(void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n");
25654565Sbostic 	exit(1);
25754565Sbostic }
2588824Smckusick 
25954565Sbostic #if __STDC__
26054565Sbostic #include <stdarg.h>
26154565Sbostic #else
26254565Sbostic #include <varargs.h>
26354565Sbostic #endif
2648824Smckusick 
26554565Sbostic void
26654565Sbostic #if __STDC__
err(int fatal,const char * fmt,...)26754565Sbostic err(int fatal, const char *fmt, ...)
26854565Sbostic #else
26954565Sbostic err(fatal, fmt, va_alist)
27054565Sbostic 	int fatal;
27154565Sbostic 	char *fmt;
27254565Sbostic         va_dcl
27354565Sbostic #endif
27454565Sbostic {
27554565Sbostic 	va_list ap;
27654565Sbostic #if __STDC__
27754565Sbostic 	va_start(ap, fmt);
27854565Sbostic #else
27954565Sbostic 	va_start(ap);
28054565Sbostic #endif
28154565Sbostic 	(void)fprintf(stderr, "gcore: ");
28254565Sbostic 	(void)vfprintf(stderr, fmt, ap);
28354565Sbostic 	va_end(ap);
28454565Sbostic 	(void)fprintf(stderr, "\n");
28554565Sbostic 	exit(1);
28654565Sbostic 	/* NOTREACHED */
2878824Smckusick }
288