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