gcore.c revision 1.2 1 /* $NetBSD: gcore.c,v 1.2 1995/09/05 02:51:00 tls Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1992, 1993\n\
39 The Regents of the University of California. All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93";
45 #else
46 static char rcsid[] = "$NetBSD: gcore.c,v 1.2 1995/09/05 02:51:00 tls Exp $";
47 #endif
48 #endif /* not lint */
49
50 /*
51 * Originally written by Eric Cooper in Fall 1981.
52 * Inspired by a version 6 program by Len Levin, 1978.
53 * Several pieces of code lifted from Bill Joy's 4BSD ps.
54 * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne,
55 * Lawrence Berkeley Laboratory.
56 *
57 * Portions of this software were developed by the Computer Systems
58 * Engineering group at Lawrence Berkeley Laboratory under DARPA
59 * contract BG 91-66 and contributed to Berkeley.
60 */
61 #include <sys/param.h>
62 #include <sys/time.h>
63 #include <sys/stat.h>
64 #include <sys/proc.h>
65 #include <sys/user.h>
66 #include <sys/sysctl.h>
67
68 #include <machine/vmparam.h>
69
70 #include <a.out.h>
71 #include <fcntl.h>
72 #include <kvm.h>
73 #include <limits.h>
74 #include <signal.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include <unistd.h>
79
80 #include "extern.h"
81
82 void core __P((int, int, struct kinfo_proc *));
83 void datadump __P((int, int, struct proc *, u_long, int));
84 void usage __P((void));
85 void userdump __P((int, struct proc *, u_long, int));
86
87 kvm_t *kd;
88 /* XXX undocumented routine, should be in kvm.h? */
89 ssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t));
90
91 static int data_offset;
92
93 int
94 main(argc, argv)
95 int argc;
96 char *argv[];
97 {
98 register struct proc *p;
99 struct kinfo_proc *ki;
100 struct exec exec;
101 int ch, cnt, efd, fd, pid, sflag, uid;
102 char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1];
103
104 sflag = 0;
105 corefile = NULL;
106 while ((ch = getopt(argc, argv, "c:s")) != EOF) {
107 switch (ch) {
108 case 'c':
109 corefile = optarg;
110 break;
111 case 's':
112 sflag = 1;
113 break;
114 default:
115 usage();
116 break;
117 }
118 }
119 argv += optind;
120 argc -= optind;
121
122 if (argc != 2)
123 usage();
124
125 kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
126 if (kd == NULL)
127 err(1, "%s", errbuf);
128
129 uid = getuid();
130 pid = atoi(argv[1]);
131
132 ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
133 if (ki == NULL || cnt != 1)
134 err(1, "%d: not found", pid);
135
136 p = &ki->kp_proc;
137 if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
138 err(1, "%d: not owner", pid);
139
140 if (p->p_stat == SZOMB)
141 err(1, "%d: zombie", pid);
142
143 if (p->p_flag & P_WEXIT)
144 err(0, "process exiting");
145 if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
146 err(1, "%d: system process");
147
148 if (corefile == NULL) {
149 (void)snprintf(fname, sizeof(fname), "core.%d", pid);
150 corefile = fname;
151 }
152 fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
153 if (fd < 0)
154 err(1, "%s: %s\n", corefile, strerror(errno));
155
156 efd = open(argv[0], O_RDONLY, 0);
157 if (efd < 0)
158 err(1, "%s: %s\n", argv[0], strerror(errno));
159
160 cnt = read(efd, &exec, sizeof(exec));
161 if (cnt != sizeof(exec))
162 err(1, "%s exec header: %s",
163 argv[0], cnt > 0 ? strerror(EIO) : strerror(errno));
164
165 data_offset = N_DATOFF(exec);
166
167 if (sflag && kill(pid, SIGSTOP) < 0)
168 err(0, "%d: stop signal: %s", pid, strerror(errno));
169
170 core(efd, fd, ki);
171
172 if (sflag && kill(pid, SIGCONT) < 0)
173 err(0, "%d: continue signal: %s", pid, strerror(errno));
174 (void)close(fd);
175
176 exit(0);
177 }
178
179 /*
180 * core --
181 * Build the core file.
182 */
183 void
184 core(efd, fd, ki)
185 int efd;
186 int fd;
187 struct kinfo_proc *ki;
188 {
189 union {
190 struct user user;
191 char ubytes[ctob(UPAGES)];
192 } uarea;
193 struct proc *p = &ki->kp_proc;
194 int tsize = ki->kp_eproc.e_vm.vm_tsize;
195 int dsize = ki->kp_eproc.e_vm.vm_dsize;
196 int ssize = ki->kp_eproc.e_vm.vm_ssize;
197 int cnt;
198
199 /* Read in user struct */
200 cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea));
201 if (cnt != sizeof(uarea))
202 err(1, "read user structure: %s",
203 cnt > 0 ? strerror(EIO) : strerror(errno));
204
205 /*
206 * Fill in the eproc vm parameters, since these are garbage unless
207 * the kernel is dumping core or something.
208 */
209 uarea.user.u_kproc = *ki;
210
211 /* Dump user area */
212 cnt = write(fd, &uarea, sizeof(uarea));
213 if (cnt != sizeof(uarea))
214 err(1, "write user structure: %s",
215 cnt > 0 ? strerror(EIO) : strerror(errno));
216
217 /* Dump data segment */
218 datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize);
219
220 /* Dump stack segment */
221 userdump(fd, p, USRSTACK - ctob(ssize), ssize);
222
223 /* Dump machine dependent portions of the core. */
224 md_core(kd, fd, ki);
225 }
226
227 void
228 datadump(efd, fd, p, addr, npage)
229 register int efd;
230 register int fd;
231 struct proc *p;
232 register u_long addr;
233 register int npage;
234 {
235 register int cc, delta;
236 char buffer[NBPG];
237
238 delta = data_offset - addr;
239 while (--npage >= 0) {
240 cc = kvm_uread(kd, p, addr, buffer, NBPG);
241 if (cc != NBPG) {
242 /* Try to read the page from the executable. */
243 if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1)
244 err(1, "seek executable: %s", strerror(errno));
245 cc = read(efd, buffer, sizeof(buffer));
246 if (cc != sizeof(buffer))
247 if (cc < 0)
248 err(1, "read executable: %s",
249 strerror(errno));
250 else /* Assume untouched bss page. */
251 bzero(buffer, sizeof(buffer));
252 }
253 cc = write(fd, buffer, NBPG);
254 if (cc != NBPG)
255 err(1, "write data segment: %s",
256 cc > 0 ? strerror(EIO) : strerror(errno));
257 addr += NBPG;
258 }
259 }
260
261 void
262 userdump(fd, p, addr, npage)
263 register int fd;
264 struct proc *p;
265 register u_long addr;
266 register int npage;
267 {
268 register int cc;
269 char buffer[NBPG];
270
271 while (--npage >= 0) {
272 cc = kvm_uread(kd, p, addr, buffer, NBPG);
273 if (cc != NBPG)
274 /* Could be an untouched fill-with-zero page. */
275 bzero(buffer, NBPG);
276 cc = write(fd, buffer, NBPG);
277 if (cc != NBPG)
278 err(1, "write stack segment: %s",
279 cc > 0 ? strerror(EIO) : strerror(errno));
280 addr += NBPG;
281 }
282 }
283
284 void
285 usage()
286 {
287 (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n");
288 exit(1);
289 }
290
291 #if __STDC__
292 #include <stdarg.h>
293 #else
294 #include <varargs.h>
295 #endif
296
297 void
298 #if __STDC__
299 err(int fatal, const char *fmt, ...)
300 #else
301 err(fatal, fmt, va_alist)
302 int fatal;
303 char *fmt;
304 va_dcl
305 #endif
306 {
307 va_list ap;
308 #if __STDC__
309 va_start(ap, fmt);
310 #else
311 va_start(ap);
312 #endif
313 (void)fprintf(stderr, "gcore: ");
314 (void)vfprintf(stderr, fmt, ap);
315 va_end(ap);
316 (void)fprintf(stderr, "\n");
317 exit(1);
318 /* NOTREACHED */
319 }
320