gcore.c revision 40350
1281SN/A/*- 2281SN/A * Copyright (c) 1992, 1993 3281SN/A * The Regents of the University of California. All rights reserved. 4281SN/A * 5281SN/A * Redistribution and use in source and binary forms, with or without 6281SN/A * modification, are permitted provided that the following conditions 7281SN/A * are met: 8281SN/A * 1. Redistributions of source code must retain the above copyright 9281SN/A * notice, this list of conditions and the following disclaimer. 10281SN/A * 2. Redistributions in binary form must reproduce the above copyright 11281SN/A * notice, this list of conditions and the following disclaimer in the 12281SN/A * documentation and/or other materials provided with the distribution. 13281SN/A * 3. All advertising materials mentioning features or use of this software 14281SN/A * must display the following acknowledgement: 15281SN/A * This product includes software developed by the University of 16281SN/A * California, Berkeley and its contributors. 17281SN/A * 4. Neither the name of the University nor the names of its contributors 18281SN/A * may be used to endorse or promote products derived from this software 19281SN/A * without specific prior written permission. 20281SN/A * 21281SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22281SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23281SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24281SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25281SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26281SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27281SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28281SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29281SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30281SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31281SN/A * SUCH DAMAGE. 32281SN/A */ 33281SN/A 34281SN/A#ifndef lint 35281SN/Astatic const char copyright[] = 36281SN/A"@(#) Copyright (c) 1992, 1993\n\ 37281SN/A The Regents of the University of California. All rights reserved.\n"; 38281SN/A#endif /* not lint */ 39281SN/A 40281SN/A#ifndef lint 41281SN/A#if 0 42281SN/Astatic char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93"; 43281SN/A#endif 44281SN/Astatic const char rcsid[] = 45281SN/A "$Id: gcore.c,v 1.9 1998/09/14 10:09:30 des Exp $"; 46281SN/A#endif /* not lint */ 47281SN/A 48281SN/A/* 49281SN/A * Originally written by Eric Cooper in Fall 1981. 50281SN/A * Inspired by a version 6 program by Len Levin, 1978. 51281SN/A * Several pieces of code lifted from Bill Joy's 4BSD ps. 52281SN/A * Most recently, hacked beyond recognition for 4.4BSD by Steven McCanne, 53281SN/A * Lawrence Berkeley Laboratory. 54928Sjoehw * 55281SN/A * Portions of this software were developed by the Computer Systems 56281SN/A * Engineering group at Lawrence Berkeley Laboratory under DARPA 57281SN/A * contract BG 91-66 and contributed to Berkeley. 58281SN/A */ 59281SN/A#include <sys/param.h> 60281SN/A#include <sys/time.h> 61281SN/A#include <sys/stat.h> 62281SN/A#include <sys/proc.h> 63281SN/A#include <sys/user.h> 64281SN/A#include <sys/sysctl.h> 65281SN/A 66281SN/A#include <machine/vmparam.h> 67281SN/A 68281SN/A#include <a.out.h> 69281SN/A#include <elf.h> 70281SN/A#include <err.h> 71281SN/A#include <fcntl.h> 72281SN/A#include <kvm.h> 73281SN/A#include <limits.h> 74281SN/A#include <signal.h> 75281SN/A#include <stdio.h> 76281SN/A#include <stdlib.h> 77281SN/A#include <string.h> 78281SN/A#include <unistd.h> 79281SN/A 80281SN/A#include "extern.h" 81281SN/A 82281SN/Avoid core __P((int, int, struct kinfo_proc *)); 83281SN/Avoid datadump __P((int, int, struct proc *, u_long, int)); 84281SN/Avoid usage __P((void)); 85281SN/Avoid userdump __P((int, struct proc *, u_long, int)); 86281SN/A 87281SN/Akvm_t *kd; 88281SN/A/* XXX undocumented routine, should be in kvm.h? */ 89281SN/Assize_t kvm_uread __P((kvm_t *, const struct proc *, u_long, char *, size_t)); 90281SN/A 91281SN/A 92281SN/Astatic int data_offset; 93281SN/A 94281SN/Aint 95281SN/Amain(argc, argv) 96281SN/A int argc; 97281SN/A char *argv[]; 98281SN/A{ 99281SN/A register struct proc *p; 100281SN/A struct kinfo_proc *ki; 101281SN/A struct exec exec; 102281SN/A int ch, cnt, efd, fd, pid, sflag, uid; 103281SN/A char *binfile, *corefile; 104281SN/A char errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1]; 105281SN/A 106281SN/A sflag = 0; 107281SN/A corefile = NULL; 108281SN/A while ((ch = getopt(argc, argv, "c:s")) != -1) { 109281SN/A switch (ch) { 110281SN/A case 'c': 111281SN/A corefile = optarg; 112281SN/A break; 113281SN/A case 's': 114281SN/A sflag = 1; 115281SN/A break; 116281SN/A default: 117281SN/A usage(); 118281SN/A break; 119281SN/A } 120281SN/A } 121281SN/A argv += optind; 122281SN/A argc -= optind; 123281SN/A 124281SN/A /* XXX we should check that the pid argument is really a number */ 125281SN/A switch (argc) { 126281SN/A case 1: 127281SN/A pid = atoi(argv[0]); 128281SN/A asprintf(&binfile, "/proc/%d/file", pid); 129281SN/A if (binfile == NULL) 130281SN/A errx(1, "allocation failure"); 131281SN/A break; 132281SN/A case 2: 133 pid = atoi(argv[1]); 134 binfile = argv[0]; 135 break; 136 default: 137 usage(); 138 } 139 140 kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf); 141 if (kd == NULL) 142 errx(1, "%s", errbuf); 143 144 uid = getuid(); 145 146 ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt); 147 if (ki == NULL || cnt != 1) 148 errx(1, "%d: not found", pid); 149 150 p = &ki->kp_proc; 151 if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0) 152 errx(1, "%d: not owner", pid); 153 154 if (p->p_stat == SZOMB) 155 errx(1, "%d: zombie", pid); 156 157 if (p->p_flag & P_WEXIT) 158 errx(1, "%d: process exiting", pid); 159 if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */ 160 errx(1, "%d: system process", pid); 161 162 if (corefile == NULL) { 163 (void)snprintf(fname, sizeof(fname), "core.%d", pid); 164 corefile = fname; 165 } 166 fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); 167 if (fd < 0) 168 err(1, "%s", corefile); 169 170 efd = open(binfile, O_RDONLY, 0); 171 if (efd < 0) 172 err(1, "%s", binfile); 173 174 cnt = read(efd, &exec, sizeof(exec)); 175 if (cnt != sizeof(exec)) 176 errx(1, "%s exec header: %s", 177 binfile, cnt > 0 ? strerror(EIO) : strerror(errno)); 178 if (N_BADMAG(exec)) { 179 const Elf_Ehdr *ehdr = (const Elf_Ehdr *)&exec; 180 181 if (IS_ELF(*ehdr)) 182 errx(1, "ELF executables are not supported yet"); 183 errx(1, "Invalid executable file"); 184 } 185 186 /* check the text segment size of the executable and the process */ 187 if (exec.a_text != ptoa(ki->kp_eproc.e_vm.vm_tsize)) 188 errx(1, 189 "The executable %s does not belong to process %d!\n" 190 "Text segment size (in bytes): executable %d, process %d", 191 binfile, pid, exec.a_text, 192 ptoa(ki->kp_eproc.e_vm.vm_tsize)); 193 194 data_offset = N_DATOFF(exec); 195 196 if (sflag && kill(pid, SIGSTOP) < 0) 197 err(1, "%d: stop signal", pid); 198 199 core(efd, fd, ki); 200 201 if (sflag && kill(pid, SIGCONT) < 0) 202 err(1, "%d: continue signal", pid); 203 (void)close(fd); 204 205 exit(0); 206} 207 208/* 209 * core -- 210 * Build the core file. 211 */ 212void 213core(efd, fd, ki) 214 int efd; 215 int fd; 216 struct kinfo_proc *ki; 217{ 218 union { 219 struct user user; 220 char ubytes[ctob(UPAGES)]; 221 } uarea; 222 struct proc *p = &ki->kp_proc; 223 int tsize = ki->kp_eproc.e_vm.vm_tsize; 224 int dsize = ki->kp_eproc.e_vm.vm_dsize; 225 int ssize = ki->kp_eproc.e_vm.vm_ssize; 226 int cnt; 227 228 /* Read in user struct */ 229 cnt = kvm_read(kd, (u_long)p->p_addr, &uarea, sizeof(uarea)); 230 if (cnt != sizeof(uarea)) 231 errx(1, "read user structure: %s", 232 cnt > 0 ? strerror(EIO) : strerror(errno)); 233 234 /* 235 * Fill in the eproc vm parameters, since these are garbage unless 236 * the kernel is dumping core or something. 237 */ 238 uarea.user.u_kproc = *ki; 239 240 /* Dump user area */ 241 cnt = write(fd, &uarea, sizeof(uarea)); 242 if (cnt != sizeof(uarea)) 243 errx(1, "write user structure: %s", 244 cnt > 0 ? strerror(EIO) : strerror(errno)); 245 246 /* Dump data segment */ 247 datadump(efd, fd, p, USRTEXT + ctob(tsize), dsize); 248 249 /* Dump stack segment */ 250 userdump(fd, p, USRSTACK - ctob(ssize), ssize); 251 252 /* Dump machine dependent portions of the core. */ 253 md_core(kd, fd, ki); 254} 255 256void 257datadump(efd, fd, p, addr, npage) 258 register int efd; 259 register int fd; 260 struct proc *p; 261 register u_long addr; 262 register int npage; 263{ 264 register int cc, delta; 265 char buffer[PAGE_SIZE]; 266 267 delta = data_offset - addr; 268 while (--npage >= 0) { 269 cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE); 270 if (cc != PAGE_SIZE) { 271 /* Try to read the page from the executable. */ 272 if (lseek(efd, (off_t)addr + delta, SEEK_SET) == -1) 273 err(1, "seek executable: %s", strerror(errno)); 274 cc = read(efd, buffer, sizeof(buffer)); 275 if (cc != sizeof(buffer)) 276 if (cc < 0) 277 err(1, "read executable"); 278 else /* Assume untouched bss page. */ 279 bzero(buffer, sizeof(buffer)); 280 } 281 cc = write(fd, buffer, PAGE_SIZE); 282 if (cc != PAGE_SIZE) 283 errx(1, "write data segment: %s", 284 cc > 0 ? strerror(EIO) : strerror(errno)); 285 addr += PAGE_SIZE; 286 } 287} 288 289void 290userdump(fd, p, addr, npage) 291 register int fd; 292 struct proc *p; 293 register u_long addr; 294 register int npage; 295{ 296 register int cc; 297 char buffer[PAGE_SIZE]; 298 299 while (--npage >= 0) { 300 cc = kvm_uread(kd, p, addr, buffer, PAGE_SIZE); 301 if (cc != PAGE_SIZE) 302 /* Could be an untouched fill-with-zero page. */ 303 bzero(buffer, PAGE_SIZE); 304 cc = write(fd, buffer, PAGE_SIZE); 305 if (cc != PAGE_SIZE) 306 errx(1, "write stack segment: %s", 307 cc > 0 ? strerror(EIO) : strerror(errno)); 308 addr += PAGE_SIZE; 309 } 310} 311 312void 313usage() 314{ 315 (void)fprintf(stderr, "usage: gcore [-s] [-c core] executable pid\n"); 316 exit(1); 317} 318