19b50d902SRodney W. Grimes /*- 29b50d902SRodney W. Grimes * Copyright (c) 1992, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 35a5bf6586SPhilippe Charnier static const char copyright[] = 369b50d902SRodney W. Grimes "@(#) Copyright (c) 1992, 1993\n\ 379b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 389b50d902SRodney W. Grimes #endif /* not lint */ 399b50d902SRodney W. Grimes 409b50d902SRodney W. Grimes #ifndef lint 41a5bf6586SPhilippe Charnier #if 0 429b50d902SRodney W. Grimes static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93"; 43a5bf6586SPhilippe Charnier #endif 44a5bf6586SPhilippe Charnier static const char rcsid[] = 45283c2d5aSJohn Polstra "$Id: gcore.c,v 1.11 1998/10/19 19:42:18 jdp Exp $"; 469b50d902SRodney W. Grimes #endif /* not lint */ 479b50d902SRodney W. Grimes 489b50d902SRodney W. Grimes /* 499b50d902SRodney W. Grimes * Originally written by Eric Cooper in Fall 1981. 509b50d902SRodney W. Grimes * Inspired by a version 6 program by Len Levin, 1978. 519b50d902SRodney W. Grimes * Several pieces of code lifted from Bill Joy's 4BSD ps. 529b50d902SRodney W. Grimes * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne, 539b50d902SRodney W. Grimes * Lawrence Berkeley Laboratory. 549b50d902SRodney W. Grimes * 559b50d902SRodney W. Grimes * Portions of this software were developed by the Computer Systems 569b50d902SRodney W. Grimes * Engineering group at Lawrence Berkeley Laboratory under DARPA 579b50d902SRodney W. Grimes * contract BG 91-66 and contributed to Berkeley. 589b50d902SRodney W. Grimes */ 599b50d902SRodney W. Grimes #include <sys/param.h> 609b50d902SRodney W. Grimes #include <sys/time.h> 619b50d902SRodney W. Grimes #include <sys/stat.h> 629b50d902SRodney W. Grimes #include <sys/proc.h> 639b50d902SRodney W. Grimes #include <sys/user.h> 649b50d902SRodney W. Grimes #include <sys/sysctl.h> 659b50d902SRodney W. Grimes 669b50d902SRodney W. Grimes #include <machine/vmparam.h> 679b50d902SRodney W. Grimes 689b50d902SRodney W. Grimes #include <a.out.h> 691c35b08eSJohn Polstra #include <elf.h> 70a5bf6586SPhilippe Charnier #include <err.h> 719b50d902SRodney W. Grimes #include <fcntl.h> 729b50d902SRodney W. Grimes #include <kvm.h> 739b50d902SRodney W. Grimes #include <limits.h> 749b50d902SRodney W. Grimes #include <signal.h> 759b50d902SRodney W. Grimes #include <stdio.h> 769b50d902SRodney W. Grimes #include <stdlib.h> 779b50d902SRodney W. Grimes #include <string.h> 789b50d902SRodney W. Grimes #include <unistd.h> 799b50d902SRodney W. Grimes 809b50d902SRodney W. Grimes #include "extern.h" 819b50d902SRodney W. Grimes 82283c2d5aSJohn Polstra static void core __P((int, int, struct kinfo_proc *)); 83283c2d5aSJohn Polstra static void datadump __P((int, int, struct proc *, u_long, int)); 84283c2d5aSJohn Polstra static void killed __P((int)); 85283c2d5aSJohn Polstra static void restart_target __P((void)); 86283c2d5aSJohn Polstra static void usage __P((void)) __dead2; 87283c2d5aSJohn Polstra static void userdump __P((int, struct proc *, u_long, int)); 889b50d902SRodney W. Grimes 899b50d902SRodney W. Grimes kvm_t *kd; 909b50d902SRodney W. Grimes /* XXX undocumented routine, should be in kvm.h? */ 91526195adSJordan K. Hubbard ssize_t kvm_uread __P((kvm_t *, const struct proc *, u_long, char *, size_t)); 92526195adSJordan K. Hubbard 939b50d902SRodney W. Grimes static int data_offset; 94283c2d5aSJohn Polstra static pid_t pid; 959b50d902SRodney W. Grimes 969b50d902SRodney W. Grimes int 979b50d902SRodney W. Grimes main(argc, argv) 989b50d902SRodney W. Grimes int argc; 999b50d902SRodney W. Grimes char *argv[]; 1009b50d902SRodney W. Grimes { 1019b50d902SRodney W. Grimes register struct proc *p; 10252e7cc0aSJohn Polstra struct kinfo_proc *ki = NULL; 1039b50d902SRodney W. Grimes struct exec exec; 104283c2d5aSJohn Polstra int ch, cnt, efd, fd, sflag, uid; 10549ee7af6SDag-Erling Smørgrav char *binfile, *corefile; 10649ee7af6SDag-Erling Smørgrav char errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1]; 10752e7cc0aSJohn Polstra int is_aout; 1089b50d902SRodney W. Grimes 1099b50d902SRodney W. Grimes sflag = 0; 1109b50d902SRodney W. Grimes corefile = NULL; 1111c8af878SWarner Losh while ((ch = getopt(argc, argv, "c:s")) != -1) { 1129b50d902SRodney W. Grimes switch (ch) { 1139b50d902SRodney W. Grimes case 'c': 1149b50d902SRodney W. Grimes corefile = optarg; 1159b50d902SRodney W. Grimes break; 1169b50d902SRodney W. Grimes case 's': 1179b50d902SRodney W. Grimes sflag = 1; 1189b50d902SRodney W. Grimes break; 1199b50d902SRodney W. Grimes default: 1209b50d902SRodney W. Grimes usage(); 1219b50d902SRodney W. Grimes break; 1229b50d902SRodney W. Grimes } 1239b50d902SRodney W. Grimes } 1249b50d902SRodney W. Grimes argv += optind; 1259b50d902SRodney W. Grimes argc -= optind; 1269b50d902SRodney W. Grimes 12749ee7af6SDag-Erling Smørgrav /* XXX we should check that the pid argument is really a number */ 12849ee7af6SDag-Erling Smørgrav switch (argc) { 12949ee7af6SDag-Erling Smørgrav case 1: 13049ee7af6SDag-Erling Smørgrav pid = atoi(argv[0]); 13149ee7af6SDag-Erling Smørgrav asprintf(&binfile, "/proc/%d/file", pid); 13249ee7af6SDag-Erling Smørgrav if (binfile == NULL) 13349ee7af6SDag-Erling Smørgrav errx(1, "allocation failure"); 13449ee7af6SDag-Erling Smørgrav break; 13549ee7af6SDag-Erling Smørgrav case 2: 13649ee7af6SDag-Erling Smørgrav pid = atoi(argv[1]); 13749ee7af6SDag-Erling Smørgrav binfile = argv[0]; 13849ee7af6SDag-Erling Smørgrav break; 13949ee7af6SDag-Erling Smørgrav default: 1409b50d902SRodney W. Grimes usage(); 14149ee7af6SDag-Erling Smørgrav } 1429b50d902SRodney W. Grimes 14352e7cc0aSJohn Polstra efd = open(binfile, O_RDONLY, 0); 14452e7cc0aSJohn Polstra if (efd < 0) 14552e7cc0aSJohn Polstra err(1, "%s", binfile); 14652e7cc0aSJohn Polstra 14752e7cc0aSJohn Polstra cnt = read(efd, &exec, sizeof(exec)); 14852e7cc0aSJohn Polstra if (cnt != sizeof(exec)) 14952e7cc0aSJohn Polstra errx(1, "%s exec header: %s", 15052e7cc0aSJohn Polstra binfile, cnt > 0 ? strerror(EIO) : strerror(errno)); 15152e7cc0aSJohn Polstra if (!N_BADMAG(exec)) { 15252e7cc0aSJohn Polstra is_aout = 1; 15352e7cc0aSJohn Polstra /* 15452e7cc0aSJohn Polstra * This legacy a.out support uses the kvm interface instead 15552e7cc0aSJohn Polstra * of procfs. 15652e7cc0aSJohn Polstra */ 1579b50d902SRodney W. Grimes kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); 1589b50d902SRodney W. Grimes if (kd == NULL) 159a5bf6586SPhilippe Charnier errx(1, "%s", errbuf); 1609b50d902SRodney W. Grimes 1619b50d902SRodney W. Grimes uid = getuid(); 1629b50d902SRodney W. Grimes 1639b50d902SRodney W. Grimes ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); 1649b50d902SRodney W. Grimes if (ki == NULL || cnt != 1) 165a5bf6586SPhilippe Charnier errx(1, "%d: not found", pid); 1669b50d902SRodney W. Grimes 1679b50d902SRodney W. Grimes p = &ki->kp_proc; 1689b50d902SRodney W. Grimes if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0) 169a5bf6586SPhilippe Charnier errx(1, "%d: not owner", pid); 1709b50d902SRodney W. Grimes 1719b50d902SRodney W. Grimes if (p->p_stat == SZOMB) 172a5bf6586SPhilippe Charnier errx(1, "%d: zombie", pid); 1739b50d902SRodney W. Grimes 1749b50d902SRodney W. Grimes if (p->p_flag & P_WEXIT) 1758f10c098SJohn Polstra errx(1, "%d: process exiting", pid); 1769b50d902SRodney W. Grimes if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */ 1778f10c098SJohn Polstra errx(1, "%d: system process", pid); 17852e7cc0aSJohn Polstra if (exec.a_text != ptoa(ki->kp_eproc.e_vm.vm_tsize)) 17952e7cc0aSJohn Polstra errx(1, "The executable %s does not belong to" 18052e7cc0aSJohn Polstra " process %d!\n" 18152e7cc0aSJohn Polstra "Text segment size (in bytes): executable %d," 18252e7cc0aSJohn Polstra " process %d", binfile, pid, exec.a_text, 18352e7cc0aSJohn Polstra ptoa(ki->kp_eproc.e_vm.vm_tsize)); 18452e7cc0aSJohn Polstra data_offset = N_DATOFF(exec); 18552e7cc0aSJohn Polstra } else if (IS_ELF(*(Elf_Ehdr *)&exec)) { 18652e7cc0aSJohn Polstra is_aout = 0; 18752e7cc0aSJohn Polstra close(efd); 18852e7cc0aSJohn Polstra } else 18952e7cc0aSJohn Polstra errx(1, "Invalid executable file"); 1909b50d902SRodney W. Grimes 1919b50d902SRodney W. Grimes if (corefile == NULL) { 1929b50d902SRodney W. Grimes (void)snprintf(fname, sizeof(fname), "core.%d", pid); 1939b50d902SRodney W. Grimes corefile = fname; 1949b50d902SRodney W. Grimes } 1959b50d902SRodney W. Grimes fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); 1969b50d902SRodney W. Grimes if (fd < 0) 197a5bf6586SPhilippe Charnier err(1, "%s", corefile); 1989b50d902SRodney W. Grimes 199283c2d5aSJohn Polstra if (sflag) { 200283c2d5aSJohn Polstra signal(SIGHUP, killed); 201283c2d5aSJohn Polstra signal(SIGINT, killed); 202283c2d5aSJohn Polstra signal(SIGTERM, killed); 203283c2d5aSJohn Polstra if (kill(pid, SIGSTOP) == -1) 204a5bf6586SPhilippe Charnier err(1, "%d: stop signal", pid); 205283c2d5aSJohn Polstra atexit(restart_target); 206283c2d5aSJohn Polstra } 2079b50d902SRodney W. Grimes 20852e7cc0aSJohn Polstra if (is_aout) 2099b50d902SRodney W. Grimes core(efd, fd, ki); 21052e7cc0aSJohn Polstra else 21152e7cc0aSJohn Polstra elf_coredump(fd, pid); 2129b50d902SRodney W. Grimes 2139b50d902SRodney W. Grimes (void)close(fd); 2149b50d902SRodney W. Grimes exit(0); 2159b50d902SRodney W. Grimes } 2169b50d902SRodney W. Grimes 2179b50d902SRodney W. Grimes /* 2189b50d902SRodney W. Grimes * core -- 2199b50d902SRodney W. Grimes * Build the core file. 2209b50d902SRodney W. Grimes */ 2219b50d902SRodney W. Grimes void 2229b50d902SRodney W. Grimes core(efd, fd, ki) 2239b50d902SRodney W. Grimes int efd; 2249b50d902SRodney W. Grimes int fd; 2259b50d902SRodney W. Grimes struct kinfo_proc *ki; 2269b50d902SRodney W. Grimes { 2279b50d902SRodney W. Grimes union { 2289b50d902SRodney W. Grimes struct user user; 2299b50d902SRodney W. Grimes char ubytes[ctob(UPAGES)]; 2309b50d902SRodney W. Grimes } uarea; 2319b50d902SRodney W. Grimes struct proc *p = &ki->kp_proc; 2329b50d902SRodney W. Grimes int tsize = ki->kp_eproc.e_vm.vm_tsize; 2339b50d902SRodney W. Grimes int dsize = ki->kp_eproc.e_vm.vm_dsize; 2349b50d902SRodney W. Grimes int ssize = ki->kp_eproc.e_vm.vm_ssize; 2359b50d902SRodney W. Grimes int cnt; 2369b50d902SRodney W. Grimes 2379b50d902SRodney W. Grimes /* Read in user struct */ 2389b50d902SRodney W. Grimes cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea)); 2399b50d902SRodney W. Grimes if (cnt != sizeof(uarea)) 240a5bf6586SPhilippe Charnier errx(1, "read user structure: %s", 2419b50d902SRodney W. Grimes cnt > 0 ? strerror(EIO) : strerror(errno)); 2429b50d902SRodney W. Grimes 2439b50d902SRodney W. Grimes /* 2449b50d902SRodney W. Grimes * Fill in the eproc vm parameters, since these are garbage unless 2459b50d902SRodney W. Grimes * the kernel is dumping core or something. 2469b50d902SRodney W. Grimes */ 2479b50d902SRodney W. Grimes uarea.user.u_kproc = *ki; 2489b50d902SRodney W. Grimes 2499b50d902SRodney W. Grimes /* Dump user area */ 2509b50d902SRodney W. Grimes cnt = write(fd, &uarea, sizeof(uarea)); 2519b50d902SRodney W. Grimes if (cnt != sizeof(uarea)) 252a5bf6586SPhilippe Charnier errx(1, "write user structure: %s", 2539b50d902SRodney W. Grimes cnt > 0 ? strerror(EIO) : strerror(errno)); 2549b50d902SRodney W. Grimes 2559b50d902SRodney W. Grimes /* Dump data segment */ 2569b50d902SRodney W. Grimes datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize); 2579b50d902SRodney W. Grimes 2589b50d902SRodney W. Grimes /* Dump stack segment */ 2599b50d902SRodney W. Grimes userdump(fd, p, USRSTACK - ctob(ssize), ssize); 2609b50d902SRodney W. Grimes 2619b50d902SRodney W. Grimes /* Dump machine dependent portions of the core. */ 2629b50d902SRodney W. Grimes md_core(kd, fd, ki); 2639b50d902SRodney W. Grimes } 2649b50d902SRodney W. Grimes 2659b50d902SRodney W. Grimes void 2669b50d902SRodney W. Grimes datadump(efd, fd, p, addr, npage) 2679b50d902SRodney W. Grimes register int efd; 2689b50d902SRodney W. Grimes register int fd; 2699b50d902SRodney W. Grimes struct proc *p; 2709b50d902SRodney W. Grimes register u_long addr; 2719b50d902SRodney W. Grimes register int npage; 2729b50d902SRodney W. Grimes { 2739b50d902SRodney W. Grimes register int cc, delta; 274875c5798SPoul-Henning Kamp char buffer[PAGE_SIZE]; 2759b50d902SRodney W. Grimes 2769b50d902SRodney W. Grimes delta = data_offset - addr; 2779b50d902SRodney W. Grimes while (--npage >= 0) { 278875c5798SPoul-Henning Kamp cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE); 279875c5798SPoul-Henning Kamp if (cc != PAGE_SIZE) { 2809b50d902SRodney W. Grimes /* Try to read the page from the executable. */ 2819b50d902SRodney W. Grimes if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1) 2829b50d902SRodney W. Grimes err(1, "seek executable: %s", strerror(errno)); 2839b50d902SRodney W. Grimes cc = read(efd, buffer, sizeof(buffer)); 2849b50d902SRodney W. Grimes if (cc != sizeof(buffer)) 2859b50d902SRodney W. Grimes if (cc < 0) 286a5bf6586SPhilippe Charnier err(1, "read executable"); 2879b50d902SRodney W. Grimes else /* Assume untouched bss page. */ 2889b50d902SRodney W. Grimes bzero(buffer, sizeof(buffer)); 2899b50d902SRodney W. Grimes } 290875c5798SPoul-Henning Kamp cc = write(fd, buffer, PAGE_SIZE); 291875c5798SPoul-Henning Kamp if (cc != PAGE_SIZE) 292a5bf6586SPhilippe Charnier errx(1, "write data segment: %s", 2939b50d902SRodney W. Grimes cc > 0 ? strerror(EIO) : strerror(errno)); 294875c5798SPoul-Henning Kamp addr += PAGE_SIZE; 2959b50d902SRodney W. Grimes } 2969b50d902SRodney W. Grimes } 2979b50d902SRodney W. Grimes 298283c2d5aSJohn Polstra static void 299283c2d5aSJohn Polstra killed(sig) 300283c2d5aSJohn Polstra int sig; 301283c2d5aSJohn Polstra { 302283c2d5aSJohn Polstra restart_target(); 303283c2d5aSJohn Polstra signal(sig, SIG_DFL); 304283c2d5aSJohn Polstra kill(getpid(), sig); 305283c2d5aSJohn Polstra } 306283c2d5aSJohn Polstra 307283c2d5aSJohn Polstra static void 308283c2d5aSJohn Polstra restart_target() 309283c2d5aSJohn Polstra { 310283c2d5aSJohn Polstra kill(pid, SIGCONT); 311283c2d5aSJohn Polstra } 312283c2d5aSJohn Polstra 3139b50d902SRodney W. Grimes void 3149b50d902SRodney W. Grimes userdump(fd, p, addr, npage) 3159b50d902SRodney W. Grimes register int fd; 3169b50d902SRodney W. Grimes struct proc *p; 3179b50d902SRodney W. Grimes register u_long addr; 3189b50d902SRodney W. Grimes register int npage; 3199b50d902SRodney W. Grimes { 3209b50d902SRodney W. Grimes register int cc; 321875c5798SPoul-Henning Kamp char buffer[PAGE_SIZE]; 3229b50d902SRodney W. Grimes 3239b50d902SRodney W. Grimes while (--npage >= 0) { 324875c5798SPoul-Henning Kamp cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE); 325875c5798SPoul-Henning Kamp if (cc != PAGE_SIZE) 3269b50d902SRodney W. Grimes /* Could be an untouched fill-with-zero page. */ 327875c5798SPoul-Henning Kamp bzero(buffer, PAGE_SIZE); 328875c5798SPoul-Henning Kamp cc = write(fd, buffer, PAGE_SIZE); 329875c5798SPoul-Henning Kamp if (cc != PAGE_SIZE) 330a5bf6586SPhilippe Charnier errx(1, "write stack segment: %s", 3319b50d902SRodney W. Grimes cc > 0 ? strerror(EIO) : strerror(errno)); 332875c5798SPoul-Henning Kamp addr += PAGE_SIZE; 3339b50d902SRodney W. Grimes } 3349b50d902SRodney W. Grimes } 3359b50d902SRodney W. Grimes 3369b50d902SRodney W. Grimes void 3379b50d902SRodney W. Grimes usage() 3389b50d902SRodney W. Grimes { 3399b50d902SRodney W. Grimes (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); 3409b50d902SRodney W. Grimes exit(1); 3419b50d902SRodney W. Grimes } 342