1 /* 2 * Copyright (c) 1982 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1982 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)gcore.c 5.10 (Berkeley) 05/02/91"; 16 #endif /* not lint */ 17 18 /* 19 * gcore - get core images of running processes 20 * 21 * Author: Eric Cooper 22 * Written: Fall 1981. 23 * 24 * Inspired by a version 6 program by Len Levin, 1978. 25 * Several pieces of code lifted from Bill Joy's 4BSD ps. 26 * 27 * Permission to copy or modify this program in whole or in part is hereby 28 * granted, provided that the above credits are preserved. 29 * 30 * This code performs a simple simulation of the virtual memory system in user 31 * code. If the virtual memory system changes, this program must be modified 32 * accordingly. It must also be recompiled whenever system data structures 33 * change. 34 */ 35 #include <machine/pte.h> 36 #include <sys/param.h> 37 #include <sys/user.h> 38 #include <sys/proc.h> 39 #include <sys/vm.h> 40 #include <setjmp.h> 41 #include <stdio.h> 42 #include <nlist.h> 43 #include <varargs.h> 44 45 /* Various macros for efficiency. */ 46 47 #define min(a, b) (a < b ? a : b) 48 49 #define Seek(f, pos) {\ 50 if (lseek(f, (long) (pos), 0) != (long) (pos)) \ 51 panic("seek error"); \ 52 } 53 54 #define Read(f, addr, n) {\ 55 if (read(f, (char *) (addr), (int) (n)) != (int) (n)) \ 56 panic("read error"); \ 57 } 58 59 #define Get(f, pos, addr, n) {\ 60 Seek(f, pos); \ 61 Read(f, addr, n); \ 62 } 63 64 struct nlist nl[] = { 65 { "_proc" }, 66 #define X_PROC 0 67 { "_Usrptmap" }, 68 #define X_USRPTMA 1 69 { "_usrpt" }, 70 #define X_USRPT 2 71 { "_nswap" }, 72 #define X_NSWAP 3 73 { "_nproc" }, 74 #define X_NPROC 4 75 { "_dmmin" }, 76 #define X_DMMIN 5 77 { "_dmmax" }, 78 #define X_DMMAX 6 79 { 0 }, 80 }; 81 82 #define FEW 20 /* for fewer system calls */ 83 struct proc proc[FEW]; 84 85 union { 86 struct user user; 87 char upages[UPAGES][NBPG]; 88 } user; 89 #define u user.user 90 #define uarea user.upages 91 92 #define NLIST "/vmunix" 93 #define KMEM "/dev/kmem" 94 #define MEM "/dev/mem" 95 #define SWAP "/dev/drum" /* "/dev/swap" on some systems */ 96 97 int nproc; 98 int nswap; 99 int dmmin, dmmax; 100 struct pte *Usrptmap, *usrpt; 101 char coref[20]; 102 int kmem, mem, swap, cor; 103 jmp_buf cont_frame; 104 105 main(argc, argv) 106 int argc; 107 char **argv; 108 { 109 register int i, j; 110 register struct proc *p; 111 off_t procbase, procp; 112 int pid, uid; 113 char c; 114 115 if (argc < 2) { 116 printf("Usage: %s pid ...\n", argv[0]); 117 exit(1); 118 } 119 openfiles(); 120 getkvars(); 121 procbase = getword(nl[X_PROC].n_value); 122 nproc = getword(nl[X_NPROC].n_value); 123 nswap = getword(nl[X_NSWAP].n_value); 124 dmmin = getword(nl[X_DMMIN].n_value); 125 dmmax = getword(nl[X_DMMAX].n_value); 126 while (--argc > 0) { 127 if ((pid = atoi(*++argv)) <= 0 || setjmp(cont_frame)) 128 continue; 129 printf("%d: ", pid); 130 procp = procbase; 131 for (i = 0; i < nproc; i += FEW) { 132 Seek(kmem, procp); 133 j = nproc - i; 134 if (j > FEW) 135 j = FEW; 136 j *= sizeof(struct proc); 137 Read(kmem, (char *) proc, j); 138 procp += j; 139 for (j = j / sizeof(struct proc) - 1; j >= 0; j--) { 140 p = &proc[j]; 141 if (p->p_pid == pid) 142 goto found; 143 } 144 } 145 printf("Process not found.\n"); 146 continue; 147 found: 148 if (p->p_uid != (uid = getuid()) && uid != 0) { 149 printf("Not owner.\n"); 150 continue; 151 } 152 if (p->p_stat == SZOMB) { 153 printf("Zombie.\n"); 154 continue; 155 } 156 if (p->p_flag & SWEXIT) 157 printf("Warning: process exiting.\n"); 158 if (p->p_flag & SSYS) { 159 printf("System process.\n"); 160 /* i.e. swapper or pagedaemon */ 161 continue; 162 } 163 sprintf(coref, "core.%d", pid); 164 if ((cor = creat(coref, 0666)) < 0) { 165 perror(coref); 166 exit(1); 167 } 168 core(p); 169 close(cor); 170 printf("%s dumped\n", coref); 171 } 172 exit(0); 173 } 174 175 getword(loc) 176 off_t loc; 177 { 178 int word; 179 180 Get(kmem, loc, &word, sizeof(int)); 181 return (word); 182 } 183 184 openfiles() 185 { 186 kmem = open(KMEM, 0); 187 if (kmem < 0) { 188 perror(KMEM); 189 exit(1); 190 } 191 mem = open(MEM, 0); 192 if (mem < 0) { 193 perror(MEM); 194 exit(1); 195 } 196 swap = open(SWAP, 0); 197 if (swap < 0) { 198 perror(SWAP); 199 exit(1); 200 } 201 } 202 203 getkvars() 204 { 205 nlist(NLIST, nl); 206 if (nl[0].n_type == 0) { 207 printf("%s: No namelist\n", NLIST); 208 exit(1); 209 } 210 Usrptmap = (struct pte *) nl[X_USRPTMA].n_value; 211 usrpt = (struct pte *) nl[X_USRPT].n_value; 212 } 213 214 /* 215 * Get the system page table entries (mapping the user page table). 216 * These are the entries Usrptmap[i .. i + szpt], 217 * where i = btokmx(p->p_p0br) and szpt = p->p_szpt. 218 * For our purposes, we can skip over the ptes mapping 219 * the text segment ptes. 220 */ 221 struct pte *syspt; /* pte's from Usrptmap */ 222 int nsysptes; 223 224 getsyspt(p) 225 register struct proc *p; 226 { 227 nsysptes = p->p_szpt - (p->p_tsize / NPTEPG); 228 syspt = (struct pte *) malloc(nsysptes * sizeof(struct pte)); 229 if (syspt == NULL) 230 panic("can't alloc %d page table entries", nsysptes); 231 Get(kmem, &Usrptmap[btokmx(p->p_p0br) + (p->p_tsize / NPTEPG)], 232 syspt, nsysptes * sizeof(struct pte)); 233 } 234 235 /* 236 * Get the user page table for a segment. 237 * seg 0 = p0 (not including text) 238 * seg 1 = p1 (stack and u area) 239 * The system pt is consulted to find each page of user ptes. 240 */ 241 struct pte * 242 getpt(p, seg) 243 register struct proc *p; 244 int seg; 245 { 246 register int i; 247 register struct pte *spt; 248 struct pte *pt; 249 int nptes, offset, n; 250 251 if (seg == 0) { 252 nptes = p->p_dsize; 253 spt = syspt; 254 offset = p->p_tsize % NPTEPG; 255 } else { 256 nptes = p->p_ssize + UPAGES; 257 spt = syspt + (nsysptes - ctopt(nptes)); 258 offset = -nptes % NPTEPG; 259 if (offset < 0) 260 offset += NPTEPG; 261 } 262 pt = (struct pte *) malloc(nptes * sizeof(struct pte)); 263 if (pt == NULL) 264 panic("can't alloc %d page table entries", nptes); 265 for (i = 0; i < nptes; i += n) { 266 n = min(NPTEPG - offset, nptes - i); 267 Get(mem, ctob(spt->pg_pfnum) + offset * sizeof(struct pte), 268 pt + i, n * sizeof(struct pte)); 269 spt++; 270 offset = 0; 271 } 272 return (pt); 273 } 274 275 /* 276 * Build the core file. 277 */ 278 core(p) 279 register struct proc *p; 280 { 281 register struct pte *p0, *p1; 282 283 if (p->p_flag & SLOAD) { /* page tables are resident */ 284 getsyspt(p); 285 p0 = getpt(p, 0); 286 p1 = getpt(p, 1); 287 #ifdef DEBUG 288 showpt(syspt, nsysptes, "system"); 289 showpt(p0, p->p_dsize, "p0"); 290 showpt(p1, p->p_ssize + UPAGES, "p1"); 291 #endif 292 } else 293 p0 = p1 = NULL; /* not actually used */ 294 getu(p, &p1[p->p_ssize]); /* u area */ 295 getseg(p, p->p_dsize, p0, &u.u_dmap, 0); /* data */ 296 getseg(p, p->p_ssize, p1, &u.u_smap, 1); /* stack */ 297 if (p->p_flag & SLOAD) { 298 free((char *) syspt); 299 free((char *) p0); 300 free((char *) p1); 301 } 302 } 303 304 /* 305 * Get the u area. 306 * Keeps around the u structure for later use 307 * (the data and stack disk map structures). 308 */ 309 getu(p, pages) 310 register struct proc *p; 311 register struct pte *pages; 312 { 313 register int i; 314 315 if ((p->p_flag & SLOAD) == 0) { 316 Get(swap, ctob(p->p_swaddr), uarea, ctob(UPAGES)); 317 write(cor, uarea, ctob(UPAGES)); 318 return; 319 } 320 for (i = 0; i < UPAGES; i += CLSIZE) { 321 Get(mem, ctob(pages[i].pg_pfnum), uarea[i], ctob(CLSIZE)); 322 write(cor, uarea[i], ctob(CLSIZE)); 323 } 324 } 325 326 /* 327 * Copy a segment to the core file. 328 * The segment is described by its size in clicks, 329 * its page table, its disk map, and whether or not 330 * it grows backwards. 331 * Note that the page table address is allowed to be meaningless 332 * if the process is swapped out. 333 */ 334 getseg(p, segsize, pages, map, rev) 335 register struct proc *p; 336 int segsize; 337 register struct pte *pages; 338 struct dmap *map; 339 int rev; 340 { 341 register int i; 342 struct dblock db; 343 int size; 344 char buf[ctob(CLSIZE)]; 345 346 for (i = 0; i < segsize; i += CLSIZE) { 347 size = min(CLSIZE, segsize - i); 348 if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod || 349 pages[i].pg_pfnum == 0) { 350 vstodb(i, size, map, &db, rev); 351 Get(swap, ctob(db.db_base), buf, ctob(size)); 352 write(cor, buf, ctob(size)); 353 } else { 354 Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size)); 355 write(cor, buf, ctob(size)); 356 } 357 } 358 } 359 360 /* 361 * Given a base/size pair in virtual swap area, 362 * return a physical base/size pair which is the 363 * (largest) initial, physically contiguous block. 364 */ 365 vstodb(vsbase, vssize, dmp, dbp, rev) 366 register int vsbase; 367 int vssize; 368 struct dmap *dmp; 369 register struct dblock *dbp; 370 int rev; 371 { 372 register int blk = dmmin; 373 register swblk_t *ip = dmp->dm_map; 374 375 if (vsbase < 0 || vsbase + vssize > dmp->dm_size) 376 panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)"); 377 while (vsbase >= blk) { 378 vsbase -= blk; 379 if (blk < dmmax) 380 blk *= 2; 381 ip++; 382 } 383 if (*ip <= 0 || *ip + blk > nswap) 384 panic("vstodb *ip"); 385 dbp->db_size = MIN(vssize, blk - vsbase); 386 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); 387 } 388 389 #ifdef lint 390 /*VARARGS1*/ 391 panic(fmt) 392 char *fmt; 393 { 394 395 fmt = fmt; 396 longjmp(cont_frame, 1); 397 } 398 #else /* lint */ 399 panic(va_alist) 400 va_dcl 401 { 402 va_list ap; 403 char *fmt; 404 405 va_start(ap); 406 fmt = va_arg(ap, char *); 407 (void) vprintf(fmt, ap); 408 va_end(ap); 409 (void) printf("\n"); 410 longjmp(cont_frame, 1); 411 } 412 #endif /* lint */ 413 414 /* 415 * Debugging routine to print out page table. 416 */ 417 #ifdef DEBUG 418 showpt(pt, n, s) 419 struct pte *pt; 420 int n; 421 char *s; 422 { 423 register struct pte *p; 424 register int i; 425 426 printf("*** %s page table\n", s); 427 for (i = 0, p = pt; i < n; i++, p++) 428 if (! p->pg_fod) 429 printf("%d: %x\n", i, p->pg_pfnum); 430 } 431 #endif 432