gcore.c revision 8874
1130803Smarcel/*- 2130803Smarcel * Copyright (c) 1992, 1993 3130803Smarcel * The Regents of the University of California. All rights reserved. 4130803Smarcel * 5130803Smarcel * Redistribution and use in source and binary forms, with or without 6130803Smarcel * modification, are permitted provided that the following conditions 7130803Smarcel * are met: 8130803Smarcel * 1. Redistributions of source code must retain the above copyright 9130803Smarcel * notice, this list of conditions and the following disclaimer. 10130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11130803Smarcel * notice, this list of conditions and the following disclaimer in the 12130803Smarcel * documentation and/or other materials provided with the distribution. 13130803Smarcel * 3. All advertising materials mentioning features or use of this software 14130803Smarcel * must display the following acknowledgement: 15130803Smarcel * This product includes software developed by the University of 16130803Smarcel * California, Berkeley and its contributors. 17130803Smarcel * 4. Neither the name of the University nor the names of its contributors 18130803Smarcel * may be used to endorse or promote products derived from this software 19130803Smarcel * without specific prior written permission. 20130803Smarcel * 21130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24130803Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31130803Smarcel * SUCH DAMAGE. 32130803Smarcel */ 33130803Smarcel 34130803Smarcel#ifndef lint 35130803Smarcelstatic char copyright[] = 36130803Smarcel"@(#) Copyright (c) 1992, 1993\n\ 37130803Smarcel The Regents of the University of California. All rights reserved.\n"; 38130803Smarcel#endif /* not lint */ 39130803Smarcel 40130803Smarcel#ifndef lint 41130803Smarcelstatic char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93"; 42130803Smarcel#endif /* not lint */ 43130803Smarcel 44130803Smarcel/* 45130803Smarcel * Originally written by Eric Cooper in Fall 1981. 46130803Smarcel * Inspired by a version 6 program by Len Levin, 1978. 47130803Smarcel * Several pieces of code lifted from Bill Joy's 4BSD ps. 48130803Smarcel * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne, 49130803Smarcel * Lawrence Berkeley Laboratory. 50130803Smarcel * 51130803Smarcel * Portions of this software were developed by the Computer Systems 52130803Smarcel * Engineering group at Lawrence Berkeley Laboratory under DARPA 53130803Smarcel * contract BG 91-66 and contributed to Berkeley. 54130803Smarcel */ 55130803Smarcel#include <sys/param.h> 56130803Smarcel#include <sys/time.h> 57130803Smarcel#include <sys/stat.h> 58130803Smarcel#include <sys/proc.h> 59130803Smarcel#include <sys/user.h> 60130803Smarcel#include <sys/sysctl.h> 61130803Smarcel 62130803Smarcel#include <machine/vmparam.h> 63130803Smarcel 64130803Smarcel#include <a.out.h> 65130803Smarcel#include <fcntl.h> 66130803Smarcel#include <kvm.h> 67130803Smarcel#include <limits.h> 68130803Smarcel#include <signal.h> 69130803Smarcel#include <stdio.h> 70130803Smarcel#include <stdlib.h> 71130803Smarcel#include <string.h> 72130803Smarcel#include <unistd.h> 73130803Smarcel 74130803Smarcel#include "extern.h" 75130803Smarcel 76130803Smarcelvoid core __P((int, int, struct kinfo_proc *)); 77130803Smarcelvoid datadump __P((int, int, struct proc *, u_long, int)); 78130803Smarcelvoid usage __P((void)); 79130803Smarcelvoid userdump __P((int, struct proc *, u_long, int)); 80130803Smarcel 81130803Smarcelkvm_t *kd; 82130803Smarcel/* XXX undocumented routine, should be in kvm.h? */ 83130803Smarcelssize_t kvm_uread __P((kvm_t *, struct proc *, u_long, char *, size_t)); 84130803Smarcel 85130803Smarcelstatic int data_offset; 86130803Smarcel 87130803Smarcelint 88130803Smarcelmain(argc, argv) 89130803Smarcel int argc; 90130803Smarcel char *argv[]; 91130803Smarcel{ 92130803Smarcel register struct proc *p; 93130803Smarcel struct kinfo_proc *ki; 94130803Smarcel struct exec exec; 95130803Smarcel int ch, cnt, efd, fd, pid, sflag, uid; 96130803Smarcel char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1]; 97130803Smarcel 98130803Smarcel sflag = 0; 99130803Smarcel corefile = NULL; 100130803Smarcel while ((ch = getopt(argc, argv, "c:s")) != EOF) { 101130803Smarcel switch (ch) { 102130803Smarcel case 'c': 103130803Smarcel corefile = optarg; 104130803Smarcel break; 105130803Smarcel case 's': 106130803Smarcel sflag = 1; 107130803Smarcel break; 108130803Smarcel default: 109130803Smarcel usage(); 110130803Smarcel break; 111130803Smarcel } 112130803Smarcel } 113130803Smarcel argv += optind; 114130803Smarcel argc -= optind; 115130803Smarcel 116130803Smarcel if (argc != 2) 117130803Smarcel usage(); 118130803Smarcel 119130803Smarcel kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); 120130803Smarcel if (kd == NULL) 121130803Smarcel err(1, "%s", errbuf); 122130803Smarcel 123130803Smarcel uid = getuid(); 124130803Smarcel pid = atoi(argv[1]); 125130803Smarcel 126130803Smarcel ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); 127130803Smarcel if (ki == NULL || cnt != 1) 128130803Smarcel err(1, "%d: not found", pid); 129130803Smarcel 130130803Smarcel p = &ki->kp_proc; 131130803Smarcel if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0) 132130803Smarcel err(1, "%d: not owner", pid); 133130803Smarcel 134130803Smarcel if (p->p_stat == SZOMB) 135130803Smarcel err(1, "%d: zombie", pid); 136130803Smarcel 137130803Smarcel if (p->p_flag & P_WEXIT) 138130803Smarcel err(0, "process exiting"); 139130803Smarcel if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */ 140130803Smarcel err(1, "%d: system process"); 141130803Smarcel 142130803Smarcel if (corefile == NULL) { 143130803Smarcel (void)snprintf(fname, sizeof(fname), "core.%d", pid); 144130803Smarcel corefile = fname; 145130803Smarcel } 146130803Smarcel fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); 147130803Smarcel if (fd < 0) 148130803Smarcel err(1, "%s: %s\n", corefile, strerror(errno)); 149130803Smarcel 150130803Smarcel efd = open(argv[0], O_RDONLY, 0); 151130803Smarcel if (efd < 0) 152130803Smarcel err(1, "%s: %s\n", argv[0], strerror(errno)); 153130803Smarcel 154130803Smarcel cnt = read(efd, &exec, sizeof(exec)); 155130803Smarcel if (cnt != sizeof(exec)) 156130803Smarcel err(1, "%s exec header: %s", 157130803Smarcel argv[0], cnt > 0 ? strerror(EIO) : strerror(errno)); 158130803Smarcel 159130803Smarcel data_offset = N_DATOFF(exec); 160130803Smarcel 161130803Smarcel if (sflag && kill(pid, SIGSTOP) < 0) 162130803Smarcel err(0, "%d: stop signal: %s", pid, strerror(errno)); 163130803Smarcel 164130803Smarcel core(efd, fd, ki); 165130803Smarcel 166130803Smarcel if (sflag && kill(pid, SIGCONT) < 0) 167130803Smarcel err(0, "%d: continue signal: %s", pid, strerror(errno)); 168130803Smarcel (void)close(fd); 169130803Smarcel 170130803Smarcel exit(0); 171130803Smarcel} 172130803Smarcel 173130803Smarcel/* 174130803Smarcel * core -- 175130803Smarcel * Build the core file. 176130803Smarcel */ 177130803Smarcelvoid 178130803Smarcelcore(efd, fd, ki) 179130803Smarcel int efd; 180130803Smarcel int fd; 181130803Smarcel struct kinfo_proc *ki; 182130803Smarcel{ 183130803Smarcel union { 184130803Smarcel struct user user; 185130803Smarcel char ubytes[ctob(UPAGES)]; 186130803Smarcel } uarea; 187130803Smarcel struct proc *p = &ki->kp_proc; 188130803Smarcel int tsize = ki->kp_eproc.e_vm.vm_tsize; 189130803Smarcel int dsize = ki->kp_eproc.e_vm.vm_dsize; 190130803Smarcel int ssize = ki->kp_eproc.e_vm.vm_ssize; 191130803Smarcel int cnt; 192130803Smarcel 193130803Smarcel /* Read in user struct */ 194130803Smarcel cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea)); 195130803Smarcel if (cnt != sizeof(uarea)) 196130803Smarcel err(1, "read user structure: %s", 197130803Smarcel cnt > 0 ? strerror(EIO) : strerror(errno)); 198130803Smarcel 199130803Smarcel /* 200130803Smarcel * Fill in the eproc vm parameters, since these are garbage unless 201130803Smarcel * the kernel is dumping core or something. 202130803Smarcel */ 203130803Smarcel uarea.user.u_kproc = *ki; 204130803Smarcel 205130803Smarcel /* Dump user area */ 206130803Smarcel cnt = write(fd, &uarea, sizeof(uarea)); 207130803Smarcel if (cnt != sizeof(uarea)) 208130803Smarcel err(1, "write user structure: %s", 209130803Smarcel cnt > 0 ? strerror(EIO) : strerror(errno)); 210130803Smarcel 211130803Smarcel /* Dump data segment */ 212130803Smarcel datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize); 213130803Smarcel 214130803Smarcel /* Dump stack segment */ 215130803Smarcel userdump(fd, p, USRSTACK - ctob(ssize), ssize); 216130803Smarcel 217130803Smarcel /* Dump machine dependent portions of the core. */ 218130803Smarcel md_core(kd, fd, ki); 219130803Smarcel} 220130803Smarcel 221130803Smarcelvoid 222130803Smarceldatadump(efd, fd, p, addr, npage) 223130803Smarcel register int efd; 224130803Smarcel register int fd; 225130803Smarcel struct proc *p; 226130803Smarcel register u_long addr; 227130803Smarcel register int npage; 228130803Smarcel{ 229130803Smarcel register int cc, delta; 230130803Smarcel char buffer[NBPG]; 231 232 delta = data_offset - addr; 233 while (--npage >= 0) { 234 cc = kvm_uread(kd, p, addr, buffer, NBPG); 235 if (cc != NBPG) { 236 /* Try to read the page from the executable. */ 237 if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1) 238 err(1, "seek executable: %s", strerror(errno)); 239 cc = read(efd, buffer, sizeof(buffer)); 240 if (cc != sizeof(buffer)) 241 if (cc < 0) 242 err(1, "read executable: %s", 243 strerror(errno)); 244 else /* Assume untouched bss page. */ 245 bzero(buffer, sizeof(buffer)); 246 } 247 cc = write(fd, buffer, NBPG); 248 if (cc != NBPG) 249 err(1, "write data segment: %s", 250 cc > 0 ? strerror(EIO) : strerror(errno)); 251 addr += NBPG; 252 } 253} 254 255void 256userdump(fd, p, addr, npage) 257 register int fd; 258 struct proc *p; 259 register u_long addr; 260 register int npage; 261{ 262 register int cc; 263 char buffer[NBPG]; 264 265 while (--npage >= 0) { 266 cc = kvm_uread(kd, p, addr, buffer, NBPG); 267 if (cc != NBPG) 268 /* Could be an untouched fill-with-zero page. */ 269 bzero(buffer, NBPG); 270 cc = write(fd, buffer, NBPG); 271 if (cc != NBPG) 272 err(1, "write stack segment: %s", 273 cc > 0 ? strerror(EIO) : strerror(errno)); 274 addr += NBPG; 275 } 276} 277 278void 279usage() 280{ 281 (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); 282 exit(1); 283} 284 285#if __STDC__ 286#include <stdarg.h> 287#else 288#include <varargs.h> 289#endif 290 291void 292#if __STDC__ 293err(int fatal, const char *fmt, ...) 294#else 295err(fatal, fmt, va_alist) 296 int fatal; 297 char *fmt; 298 va_dcl 299#endif 300{ 301 va_list ap; 302#if __STDC__ 303 va_start(ap, fmt); 304#else 305 va_start(ap); 306#endif 307 (void)fprintf(stderr, "gcore: "); 308 (void)vfprintf(stderr, fmt, ap); 309 va_end(ap); 310 (void)fprintf(stderr, "\n"); 311 exit(1); 312 /* NOTREACHED */ 313} 314