1: /* 2: * Copyright (c) 1983 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: char copyright[] = 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: #endif not lint 12: 13: #ifndef lint 14: static char sccsid[] = "@(#)gcore.c 5.2 (Berkeley) 5/31/85"; 15: #endif not lint 16: 17: /* 18: * gcore - get core images of running processes 19: * 20: * Author: Eric Cooper 21: * Written: Fall 1981. 22: * 23: * Inspired by a version 6 program by Len Levin, 1978. 24: * Several pieces of code lifted from Bill Joy's 4BSD ps. 25: * 26: * Permission to copy or modify this program in whole or in part is hereby 27: * granted, provided that the above credits are preserved. 28: * 29: * This code performs a simple simulation of the virtual memory system in user 30: * code. If the virtual memory system changes, this program must be modified 31: * accordingly. It must also be recompiled whenever system data structures 32: * change. 33: */ 34: #include <stdio.h> 35: #include <nlist.h> 36: #include <sys/param.h> 37: #include <sys/dir.h> 38: #include <sys/user.h> 39: #include <sys/proc.h> 40: #include <machine/pte.h> 41: #include <sys/vm.h> 42: #include <setjmp.h> 43: 44: /* Various macros for efficiency. */ 45: 46: #define min(a, b) (a < b ? a : b) 47: 48: #define Seek(f, pos) {\ 49: if (lseek(f, (long) (pos), 0) != (long) (pos)) \ 50: panic("seek error"); \ 51: } 52: 53: #define Read(f, addr, n) {\ 54: if (read(f, (char *) (addr), (int) (n)) != (int) (n)) \ 55: panic("read error"); \ 56: } 57: 58: #define Get(f, pos, addr, n) {\ 59: Seek(f, pos); \ 60: Read(f, addr, n); \ 61: } 62: 63: struct nlist nl[] = { 64: { "_proc" }, 65: #define X_PROC 0 66: { "_Usrptmap" }, 67: #define X_USRPTMA 1 68: { "_usrpt" }, 69: #define X_USRPT 2 70: { "_nswap" }, 71: #define X_NSWAP 3 72: { "_nproc" }, 73: #define X_NPROC 4 74: { "_dmmin" }, 75: #define X_DMMIN 5 76: { "_dmmax" }, 77: #define X_DMMAX 6 78: { 0 }, 79: }; 80: 81: #define FEW 20 /* for fewer system calls */ 82: struct proc proc[FEW]; 83: 84: union { 85: struct user user; 86: char upages[UPAGES][NBPG]; 87: } user; 88: #define u user.user 89: #define uarea user.upages 90: 91: #define NLIST "/vmunix" 92: #define KMEM "/dev/kmem" 93: #define MEM "/dev/mem" 94: #define SWAP "/dev/drum" /* "/dev/swap" on some systems */ 95: 96: int nproc; 97: int nswap; 98: int dmmin, dmmax; 99: struct pte *Usrptmap, *usrpt; 100: char coref[20]; 101: int kmem, mem, swap, cor; 102: jmp_buf cont_frame; 103: 104: main(argc, argv) 105: int argc; 106: char **argv; 107: { 108: register int i, j; 109: register struct proc *p; 110: off_t procbase, procp; 111: int pid, uid; 112: char c; 113: 114: if (argc < 2) { 115: printf("Usage: %s pid ...\n", argv[0]); 116: exit(1); 117: } 118: openfiles(); 119: getkvars(); 120: procbase = getw(nl[X_PROC].n_value); 121: nproc = getw(nl[X_NPROC].n_value); 122: nswap = getw(nl[X_NSWAP].n_value); 123: dmmin = getw(nl[X_DMMIN].n_value); 124: dmmax = getw(nl[X_DMMAX].n_value); 125: while (--argc > 0) { 126: if ((pid = atoi(*++argv)) <= 0 || setjmp(cont_frame)) 127: continue; 128: printf("%d: ", pid); 129: procp = procbase; 130: for (i = 0; i < nproc; i += FEW) { 131: Seek(kmem, procp); 132: j = nproc - i; 133: if (j > FEW) 134: j = FEW; 135: j *= sizeof(struct proc); 136: Read(kmem, (char *) proc, j); 137: procp += j; 138: for (j = j / sizeof(struct proc) - 1; j >= 0; j--) { 139: p = &proc[j]; 140: if (p->p_pid == pid) 141: goto found; 142: } 143: } 144: printf("Process not found.\n"); 145: continue; 146: found: 147: if (p->p_uid != (uid = getuid()) && uid != 0) { 148: printf("Not owner.\n"); 149: continue; 150: } 151: if (p->p_stat == SZOMB) { 152: printf("Zombie.\n"); 153: continue; 154: } 155: if (p->p_flag & SWEXIT) { 156: printf("Process exiting.\n"); 157: continue; 158: } 159: if (p->p_flag & SSYS) { 160: printf("System process.\n"); 161: /* i.e. swapper or pagedaemon */ 162: continue; 163: } 164: sprintf(coref, "core.%d", pid); 165: if ((cor = creat(coref, 0666)) < 0) { 166: perror(coref); 167: exit(1); 168: } 169: core(p); 170: close(cor); 171: printf("%s dumped\n", coref); 172: } 173: } 174: 175: getw(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: } 293: getu(p, &p1[p->p_ssize]); /* u area */ 294: getseg(p, p->p_dsize, p0, &u.u_dmap, 0); /* data */ 295: getseg(p, p->p_ssize, p1, &u.u_smap, 1); /* stack */ 296: if (p->p_flag & SLOAD) { 297: free((char *) syspt); 298: free((char *) p0); 299: free((char *) p1); 300: } 301: } 302: 303: /* 304: * Get the u area. 305: * Keeps around the u structure for later use 306: * (the data and stack disk map structures). 307: */ 308: getu(p, pages) 309: register struct proc *p; 310: register struct pte *pages; 311: { 312: register int i; 313: 314: if ((p->p_flag & SLOAD) == 0) { 315: Get(swap, ctob(p->p_swaddr), uarea, ctob(UPAGES)); 316: write(cor, uarea, ctob(UPAGES)); 317: return; 318: } 319: for (i = 0; i < UPAGES; i += CLSIZE) { 320: Get(mem, ctob(pages[i].pg_pfnum), uarea[i], ctob(CLSIZE)); 321: write(cor, uarea[i], ctob(CLSIZE)); 322: } 323: } 324: 325: /* 326: * Copy a segment to the core file. 327: * The segment is described by its size in clicks, 328: * its page table, its disk map, and whether or not 329: * it grows backwards. 330: * Note that the page table address is allowed to be meaningless 331: * if the process is swapped out. 332: */ 333: getseg(p, segsize, pages, map, rev) 334: register struct proc *p; 335: int segsize; 336: register struct pte *pages; 337: struct dmap *map; 338: { 339: register int i; 340: struct dblock db; 341: int size; 342: char buf[ctob(CLSIZE)]; 343: 344: for (i = 0; i < segsize; i += CLSIZE) { 345: size = min(CLSIZE, segsize - i); 346: if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod || 347: pages[i].pg_pfnum == 0) { 348: vstodb(i, size, map, &db, rev); 349: Get(swap, ctob(db.db_base), buf, ctob(size)); 350: write(cor, buf, ctob(size)); 351: } else { 352: Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size)); 353: write(cor, buf, ctob(size)); 354: } 355: } 356: } 357: 358: /* 359: * Given a base/size pair in virtual swap area, 360: * return a physical base/size pair which is the 361: * (largest) initial, physically contiguous block. 362: */ 363: vstodb(vsbase, vssize, dmp, dbp, rev) 364: register int vsbase; 365: int vssize; 366: struct dmap *dmp; 367: register struct dblock *dbp; 368: { 369: register int blk = dmmin; 370: register swblk_t *ip = dmp->dm_map; 371: 372: if (vsbase < 0 || vsbase + vssize > dmp->dm_size) 373: panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)"); 374: while (vsbase >= blk) { 375: vsbase -= blk; 376: if (blk < dmmax) 377: blk *= 2; 378: ip++; 379: } 380: if (*ip <= 0 || *ip + blk > nswap) 381: panic("vstodb *ip"); 382: dbp->db_size = MIN(vssize, blk - vsbase); 383: dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); 384: } 385: 386: /*VARARGS1*/ 387: panic(cp, a, b, c, d) 388: char *cp; 389: { 390: printf(cp, a, b, c, d); 391: printf("\n"); 392: longjmp(cont_frame, 1); 393: } 394: 395: /* 396: * Debugging routine to print out page table. 397: */ 398: #ifdef DEBUG 399: showpt(pt, n, s) 400: struct pte *pt; 401: int n; 402: char *s; 403: { 404: register struct pte *p; 405: register int i; 406: 407: printf("*** %s page table\n", s); 408: for (i = 0, p = pt; i < n; i++, p++) 409: if (! p->pg_fod) 410: printf("%d: %x\n", i, p->pg_pfnum); 411: } 412: #endif