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