|
|
1.1 root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.