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.1 (Berkeley) 06/06/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 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 & SWEXIT) 112 err(0, "process exiting"); 113 if (p->p_flag & SSYS) /* 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 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 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 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 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__ 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