gcore.c revision 76224
1285SN/A/*- 2462SN/A * Copyright (c) 1992, 1993 3285SN/A * The Regents of the University of California. All rights reserved. 4285SN/A * 5285SN/A * Redistribution and use in source and binary forms, with or without 6285SN/A * modification, are permitted provided that the following conditions 7285SN/A * are met: 8285SN/A * 1. Redistributions of source code must retain the above copyright 9285SN/A * notice, this list of conditions and the following disclaimer. 10285SN/A * 2. Redistributions in binary form must reproduce the above copyright 11285SN/A * notice, this list of conditions and the following disclaimer in the 12285SN/A * documentation and/or other materials provided with the distribution. 13285SN/A * 3. All advertising materials mentioning features or use of this software 14285SN/A * must display the following acknowledgement: 15285SN/A * This product includes software developed by the University of 16285SN/A * California, Berkeley and its contributors. 17285SN/A * 4. Neither the name of the University nor the names of its contributors 18285SN/A * may be used to endorse or promote products derived from this software 19285SN/A * without specific prior written permission. 20285SN/A * 21285SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22285SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23285SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24285SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25285SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26285SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27285SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28285SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29285SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30285SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31285SN/A * SUCH DAMAGE. 32285SN/A */ 33285SN/A 34285SN/A#ifndef lint 35285SN/Astatic const char copyright[] = 36285SN/A"@(#) Copyright (c) 1992, 1993\n\ 37285SN/A The Regents of the University of California. All rights reserved.\n"; 38285SN/A#endif /* not lint */ 39285SN/A 40285SN/A#ifndef lint 41285SN/A#if 0 42285SN/Astatic char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93"; 43285SN/A#endif 44285SN/Astatic const char rcsid[] = 45285SN/A "$FreeBSD: head/usr.bin/gcore/gcore.c 76224 2001-05-02 23:56:21Z obrien $"; 46285SN/A#endif /* not lint */ 47285SN/A 48285SN/A/* 49285SN/A * Originally written by Eric Cooper in Fall 1981. 50285SN/A * Inspired by a version 6 program by Len Levin, 1978. 51285SN/A * Several pieces of code lifted from Bill Joy's 4BSD ps. 52285SN/A * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne, 53285SN/A * Lawrence Berkeley Laboratory. 54285SN/A * 55285SN/A * Portions of this software were developed by the Computer Systems 56285SN/A * Engineering group at Lawrence Berkeley Laboratory under DARPA 57285SN/A * contract BG 91-66 and contributed to Berkeley. 58285SN/A */ 59285SN/A#include <sys/param.h> 60285SN/A#include <sys/lock.h> 61285SN/A#include <sys/time.h> 62285SN/A#include <sys/stat.h> 63285SN/A#include <sys/proc.h> 64285SN/A#include <sys/user.h> 65285SN/A#include <sys/sysctl.h> 66285SN/A#include <machine/elf.h> 67285SN/A 68285SN/A#include <machine/vmparam.h> 69285SN/A 70285SN/A#include <a.out.h> 71285SN/A#include <err.h> 72285SN/A#include <fcntl.h> 73285SN/A#include <kvm.h> 74285SN/A#include <limits.h> 75285SN/A#include <signal.h> 76285SN/A#include <stdio.h> 77285SN/A#include <stdlib.h> 78285SN/A#include <string.h> 79285SN/A#include <unistd.h> 80285SN/A 81285SN/A#include "extern.h" 82285SN/A 83285SN/Astatic void core __P((int, int, struct kinfo_proc *)); 84285SN/Astatic void datadump __P((int, int, struct kinfo_proc *, u_long, int)); 85285SN/Astatic void killed __P((int)); 86285SN/Astatic void restart_target __P((void)); 87285SN/Astatic void usage __P((void)) __dead2; 88285SN/Astatic void userdump __P((int, struct kinfo_proc *, u_long, int)); 89285SN/A 90285SN/Akvm_t *kd; 91285SN/A 92285SN/Astatic int data_offset; 93285SN/Astatic pid_t pid; 94285SN/A 95285SN/Aint 96285SN/Amain(argc, argv) 97285SN/A int argc; 98285SN/A char *argv[]; 99285SN/A{ 100285SN/A struct kinfo_proc *ki = NULL; 101285SN/A struct exec exec; 102285SN/A int ch, cnt, efd, fd, sflag, uid; 103285SN/A char *binfile, *corefile; 104285SN/A char errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN]; 105285SN/A int is_aout; 106285SN/A 107285SN/A sflag = 0; 108285SN/A corefile = NULL; 109285SN/A while ((ch = getopt(argc, argv, "c:s")) != -1) { 110285SN/A switch (ch) { 111285SN/A case 'c': 112285SN/A corefile = optarg; 113285SN/A break; 114285SN/A case 's': 115285SN/A sflag = 1; 116285SN/A break; 117285SN/A default: 118285SN/A usage(); 119285SN/A break; 120285SN/A } 121285SN/A } 122285SN/A argv += optind; 123285SN/A argc -= optind; 124285SN/A 125285SN/A /* XXX we should check that the pid argument is really a number */ 126285SN/A switch (argc) { 127285SN/A case 1: 128285SN/A pid = atoi(argv[0]); 129285SN/A asprintf(&binfile, "/proc/%d/file", pid); 130285SN/A if (binfile == NULL) 131285SN/A errx(1, "allocation failure"); 132285SN/A break; 133285SN/A case 2: 134285SN/A pid = atoi(argv[1]); 135285SN/A binfile = argv[0]; 136285SN/A break; 137285SN/A default: 138285SN/A usage(); 139285SN/A } 140285SN/A 141285SN/A efd = open(binfile, O_RDONLY, 0); 142285SN/A if (efd < 0) 143285SN/A err(1, "%s", binfile); 144285SN/A 145285SN/A cnt = read(efd, &exec, sizeof(exec)); 146285SN/A if (cnt != sizeof(exec)) 147285SN/A errx(1, "%s exec header: %s", 148285SN/A binfile, cnt > 0 ? strerror(EIO) : strerror(errno)); 149285SN/A if (!N_BADMAG(exec)) { 150285SN/A is_aout = 1; 151285SN/A /* 152285SN/A * This legacy a.out support uses the kvm interface instead 153285SN/A * of procfs. 154285SN/A */ 155285SN/A kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); 156285SN/A if (kd == NULL) 157285SN/A errx(1, "%s", errbuf); 158285SN/A 159285SN/A uid = getuid(); 160285SN/A 161285SN/A ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); 162285SN/A if (ki == NULL || cnt != 1) 163285SN/A errx(1, "%d: not found", pid); 164285SN/A 165285SN/A if (ki->ki_ruid != uid && uid != 0) 166285SN/A errx(1, "%d: not owner", pid); 167285SN/A 168285SN/A if (ki->ki_stat == SZOMB) 169285SN/A errx(1, "%d: zombie", pid); 170285SN/A 171285SN/A if (ki->ki_flag & P_WEXIT) 172285SN/A errx(1, "%d: process exiting", pid); 173285SN/A if (ki->ki_flag & P_SYSTEM) /* Swapper or pagedaemon. */ 174285SN/A errx(1, "%d: system process", pid); 175285SN/A if (exec.a_text != ptoa(ki->ki_tsize)) 176285SN/A errx(1, "The executable %s does not belong to" 177285SN/A " process %d!\n" 178285SN/A "Text segment size (in bytes): executable %ld," 179285SN/A " process %d", binfile, pid, exec.a_text, 180285SN/A ptoa(ki->ki_tsize)); 181285SN/A data_offset = N_DATOFF(exec); 182285SN/A } else if (IS_ELF(*(Elf_Ehdr *)&exec)) { 183285SN/A is_aout = 0; 184285SN/A close(efd); 185285SN/A } else 186285SN/A errx(1, "Invalid executable file"); 187285SN/A 188285SN/A if (corefile == NULL) { 189285SN/A (void)snprintf(fname, sizeof(fname), "core.%d", pid); 190285SN/A corefile = fname; 191285SN/A } 192285SN/A fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); 193285SN/A if (fd < 0) 194285SN/A err(1, "%s", corefile); 195285SN/A 196285SN/A if (sflag) { 197285SN/A signal(SIGHUP, killed); 198285SN/A signal(SIGINT, killed); 199285SN/A signal(SIGTERM, killed); 200285SN/A if (kill(pid, SIGSTOP) == -1) 201285SN/A err(1, "%d: stop signal", pid); 202285SN/A atexit(restart_target); 203285SN/A } 204285SN/A 205285SN/A if (is_aout) 206285SN/A core(efd, fd, ki); 207285SN/A else 208285SN/A elf_coredump(fd, pid); 209285SN/A 210285SN/A (void)close(fd); 211285SN/A exit(0); 212285SN/A} 213285SN/A 214285SN/A/* 215285SN/A * core -- 216285SN/A * Build the core file. 217285SN/A */ 218285SN/Avoid 219285SN/Acore(efd, fd, ki) 220285SN/A int efd; 221285SN/A int fd; 222285SN/A struct kinfo_proc *ki; 223285SN/A{ 224285SN/A union { 225285SN/A struct user user; 226285SN/A char ubytes[ctob(UPAGES)]; 227285SN/A } uarea; 228285SN/A int tsize = ki->ki_tsize; 229285SN/A int dsize = ki->ki_dsize; 230285SN/A int ssize = ki->ki_ssize; 231285SN/A int cnt; 232285SN/A 233285SN/A /* Read in user struct */ 234285SN/A cnt = kvm_read(kd, (u_long)ki->ki_addr, &uarea, sizeof(uarea)); 235285SN/A if (cnt != sizeof(uarea)) 236285SN/A errx(1, "read user structure: %s", 237285SN/A cnt > 0 ? strerror(EIO) : strerror(errno)); 238285SN/A 239285SN/A /* 240285SN/A * Fill in the eproc vm parameters, since these are garbage unless 241285SN/A * the kernel is dumping core or something. 242285SN/A */ 243285SN/A uarea.user.u_kproc = *ki; 244285SN/A 245285SN/A /* Dump user area */ 246285SN/A cnt = write(fd, &uarea, sizeof(uarea)); 247285SN/A if (cnt != sizeof(uarea)) 248285SN/A errx(1, "write user structure: %s", 249285SN/A cnt > 0 ? strerror(EIO) : strerror(errno)); 250285SN/A 251285SN/A /* Dump data segment */ 252285SN/A datadump(efd, fd, ki, USRTEXT + ctob(tsize), dsize); 253285SN/A 254285SN/A /* Dump stack segment */ 255285SN/A userdump(fd, ki, USRSTACK - ctob(ssize), ssize); 256285SN/A 257285SN/A /* Dump machine dependent portions of the core. */ 258285SN/A md_core(kd, fd, ki); 259285SN/A} 260285SN/A 261285SN/Avoid 262285SN/Adatadump(efd, fd, kp, addr, npage) 263285SN/A register int efd; 264285SN/A register int fd; 265285SN/A struct kinfo_proc *kp; 266285SN/A register u_long addr; 267285SN/A register int npage; 268285SN/A{ 269285SN/A register int cc, delta; 270285SN/A char buffer[PAGE_SIZE]; 271367SN/A 272285SN/A delta = data_offset - addr; 273285SN/A while (--npage >= 0) { 274285SN/A cc = kvm_uread(kd, kp, addr, buffer, PAGE_SIZE); 275285SN/A if (cc != PAGE_SIZE) { 276285SN/A /* Try to read the page from the executable. */ 277285SN/A if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1) 278285SN/A err(1, "seek executable: %s", strerror(errno)); 279285SN/A cc = read(efd, buffer, sizeof(buffer)); 280285SN/A if (cc != sizeof(buffer)) { 281285SN/A if (cc < 0) 282285SN/A err(1, "read executable"); 283285SN/A else /* Assume untouched bss page. */ 284285SN/A bzero(buffer, sizeof(buffer)); 285285SN/A } 286285SN/A } 287285SN/A cc = write(fd, buffer, PAGE_SIZE); 288285SN/A if (cc != PAGE_SIZE) 289285SN/A errx(1, "write data segment: %s", 290285SN/A cc > 0 ? strerror(EIO) : strerror(errno)); 291285SN/A addr += PAGE_SIZE; 292285SN/A } 293285SN/A} 294285SN/A 295285SN/Astatic void 296285SN/Akilled(sig) 297285SN/A int sig; 298285SN/A{ 299285SN/A restart_target(); 300285SN/A signal(sig, SIG_DFL); 301285SN/A kill(getpid(), sig); 302285SN/A} 303285SN/A 304285SN/Astatic void 305285SN/Arestart_target() 306285SN/A{ 307285SN/A kill(pid, SIGCONT); 308285SN/A} 309285SN/A 310285SN/Avoid 311285SN/Auserdump(fd, kp, addr, npage) 312285SN/A register int fd; 313285SN/A struct kinfo_proc *kp; 314285SN/A register u_long addr; 315285SN/A register int npage; 316285SN/A{ 317285SN/A register int cc; 318285SN/A char buffer[PAGE_SIZE]; 319285SN/A 320285SN/A while (--npage >= 0) { 321285SN/A cc = kvm_uread(kd, kp, addr, buffer, PAGE_SIZE); 322285SN/A if (cc != PAGE_SIZE) 323285SN/A /* Could be an untouched fill-with-zero page. */ 324285SN/A bzero(buffer, PAGE_SIZE); 325285SN/A cc = write(fd, buffer, PAGE_SIZE); 326285SN/A if (cc != PAGE_SIZE) 327285SN/A errx(1, "write stack segment: %s", 328285SN/A cc > 0 ? strerror(EIO) : strerror(errno)); 329285SN/A addr += PAGE_SIZE; 330285SN/A } 331285SN/A} 332285SN/A 333285SN/Avoid 334285SN/Ausage() 335285SN/A{ 336285SN/A (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); 337285SN/A exit(1); 338285SN/A} 339285SN/A