POSIX 1003.2B/D9 symbolic links
[unix-history] / usr / src / usr.bin / gcore / gcore.c
CommitLineData
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
9static 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 15static 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
50void core __P((int, int, struct kinfo_proc *));
51void datadump __P((int, int, struct proc *, u_long, int));
52void usage __P((void));
53void userdump __P((int, struct proc *, u_long, int));
4f626618 54
de358c72
KB
55kvm_t *kd;
56/* XXX undocumented routine, should be in kvm.h? */
57ssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t));
4f626618 58
223e9f10 59static int data_offset;
4f626618 60
de358c72 61int
4f626618
KM
62main(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 */
151void
152core(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 195void
223e9f10
SM
196datadump(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
229void
230userdump(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
252void
253usage()
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
265void
266#if __STDC__
267err(int fatal, const char *fmt, ...)
268#else
269err(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}