1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1992, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 09/23/93";
16 #endif /* not lint */
17
18 /*
19 * Originally written by Eric Cooper in Fall 1981.
20 * Inspired by a version 6 program by Len Levin, 1978.
21 * Several pieces of code lifted from Bill Joy's 4BSD ps.
22 * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne,
23 * Lawrence Berkeley Laboratory.
24 *
25 * Portions of this software were developed by the Computer Systems
26 * Engineering group at Lawrence Berkeley Laboratory under DARPA
27 * contract BG 91-66 and contributed to Berkeley.
28 */
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/stat.h>
32 #include <sys/proc.h>
33 #include <sys/user.h>
34 #include <sys/sysctl.h>
35
36 #include <machine/vmparam.h>
37
38 #include <a.out.h>
39 #include <fcntl.h>
40 #include <kvm.h>
41 #include <limits.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "extern.h"
49
50 void core __P((int, int, struct kinfo_proc *));
51 void datadump __P((int, int, struct proc *, u_long, int));
52 void usage __P((void));
53 void userdump __P((int, struct proc *, u_long, int));
54
55 kvm_t *kd;
56 /* XXX undocumented routine, should be in kvm.h? */
57 ssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t));
58
59 static int data_offset;
60
61 int
main(argc,argv)62 main(argc, argv)
63 int argc;
64 char *argv[];
65 {
66 register struct proc *p;
67 struct kinfo_proc *ki;
68 struct exec exec;
69 int ch, cnt, efd, fd, pid, sflag, uid;
70 char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1];
71
72 sflag = 0;
73 corefile = NULL;
74 while ((ch = getopt(argc, argv, "c:s")) != EOF) {
75 switch (ch) {
76 case 'c':
77 corefile = optarg;
78 break;
79 case 's':
80 sflag = 1;
81 break;
82 default:
83 usage();
84 break;
85 }
86 }
87 argv += optind;
88 argc -= optind;
89
90 if (argc != 2)
91 usage();
92
93 kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
94 if (kd == NULL)
95 err(1, "%s", errbuf);
96
97 uid = getuid();
98 pid = atoi(argv[1]);
99
100 ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
101 if (ki == NULL || cnt != 1)
102 err(1, "%d: not found", pid);
103
104 p = &ki->kp_proc;
105 if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
106 err(1, "%d: not owner", pid);
107
108 if (p->p_stat == SZOMB)
109 err(1, "%d: zombie", pid);
110
111 if (p->p_flag & P_WEXIT)
112 err(0, "process exiting");
113 if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
114 err(1, "%d: system process");
115
116 if (corefile == NULL) {
117 (void)snprintf(fname, sizeof(fname), "core.%d", pid);
118 corefile = fname;
119 }
120 fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
121 if (fd < 0)
122 err(1, "%s: %s\n", corefile, strerror(errno));
123
124 efd = open(argv[0], O_RDONLY, 0);
125 if (efd < 0)
126 err(1, "%s: %s\n", argv[0], strerror(errno));
127
128 cnt = read(efd, &exec, sizeof(exec));
129 if (cnt != sizeof(exec))
130 err(1, "%s exec header: %s",
131 argv[0], cnt > 0 ? strerror(EIO) : strerror(errno));
132
133 data_offset = N_DATOFF(exec);
134
135 if (sflag && kill(pid, SIGSTOP) < 0)
136 err(0, "%d: stop signal: %s", pid, strerror(errno));
137
138 core(efd, fd, ki);
139
140 if (sflag && kill(pid, SIGCONT) < 0)
141 err(0, "%d: continue signal: %s", pid, strerror(errno));
142 (void)close(fd);
143
144 exit(0);
145 }
146
147 /*
148 * core --
149 * Build the core file.
150 */
151 void
core(efd,fd,ki)152 core(efd, fd, ki)
153 int efd;
154 int fd;
155 struct kinfo_proc *ki;
156 {
157 union {
158 struct user user;
159 char ubytes[ctob(UPAGES)];
160 } uarea;
161 struct proc *p = &ki->kp_proc;
162 int tsize = ki->kp_eproc.e_vm.vm_tsize;
163 int dsize = ki->kp_eproc.e_vm.vm_dsize;
164 int ssize = ki->kp_eproc.e_vm.vm_ssize;
165 int cnt;
166
167 /* Read in user struct */
168 cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea));
169 if (cnt != sizeof(uarea))
170 err(1, "read user structure: %s",
171 cnt > 0 ? strerror(EIO) : strerror(errno));
172
173 /*
174 * Fill in the eproc vm parameters, since these are garbage unless
175 * the kernel is dumping core or something.
176 */
177 uarea.user.u_kproc = *ki;
178
179 /* Dump user area */
180 cnt = write(fd, &uarea, sizeof(uarea));
181 if (cnt != sizeof(uarea))
182 err(1, "write user structure: %s",
183 cnt > 0 ? strerror(EIO) : strerror(errno));
184
185 /* Dump data segment */
186 datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize);
187
188 /* Dump stack segment */
189 userdump(fd, p, USRSTACK - ctob(ssize), ssize);
190
191 /* Dump machine dependent portions of the core. */
192 md_core(kd, fd, ki);
193 }
194
195 void
datadump(efd,fd,p,addr,npage)196 datadump(efd, fd, p, addr, npage)
197 register int efd;
198 register int fd;
199 struct proc *p;
200 register u_long addr;
201 register int npage;
202 {
203 register int cc, delta;
204 char buffer[NBPG];
205
206 delta = data_offset - addr;
207 while (--npage >= 0) {
208 cc = kvm_uread(kd, p, addr, buffer, NBPG);
209 if (cc != NBPG) {
210 /* Try to read the page from the executable. */
211 if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1)
212 err(1, "seek executable: %s", strerror(errno));
213 cc = read(efd, buffer, sizeof(buffer));
214 if (cc != sizeof(buffer))
215 if (cc < 0)
216 err(1, "read executable: %s",
217 strerror(errno));
218 else /* Assume untouched bss page. */
219 bzero(buffer, sizeof(buffer));
220 }
221 cc = write(fd, buffer, NBPG);
222 if (cc != NBPG)
223 err(1, "write data segment: %s",
224 cc > 0 ? strerror(EIO) : strerror(errno));
225 addr += NBPG;
226 }
227 }
228
229 void
userdump(fd,p,addr,npage)230 userdump(fd, p, addr, npage)
231 register int fd;
232 struct proc *p;
233 register u_long addr;
234 register int npage;
235 {
236 register int cc;
237 char buffer[NBPG];
238
239 while (--npage >= 0) {
240 cc = kvm_uread(kd, p, addr, buffer, NBPG);
241 if (cc != NBPG)
242 /* Could be an untouched fill-with-zero page. */
243 bzero(buffer, NBPG);
244 cc = write(fd, buffer, NBPG);
245 if (cc != NBPG)
246 err(1, "write stack segment: %s",
247 cc > 0 ? strerror(EIO) : strerror(errno));
248 addr += NBPG;
249 }
250 }
251
252 void
usage()253 usage()
254 {
255 (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n");
256 exit(1);
257 }
258
259 #if __STDC__
260 #include <stdarg.h>
261 #else
262 #include <varargs.h>
263 #endif
264
265 void
266 #if __STDC__
err(int fatal,const char * fmt,...)267 err(int fatal, const char *fmt, ...)
268 #else
269 err(fatal, fmt, va_alist)
270 int fatal;
271 char *fmt;
272 va_dcl
273 #endif
274 {
275 va_list ap;
276 #if __STDC__
277 va_start(ap, fmt);
278 #else
279 va_start(ap);
280 #endif
281 (void)fprintf(stderr, "gcore: ");
282 (void)vfprintf(stderr, fmt, ap);
283 va_end(ap);
284 (void)fprintf(stderr, "\n");
285 exit(1);
286 /* NOTREACHED */
287 }
288