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