|
|
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.