gcore.c revision 17142
1151497Sru/*- 275584Sru * Copyright (c) 1992, 1993 375584Sru * The Regents of the University of California. All rights reserved. 475584Sru * 575584Sru * Redistribution and use in source and binary forms, with or without 675584Sru * modification, are permitted provided that the following conditions 775584Sru * are met: 875584Sru * 1. Redistributions of source code must retain the above copyright 975584Sru * notice, this list of conditions and the following disclaimer. 1075584Sru * 2. Redistributions in binary form must reproduce the above copyright 1175584Sru * notice, this list of conditions and the following disclaimer in the 1275584Sru * documentation and/or other materials provided with the distribution. 1375584Sru * 3. All advertising materials mentioning features or use of this software 1475584Sru * must display the following acknowledgement: 1575584Sru * This product includes software developed by the University of 1675584Sru * California, Berkeley and its contributors. 1775584Sru * 4. Neither the name of the University nor the names of its contributors 18151497Sru * may be used to endorse or promote products derived from this software 1975584Sru * without specific prior written permission. 2075584Sru * 21151497Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2275584Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23104862Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2475584Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2575584Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26151497Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27151497Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28151497Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29151497Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30151497Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31151497Sru * SUCH DAMAGE. 3275584Sru */ 3375584Sru 3475584Sru#ifndef lint 3575584Srustatic char copyright[] = 3675584Sru"@(#) Copyright (c) 1992, 1993\n\ 3775584Sru The Regents of the University of California. All rights reserved.\n"; 3875584Sru#endif /* not lint */ 3975584Sru 40151497Sru#ifndef lint 4175584Srustatic char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93"; 4275584Sru#endif /* not lint */ 4375584Sru 4475584Sru/* 45151497Sru * Originally written by Eric Cooper in Fall 1981. 46151497Sru * Inspired by a version 6 program by Len Levin, 1978. 4775584Sru * Several pieces of code lifted from Bill Joy's 4BSD ps. 4875584Sru * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne, 49151497Sru * Lawrence Berkeley Laboratory. 5075584Sru * 5175584Sru * Portions of this software were developed by the Computer Systems 5275584Sru * Engineering group at Lawrence Berkeley Laboratory under DARPA 5375584Sru * contract BG 91-66 and contributed to Berkeley. 5475584Sru */ 5575584Sru#include <sys/param.h> 5675584Sru#include <sys/time.h> 57151497Sru#include <sys/stat.h> 5875584Sru#include <sys/proc.h> 5975584Sru#include <sys/user.h> 60151497Sru#include <sys/sysctl.h> 61151497Sru 6275584Sru#include <machine/vmparam.h> 6375584Sru 6475584Sru#include <a.out.h> 65151497Sru#include <fcntl.h> 66151497Sru#include <kvm.h> 67151497Sru#include <limits.h> 68151497Sru#include <signal.h> 69151497Sru#include <stdio.h> 7075584Sru#include <stdlib.h> 7175584Sru#include <string.h> 7275584Sru#include <unistd.h> 73151497Sru 7475584Sru#include "extern.h" 7575584Sru 7675584Sruvoid core __P((int, int, struct kinfo_proc *)); 77151497Sruvoid datadump __P((int, int, struct proc *, u_long, int)); 7875584Sruvoid usage __P((void)); 7975584Sruvoid userdump __P((int, struct proc *, u_long, int)); 8075584Sru 81151497Srukvm_t *kd; 8275584Sru/* XXX undocumented routine, should be in kvm.h? */ 8375584Srussize_t kvm_uread __P((kvm_t *, const struct proc *, u_long, char *, size_t)); 8475584Sru 85151497Sru 8675584Srustatic int data_offset; 8775584Sru 8875584Sruint 89151497Srumain(argc, argv) 9075584Sru int argc; 9175584Sru char *argv[]; 9275584Sru{ 93151497Sru register struct proc *p; 9475584Sru struct kinfo_proc *ki; 9575584Sru struct exec exec; 9675584Sru int ch, cnt, efd, fd, pid, sflag, uid; 97151497Sru char *corefile, errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1]; 9875584Sru 9975584Sru sflag = 0; 10075584Sru corefile = NULL; 101151497Sru while ((ch = getopt(argc, argv, "c:s")) != EOF) { 10275584Sru switch (ch) { 10375584Sru case 'c': 10475584Sru corefile = optarg; 105151497Sru break; 10675584Sru case 's': 10775584Sru sflag = 1; 10875584Sru break; 109151497Sru default: 11075584Sru usage(); 11175584Sru break; 11275584Sru } 113151497Sru } 11475584Sru argv += optind; 11575584Sru argc -= optind; 11675584Sru 117151497Sru if (argc != 2) 11875584Sru usage(); 11975584Sru 12075584Sru kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); 121151497Sru if (kd == NULL) 12275584Sru err(1, "%s", errbuf); 12375584Sru 12475584Sru uid = getuid(); 125151497Sru pid = atoi(argv[1]); 12675584Sru 12775584Sru ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); 12875584Sru if (ki == NULL || cnt != 1) 129151497Sru err(1, "%d: not found", pid); 13075584Sru 13175584Sru p = &ki->kp_proc; 13275584Sru if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0) 133151497Sru err(1, "%d: not owner", pid); 13475584Sru 13575584Sru if (p->p_stat == SZOMB) 13675584Sru err(1, "%d: zombie", pid); 137151497Sru 13875584Sru if (p->p_flag & P_WEXIT) 13975584Sru err(0, "process exiting"); 14075584Sru if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */ 141151497Sru err(1, "%d: system process"); 14275584Sru 14375584Sru if (corefile == NULL) { 14475584Sru (void)snprintf(fname, sizeof(fname), "core.%d", pid); 145151497Sru corefile = fname; 14675584Sru } 14775584Sru fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); 14875584Sru if (fd < 0) 149151497Sru err(1, "%s: %s\n", corefile, strerror(errno)); 15075584Sru 15175584Sru efd = open(argv[0], O_RDONLY, 0); 15275584Sru if (efd < 0) 153151497Sru err(1, "%s: %s\n", argv[0], strerror(errno)); 15475584Sru 15575584Sru cnt = read(efd, &exec, sizeof(exec)); 15675584Sru if (cnt != sizeof(exec)) 157151497Sru err(1, "%s exec header: %s", 15875584Sru argv[0], cnt > 0 ? strerror(EIO) : strerror(errno)); 15975584Sru 16075584Sru data_offset = N_DATOFF(exec); 161151497Sru 16275584Sru if (sflag && kill(pid, SIGSTOP) < 0) 16375584Sru err(0, "%d: stop signal: %s", pid, strerror(errno)); 16475584Sru 165151497Sru core(efd, fd, ki); 16675584Sru 16775584Sru if (sflag && kill(pid, SIGCONT) < 0) 16875584Sru err(0, "%d: continue signal: %s", pid, strerror(errno)); 169151497Sru (void)close(fd); 17075584Sru 17175584Sru exit(0); 17275584Sru} 173151497Sru 17475584Sru/* 17575584Sru * core -- 17675584Sru * Build the core file. 177151497Sru */ 178151497Sruvoid 179151497Srucore(efd, fd, ki) 180151497Sru int efd; 181151497Sru int fd; 18275584Sru struct kinfo_proc *ki; 18375584Sru{ 18475584Sru union { 185151497Sru struct user user; 18675584Sru char ubytes[ctob(UPAGES)]; 18775584Sru } uarea; 18875584Sru struct proc *p = &ki->kp_proc; 189151497Sru int tsize = ki->kp_eproc.e_vm.vm_tsize; 19075584Sru int dsize = ki->kp_eproc.e_vm.vm_dsize; 19175584Sru int ssize = ki->kp_eproc.e_vm.vm_ssize; 19275584Sru int cnt; 193151497Sru 19475584Sru /* Read in user struct */ 19575584Sru cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea)); 19675584Sru if (cnt != sizeof(uarea)) 197151497Sru err(1, "read user structure: %s", 19875584Sru cnt > 0 ? strerror(EIO) : strerror(errno)); 19975584Sru 20075584Sru /* 201151497Sru * Fill in the eproc vm parameters, since these are garbage unless 202151497Sru * the kernel is dumping core or something. 203151497Sru */ 20475584Sru uarea.user.u_kproc = *ki; 205151497Sru 20675584Sru /* Dump user area */ 20775584Sru cnt = write(fd, &uarea, sizeof(uarea)); 20875584Sru if (cnt != sizeof(uarea)) 209151497Sru err(1, "write user structure: %s", 210151497Sru cnt > 0 ? strerror(EIO) : strerror(errno)); 211151497Sru 21275584Sru /* Dump data segment */ 213151497Sru datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize); 214151497Sru 215151497Sru /* Dump stack segment */ 216151497Sru userdump(fd, p, USRSTACK - ctob(ssize), ssize); 217151497Sru 218151497Sru /* Dump machine dependent portions of the core. */ 219151497Sru md_core(kd, fd, ki); 220151497Sru} 221151497Sru 222151497Sruvoid 223151497Srudatadump(efd, fd, p, addr, npage) 224151497Sru register int efd; 225151497Sru register int fd; 226151497Sru struct proc *p; 227151497Sru register u_long addr; 228151497Sru register int npage; 229151497Sru{ 230151497Sru register int cc, delta; 231151497Sru char buffer[PAGE_SIZE]; 232151497Sru 233151497Sru delta = data_offset - addr; 234151497Sru while (--npage >= 0) { 235151497Sru cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE); 236151497Sru if (cc != PAGE_SIZE) { 237151497Sru /* Try to read the page from the executable. */ 238151497Sru if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1) 239151497Sru err(1, "seek executable: %s", strerror(errno)); 240151497Sru cc = read(efd, buffer, sizeof(buffer)); 241151497Sru if (cc != sizeof(buffer)) 242151497Sru if (cc < 0) 243151497Sru err(1, "read executable: %s", 244151497Sru strerror(errno)); 245151497Sru else /* Assume untouched bss page. */ 246151497Sru bzero(buffer, sizeof(buffer)); 247151497Sru } 248151497Sru cc = write(fd, buffer, PAGE_SIZE); 249151497Sru if (cc != PAGE_SIZE) 250151497Sru err(1, "write data segment: %s", 251151497Sru cc > 0 ? strerror(EIO) : strerror(errno)); 252151497Sru addr += PAGE_SIZE; 253151497Sru } 254151497Sru} 255151497Sru 256151497Sruvoid 257151497Sruuserdump(fd, p, addr, npage) 25875584Sru register int fd; 25975584Sru struct proc *p; 26075584Sru register u_long addr; 26175584Sru register int npage; 26275584Sru{ 26375584Sru register int cc; 26475584Sru char buffer[PAGE_SIZE]; 26575584Sru 26675584Sru while (--npage >= 0) { 267 cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE); 268 if (cc != PAGE_SIZE) 269 /* Could be an untouched fill-with-zero page. */ 270 bzero(buffer, PAGE_SIZE); 271 cc = write(fd, buffer, PAGE_SIZE); 272 if (cc != PAGE_SIZE) 273 err(1, "write stack segment: %s", 274 cc > 0 ? strerror(EIO) : strerror(errno)); 275 addr += PAGE_SIZE; 276 } 277} 278 279void 280usage() 281{ 282 (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); 283 exit(1); 284} 285 286#if __STDC__ 287#include <stdarg.h> 288#else 289#include <varargs.h> 290#endif 291 292void 293#if __STDC__ 294err(int fatal, const char *fmt, ...) 295#else 296err(fatal, fmt, va_alist) 297 int fatal; 298 char *fmt; 299 va_dcl 300#endif 301{ 302 va_list ap; 303#if __STDC__ 304 va_start(ap, fmt); 305#else 306 va_start(ap); 307#endif 308 (void)fprintf(stderr, "gcore: "); 309 (void)vfprintf(stderr, fmt, ap); 310 va_end(ap); 311 (void)fprintf(stderr, "\n"); 312 exit(1); 313 /* NOTREACHED */ 314} 315