date and time created 83/02/11 15:45:08 by rrh
[unix-history] / usr / src / usr.bin / gcore / gcore.c
CommitLineData
4f626618
KM
1/* Copyright (c) 1982 Regents of the University of California */
2
57ee57ff 3static char sccsid[] = "@(#)gcore.c 4.2 (Berkeley) %G%";
4f626618
KM
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>
57ee57ff 28#include <machine/pte.h>
4f626618
KM
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
51struct 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 { 0 },
63};
64
65#define FEW 20 /* for fewer system calls */
66struct proc proc[FEW];
67
68union {
69 struct user user;
70 char upages[UPAGES][NBPG];
71} user;
72#define u user.user
73#define uarea user.upages
74
75#define NLIST "/vmunix"
76#define KMEM "/dev/kmem"
77#define MEM "/dev/mem"
78#define SWAP "/dev/drum" /* "/dev/swap" on some systems */
79
80int nproc;
81int nswap;
82struct pte *Usrptmap, *usrpt;
83char coref[20];
84int kmem, mem, swap, cor;
85jmp_buf cont_frame;
86
87main(argc, argv)
88 int argc;
89 char **argv;
90{
91 register int i, j;
92 register struct proc *p;
93 off_t procbase, procp;
94 int pid, uid;
95 char c;
96
97 if (argc < 2) {
98 printf("Usage: %s pid ...\n", argv[0]);
99 exit(1);
100 }
101 openfiles();
102 getkvars();
103 procbase = getw(nl[X_PROC].n_value);
104 nproc = getw(nl[X_NPROC].n_value);
105 nswap = getw(nl[X_NSWAP].n_value);
106 while (--argc > 0) {
107 if ((pid = atoi(*++argv)) <= 0 || setjmp(cont_frame))
108 continue;
109 printf("%d: ", pid);
110 procp = procbase;
111 for (i = 0; i < nproc; i += FEW) {
112 Seek(kmem, procp);
113 j = nproc - i;
114 if (j > FEW)
115 j = FEW;
116 j *= sizeof(struct proc);
117 Read(kmem, (char *) proc, j);
118 procp += j;
119 for (j = j / sizeof(struct proc) - 1; j >= 0; j--) {
120 p = &proc[j];
121 if (p->p_pid == pid)
122 goto found;
123 }
124 }
125 printf("Process not found.\n");
126 continue;
127 found:
128 if (p->p_uid != (uid = getuid()) && uid != 0) {
129 printf("Not owner.\n");
130 continue;
131 }
132 if (p->p_stat == SZOMB) {
133 printf("Zombie.\n");
134 continue;
135 }
136 if (p->p_flag & SWEXIT) {
137 printf("Process exiting.\n");
138 continue;
139 }
140 if (p->p_flag & SSYS) {
141 printf("System process.\n");
142 /* i.e. swapper or pagedaemon */
143 continue;
144 }
145 sprintf(coref, "core.%d", pid);
146 if ((cor = creat(coref, 0666)) < 0) {
147 perror(coref);
148 exit(1);
149 }
150 core(p);
151 close(cor);
152 printf("%s dumped\n", coref);
153 }
154}
155
156getw(loc)
157 off_t loc;
158{
159 int word;
160
161 Get(kmem, loc, &word, sizeof(int));
162 return (word);
163}
164
165openfiles()
166{
167 kmem = open(KMEM, 0);
168 if (kmem < 0) {
169 perror(KMEM);
170 exit(1);
171 }
172 mem = open(MEM, 0);
173 if (mem < 0) {
174 perror(MEM);
175 exit(1);
176 }
177 swap = open(SWAP, 0);
178 if (swap < 0) {
179 perror(SWAP);
180 exit(1);
181 }
182}
183
184getkvars()
185{
186 nlist(NLIST, nl);
187 if (nl[0].n_type == 0) {
188 printf("%s: No namelist\n", NLIST);
189 exit(1);
190 }
191 Usrptmap = (struct pte *) nl[X_USRPTMA].n_value;
192 usrpt = (struct pte *) nl[X_USRPT].n_value;
193}
194
195/*
196 * Get the system page table entries (mapping the user page table).
197 * These are the entries Usrptmap[i .. i + szpt],
198 * where i = btokmx(p->p_p0br) and szpt = p->p_szpt.
199 * For our purposes, we can skip over the ptes mapping
200 * the text segment ptes.
201 */
202struct pte *syspt; /* pte's from Usrptmap */
203int nsysptes;
204
205getsyspt(p)
206 register struct proc *p;
207{
208 nsysptes = p->p_szpt - (p->p_tsize / NPTEPG);
209 syspt = (struct pte *) malloc(nsysptes * sizeof(struct pte));
210 if (syspt == NULL)
211 panic("can't alloc %d page table entries", nsysptes);
212 Get(kmem, &Usrptmap[btokmx(p->p_p0br) + (p->p_tsize / NPTEPG)],
213 syspt, nsysptes * sizeof(struct pte));
214}
215
216/*
217 * Get the user page table for a segment.
218 * seg 0 = p0 (not including text)
219 * seg 1 = p1 (stack and u area)
220 * The system pt is consulted to find each page of user ptes.
221 */
222struct pte *
223getpt(p, seg)
224 register struct proc *p;
225 int seg;
226{
227 register int i;
228 register struct pte *spt;
229 struct pte *pt;
230 int nptes, offset, n;
231
232 if (seg == 0) {
233 nptes = p->p_dsize;
234 spt = syspt;
235 offset = p->p_tsize % NPTEPG;
236 } else {
237 nptes = p->p_ssize + UPAGES;
238 spt = syspt + (nsysptes - ctopt(nptes));
239 offset = -nptes % NPTEPG;
240 if (offset < 0)
241 offset += NPTEPG;
242 }
243 pt = (struct pte *) malloc(nptes * sizeof(struct pte));
244 if (pt == NULL)
245 panic("can't alloc %d page table entries", nptes);
246 for (i = 0; i < nptes; i += n) {
247 n = min(NPTEPG - offset, nptes - i);
248 Get(mem, ctob(spt->pg_pfnum) + offset * sizeof(struct pte),
249 pt + i, n * sizeof(struct pte));
250 spt++;
251 offset = 0;
252 }
253 return (pt);
254}
255
256/*
257 * Build the core file.
258 */
259core(p)
260 register struct proc *p;
261{
262 register struct pte *p0, *p1;
263
264 if (p->p_flag & SLOAD) { /* page tables are resident */
265 getsyspt(p);
266 p0 = getpt(p, 0);
267 p1 = getpt(p, 1);
268#ifdef DEBUG
269 showpt(syspt, nsysptes, "system");
270 showpt(p0, p->p_dsize, "p0");
271 showpt(p1, p->p_ssize + UPAGES, "p1");
272#endif
273 }
274 getu(p, &p1[p->p_ssize]); /* u area */
275 getseg(p, p->p_dsize, p0, &u.u_dmap, 0); /* data */
276 getseg(p, p->p_ssize, p1, &u.u_smap, 1); /* stack */
277 if (p->p_flag & SLOAD) {
278 free((char *) syspt);
279 free((char *) p0);
280 free((char *) p1);
281 }
282}
283
284/*
285 * Get the u area.
286 * Keeps around the u structure for later use
287 * (the data and stack disk map structures).
288 */
289getu(p, pages)
290 register struct proc *p;
291 register struct pte *pages;
292{
293 register int i;
294
295 if ((p->p_flag & SLOAD) == 0) {
296 Get(swap, ctob(p->p_swaddr), uarea, ctob(UPAGES));
297 write(cor, uarea, ctob(UPAGES));
298 return;
299 }
300 for (i = 0; i < UPAGES; i += CLSIZE) {
301 Get(mem, ctob(pages[i].pg_pfnum), uarea[i], ctob(CLSIZE));
302 write(cor, uarea[i], ctob(CLSIZE));
303 }
304}
305
306/*
307 * Copy a segment to the core file.
308 * The segment is described by its size in clicks,
309 * its page table, its disk map, and whether or not
310 * it grows backwards.
311 * Note that the page table address is allowed to be meaningless
312 * if the process is swapped out.
313 */
314getseg(p, segsize, pages, map, rev)
315 register struct proc *p;
316 int segsize;
317 register struct pte *pages;
318 struct dmap *map;
319{
320 register int i;
321 struct dblock db;
322 int size;
323 char buf[ctob(CLSIZE)];
324
325 for (i = 0; i < segsize; i += CLSIZE) {
326 size = min(CLSIZE, segsize - i);
327 if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod ||
328 pages[i].pg_pfnum == 0) {
329 vstodb(i, size, map, &db, rev);
330 Get(swap, ctob(db.db_base), buf, ctob(size));
331 write(cor, buf, ctob(size));
332 } else {
333 Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size));
334 write(cor, buf, ctob(size));
335 }
336 }
337}
338
339/*
340 * Given a base/size pair in virtual swap area,
341 * return a physical base/size pair which is the
342 * (largest) initial, physically contiguous block.
343 */
344vstodb(vsbase, vssize, dmp, dbp, rev)
345 register int vsbase;
346 int vssize;
347 struct dmap *dmp;
348 register struct dblock *dbp;
349{
350 register int blk = DMMIN;
351 register swblk_t *ip = dmp->dm_map;
352
353 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
354 panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)");
355 while (vsbase >= blk) {
356 vsbase -= blk;
357 if (blk < DMMAX)
358 blk *= 2;
359 ip++;
360 }
361 if (*ip <= 0 || *ip + blk > nswap)
362 panic("vstodb *ip");
363 dbp->db_size = MIN(vssize, blk - vsbase);
364 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
365}
366
367/*VARARGS1*/
368panic(cp, a, b, c, d)
369 char *cp;
370{
371 printf(cp, a, b, c, d);
372 printf("\n");
373 longjmp(cont_frame, 1);
374}
375
376/*
377 * Debugging routine to print out page table.
378 */
379#ifdef DEBUG
380showpt(pt, n, s)
381 struct pte *pt;
382 int n;
383 char *s;
384{
385 register struct pte *p;
386 register int i;
387
388 printf("*** %s page table\n", s);
389 for (i = 0, p = pt; i < n; i++, p++)
390 if (! p->pg_fod)
391 printf("%d: %x\n", i, p->pg_pfnum);
392}
393#endif