Commit | Line | Data |
---|---|---|
223e9f10 | 1 | /*- |
acd4f2e1 KB |
2 | * Copyright (c) 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
fa6237e9 | 4 | * |
19e614c2 | 5 | * %sccs.include.redist.c% |
223e9f10 SM |
6 | */ |
7 | ||
de358c72 | 8 | #ifndef lint |
acd4f2e1 KB |
9 | static char copyright[] = |
10 | "@(#) Copyright (c) 1992, 1993\n\ | |
11 | The Regents of the University of California. All rights reserved.\n"; | |
de358c72 KB |
12 | #endif /* not lint */ |
13 | ||
14 | #ifndef lint | |
39e484b3 | 15 | static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) %G%"; |
de358c72 KB |
16 | #endif /* not lint */ |
17 | ||
223e9f10 | 18 | /* |
de358c72 KB |
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. | |
4f626618 | 28 | */ |
4f626618 | 29 | #include <sys/param.h> |
223e9f10 | 30 | #include <sys/time.h> |
de358c72 | 31 | #include <sys/stat.h> |
4f626618 | 32 | #include <sys/proc.h> |
223e9f10 | 33 | #include <sys/user.h> |
038ba33c | 34 | #include <sys/sysctl.h> |
fafa755d | 35 | |
223e9f10 | 36 | #include <machine/vmparam.h> |
4f626618 | 37 | |
de358c72 KB |
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> | |
fafa755d | 47 | |
de358c72 KB |
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)); | |
4f626618 | 54 | |
de358c72 KB |
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)); | |
4f626618 | 58 | |
223e9f10 | 59 | static int data_offset; |
4f626618 | 60 | |
de358c72 | 61 | int |
4f626618 KM |
62 | main(argc, argv) |
63 | int argc; | |
de358c72 | 64 | char *argv[]; |
4f626618 | 65 | { |
4f626618 | 66 | register struct proc *p; |
223e9f10 | 67 | struct kinfo_proc *ki; |
223e9f10 | 68 | struct exec exec; |
de358c72 KB |
69 | int ch, cnt, efd, fd, pid, sflag, uid; |
70 | char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1]; | |
223e9f10 | 71 | |
de358c72 KB |
72 | sflag = 0; |
73 | corefile = NULL; | |
74 | while ((ch = getopt(argc, argv, "c:s")) != EOF) { | |
75 | switch (ch) { | |
223e9f10 SM |
76 | case 'c': |
77 | corefile = optarg; | |
78 | break; | |
223e9f10 | 79 | case 's': |
de358c72 | 80 | sflag = 1; |
223e9f10 | 81 | break; |
223e9f10 SM |
82 | default: |
83 | usage(); | |
84 | break; | |
4f626618 | 85 | } |
4f626618 | 86 | } |
223e9f10 SM |
87 | argv += optind; |
88 | argc -= optind; | |
de358c72 | 89 | |
223e9f10 SM |
90 | if (argc != 2) |
91 | usage(); | |
92 | ||
93 | kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); | |
de358c72 KB |
94 | if (kd == NULL) |
95 | err(1, "%s", errbuf); | |
223e9f10 SM |
96 | |
97 | uid = getuid(); | |
98 | pid = atoi(argv[1]); | |
99 | ||
038ba33c | 100 | ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); |
de358c72 KB |
101 | if (ki == NULL || cnt != 1) |
102 | err(1, "%d: not found", pid); | |
223e9f10 SM |
103 | |
104 | p = &ki->kp_proc; | |
105 | if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0) | |
de358c72 | 106 | err(1, "%d: not owner", pid); |
223e9f10 SM |
107 | |
108 | if (p->p_stat == SZOMB) | |
de358c72 | 109 | err(1, "%d: zombie", pid); |
223e9f10 | 110 | |
39e484b3 | 111 | if (p->p_flag & P_WEXIT) |
de358c72 | 112 | err(0, "process exiting"); |
39e484b3 | 113 | if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */ |
de358c72 | 114 | err(1, "%d: system process"); |
223e9f10 | 115 | |
de358c72 KB |
116 | if (corefile == NULL) { |
117 | (void)snprintf(fname, sizeof(fname), "core.%d", pid); | |
223e9f10 | 118 | corefile = fname; |
4f626618 | 119 | } |
de358c72 KB |
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)); | |
4f626618 | 132 | |
223e9f10 | 133 | data_offset = N_DATOFF(exec); |
4f626618 | 134 | |
de358c72 KB |
135 | if (sflag && kill(pid, SIGSTOP) < 0) |
136 | err(0, "%d: stop signal: %s", pid, strerror(errno)); | |
4f626618 | 137 | |
de358c72 | 138 | core(efd, fd, ki); |
4f626618 | 139 | |
223e9f10 | 140 | if (sflag && kill(pid, SIGCONT) < 0) |
de358c72 KB |
141 | err(0, "%d: continue signal: %s", pid, strerror(errno)); |
142 | (void)close(fd); | |
4f626618 | 143 | |
223e9f10 | 144 | exit(0); |
4f626618 KM |
145 | } |
146 | ||
de358c72 KB |
147 | /* |
148 | * core -- | |
149 | * Build the core file. | |
150 | */ | |
151 | void | |
152 | core(efd, fd, ki) | |
153 | int efd; | |
154 | int fd; | |
155 | struct kinfo_proc *ki; | |
4f626618 | 156 | { |
de358c72 KB |
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; | |
223e9f10 | 166 | |
de358c72 KB |
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); | |
4f626618 KM |
193 | } |
194 | ||
de358c72 | 195 | void |
223e9f10 SM |
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; | |
4f626618 | 202 | { |
223e9f10 SM |
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) { | |
de358c72 KB |
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)) | |
375fcabd KB |
215 | if (cc < 0) |
216 | err(1, "read executable: %s", | |
217 | strerror(errno)); | |
218 | else /* Assume untouched bss page. */ | |
219 | bzero(buffer, sizeof(buffer)); | |
4f626618 | 220 | } |
de358c72 KB |
221 | cc = write(fd, buffer, NBPG); |
222 | if (cc != NBPG) | |
223 | err(1, "write data segment: %s", | |
224 | cc > 0 ? strerror(EIO) : strerror(errno)); | |
223e9f10 | 225 | addr += NBPG; |
4f626618 KM |
226 | } |
227 | } | |
228 | ||
de358c72 KB |
229 | void |
230 | userdump(fd, p, addr, npage) | |
231 | register int fd; | |
232 | struct proc *p; | |
233 | register u_long addr; | |
234 | register int npage; | |
4f626618 | 235 | { |
de358c72 KB |
236 | register int cc; |
237 | char buffer[NBPG]; | |
223e9f10 | 238 | |
de358c72 KB |
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 | } | |
223e9f10 | 251 | |
de358c72 KB |
252 | void |
253 | usage() | |
254 | { | |
255 | (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); | |
256 | exit(1); | |
257 | } | |
223e9f10 | 258 | |
de358c72 KB |
259 | #if __STDC__ |
260 | #include <stdarg.h> | |
261 | #else | |
262 | #include <varargs.h> | |
263 | #endif | |
223e9f10 | 264 | |
de358c72 KB |
265 | void |
266 | #if __STDC__ | |
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 */ | |
4f626618 | 287 | } |