xref: /original-bsd/usr.bin/gcore/gcore.c (revision 68d9582f)
1 /*-
2  * Copyright (c) 1992 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * %sccs.include.redist.c%
10  */
11 
12 /*
13  * gcore - get core images of running processes
14  */
15 #include <stdio.h>
16 #include <limits.h>
17 #include <kvm.h>
18 #include <a.out.h>
19 #include <sys/param.h>
20 #include <sys/time.h>
21 #include <sys/file.h>
22 #include <sys/proc.h>
23 #include <sys/user.h>
24 #include <sys/kinfo.h>
25 #include <sys/kinfo_proc.h>
26 #include <machine/vmparam.h>
27 
28 kvm_t *kd;
29 
30 extern int getopt();
31 extern int optind, opterr;
32 extern char *optarg;
33 
34 static int data_offset;
35 
36 main(argc, argv)
37 	int argc;
38 	char **argv;
39 {
40 	register struct proc *p;
41 	off_t procbase, procp;
42 	int pid, uid, fd, cnt, i, op, efd;
43 	struct kinfo_proc *ki;
44 	char *corefile = 0;
45 	int err;
46 	int sflag = 0;
47 	struct exec exec;
48 	char errbuf[_POSIX2_LINE_MAX];
49 	char fname[64];
50 
51 	setprog(argv[0]);
52 
53         opterr = 0;
54         while ((op = getopt(argc, argv, "c:s")) != EOF) {
55                 switch (op) {
56 
57                 case 'c':
58 			corefile = optarg;
59                         break;
60 
61 		case 's':
62 			++sflag;
63 			break;
64 
65 		default:
66 			usage();
67 			break;
68 		}
69 	}
70 	argv += optind;
71 	argc -= optind;
72 	if (argc != 2)
73 		usage();
74 
75 	kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
76 	if (kd == 0)
77 		error("%s", errbuf);
78 
79 	uid = getuid();
80 	pid = atoi(argv[1]);
81 
82 	ki = kvm_getprocs(kd, KINFO_PROC_PID, pid, &cnt);
83 	if (ki == 0 || cnt != 1)
84 		error("%d: not found", pid);
85 
86 	p = &ki->kp_proc;
87 	if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
88 		error("%d: not owner", pid);
89 
90 	if (p->p_stat == SZOMB)
91 		error("%d: zombie", pid);
92 
93 	if (p->p_flag & SWEXIT)
94 		warning("process exiting");
95 	if (p->p_flag & SSYS)
96 		/* i.e. swapper or pagedaemon */
97 		error("%d: system process");
98 
99 	if (corefile == 0) {
100 		sprintf(fname, "core.%d", pid);
101 		corefile = fname;
102 	}
103 	fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, 0666);
104 	if (fd < 0) {
105 		perror(corefile);
106 		exit(1);
107 	}
108 	efd = open(argv[0], O_RDONLY);
109 	if (efd < 0) {
110 		perror(argv[0]);
111 		exit(1);
112 	}
113 	if (read(efd, &exec, sizeof(exec)) != sizeof(exec))
114 		error("cannot read exec header of %s", argv[0]);
115 
116 	data_offset = N_DATOFF(exec);
117 
118 	if (sflag && kill(pid, SIGSTOP) < 0)
119 		warning("%d: could not deliver stop signal", pid);
120 
121 	err = core(efd, fd, p);
122 	if (err == 0)
123 		err = md_core(kd, fd, p);
124 
125 	if (sflag && kill(pid, SIGCONT) < 0)
126 		warning("%d: could not deliver continue signal", pid);
127 	close(fd);
128 
129 	exit(0);
130 }
131 
132 int
133 userdump(fd, p, addr, npage)
134 	register int fd;
135 	struct proc *p;
136 	register u_long addr;
137 	register int npage;
138 {
139 	register int cc;
140 	char buffer[NBPG];
141 
142 	while (--npage >= 0) {
143 		cc = kvm_uread(kd, p, addr, buffer, NBPG);
144 		if (cc != NBPG)
145 			return (-1);
146 		(void)write(fd, buffer, NBPG);
147 		addr += NBPG;
148 	}
149 	return (0);
150 }
151 
152 int
153 datadump(efd, fd, p, addr, npage)
154 	register int efd;
155 	register int fd;
156 	struct proc *p;
157 	register u_long addr;
158 	register int npage;
159 {
160 	register int cc, delta;
161 	char buffer[NBPG];
162 
163 	delta = data_offset - addr;
164 	while (--npage >= 0) {
165 		cc = kvm_uread(kd, p, addr, buffer, NBPG);
166 		if (cc != NBPG) {
167 			/*
168 			 * Try to read page from executable.
169 			 */
170 			if (lseek(efd, addr + delta, SEEK_SET) == -1)
171 				return (-1);
172 			if (read(efd, buffer, sizeof(buffer)) < 0)
173 				return (-1);
174 		}
175 		(void)write(fd, buffer, NBPG);
176 		addr += NBPG;
177 	}
178 	return (0);
179 }
180 
181 /*
182  * Build the core file.
183  */
184 int
185 core(efd, fd, ki)
186 	int efd;
187 	int fd;
188 	struct kinfo_proc *ki;
189 {
190 	struct user user;
191 
192 	int tsize = ki->kp_eproc.e_vm.vm_tsize;
193 	int dsize = ki->kp_eproc.e_vm.vm_dsize;
194 	int ssize = ki->kp_eproc.e_vm.vm_ssize;
195 	struct proc *p = &ki->kp_proc;
196 
197 	/* Read in user struct */
198 	if (kvm_read(kd, (u_long)p->p_addr, (void *)&user, sizeof(user))
199 	    != sizeof(user))
200 		error("could not read user structure");
201 
202 	/*
203 	 * Fill in the eproc vm parameters, since these are garbage unless
204 	 * the kernel is dumping core or something.
205 	 */
206 	user.u_kproc.kp_eproc.e_vm.vm_tsize = tsize;
207 	user.u_kproc.kp_eproc.e_vm.vm_dsize = dsize;
208 	user.u_kproc.kp_eproc.e_vm.vm_ssize = ssize;
209 	/* write out the user struct and leave the right amount of space */
210 	(void)write(fd, (char *)&user, sizeof(user));
211 	(void)lseek(fd, UPAGES * NBPG, SEEK_SET);
212 
213 	/* Dump data segment */
214 	if (datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize) < 0)
215 		error("could not dump data segment");
216 
217 	/* Dump stack segment */
218 	if (userdump(fd, p, USRSTACK - ctob(ssize), ssize) < 0)
219 		error("could not dump stack segment");
220 
221 	return (0);
222 }
223